Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

imbue builders and readers with cap tables #131

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 54 additions & 12 deletions runtime/src/main/java/org/capnproto/AnyPointer.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,47 @@ public static final class Factory
public final Reader fromPointerReader(SegmentReader segment, int pointer, int nestingLimit) {
return new Reader(segment, pointer, nestingLimit);
}
public final Reader fromPointerReader(SegmentReader segment, CapTableReader capTable, int pointer, int nestingLimit) {
return new Reader(segment, capTable, pointer, nestingLimit);
}
public final Builder fromPointerBuilder(SegmentBuilder segment, int pointer) {
return new Builder(segment, pointer);
}
public final Builder fromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer) {
return new Builder(segment, capTable, pointer);
}
public final Builder initFromPointerBuilder(SegmentBuilder segment, int pointer, int elementCount) {
Builder result = new Builder(segment, pointer);
result.clear();
return result;
}
public final Builder initFromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, int elementCount) {
Builder result = new Builder(segment, capTable, pointer);
result.clear();
return result;
}
public void setPointerBuilder(SegmentBuilder segment, int pointer, Reader value) {
if (value.isNull()) {
WireHelpers.zeroObject(segment, pointer);
WireHelpers.zeroObject(segment, null, pointer);
WireHelpers.zeroPointerAndFars(segment, pointer);
}
else {
WireHelpers.copyPointer(segment, pointer, value.segment, value.pointer, value.nestingLimit);
WireHelpers.copyPointer(segment, null, pointer, value.segment, value.capTable, value.pointer, value.nestingLimit);
}
}
public void setPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, Reader value) {
if (value.isNull()) {
WireHelpers.zeroObject(segment, capTable, pointer);
WireHelpers.zeroPointerAndFars(segment, pointer);
}
else {
WireHelpers.copyPointer(segment, capTable, pointer, value.segment, value.capTable, value.pointer, value.nestingLimit);
}
}
}
public static final Factory factory = new Factory();

public final static class Reader {
public final static class Reader extends CapTableReader.ReaderContext {
final SegmentReader segment;
final int pointer; // offset in words
final int nestingLimit;
Expand All @@ -60,16 +80,29 @@ public Reader(SegmentReader segment, int pointer, int nestingLimit) {
this.nestingLimit = nestingLimit;
}

public Reader(SegmentReader segment, CapTableReader capTable, int pointer, int nestingLimit) {
this.segment = segment;
this.pointer = pointer;
this.nestingLimit = nestingLimit;
this.capTable = capTable;
}

final Reader imbue(CapTableReader capTable) {
Reader result = new Reader(segment, pointer, nestingLimit);
result.capTable = capTable;
return result;
}

public final boolean isNull() {
return WirePointer.isNull(this.segment.buffer.getLong(this.pointer * Constants.BYTES_PER_WORD));
}

public final <T> T getAs(FromPointerReader<T> factory) {
return factory.fromPointerReader(this.segment, this.pointer, this.nestingLimit);
return factory.fromPointerReader(this.segment, this.capTable, this.pointer, this.nestingLimit);
}
}

public static final class Builder {
public static final class Builder extends CapTableBuilder.BuilderContext {
final SegmentBuilder segment;
final int pointer;

Expand All @@ -78,34 +111,43 @@ public Builder(SegmentBuilder segment, int pointer) {
this.pointer = pointer;
}

Builder(SegmentBuilder segment, CapTableBuilder capTable, int pointer) {
this.segment = segment;
this.pointer = pointer;
this.capTable = capTable;
}

final Builder imbue(CapTableBuilder capTable) {
return new Builder(segment, capTable, pointer);
}

public final boolean isNull() {
return WirePointer.isNull(this.segment.buffer.getLong(this.pointer * Constants.BYTES_PER_WORD));
}

public final <T> T getAs(FromPointerBuilder<T> factory) {
return factory.fromPointerBuilder(this.segment, this.pointer);
return factory.fromPointerBuilder(this.segment, this.capTable, this.pointer);
}

public final <T> T initAs(FromPointerBuilder<T> factory) {
return factory.initFromPointerBuilder(this.segment, this.pointer, 0);
return factory.initFromPointerBuilder(this.segment, this.capTable, this.pointer, 0);
}

public final <T> T initAs(FromPointerBuilder<T> factory, int elementCount) {
return factory.initFromPointerBuilder(this.segment, this.pointer, elementCount);
return factory.initFromPointerBuilder(this.segment, this.capTable, this.pointer, elementCount);
}

public final <T, U> void setAs(SetPointerBuilder<T, U> factory, U reader) {
factory.setPointerBuilder(this.segment, this.pointer, reader);
factory.setPointerBuilder(this.segment, this.capTable, this.pointer, reader);
}

public final Reader asReader() {
return new Reader(segment, pointer, java.lang.Integer.MAX_VALUE);
return new Reader(segment, this.capTable, pointer, java.lang.Integer.MAX_VALUE);
}

public final void clear() {
WireHelpers.zeroObject(this.segment, this.pointer);
WireHelpers.zeroObject(this.segment, this.capTable, this.pointer);
this.segment.buffer.putLong(this.pointer * 8, 0L);
}
}

}
41 changes: 40 additions & 1 deletion runtime/src/main/java/org/capnproto/BuilderArena.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;

public final class BuilderArena implements Arena {
public enum AllocationStrategy {
Expand All @@ -38,6 +39,34 @@ public enum AllocationStrategy {
public final ArrayList<SegmentBuilder> segments;
private final Allocator allocator;

private final CapTableBuilder localCapTable = new CapTableBuilder() {

private final List<ClientHook> capTable = new ArrayList<>();

@Override
public int injectCap(ClientHook cap) {
int result = this.capTable.size();
this.capTable.add(cap);
return result;
}

@Override
public void dropCap(int index) {
if (index >= this.capTable.size()) {
assert false : "Invalid capability descriptor in message.";
return;
}
this.capTable.set(index, null);
}

@Override
public ClientHook extractCap(int index) {
return index < this.capTable.size()
? this.capTable.get(index)
: null;
}
};

public BuilderArena(int firstSegmentSizeWords, AllocationStrategy allocationStrategy) {
this.segments = new ArrayList<SegmentBuilder>();
{
Expand All @@ -64,7 +93,17 @@ public BuilderArena(Allocator allocator, ByteBuffer firstSegment) {
this.allocator = allocator;
}

/**
/**
* Return a CapTableBuilder that merely implements local loopback. That is, you can set
* capabilities, then read the same capabilities back, but there is no intent ever to transmit
* these capabilities. A MessageBuilder that isn't imbued with some other CapTable uses this
* by default.
*/
public CapTableBuilder getLocalCapTable() {
return this.localCapTable;
}

/**
* Constructs a BuilderArena from a ReaderArena and uses the size of the largest segment
* as the next allocation size.
*/
Expand Down
16 changes: 16 additions & 0 deletions runtime/src/main/java/org/capnproto/CapTableBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.capnproto;

public interface CapTableBuilder extends CapTableReader {

class BuilderContext {
public CapTableBuilder capTable;
}

int injectCap(ClientHook cap);

void dropCap(int index);

default ClientHook[] getTable() {
return new ClientHook[0];
}
}
10 changes: 10 additions & 0 deletions runtime/src/main/java/org/capnproto/CapTableReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.capnproto;

public interface CapTableReader {

class ReaderContext {
public CapTableReader capTable;
}

ClientHook extractCap(int index);
}
24 changes: 24 additions & 0 deletions runtime/src/main/java/org/capnproto/Capability.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.capnproto;

import static org.capnproto.ClientHook.BROKEN_CAPABILITY_BRAND;
import static org.capnproto.ClientHook.NULL_CAPABILITY_BRAND;

public final class Capability {

public static ClientHook newBrokenCap(String reason) {
return newBrokenClient(BROKEN_CAPABILITY_BRAND);
}

public static ClientHook newNullCap() {
return newBrokenClient(NULL_CAPABILITY_BRAND);
}

private static ClientHook newBrokenClient(Object brand) {
return new ClientHook() {
@Override
public Object getBrand() {
return brand;
}
};
}
}
29 changes: 29 additions & 0 deletions runtime/src/main/java/org/capnproto/ClientHook.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.capnproto;

public interface ClientHook {

static final Object NULL_CAPABILITY_BRAND = new Object();
static final Object BROKEN_CAPABILITY_BRAND = new Object();

/**
Returns an opaque object that identifies who made this client. This can be used by an RPC adapter to
discover when a capability it needs to marshal is one that it created in the first place, and
therefore it can transfer the capability without proxying.
*/
Object getBrand();

/**
* Returns true if the capability was created as a result of assigning a Client to null or by
* reading a null pointer out of a Cap'n Proto message.
*/
default boolean isNull() {
return getBrand() == NULL_CAPABILITY_BRAND;
}

/**
* Returns true if the capability was created by newBrokenCap().
*/
default boolean isError() {
return getBrand() == BROKEN_CAPABILITY_BRAND;
}
}
19 changes: 13 additions & 6 deletions runtime/src/main/java/org/capnproto/Data.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,35 +39,42 @@ public final Reader fromPointerReader(SegmentReader segment, int pointer, int ne
return WireHelpers.readDataPointer(segment, pointer, null, 0, 0);
}

@Override
public final Reader fromPointerReader(SegmentReader segment, CapTableReader capTable, int pointer, int nestingLimit) {
return WireHelpers.readDataPointer(segment, pointer, null, 0, 0);
}

@Override
public final Builder fromPointerBuilderBlobDefault(
SegmentBuilder segment,
CapTableBuilder capTable,
int pointer,
java.nio.ByteBuffer defaultBuffer,
int defaultOffset,
int defaultSize) {
return WireHelpers.getWritableDataPointer(pointer,
segment,
capTable,
defaultBuffer,
defaultOffset,
defaultSize);
}

@Override
public final Builder fromPointerBuilder(SegmentBuilder segment, int pointer) {
public final Builder fromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer) {
return WireHelpers.getWritableDataPointer(pointer,
segment,
capTable,
null, 0, 0);
}

@Override
public final Builder initFromPointerBuilder(SegmentBuilder segment, int pointer, int size) {
return WireHelpers.initDataPointer(pointer, segment, size);
public final Builder initFromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, int size) {
return WireHelpers.initDataPointer(pointer, segment, capTable, size);
}

@Override
public final void setPointerBuilder(SegmentBuilder segment, int pointer, Reader value) {
WireHelpers.setDataPointer(pointer, segment, value);
public final void setPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, Reader value) {
WireHelpers.setDataPointer(pointer, segment, capTable, value);
}
}
public static final Factory factory = new Factory();
Expand Down
13 changes: 11 additions & 2 deletions runtime/src/main/java/org/capnproto/FromPointerBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@
package org.capnproto;

public interface FromPointerBuilder<T> {
T fromPointerBuilder(SegmentBuilder segment, int pointer);
T initFromPointerBuilder(SegmentBuilder segment, int pointer, int elementCount);
default T fromPointerBuilder(SegmentBuilder segment, int pointer) {
return fromPointerBuilder(segment, null, pointer);
}

T fromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer);

default T initFromPointerBuilder(SegmentBuilder segment, int pointer, int elementCount) {
return initFromPointerBuilder(segment, null, pointer, elementCount);
}

T initFromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, int elementCount);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
package org.capnproto;

public interface FromPointerBuilderBlobDefault<T> {
T fromPointerBuilderBlobDefault(SegmentBuilder segment, int pointer,
default T fromPointerBuilderBlobDefault(SegmentBuilder segment, int pointer,
java.nio.ByteBuffer defaultBuffer, int defaultOffset, int defaultSize) {
return fromPointerBuilderBlobDefault(segment, null, pointer, defaultBuffer, defaultOffset, defaultSize);
}

T fromPointerBuilderBlobDefault(SegmentBuilder segment, CapTableBuilder capTable, int pointer,
java.nio.ByteBuffer defaultBuffer, int defaultOffset, int defaultSize);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,10 @@
package org.capnproto;

public interface FromPointerBuilderRefDefault<T> {
T fromPointerBuilderRefDefault(SegmentBuilder segment, int pointer, SegmentReader defaultSegment, int defaultOffset);

default T fromPointerBuilderRefDefault(SegmentBuilder segment, int pointer, SegmentReader defaultSegment, int defaultOffset) {
return fromPointerBuilderRefDefault(segment, null, pointer, defaultSegment, defaultOffset);
}

T fromPointerBuilderRefDefault(SegmentBuilder segment, CapTableBuilder capTable, int pointer, SegmentReader defaultSegment, int defaultOffset);
}
5 changes: 4 additions & 1 deletion runtime/src/main/java/org/capnproto/FromPointerReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@
package org.capnproto;

public interface FromPointerReader<T> {
T fromPointerReader(SegmentReader segment, int pointer, int nestingLimit);
default T fromPointerReader(SegmentReader segment, int pointer, int nestingLimit) {
return fromPointerReader(segment, null, pointer, nestingLimit);
}
T fromPointerReader(SegmentReader segment, CapTableReader capTable, int pointer, int nestingLimit);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@
package org.capnproto;

public interface FromPointerReaderRefDefault<T> {
T fromPointerReaderRefDefault(SegmentReader segment, int pointer, SegmentReader defaultSegment, int defaultOffset, int nestingLimit);
default T fromPointerReaderRefDefault(SegmentReader segment, int pointer, SegmentReader defaultSegment, int defaultOffset, int nestingLimit) {
return fromPointerReaderRefDefault(segment, null, pointer, defaultSegment, defaultOffset, nestingLimit);
}
T fromPointerReaderRefDefault(SegmentReader segment, CapTableReader capTable, int pointer, SegmentReader defaultSegment, int defaultOffset, int nestingLimit);
}
Loading