From df2233a52bfedf932ede64e951e14d9a23afd5d1 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Mon, 16 Jun 2014 19:46:33 -0400 Subject: [PATCH] followBuilderFars. does not pass unit tests yet --- .../scala/org/capnproto/EncodingTest.scala | 7 ++ .../main/java/org/capnproto/BuilderArena.java | 2 +- .../main/java/org/capnproto/FarPointer.java | 14 +++- .../main/java/org/capnproto/WireHelpers.java | 79 +++++++++++++------ 4 files changed, 78 insertions(+), 24 deletions(-) diff --git a/compiler/src/test/scala/org/capnproto/EncodingTest.scala b/compiler/src/test/scala/org/capnproto/EncodingTest.scala index 3c46499..f2a25de 100644 --- a/compiler/src/test/scala/org/capnproto/EncodingTest.scala +++ b/compiler/src/test/scala/org/capnproto/EncodingTest.scala @@ -14,4 +14,11 @@ class EncodingSuite extends FunSuite { TestUtil.checkTestMessage(allTypes); } + test("AllTypesMultiSegment") { + val message = new MessageBuilder(5, BuilderArena.AllocationStrategy.FIXED_SIZE); + val allTypes = message.initRoot(TestAllTypes.Builder.factory); + TestUtil.initTestMessage(allTypes); + //TestUtil.checkTestMessage(allTypes); + } + } diff --git a/runtime/src/main/java/org/capnproto/BuilderArena.java b/runtime/src/main/java/org/capnproto/BuilderArena.java index abf8fb5..6e7e61f 100644 --- a/runtime/src/main/java/org/capnproto/BuilderArena.java +++ b/runtime/src/main/java/org/capnproto/BuilderArena.java @@ -36,7 +36,7 @@ public final class BuilderArena implements Arena { throw new Error("unimplemented"); } public SegmentBuilder getSegment(int id) { - throw new Error("unimplemented"); + return this.segments.get(id); } public static class AllocateResult { diff --git a/runtime/src/main/java/org/capnproto/FarPointer.java b/runtime/src/main/java/org/capnproto/FarPointer.java index 65c8fa6..00af0be 100644 --- a/runtime/src/main/java/org/capnproto/FarPointer.java +++ b/runtime/src/main/java/org/capnproto/FarPointer.java @@ -3,7 +3,19 @@ package org.capnproto; import java.nio.ByteBuffer; final class FarPointer { - public static void set(ByteBuffer buffer, int offset, int segmentId) { + public static int getSegmentId(long ref) { + return WirePointer.upper32Bits(ref); + } + + public static int positionInSegment(long ref) { + return WirePointer.offsetAndKind(ref) >>> 3; + } + + public static boolean isDoubleFar(long ref) { + return ((WirePointer.offsetAndKind(ref) >>> 2) & 1) != 0; + } + + public static void setSegmentId(ByteBuffer buffer, int offset, int segmentId) { buffer.putInt(8 * offset + 4, segmentId); } } diff --git a/runtime/src/main/java/org/capnproto/WireHelpers.java b/runtime/src/main/java/org/capnproto/WireHelpers.java index 9b349b6..9f4938d 100644 --- a/runtime/src/main/java/org/capnproto/WireHelpers.java +++ b/runtime/src/main/java/org/capnproto/WireHelpers.java @@ -39,7 +39,7 @@ final class WireHelpers { //# Set up the original pointer to be a far pointer to //# the new segment. WirePointer.setKindAndTarget(segment.buffer, refOffset, WirePointer.FAR, allocation.offset); - FarPointer.set(segment.buffer, refOffset, allocation.segment.id); + FarPointer.setSegmentId(segment.buffer, refOffset, allocation.segment.id); //# Initialize the landing pad to indicate that the //# data immediately follows the pad. @@ -56,6 +56,46 @@ final class WireHelpers { } } + static class FollowBuilderFarsResult { + public final int ptr; + public final long ref; + public final SegmentBuilder segment; + FollowBuilderFarsResult(int ptr, long ref, SegmentBuilder segment) { + this.ptr = ptr; this.ref = ref; this.segment = segment; + } + } + + public static FollowBuilderFarsResult followBuilderFars(long ref, int refTarget, + SegmentBuilder segment) { + //# If `ref` is a far pointer, follow it. On return, `ref` will + //# have been updated to point at a WirePointer that contains + //# the type information about the target object, and a pointer + //# to the object contents is returned. The caller must NOT use + //# `ref->target()` as this may or may not actually return a + //# valid pointer. `segment` is also updated to point at the + //# segment which actually contains the object. + //# + //# If `ref` is not a far pointer, this simply returns + //# `refTarget`. Usually, `refTarget` should be the same as + //# `ref->target()`, but may not be in cases where `ref` is + //# only a tag. + + if (WirePointer.kind(ref) == WirePointer.FAR) { + SegmentBuilder resultSegment = segment.getArena().getSegment(FarPointer.getSegmentId(ref)); + + int padOffset = FarPointer.positionInSegment(ref); + long pad = WirePointer.get(resultSegment.buffer, padOffset); + if (! FarPointer.isDoubleFar(ref)) { + return new FollowBuilderFarsResult(WirePointer.target(padOffset, pad), pad, resultSegment); + } + + throw new Error("unimplemented"); + + } else { + return new FollowBuilderFarsResult(refTarget, ref, segment); + } + } + public static StructBuilder initStructPointer(int refOffset, SegmentBuilder segment, StructSize size) { @@ -74,20 +114,17 @@ final class WireHelpers { if (WirePointer.isNull(ref)) { return initStructPointer(refOffset, segment, size); } - long oldRef = ref; - SegmentBuilder oldSegment = segment; - // TODO follow fars. - int oldPtrOffset = target; + FollowBuilderFarsResult resolved = followBuilderFars(ref, target, segment); - short oldDataSize = StructPointer.dataSize(WirePointer.structPointer(oldRef)); - short oldPointerCount = StructPointer.ptrCount(WirePointer.structPointer(oldRef)); - int oldPointerSectionOffset = oldPtrOffset + oldDataSize; + short oldDataSize = StructPointer.dataSize(WirePointer.structPointer(resolved.ref)); + short oldPointerCount = StructPointer.ptrCount(WirePointer.structPointer(resolved.ref)); + int oldPointerSectionOffset = resolved.ptr + oldDataSize; if (oldDataSize < size.data || oldPointerCount < size.pointers) { throw new Error("unimplemented"); } else { - return new StructBuilder(oldSegment, oldPtrOffset * 8, - oldPointerSectionOffset, oldDataSize * 64, + return new StructBuilder(resolved.segment, resolved.ptr * Constants.BYTES_PER_WORD, + oldPointerSectionOffset, oldDataSize * Constants.BITS_PER_WORD, oldPointerCount, (byte)0); } @@ -163,15 +200,13 @@ final class WireHelpers { //# non-struct lists, and there is no allowed upgrade path *to* //# a non-struct list, only *from* them. - long ref = origRef; - SegmentBuilder segment = origSegment; - int ptr = origRefTarget; // TODO follow fars. + FollowBuilderFarsResult resolved = followBuilderFars(origRef, origRefTarget, origSegment); - if (WirePointer.kind(ref) != WirePointer.LIST) { + if (WirePointer.kind(resolved.ref) != WirePointer.LIST) { throw new DecodeException("Called getList{Field,Element}() but existing pointer is not a list"); } - byte oldSize = ListPointer.elementSize(WirePointer.listPointer(ref)); + byte oldSize = ListPointer.elementSize(WirePointer.listPointer(resolved.ref)); if (oldSize == FieldSize.INLINE_COMPOSITE) { //# The existing element size is InlineComposite, which @@ -196,8 +231,8 @@ final class WireHelpers { int step = dataSize + pointerCount * Constants.BITS_PER_POINTER; - return new ListBuilder(segment, ptr * Constants.BYTES_PER_WORD, - ListPointer.elementCount(WirePointer.listPointer(ref)), + return new ListBuilder(resolved.segment, resolved.ptr * Constants.BYTES_PER_WORD, + ListPointer.elementCount(WirePointer.listPointer(resolved.ref)), step, dataSize, (short) pointerCount); } } @@ -241,20 +276,20 @@ final class WireHelpers { } int refTarget = WirePointer.target(refOffset, ref); - int ptr = refTarget; + FollowBuilderFarsResult resolved = followBuilderFars(ref, refTarget, segment); - if (WirePointer.kind(ref) != WirePointer.LIST) { + if (WirePointer.kind(resolved.ref) != WirePointer.LIST) { throw new DecodeException("Called getText{Field,Element} but existing pointer is not a list."); } - if (ListPointer.elementSize(WirePointer.listPointer(ref)) != FieldSize.BYTE) { + if (ListPointer.elementSize(WirePointer.listPointer(resolved.ref)) != FieldSize.BYTE) { throw new DecodeException( "Called getText{Field,Element} but existing list pointer is not byte-sized."); } //# Subtract 1 from the size for the NUL terminator. - return new Text.Builder(segment.buffer, ptr * 8, - ListPointer.elementCount(WirePointer.listPointer(ref)) - 1); + return new Text.Builder(resolved.segment.buffer, resolved.ptr * Constants.BYTES_PER_WORD, + ListPointer.elementCount(WirePointer.listPointer(resolved.ref)) - 1); }