struct field upgrades

This commit is contained in:
David Renshaw 2014-11-17 17:39:16 -05:00
parent a5f234136f
commit 57f8a5cdfc
2 changed files with 79 additions and 24 deletions

View file

@ -98,6 +98,43 @@ class EncodingSuite extends FunSuite {
root.getInt16Field() should equal (32767); root.getInt16Field() should equal (32767);
} }
test("UpgradeStructInBuilder") {
val builder = new MessageBuilder();
val root = builder.initRoot(TestAnyPointer.factory);
{
val oldVersion = root.getAnyPointerField().initAs(TestOldVersion.factory);
oldVersion.setOld1(123);
oldVersion.setOld2("foo");
val sub = oldVersion.initOld3();
sub.setOld1(456);
sub.setOld2("bar");
}
{
val newVersion = root.getAnyPointerField().getAs(TestNewVersion.factory);
newVersion.getOld1() should equal (123);
newVersion.getOld2().toString() should equal ("foo");
newVersion.getNew1() should equal (987);
newVersion.getNew2().toString() should equal ("baz");
val sub = newVersion.getOld3();
sub.getOld1() should equal (456);
sub.getOld2().toString() should equal ("bar");
newVersion.setOld1(234);
newVersion.setOld2("qux");
newVersion.setNew1(654);
newVersion.setNew2("quux");
}
{
val oldVersion = root.getAnyPointerField().getAs(TestOldVersion.factory);
oldVersion.getOld1() should equal (234);
oldVersion.getOld2.toString() should equal ("qux");
}
}
test("StructListUpgrade") { test("StructListUpgrade") {
val message = new MessageBuilder(); val message = new MessageBuilder();
val root = message.initRoot(TestAnyPointer.factory); val root = message.initRoot(TestAnyPointer.factory);
@ -254,27 +291,6 @@ class EncodingSuite extends FunSuite {
} }
} }
test("UpgradeStructInBuilder") {
val builder = new MessageBuilder();
val root = builder.initRoot(TestAnyPointer.factory);
val oldReader = {
val oldVersion = root.getAnyPointerField().initAs(TestOldVersion.factory);
oldVersion.setOld1(123);
oldVersion.setOld2("foo");
val sub = oldVersion.initOld3();
sub.setOld1(456);
sub.setOld2("bar");
oldVersion
}
{
//val newVersion = root.getAnyPointerField().getAsStruct(TestNewVersion.factory);
}
//...
}
test("Constants") { test("Constants") {
assert(Void.VOID == TestConstants.VOID_CONST); assert(Void.VOID == TestConstants.VOID_CONST);
assert(true == TestConstants.BOOL_CONST); assert(true == TestConstants.BOOL_CONST);

View file

@ -378,13 +378,52 @@ final class WireHelpers {
short oldDataSize = StructPointer.dataSize(resolved.ref); short oldDataSize = StructPointer.dataSize(resolved.ref);
short oldPointerCount = StructPointer.ptrCount(resolved.ref); short oldPointerCount = StructPointer.ptrCount(resolved.ref);
int oldPointerSectionOffset = resolved.ptr + oldDataSize; int oldPointerSection = resolved.ptr + oldDataSize;
if (oldDataSize < size.data || oldPointerCount < size.pointers) { if (oldDataSize < size.data || oldPointerCount < size.pointers) {
throw new Error("unimplemented"); //# The space allocated for this struct is too small. Unlike with readers, we can't just
//# run with it and do bounds checks at access time, because how would we handle writes?
//# Instead, we have to copy the struct to a new space now.
short newDataSize = (short)Math.max(oldDataSize, size.data);
short newPointerCount = (short)Math.max(oldPointerCount, size.pointers);
int totalSize = newDataSize + newPointerCount * Constants.WORDS_PER_POINTER;
//# Don't let allocate() zero out the object just yet.
zeroPointerAndFars(segment, refOffset);
AllocateResult allocation = allocate(refOffset, segment,
totalSize, WirePointer.STRUCT);
StructPointer.set(allocation.segment.buffer, allocation.refOffset,
newDataSize, newPointerCount);
//# Copy data section.
memcpy(allocation.segment.buffer, allocation.ptr * Constants.BYTES_PER_WORD,
resolved.segment.buffer, resolved.ptr * Constants.BYTES_PER_WORD,
oldDataSize * Constants.BYTES_PER_WORD);
//# Copy pointer section.
int newPointerSection = allocation.ptr + newDataSize;
for (int ii = 0; ii < oldPointerCount; ++ii) {
transferPointer(allocation.segment, newPointerSection + ii,
resolved.segment, oldPointerSection + ii);
}
//# Zero out old location. This has two purposes:
//# 1) We don't want to leak the original contents of the struct when the message is written
//# out as it may contain secrets that the caller intends to remove from the new copy.
//# 2) Zeros will be deflated by packing, making this dead memory almost-free if it ever
//# hits the wire.
memset(resolved.segment.buffer, resolved.ptr * Constants.BYTES_PER_WORD, (byte)0,
(oldDataSize + oldPointerCount * Constants.WORDS_PER_POINTER) * Constants.BYTES_PER_WORD);
return factory.constructBuilder(allocation.segment, allocation.ptr * Constants.BYTES_PER_WORD,
newPointerSection, newDataSize * Constants.BITS_PER_WORD,
newPointerCount);
} else { } else {
return factory.constructBuilder(resolved.segment, resolved.ptr * Constants.BYTES_PER_WORD, return factory.constructBuilder(resolved.segment, resolved.ptr * Constants.BYTES_PER_WORD,
oldPointerSectionOffset, oldDataSize * Constants.BITS_PER_WORD, oldPointerSection, oldDataSize * Constants.BITS_PER_WORD,
oldPointerCount); oldPointerCount);
} }