Skip to content

Commit

Permalink
Proof-of-concept for a flatbuffer-based interpreter.
Browse files Browse the repository at this point in the history
This is a first attempt at a buffer that uses flatbuffers to
execute directly from disk. Enough instructions and operands are
implemented for a simple "hello world" but there's a few corners
cut for simplicity.

Much will need to be improved for this to be viable, but it shows
promise that I could get something working in a basic form this
quickly.

* Most tables from the buffer are created new every time. A better
  approach would be to have a pool of these table objects that
  can be reused within a given interpreter frame without
  reallocating on every entry or every operation.
* I have glossed over some details of how calls work, but the
  basics are there.
* This implementation will lead to the "big switch" problem we
  have seen impact straight-line performance in previous
  interpreters. However, since this is not intended to be the
  "fast" way to run Ruby code (the goal is starting up without
  parsing and compiling Ruby code) it may not be important.

Here's an example run:

```
$ java -Djruby.home=`pwd` -cp lib/jruby.jar org.jruby.ir.persistence.flat.FlatIRInterpreter 'puts "Hello, flatbuffers!"'
Hello, flatbuffers!
```
headius committed Jun 7, 2016
1 parent ecdf4fd commit fb5a31c
Showing 26 changed files with 953 additions and 127 deletions.
14 changes: 7 additions & 7 deletions core/src/main/java/org/jruby/ir/Operation.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.jruby.ir;

import org.jruby.ir.persistence.flat.OperationFlat;
import org.jruby.ir.persistence.flat.InstrUnion;

class OpFlags {
final static int f_has_side_effect = 0x00001; // Used by analyses
@@ -44,7 +44,7 @@ public enum Operation {
B_FALSE(OpFlags.f_is_jump_or_branch),

/** argument receive in methods and blocks **/
RECV_SELF(0, OperationFlat.RECEIVE_SELF),
RECV_SELF(0, InstrUnion.ReceiveSelfFlat),
RECV_PRE_REQD_ARG(OpFlags.f_is_arg_receive),
RECV_POST_REQD_ARG(OpFlags.f_is_arg_receive),
RECV_KW_ARG(OpFlags.f_is_arg_receive),
@@ -57,7 +57,7 @@ public enum Operation {

/** Instruction to reify an passed-in block to a Proc for def foo(&b) */
REIFY_CLOSURE(0),
LOAD_FRAME_CLOSURE(0, OperationFlat.LOAD_FRAME_CLOSURE),
LOAD_FRAME_CLOSURE(0, InstrUnion.LoadFrameClosureFlat),

/* By default, call instructions cannot be deleted even if their results
* aren't used by anyone unless we know more about what the call is,
@@ -76,7 +76,7 @@ public enum Operation {
/* specialized calls */
CALL_1F(OpFlags.f_has_side_effect | OpFlags.f_is_call | OpFlags.f_can_raise_exception),
CALL_1D(OpFlags.f_has_side_effect | OpFlags.f_is_call | OpFlags.f_can_raise_exception),
CALL_1O(OpFlags.f_has_side_effect | OpFlags.f_is_call | OpFlags.f_can_raise_exception, OperationFlat.CALL_1_OBJ),
CALL_1O(OpFlags.f_has_side_effect | OpFlags.f_is_call | OpFlags.f_can_raise_exception, InstrUnion.CallFlat),
CALL_1OB(OpFlags.f_has_side_effect | OpFlags.f_is_call | OpFlags.f_can_raise_exception),
CALL_0O(OpFlags.f_has_side_effect | OpFlags.f_is_call | OpFlags.f_can_raise_exception),
NORESULT_CALL_1O(OpFlags.f_has_side_effect | OpFlags.f_is_call | OpFlags.f_can_raise_exception),
@@ -90,7 +90,7 @@ public enum Operation {
YIELD(OpFlags.f_has_side_effect | OpFlags.f_can_raise_exception),

/** returns -- returns unwind stack, etc. */
RETURN(OpFlags.f_has_side_effect | OpFlags.f_is_return, OperationFlat.RETURN),
RETURN(OpFlags.f_has_side_effect | OpFlags.f_is_return, InstrUnion.ReturnFlat),
/* These two insructions use exceptions to exit closures
* BREAK is a return because it can only be used within closures
* and the net result is to return from the closure. */
@@ -140,7 +140,7 @@ public enum Operation {
PUT_FIELD(OpFlags.f_is_store | OpFlags.f_has_side_effect | OpFlags.f_can_raise_exception),

/** debugging ops **/
LINE_NUM(OpFlags.f_is_book_keeping_op | OpFlags.f_is_debug_op, OperationFlat.LINE_NUMBER),
LINE_NUM(OpFlags.f_is_book_keeping_op | OpFlags.f_is_debug_op, InstrUnion.LineNumberFlat),
TRACE(OpFlags.f_is_book_keeping_op | OpFlags.f_is_debug_op | OpFlags.f_has_side_effect),

/** JRuby-impl instructions **/
@@ -158,7 +158,7 @@ public enum Operation {
CHECK_ARITY(OpFlags.f_is_book_keeping_op | OpFlags.f_can_raise_exception),
CHECK_FOR_LJE(OpFlags.f_has_side_effect | OpFlags.f_can_raise_exception),
CLASS_VAR_MODULE(0),
COPY(0, OperationFlat.COPY),
COPY(0, InstrUnion.CopyFlat),
GET_ENCODING(0),
MASGN_OPT(0),
MASGN_REQD(0),
32 changes: 32 additions & 0 deletions core/src/main/java/org/jruby/ir/instructions/CallBase.java
Original file line number Diff line number Diff line change
@@ -6,6 +6,11 @@
import org.jruby.ir.operands.*;
import org.jruby.ir.operands.Float;
import org.jruby.ir.persistence.IRWriterEncoder;
import org.jruby.ir.persistence.flat.CallFlat;
import org.jruby.ir.persistence.flat.FlatIRInterpreter;
import org.jruby.ir.persistence.flat.FlatIRWriter;
import org.jruby.ir.persistence.flat.InstrFlat;
import org.jruby.ir.persistence.flat.OperandFlat;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.parser.StaticScope;
@@ -461,4 +466,31 @@ public Block prepareBlock(ThreadContext context, IRubyObject self, StaticScope c

return IRRuntimeHelpers.getBlockFromObject(context, getClosureArg().retrieve(context, self, currScope, currDynScope, temp));
}

public static Object interpret(InstrFlat instrFlat, CallFlat callFlat, ThreadContext context, StaticScope currScope, DynamicScope dynamicScope, IRubyObject self, Object[] temp) {
IRubyObject object = (IRubyObject) FlatIRInterpreter.interpretOperand(instrFlat.operands(0), context, currScope, dynamicScope, self, temp);
IRubyObject[] values = prepareArguments(instrFlat, callFlat, context, self, currScope, dynamicScope, temp);
// Block preparedBlock = prepareBlock(context, self, currScope, dynamicScope, temp);

return object.callMethod(context, callFlat.name(), values/*, preparedBlock*/);
}

protected static IRubyObject[] prepareArguments(InstrFlat instrFlat, CallFlat callFlat, ThreadContext context, IRubyObject self, StaticScope currScope, DynamicScope dynamicScope, Object[] temp) {
// if (call.splatMapLength() > 0) {
// return prepareArgumentsComplex(context, self, currScope, dynamicScope, temp);
// }

return prepareArgumentsSimple(instrFlat, callFlat, context, self, currScope, dynamicScope, temp);
}

protected static IRubyObject[] prepareArgumentsSimple(InstrFlat instr, CallFlat call, ThreadContext context, IRubyObject self, StaticScope currScope, DynamicScope currDynScope, Object[] temp) {
IRubyObject[] newArgs = new IRubyObject[call.argsCount()];

OperandFlat operandFlat = new OperandFlat();
for (int i = 0; i < call.argsCount(); i++) { // receiver is operands[0]
newArgs[i] = (IRubyObject) FlatIRInterpreter.interpretOperand(instr.operands(operandFlat, i+1), context, currScope, currDynScope, self, temp);
}

return newArgs;
}
}
14 changes: 7 additions & 7 deletions core/src/main/java/org/jruby/ir/operands/OperandType.java
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
*/
package org.jruby.ir.operands;

import org.jruby.ir.persistence.flat.OperandTypeFlat;
import org.jruby.ir.persistence.flat.OperandUnion;

public enum OperandType {

@@ -14,7 +14,7 @@ public enum OperandType {
BIGNUM("big", (byte) 'B'),
BOOLEAN("bool", (byte) 'b'),
COMPLEX("com", (byte) 'C'),
CURRENT_SCOPE("scope", (byte) 's', OperandTypeFlat.CURRENT_SCOPE),
CURRENT_SCOPE("scope", (byte) 's', OperandUnion.CurrentScopeFlat),
DYNAMIC_SYMBOL("dsym", (byte) 'd'),
FIXNUM("fix", (byte) 'f'),
FLOAT("flo", (byte) 'F'),
@@ -29,21 +29,21 @@ public enum OperandType {
RANGE("rng", (byte) '.'),
RATIONAL("rat", (byte) 'r'),
REGEXP("reg", (byte) '/'),
SCOPE_MODULE("mod", (byte) '_', OperandTypeFlat.SCOPE_MODULE),
SELF("self", (byte) 'S', OperandTypeFlat.SELF),
SCOPE_MODULE("mod", (byte) '_', OperandUnion.ScopeModuleFlat),
SELF("self", (byte) 'S', OperandUnion.SelfFlat),
SPLAT("splat", (byte) '*'),
STANDARD_ERROR("stderr", (byte) 'E'),
STRING_LITERAL("str", (byte) '\'', OperandTypeFlat.STRING_LITERAL),
STRING_LITERAL("str", (byte) '\'', OperandUnion.StringLiteralFlat),
SVALUE("sval", (byte) 'V'),
SYMBOL("sym", (byte) ':'),
TEMPORARY_VARIABLE("reg", (byte) 't', OperandTypeFlat.TEMPORARY_VARIABLE),
TEMPORARY_VARIABLE("reg", (byte) 't', OperandUnion.TemporaryVariableFlat),
UNBOXED_BOOLEAN("rawbool", (byte) 'v'),
UNBOXED_FIXNUM("rawfix", (byte) 'j'),
UNBOXED_FLOAT("rawflo", (byte) 'J'),
UNDEFINED_VALUE("undef", (byte) 'u'),
UNEXECUTABLE_NIL("noex", (byte) 'n'),
WRAPPED_IR_CLOSURE("block", (byte) 'w'),
FROZEN_STRING("fstr", (byte) 'z'),
FROZEN_STRING("fstr", (byte) 'z', OperandUnion.FrozenStringFlat),
NULL_BLOCK("noblock", (byte) 'o'),
FILENAME("file", (byte) 'm'),
SYMBOL_PROC("symproc", (byte) 'P')
69 changes: 69 additions & 0 deletions core/src/main/java/org/jruby/ir/persistence/flat/CallFlat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;

@SuppressWarnings("unused")
public final class CallFlat extends Table {
public static CallFlat getRootAsCallFlat(ByteBuffer _bb) { return getRootAsCallFlat(_bb, new CallFlat()); }
public static CallFlat getRootAsCallFlat(ByteBuffer _bb, CallFlat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public CallFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public int callType() { int o = __offset(4); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
public String name() { int o = __offset(6); return o != 0 ? __string(o + bb_pos) : null; }
public ByteBuffer nameAsByteBuffer() { return __vector_as_bytebuffer(6, 1); }
public int argsCount() { int o = __offset(8); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
public boolean hasClosure() { int o = __offset(10); return o != 0 ? 0!=bb.get(o + bb_pos) : false; }
public boolean canBeEval() { int o = __offset(12); return o != 0 ? 0!=bb.get(o + bb_pos) : false; }
public boolean targetRequiresCallersBinding() { int o = __offset(14); return o != 0 ? 0!=bb.get(o + bb_pos) : false; }
public boolean targetRequiresCallersFrame() { int o = __offset(16); return o != 0 ? 0!=bb.get(o + bb_pos) : false; }
public boolean splatMap(int j) { int o = __offset(18); return o != 0 ? 0!=bb.get(__vector(o) + j * 1) : false; }
public int splatMapLength() { int o = __offset(18); return o != 0 ? __vector_len(o) : 0; }
public ByteBuffer splatMapAsByteBuffer() { return __vector_as_bytebuffer(18, 1); }
public boolean potentiallyRefined() { int o = __offset(20); return o != 0 ? 0!=bb.get(o + bb_pos) : false; }

public static int createCallFlat(FlatBufferBuilder builder,
int callType,
int nameOffset,
int argsCount,
boolean hasClosure,
boolean canBeEval,
boolean targetRequiresCallersBinding,
boolean targetRequiresCallersFrame,
int splatMapOffset,
boolean potentiallyRefined) {
builder.startObject(9);
CallFlat.addSplatMap(builder, splatMapOffset);
CallFlat.addArgsCount(builder, argsCount);
CallFlat.addName(builder, nameOffset);
CallFlat.addCallType(builder, callType);
CallFlat.addPotentiallyRefined(builder, potentiallyRefined);
CallFlat.addTargetRequiresCallersFrame(builder, targetRequiresCallersFrame);
CallFlat.addTargetRequiresCallersBinding(builder, targetRequiresCallersBinding);
CallFlat.addCanBeEval(builder, canBeEval);
CallFlat.addHasClosure(builder, hasClosure);
return CallFlat.endCallFlat(builder);
}

public static void startCallFlat(FlatBufferBuilder builder) { builder.startObject(9); }
public static void addCallType(FlatBufferBuilder builder, int callType) { builder.addInt(0, callType, 0); }
public static void addName(FlatBufferBuilder builder, int nameOffset) { builder.addOffset(1, nameOffset, 0); }
public static void addArgsCount(FlatBufferBuilder builder, int argsCount) { builder.addInt(2, argsCount, 0); }
public static void addHasClosure(FlatBufferBuilder builder, boolean hasClosure) { builder.addBoolean(3, hasClosure, false); }
public static void addCanBeEval(FlatBufferBuilder builder, boolean canBeEval) { builder.addBoolean(4, canBeEval, false); }
public static void addTargetRequiresCallersBinding(FlatBufferBuilder builder, boolean targetRequiresCallersBinding) { builder.addBoolean(5, targetRequiresCallersBinding, false); }
public static void addTargetRequiresCallersFrame(FlatBufferBuilder builder, boolean targetRequiresCallersFrame) { builder.addBoolean(6, targetRequiresCallersFrame, false); }
public static void addSplatMap(FlatBufferBuilder builder, int splatMapOffset) { builder.addOffset(7, splatMapOffset, 0); }
public static int createSplatMapVector(FlatBufferBuilder builder, boolean[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addBoolean(data[i]); return builder.endVector(); }
public static void startSplatMapVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
public static void addPotentiallyRefined(FlatBufferBuilder builder, boolean potentiallyRefined) { builder.addBoolean(8, potentiallyRefined, false); }
public static int endCallFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

32 changes: 32 additions & 0 deletions core/src/main/java/org/jruby/ir/persistence/flat/CopyFlat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;

@SuppressWarnings("unused")
public final class CopyFlat extends Table {
public static CopyFlat getRootAsCopyFlat(ByteBuffer _bb) { return getRootAsCopyFlat(_bb, new CopyFlat()); }
public static CopyFlat getRootAsCopyFlat(ByteBuffer _bb, CopyFlat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public CopyFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public byte dummy() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) : 0; }

public static int createCopyFlat(FlatBufferBuilder builder,
byte dummy) {
builder.startObject(1);
CopyFlat.addDummy(builder, dummy);
return CopyFlat.endCopyFlat(builder);
}

public static void startCopyFlat(FlatBufferBuilder builder) { builder.startObject(1); }
public static void addDummy(FlatBufferBuilder builder, byte dummy) { builder.addByte(0, dummy, 0); }
public static int endCopyFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;

@SuppressWarnings("unused")
public final class CurrentScopeFlat extends Table {
public static CurrentScopeFlat getRootAsCurrentScopeFlat(ByteBuffer _bb) { return getRootAsCurrentScopeFlat(_bb, new CurrentScopeFlat()); }
public static CurrentScopeFlat getRootAsCurrentScopeFlat(ByteBuffer _bb, CurrentScopeFlat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public CurrentScopeFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public byte dummy() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) : 0; }

public static int createCurrentScopeFlat(FlatBufferBuilder builder,
byte dummy) {
builder.startObject(1);
CurrentScopeFlat.addDummy(builder, dummy);
return CurrentScopeFlat.endCurrentScopeFlat(builder);
}

public static void startCurrentScopeFlat(FlatBufferBuilder builder) { builder.startObject(1); }
public static void addDummy(FlatBufferBuilder builder, byte dummy) { builder.addByte(0, dummy, 0); }
public static int endCurrentScopeFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package org.jruby.ir.persistence.flat;

import com.google.flatbuffers.FlatBufferBuilder;
import org.jruby.ParseResult;
import org.jruby.Ruby;
import org.jruby.RubyModule;
import org.jruby.ast.RootNode;
import org.jruby.ir.IRBuilder;
import org.jruby.ir.IRScope;
import org.jruby.ir.instructions.CallBase;
import org.jruby.ir.interpreter.InterpreterContext;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;

import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class FlatIRInterpreter {

public static void main(String[] args) {
Ruby runtime = Ruby.newInstance();
byte[] src = args[0].getBytes();
ParseResult result = runtime.parseFromMain("blah.rb", new ByteArrayInputStream(src));
InterpreterContext ic = IRBuilder.buildRoot(runtime.getIRManager(), (RootNode) result);
IRScope scope = ic.getScope();
FlatBufferBuilder builder = new FlatBufferBuilder();
int index = FlatIRWriter.createIRScopeFlat(builder, scope);

builder.finish(index);

ByteBuffer buffer = builder.dataBuffer();
int size = buffer.limit();

try {
FileOutputStream out = new FileOutputStream("blah.ir");
out.getChannel().write(buffer);
out.close();
} catch (Throwable t) {
throw new RuntimeException(t);
}

try {
RandomAccessFile file = new RandomAccessFile("blah.ir", "rw");
buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, size);
} catch (Throwable t) {
throw new RuntimeException(t);
}

IRScopeFlat scopeFlat = IRScopeFlat.getRootAsIRScopeFlat(buffer);

FlatIRInterpreter.interpretScope(runtime.getCurrentContext(), Block.NULL_BLOCK, runtime.getTopSelf(), scopeFlat, runtime.getTopSelf().getType(), "<script>", IRubyObject.NULL_ARRAY, Block.NULL_BLOCK);
}

public static Object interpretOperand(OperandFlat operandFlat, ThreadContext context, StaticScope currStaticScope, DynamicScope currDynScope, IRubyObject self, Object[] temp) {
switch (operandFlat.operandType()) {
case OperandUnion.CurrentScopeFlat:
return currStaticScope;
case OperandUnion.FrozenStringFlat: {
FrozenStringFlat frozenStringFlat = new FrozenStringFlat();
operandFlat.operand(frozenStringFlat);
return createFrozenString(frozenStringFlat, context);
}
case OperandUnion.ScopeModuleFlat:
return currStaticScope.getModule();
case OperandUnion.SelfFlat:
return self;
case OperandUnion.StringLiteralFlat: {
StringLiteralFlat stringLiteralFlat = new StringLiteralFlat();
operandFlat.operand(stringLiteralFlat);
FrozenStringFlat frozenStringFlat = stringLiteralFlat.frozenString();
return createFrozenString(frozenStringFlat, context);
}
case OperandUnion.TemporaryVariableFlat: {
TemporaryVariableFlat temporaryVariableFlat = new TemporaryVariableFlat();
operandFlat.operand(temporaryVariableFlat);
return temp[temporaryVariableFlat.offset()];
}
default:
throw new RuntimeException("unexpected operand in map: " + operandFlat.operandType());
}
}

public static Object createFrozenString(FrozenStringFlat frozenStringFlat, ThreadContext context) {
ByteBuffer byteBuffer = frozenStringFlat.bytesAsByteBuffer();
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
return context.runtime.newString(new ByteList(bytes, 0, bytes.length, context.runtime.getEncodingService().getEncodingFromString(frozenStringFlat.encoding()), false));
}

private static Object interpretScope(ThreadContext context, Block block, IRubyObject self,
IRScopeFlat scopeFlat, RubyModule implClass,
String name, IRubyObject[] args, Block blockArg) {
Object result;

StaticScope currScope = context.runtime.getStaticScopeFactory().getDummyScope();
DynamicScope currDynScope = currScope.getDummyScope();

Object[] temp = new Object[scopeFlat.tempVariables()];

InstrFlat instrFlat = new InstrFlat();
int instrsLength = scopeFlat.instrsLength();
int ipc = 0;

while (ipc < instrsLength) {
scopeFlat.instrs(instrFlat, ipc);

switch (instrFlat.instrType()) {
case InstrUnion.CallFlat: {
CallFlat callFlat = new CallFlat();
instrFlat.instr(callFlat);
result = CallBase.interpret(instrFlat, callFlat, context, currScope, currDynScope, self, temp);
assignResult(instrFlat, result, temp);
break;
}
case InstrUnion.CopyFlat: {
assignResult(instrFlat, interpretOperand(instrFlat.operands(0), context, currScope, currDynScope, self, temp), temp);
break;
}
case InstrUnion.LineNumberFlat: {
LineNumberFlat lineNumberFlat = new LineNumberFlat();
instrFlat.instr(lineNumberFlat);
context.setLine(lineNumberFlat.line());
break;
}
case InstrUnion.LoadFrameClosureFlat:
assignResult(instrFlat, context.getFrameBlock(), temp);
break;
case InstrUnion.LoadImplicitClosureFlat:
assignResult(instrFlat, blockArg, temp);
break;
case InstrUnion.ReceiveSelfFlat:
break;
case InstrUnion.ReturnFlat:
return interpretOperand(instrFlat.operands(0), context, currScope, currDynScope, self, temp);
default:
throw new RuntimeException("unexpected instr type in map: " + instrFlat.instrType());
}
ipc++;
}

throw new RuntimeException("flatbuffer interpreter fell off the world: " + scopeFlat.name());
}

private static Object assignResult(InstrFlat instrFlat, Object result, Object[] temp) {
TemporaryVariableFlat temporaryVariableFlat = instrFlat.result();
return temp[temporaryVariableFlat.offset()] = result;
}
}
174 changes: 120 additions & 54 deletions core/src/main/java/org/jruby/ir/persistence/flat/FlatIRWriter.java
Original file line number Diff line number Diff line change
@@ -3,26 +3,39 @@
import com.google.flatbuffers.FlatBufferBuilder;
import org.jruby.ParseResult;
import org.jruby.Ruby;
import org.jruby.RubyModule;
import org.jruby.ast.RootNode;
import org.jruby.ir.IRBuilder;
import org.jruby.ir.IRScope;
import org.jruby.ir.IRScriptBody;
import org.jruby.ir.Operation;
import org.jruby.ir.instructions.CallBase;
import org.jruby.ir.instructions.CallInstr;
import org.jruby.ir.instructions.Instr;
import org.jruby.ir.instructions.LineNumberInstr;
import org.jruby.ir.instructions.ResultInstr;
import org.jruby.ir.interpreter.InterpreterContext;
import org.jruby.ir.operands.FrozenString;
import org.jruby.ir.operands.Operand;
import org.jruby.ir.operands.OperandType;
import org.jruby.ir.operands.Self;
import org.jruby.ir.operands.StringLiteral;
import org.jruby.ir.operands.TemporaryLocalVariable;
import org.jruby.ir.operands.Variable;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class FlatIRWriter {
public static int createIRScopeFlat(FlatBufferBuilder builder, IRScope scope) {
int nameOffset = builder.createString(scope.getName());
int scopeNameOffset = builder.createString(scope.getName());

int[] children = new int[scope.getLexicalScopes().size()];

@@ -42,71 +55,124 @@ public static int createIRScopeFlat(FlatBufferBuilder builder, IRScope scope) {
for (int i = 0; i < instrs.length; i++) {
Instr instr = instrs[i];

if (instr.getOperation().getFlat() == -1) throw new RuntimeException("unsupported operation: " + instr.getOperation());
int instrType = instr.getOperation().getFlat();

if (instrType == -1) throw new RuntimeException("unsupported operation: " + instr.getOperation());

Operand[] operands = instr.getOperands();
int[] operandOffsets = new int[operands.length];

for (int j = 0; j < operands.length; j++) {
Operand operand = operands[j];

if (operand.getOperandType().getFlat() == -1) throw new RuntimeException("unsupported operand: " + operand.getOperandType());

operandOffsets[j] = OperandFlat.createOperandFlat(builder, operand.getOperandType().getFlat());
int operandType = operand.getOperandType().getFlat();

if (operandType == -1) throw new RuntimeException("unsupported operand: " + operand.getOperandType());

int operandOffset = -1;

switch (operandType) {
case OperandUnion.CurrentScopeFlat:
operandOffset = CurrentScopeFlat.createCurrentScopeFlat(builder, (byte) -1);
break;
case OperandUnion.ScopeModuleFlat:
operandOffset = ScopeModuleFlat.createScopeModuleFlat(builder, (byte) -1);
break;
case OperandUnion.SelfFlat:
operandOffset = SelfFlat.createSelfFlat(builder, (byte) -1);
break;
case OperandUnion.StringLiteralFlat: {
int frozenStringOffset = createFrozenString(builder, ((StringLiteral) operand).frozenString);
operandOffset = StringLiteralFlat.createStringLiteralFlat(builder, frozenStringOffset);
break;
}
case OperandUnion.FrozenStringFlat:
operandOffset = createFrozenString(builder, ((StringLiteral) operand).frozenString);
break;
case OperandUnion.TemporaryVariableFlat:
operandOffset = TemporaryVariableFlat.createTemporaryVariableFlat(builder, ((TemporaryLocalVariable) operand).offset);
break;
default:
throw new RuntimeException("unsupported operand: " + operand.getOperandType());
}
operandOffsets[j] = OperandFlat.createOperandFlat(builder, (byte) operandType, operandOffset);
}

int operandsOffset = InstrFlat.createOperandsVector(builder, operandOffsets);

instrOffsets[i] = InstrFlat.createInstrFlat(builder, instr.getOperation().getFlat(), operandsOffset);
int instrOffset = -1;

switch (instrType) {
case InstrUnion.CallFlat: {
CallInstr callInstr = (CallInstr) instr;
boolean[] splatMap = callInstr.splatMap();
if (splatMap == null) splatMap = new boolean[0];
int splatMapOffset = CallFlat.createSplatMapVector(builder, splatMap);
int callNameOffset = builder.createString(callInstr.getName());
instrOffset = CallFlat.createCallFlat(
builder,
callInstr.getCallType().ordinal(),
callNameOffset,
callInstr.getArgsCount(),
callInstr.hasLiteralClosure(),
callInstr.canBeEval(),
callInstr.targetRequiresCallersBinding(),
callInstr.targetRequiresCallersFrame(),
splatMapOffset,
callInstr.isPotentiallyRefined());
break;
}
case InstrUnion.CopyFlat:
instrOffset = CopyFlat.createCopyFlat(builder, (byte) -1);
break;
case InstrUnion.LineNumberFlat:
instrOffset = LineNumberFlat.createLineNumberFlat(builder, ((LineNumberInstr) instr).lineNumber);
break;
case InstrUnion.LoadFrameClosureFlat:
instrOffset = LoadFrameClosureFlat.createLoadFrameClosureFlat(builder, (byte) -1);
break;
case InstrUnion.LoadImplicitClosureFlat:
instrOffset = LoadImplicitClosureFlat.createLoadImplicitClosureFlat(builder, (byte) -1);
break;
case InstrUnion.ReceiveSelfFlat:
instrOffset = ReceiveSelfFlat.createReceiveSelfFlat(builder, (byte) -1);
break;
case InstrUnion.ReturnFlat:
instrOffset = ReturnFlat.createReturnFlat(builder, (byte) -1);
break;
default:
throw new RuntimeException("unsupported operation: " + instr.getOperation());
}

int resultOffset = -1;
if (instr instanceof ResultInstr) {
Variable result = ((ResultInstr) instr).getResult();

if (result instanceof TemporaryLocalVariable) {
resultOffset = TemporaryVariableFlat.createTemporaryVariableFlat(builder, ((TemporaryLocalVariable) result).offset);
} else if (result instanceof Self) {
// dummy for now until all Variable types are represented
resultOffset = TemporaryVariableFlat.createTemporaryVariableFlat(builder, -1);
} else {
throw new RuntimeException("unsupported result type: " + result.getClass());
}
} else {
resultOffset = TemporaryVariableFlat.createTemporaryVariableFlat(builder, -1);
}

instrOffsets[i] = InstrFlat.createInstrFlat(builder, resultOffset, operandsOffset, (byte) instrType, instrOffset);
}

int instrsOffset = IRScopeFlat.createInstrsVector(builder, instrOffsets);

return IRScopeFlat.createIRScopeFlat(builder, nameOffset, closuresOffset, childrenOffset, instrsOffset);
return IRScopeFlat.createIRScopeFlat(builder, scopeNameOffset, closuresOffset, childrenOffset, instrsOffset, (short) scope.getTemporaryVariablesCount(), scope.receivesKeywordArgs());
}

public static void main(String[] args) {
Ruby runtime = Ruby.newInstance();
byte[] src = "puts 'hello'".getBytes();
ParseResult result = runtime.parseFromMain("blah.rb", new ByteArrayInputStream(src));
InterpreterContext ic = IRBuilder.buildRoot(runtime.getIRManager(), (RootNode) result);
IRScope scope = ic.getScope();
FlatBufferBuilder builder = new FlatBufferBuilder();
int index = createIRScopeFlat(builder, scope);

builder.finish(index);

ByteBuffer buffer = builder.dataBuffer();
int size = buffer.limit();

try {
FileOutputStream out = new FileOutputStream("blah.ir");
out.getChannel().write(buffer);
out.close();
} catch (Throwable t) {
throw new RuntimeException(t);
}

try {
RandomAccessFile file = new RandomAccessFile("blah.ir", "rw");
buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, size);
} catch (Throwable t) {
throw new RuntimeException(t);
}

System.out.println("persisted and loaded:");
IRScopeFlat scopeFlat = IRScopeFlat.getRootAsIRScopeFlat(buffer);
System.out.println("IRScope: " + scopeFlat.name());
System.out.println("Instructions:");
InstrFlat instrFlat = new InstrFlat();
for (int i = 0; i < scopeFlat.instrsLength(); i++) {
scopeFlat.instrs(instrFlat, i);
System.out.println(" " + Operation.flatMap(instrFlat.operation()));
OperandFlat operandFlat = new OperandFlat();
for (int j = 0; j < instrFlat.operandsLength(); j++) {
instrFlat.operands(operandFlat, j);
System.out.println(" " + OperandType.flatMap(operandFlat.operandType()));
}
}
private static int createFrozenString(FlatBufferBuilder builder, FrozenString frozenString) {
int bytesOffset = FrozenStringFlat.createBytesVector(builder, frozenString.bytelist.bytes());
int encodingOffset = builder.createString(frozenString.bytelist.getEncoding().toString());
int strOffset = builder.createString(frozenString.string);
int fileOffset = builder.createString(frozenString.file);
return FrozenStringFlat.createFrozenStringFlat(builder, bytesOffset, encodingOffset, strOffset, frozenString.coderange, fileOffset, frozenString.line);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;

@SuppressWarnings("unused")
public final class FrozenStringFlat extends Table {
public static FrozenStringFlat getRootAsFrozenStringFlat(ByteBuffer _bb) { return getRootAsFrozenStringFlat(_bb, new FrozenStringFlat()); }
public static FrozenStringFlat getRootAsFrozenStringFlat(ByteBuffer _bb, FrozenStringFlat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public FrozenStringFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public byte bytes(int j) { int o = __offset(4); return o != 0 ? bb.get(__vector(o) + j * 1) : 0; }
public int bytesLength() { int o = __offset(4); return o != 0 ? __vector_len(o) : 0; }
public ByteBuffer bytesAsByteBuffer() { return __vector_as_bytebuffer(4, 1); }
public String encoding() { int o = __offset(6); return o != 0 ? __string(o + bb_pos) : null; }
public ByteBuffer encodingAsByteBuffer() { return __vector_as_bytebuffer(6, 1); }
public String str() { int o = __offset(8); return o != 0 ? __string(o + bb_pos) : null; }
public ByteBuffer strAsByteBuffer() { return __vector_as_bytebuffer(8, 1); }
public int coderange() { int o = __offset(10); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
public String file() { int o = __offset(12); return o != 0 ? __string(o + bb_pos) : null; }
public ByteBuffer fileAsByteBuffer() { return __vector_as_bytebuffer(12, 1); }
public int line() { int o = __offset(14); return o != 0 ? bb.getInt(o + bb_pos) : 0; }

public static int createFrozenStringFlat(FlatBufferBuilder builder,
int bytesOffset,
int encodingOffset,
int strOffset,
int coderange,
int fileOffset,
int line) {
builder.startObject(6);
FrozenStringFlat.addLine(builder, line);
FrozenStringFlat.addFile(builder, fileOffset);
FrozenStringFlat.addCoderange(builder, coderange);
FrozenStringFlat.addStr(builder, strOffset);
FrozenStringFlat.addEncoding(builder, encodingOffset);
FrozenStringFlat.addBytes(builder, bytesOffset);
return FrozenStringFlat.endFrozenStringFlat(builder);
}

public static void startFrozenStringFlat(FlatBufferBuilder builder) { builder.startObject(6); }
public static void addBytes(FlatBufferBuilder builder, int bytesOffset) { builder.addOffset(0, bytesOffset, 0); }
public static int createBytesVector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
public static void startBytesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
public static void addEncoding(FlatBufferBuilder builder, int encodingOffset) { builder.addOffset(1, encodingOffset, 0); }
public static void addStr(FlatBufferBuilder builder, int strOffset) { builder.addOffset(2, strOffset, 0); }
public static void addCoderange(FlatBufferBuilder builder, int coderange) { builder.addInt(3, coderange, 0); }
public static void addFile(FlatBufferBuilder builder, int fileOffset) { builder.addOffset(4, fileOffset, 0); }
public static void addLine(FlatBufferBuilder builder, int line) { builder.addInt(5, line, 0); }
public static int endFrozenStringFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

14 changes: 11 additions & 3 deletions core/src/main/java/org/jruby/ir/persistence/flat/IRScopeFlat.java
Original file line number Diff line number Diff line change
@@ -24,21 +24,27 @@ public final class IRScopeFlat extends Table {
public InstrFlat instrs(int j) { return instrs(new InstrFlat(), j); }
public InstrFlat instrs(InstrFlat obj, int j) { int o = __offset(10); return o != 0 ? obj.__init(__indirect(__vector(o) + j * 4), bb) : null; }
public int instrsLength() { int o = __offset(10); return o != 0 ? __vector_len(o) : 0; }
public short tempVariables() { int o = __offset(12); return o != 0 ? bb.getShort(o + bb_pos) : 0; }
public boolean acceptsKeywordArguments() { int o = __offset(14); return o != 0 ? 0!=bb.get(o + bb_pos) : false; }

public static int createIRScopeFlat(FlatBufferBuilder builder,
int nameOffset,
int nestedClosuresOffset,
int lexicalChildrenOffset,
int instrsOffset) {
builder.startObject(4);
int instrsOffset,
short tempVariables,
boolean acceptsKeywordArguments) {
builder.startObject(6);
IRScopeFlat.addInstrs(builder, instrsOffset);
IRScopeFlat.addLexicalChildren(builder, lexicalChildrenOffset);
IRScopeFlat.addNestedClosures(builder, nestedClosuresOffset);
IRScopeFlat.addName(builder, nameOffset);
IRScopeFlat.addTempVariables(builder, tempVariables);
IRScopeFlat.addAcceptsKeywordArguments(builder, acceptsKeywordArguments);
return IRScopeFlat.endIRScopeFlat(builder);
}

public static void startIRScopeFlat(FlatBufferBuilder builder) { builder.startObject(4); }
public static void startIRScopeFlat(FlatBufferBuilder builder) { builder.startObject(6); }
public static void addName(FlatBufferBuilder builder, int nameOffset) { builder.addOffset(0, nameOffset, 0); }
public static void addNestedClosures(FlatBufferBuilder builder, int nestedClosuresOffset) { builder.addOffset(1, nestedClosuresOffset, 0); }
public static int createNestedClosuresVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
@@ -49,6 +55,8 @@ public static int createIRScopeFlat(FlatBufferBuilder builder,
public static void addInstrs(FlatBufferBuilder builder, int instrsOffset) { builder.addOffset(3, instrsOffset, 0); }
public static int createInstrsVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
public static void startInstrsVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
public static void addTempVariables(FlatBufferBuilder builder, short tempVariables) { builder.addShort(4, tempVariables, 0); }
public static void addAcceptsKeywordArguments(FlatBufferBuilder builder, boolean acceptsKeywordArguments) { builder.addBoolean(5, acceptsKeywordArguments, false); }
public static int endIRScopeFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
23 changes: 16 additions & 7 deletions core/src/main/java/org/jruby/ir/persistence/flat/InstrFlat.java
Original file line number Diff line number Diff line change
@@ -13,25 +13,34 @@ public final class InstrFlat extends Table {
public static InstrFlat getRootAsInstrFlat(ByteBuffer _bb, InstrFlat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public InstrFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public short operation() { int o = __offset(4); return o != 0 ? bb.getShort(o + bb_pos) : 0; }
public TemporaryVariableFlat result() { return result(new TemporaryVariableFlat()); }
public TemporaryVariableFlat result(TemporaryVariableFlat obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
public OperandFlat operands(int j) { return operands(new OperandFlat(), j); }
public OperandFlat operands(OperandFlat obj, int j) { int o = __offset(6); return o != 0 ? obj.__init(__indirect(__vector(o) + j * 4), bb) : null; }
public int operandsLength() { int o = __offset(6); return o != 0 ? __vector_len(o) : 0; }
public byte instrType() { int o = __offset(8); return o != 0 ? bb.get(o + bb_pos) : 0; }
public Table instr(Table obj) { int o = __offset(10); return o != 0 ? __union(obj, o) : null; }

public static int createInstrFlat(FlatBufferBuilder builder,
short operation,
int operandsOffset) {
builder.startObject(2);
int resultOffset,
int operandsOffset,
byte instr_type,
int instrOffset) {
builder.startObject(4);
InstrFlat.addInstr(builder, instrOffset);
InstrFlat.addOperands(builder, operandsOffset);
InstrFlat.addOperation(builder, operation);
InstrFlat.addResult(builder, resultOffset);
InstrFlat.addInstrType(builder, instr_type);
return InstrFlat.endInstrFlat(builder);
}

public static void startInstrFlat(FlatBufferBuilder builder) { builder.startObject(2); }
public static void addOperation(FlatBufferBuilder builder, short operation) { builder.addShort(0, operation, 0); }
public static void startInstrFlat(FlatBufferBuilder builder) { builder.startObject(4); }
public static void addResult(FlatBufferBuilder builder, int resultOffset) { builder.addOffset(0, resultOffset, 0); }
public static void addOperands(FlatBufferBuilder builder, int operandsOffset) { builder.addOffset(1, operandsOffset, 0); }
public static int createOperandsVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
public static void startOperandsVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
public static void addInstrType(FlatBufferBuilder builder, byte instrType) { builder.addByte(2, instrType, 0); }
public static void addInstr(FlatBufferBuilder builder, int instrOffset) { builder.addOffset(3, instrOffset, 0); }
public static int endInstrFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
20 changes: 20 additions & 0 deletions core/src/main/java/org/jruby/ir/persistence/flat/InstrUnion.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

public final class InstrUnion {
private InstrUnion() { }
public static final byte NONE = 0;
public static final byte CopyFlat = 1;
public static final byte ReceiveSelfFlat = 2;
public static final byte LineNumberFlat = 3;
public static final byte CallFlat = 4;
public static final byte ReturnFlat = 5;
public static final byte LoadImplicitClosureFlat = 6;
public static final byte LoadFrameClosureFlat = 7;

private static final String[] names = { "NONE", "CopyFlat", "ReceiveSelfFlat", "LineNumberFlat", "CallFlat", "ReturnFlat", "LoadImplicitClosureFlat", "LoadFrameClosureFlat", };

public static String name(int e) { return names[e]; }
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;

@SuppressWarnings("unused")
public final class LineNumberFlat extends Table {
public static LineNumberFlat getRootAsLineNumberFlat(ByteBuffer _bb) { return getRootAsLineNumberFlat(_bb, new LineNumberFlat()); }
public static LineNumberFlat getRootAsLineNumberFlat(ByteBuffer _bb, LineNumberFlat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public LineNumberFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public int line() { int o = __offset(4); return o != 0 ? bb.getInt(o + bb_pos) : 0; }

public static int createLineNumberFlat(FlatBufferBuilder builder,
int line) {
builder.startObject(1);
LineNumberFlat.addLine(builder, line);
return LineNumberFlat.endLineNumberFlat(builder);
}

public static void startLineNumberFlat(FlatBufferBuilder builder) { builder.startObject(1); }
public static void addLine(FlatBufferBuilder builder, int line) { builder.addInt(0, line, 0); }
public static int endLineNumberFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;

@SuppressWarnings("unused")
public final class LoadFrameClosureFlat extends Table {
public static LoadFrameClosureFlat getRootAsLoadFrameClosureFlat(ByteBuffer _bb) { return getRootAsLoadFrameClosureFlat(_bb, new LoadFrameClosureFlat()); }
public static LoadFrameClosureFlat getRootAsLoadFrameClosureFlat(ByteBuffer _bb, LoadFrameClosureFlat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public LoadFrameClosureFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public byte dummy() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) : 0; }

public static int createLoadFrameClosureFlat(FlatBufferBuilder builder,
byte dummy) {
builder.startObject(1);
LoadFrameClosureFlat.addDummy(builder, dummy);
return LoadFrameClosureFlat.endLoadFrameClosureFlat(builder);
}

public static void startLoadFrameClosureFlat(FlatBufferBuilder builder) { builder.startObject(1); }
public static void addDummy(FlatBufferBuilder builder, byte dummy) { builder.addByte(0, dummy, 0); }
public static int endLoadFrameClosureFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;

@SuppressWarnings("unused")
public final class LoadImplicitClosureFlat extends Table {
public static LoadImplicitClosureFlat getRootAsLoadImplicitClosureFlat(ByteBuffer _bb) { return getRootAsLoadImplicitClosureFlat(_bb, new LoadImplicitClosureFlat()); }
public static LoadImplicitClosureFlat getRootAsLoadImplicitClosureFlat(ByteBuffer _bb, LoadImplicitClosureFlat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public LoadImplicitClosureFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public byte dummy() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) : 0; }

public static int createLoadImplicitClosureFlat(FlatBufferBuilder builder,
byte dummy) {
builder.startObject(1);
LoadImplicitClosureFlat.addDummy(builder, dummy);
return LoadImplicitClosureFlat.endLoadImplicitClosureFlat(builder);
}

public static void startLoadImplicitClosureFlat(FlatBufferBuilder builder) { builder.startObject(1); }
public static void addDummy(FlatBufferBuilder builder, byte dummy) { builder.addByte(0, dummy, 0); }
public static int endLoadImplicitClosureFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

Original file line number Diff line number Diff line change
@@ -14,16 +14,20 @@ public final class OperandFlat extends Table {
public OperandFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public byte operandType() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) : 0; }
public Table operand(Table obj) { int o = __offset(6); return o != 0 ? __union(obj, o) : null; }

public static int createOperandFlat(FlatBufferBuilder builder,
byte operandType) {
builder.startObject(1);
OperandFlat.addOperandType(builder, operandType);
byte operand_type,
int operandOffset) {
builder.startObject(2);
OperandFlat.addOperand(builder, operandOffset);
OperandFlat.addOperandType(builder, operand_type);
return OperandFlat.endOperandFlat(builder);
}

public static void startOperandFlat(FlatBufferBuilder builder) { builder.startObject(1); }
public static void startOperandFlat(FlatBufferBuilder builder) { builder.startObject(2); }
public static void addOperandType(FlatBufferBuilder builder, byte operandType) { builder.addByte(0, operandType, 0); }
public static void addOperand(FlatBufferBuilder builder, int operandOffset) { builder.addOffset(1, operandOffset, 0); }
public static int endOperandFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;

This file was deleted.

19 changes: 19 additions & 0 deletions core/src/main/java/org/jruby/ir/persistence/flat/OperandUnion.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

public final class OperandUnion {
private OperandUnion() { }
public static final byte NONE = 0;
public static final byte StringLiteralFlat = 1;
public static final byte FrozenStringFlat = 2;
public static final byte TemporaryVariableFlat = 3;
public static final byte CurrentScopeFlat = 4;
public static final byte ScopeModuleFlat = 5;
public static final byte SelfFlat = 6;

private static final String[] names = { "NONE", "StringLiteralFlat", "FrozenStringFlat", "TemporaryVariableFlat", "CurrentScopeFlat", "ScopeModuleFlat", "SelfFlat", };

public static String name(int e) { return names[e]; }
};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;

@SuppressWarnings("unused")
public final class ReceiveSelfFlat extends Table {
public static ReceiveSelfFlat getRootAsReceiveSelfFlat(ByteBuffer _bb) { return getRootAsReceiveSelfFlat(_bb, new ReceiveSelfFlat()); }
public static ReceiveSelfFlat getRootAsReceiveSelfFlat(ByteBuffer _bb, ReceiveSelfFlat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public ReceiveSelfFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public byte dummy() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) : 0; }

public static int createReceiveSelfFlat(FlatBufferBuilder builder,
byte dummy) {
builder.startObject(1);
ReceiveSelfFlat.addDummy(builder, dummy);
return ReceiveSelfFlat.endReceiveSelfFlat(builder);
}

public static void startReceiveSelfFlat(FlatBufferBuilder builder) { builder.startObject(1); }
public static void addDummy(FlatBufferBuilder builder, byte dummy) { builder.addByte(0, dummy, 0); }
public static int endReceiveSelfFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

32 changes: 32 additions & 0 deletions core/src/main/java/org/jruby/ir/persistence/flat/ReturnFlat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;

@SuppressWarnings("unused")
public final class ReturnFlat extends Table {
public static ReturnFlat getRootAsReturnFlat(ByteBuffer _bb) { return getRootAsReturnFlat(_bb, new ReturnFlat()); }
public static ReturnFlat getRootAsReturnFlat(ByteBuffer _bb, ReturnFlat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public ReturnFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public byte dummy() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) : 0; }

public static int createReturnFlat(FlatBufferBuilder builder,
byte dummy) {
builder.startObject(1);
ReturnFlat.addDummy(builder, dummy);
return ReturnFlat.endReturnFlat(builder);
}

public static void startReturnFlat(FlatBufferBuilder builder) { builder.startObject(1); }
public static void addDummy(FlatBufferBuilder builder, byte dummy) { builder.addByte(0, dummy, 0); }
public static int endReturnFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;

@SuppressWarnings("unused")
public final class ScopeModuleFlat extends Table {
public static ScopeModuleFlat getRootAsScopeModuleFlat(ByteBuffer _bb) { return getRootAsScopeModuleFlat(_bb, new ScopeModuleFlat()); }
public static ScopeModuleFlat getRootAsScopeModuleFlat(ByteBuffer _bb, ScopeModuleFlat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public ScopeModuleFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public byte dummy() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) : 0; }

public static int createScopeModuleFlat(FlatBufferBuilder builder,
byte dummy) {
builder.startObject(1);
ScopeModuleFlat.addDummy(builder, dummy);
return ScopeModuleFlat.endScopeModuleFlat(builder);
}

public static void startScopeModuleFlat(FlatBufferBuilder builder) { builder.startObject(1); }
public static void addDummy(FlatBufferBuilder builder, byte dummy) { builder.addByte(0, dummy, 0); }
public static int endScopeModuleFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

32 changes: 32 additions & 0 deletions core/src/main/java/org/jruby/ir/persistence/flat/SelfFlat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;

@SuppressWarnings("unused")
public final class SelfFlat extends Table {
public static SelfFlat getRootAsSelfFlat(ByteBuffer _bb) { return getRootAsSelfFlat(_bb, new SelfFlat()); }
public static SelfFlat getRootAsSelfFlat(ByteBuffer _bb, SelfFlat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public SelfFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public byte dummy() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) : 0; }

public static int createSelfFlat(FlatBufferBuilder builder,
byte dummy) {
builder.startObject(1);
SelfFlat.addDummy(builder, dummy);
return SelfFlat.endSelfFlat(builder);
}

public static void startSelfFlat(FlatBufferBuilder builder) { builder.startObject(1); }
public static void addDummy(FlatBufferBuilder builder, byte dummy) { builder.addByte(0, dummy, 0); }
public static int endSelfFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;

@SuppressWarnings("unused")
public final class StringLiteralFlat extends Table {
public static StringLiteralFlat getRootAsStringLiteralFlat(ByteBuffer _bb) { return getRootAsStringLiteralFlat(_bb, new StringLiteralFlat()); }
public static StringLiteralFlat getRootAsStringLiteralFlat(ByteBuffer _bb, StringLiteralFlat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public StringLiteralFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public FrozenStringFlat frozenString() { return frozenString(new FrozenStringFlat()); }
public FrozenStringFlat frozenString(FrozenStringFlat obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }

public static int createStringLiteralFlat(FlatBufferBuilder builder,
int frozenStringOffset) {
builder.startObject(1);
StringLiteralFlat.addFrozenString(builder, frozenStringOffset);
return StringLiteralFlat.endStringLiteralFlat(builder);
}

public static void startStringLiteralFlat(FlatBufferBuilder builder) { builder.startObject(1); }
public static void addFrozenString(FlatBufferBuilder builder, int frozenStringOffset) { builder.addOffset(0, frozenStringOffset, 0); }
public static int endStringLiteralFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// automatically generated, do not modify

package org.jruby.ir.persistence.flat;

import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;

@SuppressWarnings("unused")
public final class TemporaryVariableFlat extends Table {
public static TemporaryVariableFlat getRootAsTemporaryVariableFlat(ByteBuffer _bb) { return getRootAsTemporaryVariableFlat(_bb, new TemporaryVariableFlat()); }
public static TemporaryVariableFlat getRootAsTemporaryVariableFlat(ByteBuffer _bb, TemporaryVariableFlat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public TemporaryVariableFlat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }

public int offset() { int o = __offset(4); return o != 0 ? bb.getInt(o + bb_pos) : 0; }

public static int createTemporaryVariableFlat(FlatBufferBuilder builder,
int offset) {
builder.startObject(1);
TemporaryVariableFlat.addOffset(builder, offset);
return TemporaryVariableFlat.endTemporaryVariableFlat(builder);
}

public static void startTemporaryVariableFlat(FlatBufferBuilder builder) { builder.startObject(1); }
public static void addOffset(FlatBufferBuilder builder, int offset) { builder.addInt(0, offset, 0); }
public static int endTemporaryVariableFlat(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

86 changes: 77 additions & 9 deletions core/src/main/resources/jruby.fbs
Original file line number Diff line number Diff line change
@@ -6,27 +6,95 @@ table IRScopeFlat {
nestedClosures:[IRClosureFlat];
lexicalChildren:[IRScopeFlat];
instrs:[InstrFlat];
tempVariables:short;
acceptsKeywordArguments:bool;
}

table IRClosureFlat {
scope:IRScopeFlat;
}

enum OperationFlat : short {
COPY, RECEIVE_SELF, LINE_NUMBER, CALL_1_OBJ, RETURN, LOAD_IMPLICIT_CLOSURE, LOAD_FRAME_CLOSURE
union OperandUnion {
StringLiteralFlat, FrozenStringFlat, TemporaryVariableFlat, CurrentScopeFlat, ScopeModuleFlat, SelfFlat
}

table InstrFlat {
operation:OperationFlat;
operands:[OperandFlat];
table OperandFlat {
operand:OperandUnion;
}

enum OperandTypeFlat : byte {
TEMPORARY_VARIABLE, CURRENT_SCOPE, SCOPE_MODULE, STRING_LITERAL, SELF
table StringLiteralFlat {
frozenString:FrozenStringFlat;
}

table OperandFlat {
operandType:OperandTypeFlat;
table FrozenStringFlat {
bytes:[byte];
encoding:string;
str:string;
coderange:int;
file:string;
line:int;
}

table TemporaryVariableFlat {
offset:int;
}

table CurrentScopeFlat {
dummy:byte;
}

table ScopeModuleFlat {
dummy:byte;
}

table SelfFlat {
dummy:byte;
}

union InstrUnion {
CopyFlat, ReceiveSelfFlat, LineNumberFlat, CallFlat, ReturnFlat, LoadImplicitClosureFlat, LoadFrameClosureFlat
}

table CopyFlat {
dummy:byte;
}

table ReceiveSelfFlat {
dummy:byte;
}

table LineNumberFlat {
line:int;
}

table CallFlat {
callType:int;
name:string;
argsCount:int;
hasClosure:bool;
canBeEval:bool;
targetRequiresCallersBinding:bool; // Does this call make use of the caller's binding?
targetRequiresCallersFrame:bool; // Does this call make use of the caller's frame?
splatMap:[bool];
potentiallyRefined:bool;
}

table ReturnFlat {
dummy:byte;
}

table LoadImplicitClosureFlat {
dummy:byte;
}

table LoadFrameClosureFlat {
dummy:byte;
}

table InstrFlat {
result:TemporaryVariableFlat;
operands:[OperandFlat];
instr:InstrUnion;
}

root_type IRScopeFlat;

0 comments on commit fb5a31c

Please sign in to comment.