From b63cfb11f1ed806b042b6a149a85c0c7803f1214 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sun, 15 Jun 2014 16:38:26 -0400 Subject: [PATCH] BuilderArena.allocate --- .../main/java/org/capnproto/BuilderArena.java | 30 +++++++++++++++---- .../java/org/capnproto/MessageReader.java | 2 +- .../java/org/capnproto/SegmentBuilder.java | 15 ++++++++-- .../java/org/capnproto/SegmentReader.java | 5 +++- .../main/java/org/capnproto/WireHelpers.java | 12 +++++--- .../test/scala/org/capnproto/LayoutTest.scala | 7 +++-- 6 files changed, 54 insertions(+), 17 deletions(-) diff --git a/runtime/src/main/java/org/capnproto/BuilderArena.java b/runtime/src/main/java/org/capnproto/BuilderArena.java index cb0da8a..5734725 100644 --- a/runtime/src/main/java/org/capnproto/BuilderArena.java +++ b/runtime/src/main/java/org/capnproto/BuilderArena.java @@ -2,7 +2,7 @@ package org.capnproto; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.util.Vector; +import java.util.ArrayList; public final class BuilderArena implements Arena { @@ -15,19 +15,18 @@ public final class BuilderArena implements Arena { public static final AllocationStrategy SUGGESTED_ALLOCATION_STRATEGY = AllocationStrategy.GROW_HEURISTICALLY; - // Maybe this should be ArrayList? - public final Vector segments; + public final ArrayList segments; public int nextSize; public final AllocationStrategy allocationStrategy; public BuilderArena(int firstSegmentSizeWords, AllocationStrategy allocationStrategy) { - this.segments = new Vector(); + this.segments = new ArrayList(); this.nextSize = firstSegmentSizeWords; this.allocationStrategy = allocationStrategy; SegmentBuilder segment0 = new SegmentBuilder( - ByteBuffer.allocate(firstSegmentSizeWords * Constants.BYTES_PER_WORD)); + ByteBuffer.allocate(firstSegmentSizeWords * Constants.BYTES_PER_WORD), this); segment0.buffer.mark(); segment0.buffer.order(ByteOrder.LITTLE_ENDIAN); this.segments.add(segment0); @@ -42,7 +41,10 @@ public final class BuilderArena implements Arena { public static class AllocateResult { public final SegmentBuilder segment; + + // offset to the beginning the of allocated memory public final int offset; + public AllocateResult(SegmentBuilder segment, int offset) { this.segment = segment; this.offset = offset; @@ -50,7 +52,23 @@ public final class BuilderArena implements Arena { } public AllocateResult allocate(int amount) { - throw new Error("unimplemented"); + + int len = this.segments.size(); + // we allocate the first segment in the constructor. + + int result = this.segments.get(len - 1).allocate(amount); + if (result != SegmentBuilder.FAILED_ALLOCATION) { + return new AllocateResult(this.segments.get(len - 1), result); + } + + SegmentBuilder newSegment = new SegmentBuilder( + ByteBuffer.allocate(amount * Constants.BYTES_PER_WORD), + this); + newSegment.buffer.mark(); + newSegment.buffer.order(ByteOrder.LITTLE_ENDIAN); + this.segments.add(newSegment); + + return new AllocateResult(newSegment, newSegment.allocate(amount)); } public final ByteBuffer[] getSegmentsForOutput() { diff --git a/runtime/src/main/java/org/capnproto/MessageReader.java b/runtime/src/main/java/org/capnproto/MessageReader.java index 9f0d2b5..3aed7ce 100644 --- a/runtime/src/main/java/org/capnproto/MessageReader.java +++ b/runtime/src/main/java/org/capnproto/MessageReader.java @@ -10,7 +10,7 @@ public final class MessageReader { } public T getRoot(FromStructReader factory) { - SegmentReader segment = new SegmentReader(this.segmentSlices[0]); + SegmentReader segment = new SegmentReader(this.segmentSlices[0], new ReaderArena()); PointerReader pointerReader = PointerReader.getRoot(segment, 0, 0x7fffffff /* XXX */); AnyPointer.Reader any = new AnyPointer.Reader(pointerReader); diff --git a/runtime/src/main/java/org/capnproto/SegmentBuilder.java b/runtime/src/main/java/org/capnproto/SegmentBuilder.java index 5b87aff..38581ff 100644 --- a/runtime/src/main/java/org/capnproto/SegmentBuilder.java +++ b/runtime/src/main/java/org/capnproto/SegmentBuilder.java @@ -3,12 +3,13 @@ package org.capnproto; import java.nio.ByteBuffer; public final class SegmentBuilder extends SegmentReader { + public static final int FAILED_ALLOCATION = -1; public int pos = 0; // in words - public SegmentBuilder(ByteBuffer buf) { - super(buf); + public SegmentBuilder(ByteBuffer buf, Arena arena) { + super(buf, arena); } // the total number of words the buffer can hold @@ -22,10 +23,14 @@ public final class SegmentBuilder extends SegmentReader { return this.pos; } - /** + /* Allocate `amount` words. */ public final int allocate(int amount) { + if (amount < 0) { + throw new InternalError("tried to allocate a negative number of words"); + } + if (amount > this.capacity() - this.currentSize()) { return FAILED_ALLOCATION; // no space left; } else { @@ -34,4 +39,8 @@ public final class SegmentBuilder extends SegmentReader { return result; } } + + public final BuilderArena getArena() { + return (BuilderArena)this.arena; + } } diff --git a/runtime/src/main/java/org/capnproto/SegmentReader.java b/runtime/src/main/java/org/capnproto/SegmentReader.java index fcf5d3a..7a59e2e 100644 --- a/runtime/src/main/java/org/capnproto/SegmentReader.java +++ b/runtime/src/main/java/org/capnproto/SegmentReader.java @@ -7,7 +7,10 @@ public class SegmentReader { // invariant: buffer's mark is at its beginning. final ByteBuffer buffer; - public SegmentReader(ByteBuffer buffer) { + final Arena arena; + + public SegmentReader(ByteBuffer buffer, Arena arena) { this.buffer = buffer; + this.arena = arena; } } diff --git a/runtime/src/main/java/org/capnproto/WireHelpers.java b/runtime/src/main/java/org/capnproto/WireHelpers.java index 03c6152..96d8bb0 100644 --- a/runtime/src/main/java/org/capnproto/WireHelpers.java +++ b/runtime/src/main/java/org/capnproto/WireHelpers.java @@ -18,15 +18,19 @@ final class WireHelpers { // TODO check for nullness, amount == 0 case. - int allocation = segment.allocate(amount); - if (allocation == SegmentBuilder.FAILED_ALLOCATION) { + int ptr = segment.allocate(amount); + if (ptr == SegmentBuilder.FAILED_ALLOCATION) { //# Need to allocate in a new segment. We'll need to //# allocate an extra pointer worth of space to act as //# the landing pad for a far pointer. + + int amountPlusRef = amount + Constants.POINTER_SIZE_IN_WORDS; + BuilderArena.AllocateResult allocation = segment.getArena().allocate(amountPlusRef); + throw new Error("unimplemented"); } else { - WirePointer.setKindAndTarget(segment.buffer, refOffset, kind, allocation); - return allocation; + WirePointer.setKindAndTarget(segment.buffer, refOffset, kind, ptr); + return ptr; } } diff --git a/runtime/src/test/scala/org/capnproto/LayoutTest.scala b/runtime/src/test/scala/org/capnproto/LayoutTest.scala index d149dae..fa1b639 100644 --- a/runtime/src/test/scala/org/capnproto/LayoutTest.scala +++ b/runtime/src/test/scala/org/capnproto/LayoutTest.scala @@ -13,7 +13,7 @@ class LayoutSuite extends FunSuite { val buffer = java.nio.ByteBuffer.wrap(data); buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN); - val pointerReader = new PointerReader(new SegmentReader(buffer), 0, 0x7fffffff); + val pointerReader = new PointerReader(new SegmentReader(buffer, new ReaderArena()), 0, 0x7fffffff); val reader = pointerReader.getStruct(); assert(reader.getLongField(0) === 0xefcdab8967452301L); @@ -91,7 +91,10 @@ class LayoutSuite extends FunSuite { buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN); buffer.mark(); - val pointerBuilder = PointerBuilder.getRoot(new SegmentBuilder(buffer), 0); + val pointerBuilder = PointerBuilder.getRoot( + new SegmentBuilder(buffer, new BuilderArena(BuilderArena.SUGGESTED_FIRST_SEGMENT_WORDS, + BuilderArena.SUGGESTED_ALLOCATION_STRATEGY)), + 0); val builder = pointerBuilder.initStruct(new StructSize(2, 4, FieldSize.INLINE_COMPOSITE)); setupStruct(builder);