diff --git a/src/NQP/World.nqp b/src/NQP/World.nqp index b58fc8e528..44867d85ac 100644 --- a/src/NQP/World.nqp +++ b/src/NQP/World.nqp @@ -101,7 +101,8 @@ class NQP::World is HLL::World { QAST::VM.new( :jvm(QAST::SVal.new( :value('ModuleLoader.class') )), :moar(QAST::SVal.new( :value('ModuleLoader.moarvm') )), - :js(QAST::SVal.new( :value('ModuleLoader') )) + :truffle(QAST::SVal.new( :value('ModuleLoader.truffle6') )), + :js(QAST::SVal.new( :value('ModuleLoader') )), ) ), ), diff --git a/src/vm/jvm/QAST/Compiler.nqp b/src/vm/jvm/QAST/Compiler.nqp index 49a6be2419..2555995e1d 100644 --- a/src/vm/jvm/QAST/Compiler.nqp +++ b/src/vm/jvm/QAST/Compiler.nqp @@ -3617,10 +3617,19 @@ class QAST::CompilerJAST { return 0; } - method deserialization_code($sc, @code_ref_blocks, $repo_conf_res) { - # Serialize it. + # This method is a hook point so that we can override serialization when cross-compiling + method serialize_sc($sc) { my $sh := nqp::list_s(); my $serialized := nqp::serialize($sc, $sh); + [$serialized, $sh]; + } + + method deserialization_code($sc, @code_ref_blocks, $repo_conf_res) { + # Serialize it. + + my $sc_tuple := self.serialize_sc($sc); + my $serialized := $sc_tuple[0]; + my $sh := $sc_tuple[1]; if %*COMPILING<%?OPTIONS> eq 'jar' { $*JCLASS.serialized($serialized); diff --git a/src/vm/jvm/Truffle.nqp b/src/vm/jvm/Truffle.nqp index d01e6b9476..523265ad83 100644 --- a/src/vm/jvm/Truffle.nqp +++ b/src/vm/jvm/Truffle.nqp @@ -135,6 +135,10 @@ class QAST::OperationsTruffle { }); } + add_simple_op('createsc', $OBJ, [$STR]); + add_simple_op('scsetdesc', $STR, [$OBJ, $STR]); + add_simple_op('deserialize', $STR, [$STR, $OBJ, $OBJ, $OBJ, $OBJ]); + add_simple_op('die', $VOID, [$STR]); %ops := %ops; @@ -146,6 +150,9 @@ class QAST::OperationsTruffle { add_simple_op('gethllsym', $OBJ, [$STR, $STR]); add_simple_op('bindhllsym', $OBJ, [$STR, $STR, $OBJ]); + add_simple_op('loadbytecode', $STR, [$STR]); + add_simple_op('forceouterctx', $OBJ, [$OBJ, $OBJ]); + add_simple_op('say', $STR, [$STR], :side_effects); add_simple_op('print', $STR, [$STR], :side_effects); @@ -398,25 +405,10 @@ class QAST::OperationsTruffle { $comp.as_truffle($node[0], :want($want)); }); - - # TODO :$want - add_op('call', :!inlinable, sub ($comp, $node, :$want) { + my sub compile_args($comp, @args, @trees, @flags, @names) { my int $NAMED := 1; my int $FLAT := 2; - my $ret := ['call']; - - my @args := $node.list; - - if $node.name { - nqp::push($ret, ['get-lexical', $node.name]); - } - else { - nqp::push($ret, $comp.as_truffle(nqp::shift(@args), :want($OBJ)).tree); - } - - my @names; - my @flags; for @args -> $arg { my int $flags := 0; @@ -430,24 +422,60 @@ class QAST::OperationsTruffle { nqp::push(@flags, $flags); - nqp::push($ret, $comp.as_truffle($arg, :want($CALL_ARG)).tree); + nqp::push(@trees, $comp.as_truffle($arg, :want($CALL_ARG)).tree); } - nqp::splice($ret, [@flags, @names], 2, 0); + } - TAST.new($OBJ, $ret); + add_op('callmethod', :!inlinable, sub ($comp, $node, :$want) { + my $call := ['callmethod']; + + my @args := nqp::clone($node.list); + + nqp::push($call, $comp.as_truffle(@args.shift, :want($OBJ)).tree); + + if $node.name { + nqp::push($call, ['sval', $node.name]); + } + else { + nqp::push($call, $comp.as_truffle(@args.shift, :want($STR)).tree); + } + + my @flags; + my @names; + + compile_args($comp, @args, $call, @flags, @names); + + nqp::splice($call, [@flags, @names], 3, 0); + + TAST.new($OBJ, $call); }); - %ops := %ops; - add_op('callmethod', :!inlinable, sub ($comp, $node, :$want) { - # HACK till we get proper callmethod - if $node.name eq 'name' && nqp::istype($node[0], QAST::Op) && $node[0].op eq 'callmethod' && $node[0].name eq 'backend' && nqp::istype($node[0][0], QAST::Op) && $node[0][0].op eq 'getcomp' { - TAST.new($STR, ['sval', 'truffle']) - } else { - $comp.NYI("unimplemented QAST::Op {$node.op}"); + # TODO :$want + add_op('call', :!inlinable, sub ($comp, $node, :$want) { + my $ret := ['call']; + + my @args := $node.list; + + if $node.name { + nqp::push($ret, ['get-lexical', $node.name]); + } + else { + nqp::push($ret, $comp.as_truffle(nqp::shift(@args), :want($OBJ)).tree); } + + my @flags; + my @names; + + compile_args($comp, @args, $ret, @flags, @names); + + nqp::splice($ret, [@flags, @names], 2, 0); + + TAST.new($OBJ, $ret); }); + %ops := %ops; + add_op('bind', sub ($comp, $node, :$want) { my @children := $node.list; if +@children != 2 { @@ -495,7 +523,45 @@ class QAST::OperationsTruffle { } } -class QAST::TruffleCompiler { +# It only makes sense to serialize a serialization context once, so when cross compiling we cache the result +role SerializeOnce { + method serialize_sc_without_caching($sc) { + # Serialize it. + + # HACK - we are avoiding an MoarVM specific optimalization + # On MoarVM if an sc is on top of the compiling_scs stackthread the serialized data is stored on the thread context + # We have no way of accessing it, so we try to avoid that + # If we put a fake sc on top of the stack it won't be cached + # we avoid anything that creates a write barrier while it's on top + my $fake_stack_top_sc := nqp::createsc('JS_HACK'); + nqp::pushcompsc($fake_stack_top_sc); + + my $sh := nqp::list_s(); + my $serialized := nqp::serialize($sc, $sh); + + # HACK - now we pop our fake sc + nqp::popcompsc(); + + [$serialized,$sh]; + } + + method serialize_sc($sc) { + if %*SC_CACHE { + my $handle := nqp::scgethandle($sc); + if nqp::existskey(%*SC_CACHE,$handle) { + %*SC_CACHE{$handle}; + } + else { + %*SC_CACHE{$handle} := self.serialize_sc_without_caching($sc); + } + } + else { + self.serialize_sc_without_caching($sc); + } + } +} + +class QAST::TruffleCompiler does SerializeOnce { my class BlockInfo { has $!qast; # The QAST::Block has $!outer; # Outer block's BlockInfo @@ -685,6 +751,78 @@ class QAST::TruffleCompiler { } } + method deserialization_code($cu) { + # Serialize it. + + my $sc_tuple := self.serialize_sc($cu.sc); + my $serialized := $sc_tuple[0]; + my $sh := $sc_tuple[1]; + + # Now it's serialized, pop this SC off the compiling SC stack. + nqp::popcompsc(); + + # String heap QAST. + my $sh_ast := QAST::Op.new( :op('list_s') ); + my $sh_elems := nqp::elems($sh); + my $i := 0; + while $i < $sh_elems { + $sh_ast.push(nqp::isnull_s(nqp::atpos_s($sh, $i)) + ?? QAST::Op.new( :op('null_s') ) + !! QAST::SVal.new( :value(nqp::atpos_s($sh, $i)) )); + $i := $i + 1; + } + $sh_ast := QAST::Block.new( :blocktype('immediate'), $sh_ast ); + + my $repo_conflict_resolver; + + # Handle repossession conflict resolution code, if any. + if $cu.repo_conflict_resolver { + $repo_conflict_resolver := nqp::clone($cu.repo_conflict_resolver); + $repo_conflict_resolver.push(QAST::Var.new( :name('conflicts'), :scope('local') )); + } + else { + $repo_conflict_resolver := QAST::Op.new( + :op('die_s'), + QAST::SVal.new( :value('Repossession conflicts occurred during deserialization') ) + ); + } + + # Overall deserialization QAST. + QAST::Stmts.new( + QAST::Op.new( + :op('bind'), + QAST::Var.new( :name('cur_sc'), :scope('local'), :decl('var') ), + QAST::Op.new( :op('createsc'), QAST::SVal.new( :value(nqp::scgethandle($cu.sc)) ) ) + ), + QAST::Op.new( + :op('scsetdesc'), + QAST::Var.new( :name('cur_sc'), :scope('local') ), + QAST::SVal.new( :value(nqp::scgetdesc($cu.sc)) ) + ), + QAST::Op.new( + :op('bind'), + QAST::Var.new( :name('conflicts'), :scope('local'), :decl('var') ), + QAST::Op.new( :op('list') ) + ), + QAST::Op.new( + :op('deserialize'), + nqp::isnull($serialized) ?? QAST::Op.new( :op('null_s') ) !! QAST::SVal.new( :value($serialized) ), + QAST::Var.new( :name('cur_sc'), :scope('local') ), + $sh_ast, + QAST::Op.new( :op('null') ), + QAST::Var.new( :name('conflicts'), :scope('local') ) + ), + QAST::Op.new( + :op('if'), + QAST::Op.new( + :op('elems'), + QAST::Var.new( :name('conflicts'), :scope('local') ) + ), + $repo_conflict_resolver + ) + ); + } + multi method as_truffle(QAST::CompUnit $node, :$want) { my $*HLL := ''; if $node.hll { @@ -693,7 +831,20 @@ class QAST::TruffleCompiler { my $*BLOCK := BlockInfo.new(NQPMu, NQPMu); - TAST.new($OBJ, ['comp-unit', $node.hll, ['stmts', self.as_truffle($node[0][1], :want($VOID)).tree, self.as_truffle($node[0][3], :want($OBJ)).tree]]); + my $pre_deserialize := ['stmts']; + + my $deserialization_code := $node.compilation_mode + ?? self.as_truffle(self.deserialization_code($node), :want($VOID)).tree + !! ['stmts']; + + + if $node.pre_deserialize { + for $node.pre_deserialize -> $pre { + nqp::push($pre_deserialize, self.as_truffle($pre, :want($VOID)).tree); + } + } + + TAST.new($OBJ, ['comp-unit', $node.hll, ['stmts', $pre_deserialize, $deserialization_code, self.as_truffle($node[0][1], :want($VOID)).tree, self.as_truffle($node[0][3], :want($OBJ)).tree]]); } multi method as_truffle(QAST::VM $node, :$want) { @@ -879,9 +1030,16 @@ class QAST::TruffleCompiler { self.NYI('QAST node: ' ~ $node.HOW.name($node)); } - # HACK before we deserialize objects + multi method as_truffle(QAST::BVal $node, :$want) { + TAST.new($OBJ, ['bval', $node.value.cuid]); + } + multi method as_truffle(QAST::WVal $node, :$want) { - TAST.new($OBJ, ['null']); + my $value := $node.value; + my $sc := nqp::getobjsc($value); + my str $handle := nqp::scgethandle($sc); + my int $idx := nqp::scgetobjidx($sc, $value); + TAST.new($OBJ, ['wval', $handle, $idx]); } method NYI($msg) { @@ -961,7 +1119,8 @@ class TruffleBackend { } method is_precomp_stage($stage) { - 0; + # Currently, everything is pre-comp since we're a cross-compiler. + 1; } method is_textual_stage($stage) { diff --git a/src/vm/jvm/bin/run_tests.pl b/src/vm/jvm/bin/run_tests.pl index 5855758053..d375fffac0 100644 --- a/src/vm/jvm/bin/run_tests.pl +++ b/src/vm/jvm/bin/run_tests.pl @@ -9,6 +9,6 @@ } }); -my @nqp_tests = glob "t/nqp/{001,002,003,004,005,006,007,008,010,011,013,015,016,036,037,038,046,083,109}*.t"; +my @nqp_tests = glob "t/nqp/{001,002,003,004,005,006,007,008,010,011,013,015,016,036,037,038,046,083}*.t"; $harness->runtests(@nqp_tests); diff --git a/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/NQPBValNode.java b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/NQPBValNode.java new file mode 100644 index 0000000000..1e2ebdec83 --- /dev/null +++ b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/NQPBValNode.java @@ -0,0 +1,23 @@ +package org.perl6.nqp.truffle.nodes.expression; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.NodeInfo; +import org.perl6.nqp.truffle.nodes.NQPNode; +import org.perl6.nqp.truffle.nodes.NQPObjNode; +import org.perl6.nqp.dsl.Deserializer; + +@NodeInfo(shortName = "BVal") +public final class NQPBValNode extends NQPObjNode { + final String cuid; + + @Deserializer + public NQPBValNode(String cuid) { + this.cuid = cuid; + } + + @Override + public Object execute(VirtualFrame frame) { + //return bval(argNode.executeStr(frame)); + System.out.println("BVal NYI"); + return org.perl6.nqp.truffle.runtime.NQPNull.SINGLETON; + } +} diff --git a/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/call/NQPCallmethodNode.java b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/call/NQPCallmethodNode.java new file mode 100644 index 0000000000..4f6cc88a39 --- /dev/null +++ b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/call/NQPCallmethodNode.java @@ -0,0 +1,42 @@ +package org.perl6.nqp.truffle.nodes.call; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.nodes.NodeInfo; +import org.perl6.nqp.truffle.nodes.NQPNode; +import org.perl6.nqp.truffle.nodes.NQPObjNode; +import org.perl6.nqp.dsl.Deserializer; + +@NodeInfo(shortName = "invoke") +public final class NQPCallmethodNode extends NQPObjNode { + + public static final long NAMED = 1; + public static final long FLAT = 2; + + @Child private NQPNode invocantNode; + @Child private NQPNode methodNode; + + @CompilationFinal(dimensions = 1) + private final long[] argumentFlags; + + @CompilationFinal(dimensions = 1) + private final String[] argumentNames; + + @Children private final NQPNode[] argumentNodes; + + @Deserializer("callmethod") + public NQPCallmethodNode(NQPNode invocantNode, NQPNode methodNode, long[] argumentFlags, String[] argumentNames, NQPNode[] argumentNodes) { + this.invocantNode = invocantNode; + this.methodNode = methodNode; + this.argumentFlags = argumentFlags; + this.argumentNames = argumentNames; + this.argumentNodes = argumentNodes; + } + + @Override + public Object execute(VirtualFrame frame) { + System.out.println("callmethod NYI"); + return org.perl6.nqp.truffle.runtime.NQPNull.SINGLETON; + } +} + diff --git a/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPCreatescNode.java b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPCreatescNode.java new file mode 100644 index 0000000000..0ffd4a685d --- /dev/null +++ b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPCreatescNode.java @@ -0,0 +1,24 @@ +package org.perl6.nqp.truffle.nodes.expression; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.NodeInfo; +import org.perl6.nqp.truffle.nodes.NQPNode; +import org.perl6.nqp.truffle.nodes.NQPObjNode; + +import org.perl6.nqp.truffle.sixmodel.SerializationContext; + +import org.perl6.nqp.dsl.Deserializer; + +@NodeInfo(shortName = "createsc") +public final class NQPCreatescNode extends NQPObjNode { + @Child private NQPNode handleNode; + + @Deserializer + public NQPCreatescNode(NQPNode handleNode) { + this.handleNode = handleNode; + } + + @Override + public Object execute(VirtualFrame frame) { + return new SerializationContext(handleNode.executeStr(frame)); + } +} diff --git a/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPDeserializeNode.java b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPDeserializeNode.java new file mode 100644 index 0000000000..e74aa6f619 --- /dev/null +++ b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPDeserializeNode.java @@ -0,0 +1,51 @@ +package org.perl6.nqp.truffle.nodes.expression; + +import java.nio.ByteBuffer; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.NodeInfo; +import org.perl6.nqp.dsl.Deserializer; +import org.perl6.nqp.truffle.nodes.NQPNode; +import org.perl6.nqp.truffle.nodes.NQPStrNode; +import org.perl6.nqp.truffle.runtime.NQPListStr; +import org.perl6.nqp.truffle.runtime.Base64; +import org.perl6.nqp.truffle.sixmodel.SerializationReader; +import org.perl6.nqp.truffle.sixmodel.SerializationContext; + +@NodeInfo(shortName = "deserialize") +public final class NQPDeserializeNode extends NQPStrNode { + @Child private NQPNode blobNode; + @Child private NQPNode scRefNode; + @Child private NQPNode shNode; + @Child private NQPNode crNode; + @Child private NQPNode conflictNode; + + @Deserializer + public NQPDeserializeNode(NQPNode blobNode, NQPNode scRefNode, NQPNode shNode, NQPNode crNode, NQPNode conflictNode) { + this.blobNode = blobNode; + this.scRefNode = scRefNode; + this.shNode = shNode; + this.crNode = crNode; + this.conflictNode = conflictNode; + } + + @Override + public String executeStr(VirtualFrame frame) { + String blob = blobNode.executeStr(frame); + SerializationContext sc = (SerializationContext) scRefNode.execute(frame); + NQPListStr shList = (NQPListStr) shNode.execute(frame); + Object cr = crNode.execute(frame); + Object conflict = conflictNode.execute(frame); + + System.out.println("deserializing"); + ByteBuffer binaryBlob = Base64.decode(blob); + + + String[] sh = new String[shList.elems()]; + + SerializationReader sr = new SerializationReader(sc, sh, binaryBlob); + // tc, sc, shArray, crArray, crCount, binaryBlob); + sr.deserialize(); + + return blob; + } +} diff --git a/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPForceouterctxNode.java b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPForceouterctxNode.java new file mode 100644 index 0000000000..837229b798 --- /dev/null +++ b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPForceouterctxNode.java @@ -0,0 +1,26 @@ +package org.perl6.nqp.truffle.nodes.expression; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.NodeInfo; +import org.perl6.nqp.truffle.nodes.NQPNode; +import org.perl6.nqp.truffle.nodes.NQPObjNode; +import org.perl6.nqp.dsl.Deserializer; + +@NodeInfo(shortName = "forceouterctx") +public final class NQPForceouterctxNode extends NQPObjNode { + @Child private NQPNode codeNode; + @Child private NQPNode ctxNode; + + @Deserializer + public NQPForceouterctxNode(NQPNode codeNode, NQPNode ctxNode) { + this.codeNode = codeNode; + this.ctxNode = ctxNode; + } + + @Override + public Object execute(VirtualFrame frame) { + Object code = codeNode.execute(frame); + Object ctx = ctxNode.execute(frame); + System.out.println("forceouterctx NYI"); + return code; + } +} diff --git a/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPLoadbytecodeNode.java b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPLoadbytecodeNode.java new file mode 100644 index 0000000000..805ab20513 --- /dev/null +++ b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPLoadbytecodeNode.java @@ -0,0 +1,23 @@ +package org.perl6.nqp.truffle.nodes.expression; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.NodeInfo; +import org.perl6.nqp.truffle.nodes.NQPNode; +import org.perl6.nqp.truffle.nodes.NQPStrNode; +import org.perl6.nqp.dsl.Deserializer; + +@NodeInfo(shortName = "loadbytecode") +public final class NQPLoadbytecodeNode extends NQPStrNode { + @Child private NQPNode argNode; + + @Deserializer + public NQPLoadbytecodeNode(NQPNode argNode) { + this.argNode = argNode; + } + + @Override + public String executeStr(VirtualFrame frame) { + String file = argNode.executeStr(frame); + System.out.println("loadbytecode NYI"); + return file; + } +} diff --git a/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPScsetdescNode.java b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPScsetdescNode.java new file mode 100644 index 0000000000..66580a80f2 --- /dev/null +++ b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPScsetdescNode.java @@ -0,0 +1,27 @@ +package org.perl6.nqp.truffle.nodes.expression; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.NodeInfo; +import org.perl6.nqp.truffle.nodes.NQPNode; +import org.perl6.nqp.truffle.nodes.NQPStrNode; +import org.perl6.nqp.dsl.Deserializer; +import org.perl6.nqp.truffle.sixmodel.SerializationContext; + +@NodeInfo(shortName = "scsetdesc") +public final class NQPScsetdescNode extends NQPStrNode { + @Child private NQPNode scRefNode; + @Child private NQPNode descriptionNode; + + @Deserializer + public NQPScsetdescNode(NQPNode scRefNode, NQPNode descriptionNode) { + this.scRefNode = scRefNode; + this.descriptionNode = descriptionNode; + } + + @Override + public String executeStr(VirtualFrame frame) { + SerializationContext scRef = (SerializationContext) scRefNode.execute(frame); + String description = descriptionNode.executeStr(frame); + scRef.description = description; + return description; + } +} diff --git a/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPWValNode.java b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPWValNode.java new file mode 100644 index 0000000000..99a70d63fb --- /dev/null +++ b/src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/expression/NQPWValNode.java @@ -0,0 +1,24 @@ +package org.perl6.nqp.truffle.nodes.expression; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.NodeInfo; +import org.perl6.nqp.dsl.Deserializer; +import org.perl6.nqp.truffle.nodes.NQPNode; +import org.perl6.nqp.truffle.nodes.NQPObjNode; +import org.perl6.nqp.truffle.runtime.NQPNull; + +@NodeInfo(shortName = "wval") +public final class NQPWValNode extends NQPObjNode { + private final String handle; + private final long idx; + + @Deserializer + public NQPWValNode(String handle, long idx) { + this.handle = handle; + this.idx = idx; + } + + @Override + public Object execute(VirtualFrame frame) { + return NQPNull.SINGLETON; + } +} diff --git a/src/vm/jvm/runtime/org/perl6/nqp/truffle/runtime/Base64.java b/src/vm/jvm/runtime/org/perl6/nqp/truffle/runtime/Base64.java new file mode 100644 index 0000000000..e34e7b5c1a --- /dev/null +++ b/src/vm/jvm/runtime/org/perl6/nqp/truffle/runtime/Base64.java @@ -0,0 +1,102 @@ +package org.perl6.nqp.truffle.runtime; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import java.nio.ByteBuffer; + +public class Base64 { + private static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray(); + + /* This works around a lack of unsigned in Java. */ + private static int deSign(byte b) { + if (b < 0) + return (int)b + 256; + else + return (int)b; + } + + public static String encode(ByteBuffer buf) + { + int size = buf.capacity(); + char[] str = new char[(size + 3) * 4/3 + 1]; + + int p = 0; + int i = 0; + buf.position(0); + while (i < size) { + int c = deSign(buf.get()); + i++; + + c *= 256; + if (i < size) + c += deSign(buf.get()); + i++; + + c *= 256; + if (i < size) + c += deSign(buf.get()); + i++; + + str[p++] = base64[(c & 0x00fc0000) >> 18]; + str[p++] = base64[(c & 0x0003f000) >> 12]; + + if (i > size + 1) + str[p++] = '='; + else + str[p++] = base64[(c & 0x00000fc0) >> 6]; + + if (i > size) + str[p++] = '='; + else + str[p++] = base64[c & 0x0000003f]; + } + + return String.copyValueOf(str, 0, p); + } + + private static int POS(char c) + { + if (c >= 'A' && c <= 'Z') return c - 'A'; + if (c >= 'a' && c <= 'z') return c - 'a' + 26; + if (c >= '0' && c <= '9') return c - '0' + 52; + if (c == '+') return 62; + if (c == '/') return 63; + if (c == '=') return -1; + return -2; + } + + @TruffleBoundary + public static ByteBuffer decode(String s) + { + if (s.length() % 4 != 0) + new RuntimeException("Invalid Base64 input"); + + byte[] data = new byte[s.length() / 4 * 3]; + int n[] = new int[4]; + int p = 0, q = 0; + + while (p < s.length()) { + n[0] = POS(s.charAt(p++)); + n[1] = POS(s.charAt(p++)); + n[2] = POS(s.charAt(p++)); + n[3] = POS(s.charAt(p++)); + + if (n[0] == -2 || n[1] == -2 || n[2] == -2 || n[3] == -2) + new RuntimeException("Invalid Base64 input"); + + if (n[0] == -1 || n[1] == -1) + new RuntimeException("Invalid Base64 input"); + + if (n[2] == -1 && n[3] != -1) + new RuntimeException("Invalid Base64 input"); + + data[q] = (byte)((n[0] << 2) + (n[1] >> 4)); + if (n[2] != -1) + data[q + 1] = (byte)(((n[1] & 15) << 4) + (n[2] >> 2)); + if (n[3] != -1) + data[q + 2] = (byte)(((n[2] & 3) << 6) + n[3]); + q += 3; + } + + return ByteBuffer.wrap(data, 0, q - (n[2] == -1 ? 1 : 0) - (n[3]==-1 ? 1 : 0)); + } +} diff --git a/src/vm/jvm/runtime/org/perl6/nqp/truffle/sixmodel/SerializationContext.java b/src/vm/jvm/runtime/org/perl6/nqp/truffle/sixmodel/SerializationContext.java new file mode 100644 index 0000000000..e58d3dcebd --- /dev/null +++ b/src/vm/jvm/runtime/org/perl6/nqp/truffle/sixmodel/SerializationContext.java @@ -0,0 +1,14 @@ +package org.perl6.nqp.truffle.sixmodel; + +public final class SerializationContext { + /* The handle of this SC. */ + public String handle; + + /* Description (probably the file name) if any. */ + public String description; + + public SerializationContext(String handle) { + this.handle = handle; + } + +} diff --git a/src/vm/jvm/runtime/org/perl6/nqp/truffle/sixmodel/SerializationReader.java b/src/vm/jvm/runtime/org/perl6/nqp/truffle/sixmodel/SerializationReader.java new file mode 100644 index 0000000000..5ce8a75cfa --- /dev/null +++ b/src/vm/jvm/runtime/org/perl6/nqp/truffle/sixmodel/SerializationReader.java @@ -0,0 +1,726 @@ +package org.perl6.nqp.truffle.sixmodel; + +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.Map; + +public class SerializationReader { + /* The current version of the serialization format. */ + private final int CURRENT_VERSION = 11; + + /* The minimum version of the serialization format. */ + private final int MIN_VERSION = 4; + + /* Various sizes (in bytes). */ + private final int V10_HEADER_SIZE = 4 * 16; + private final int HEADER_SIZE = 4 * 18; + private final int DEP_TABLE_ENTRY_SIZE = 8; + private final int STABLES_TABLE_ENTRY_SIZE = 12; + private final int OBJECTS_TABLE_ENTRY_SIZE = 16; + private final int CLOSURES_TABLE_ENTRY_SIZE = 24; + private final int CONTEXTS_TABLE_ENTRY_SIZE = 16; + private final int REPOS_TABLE_ENTRY_SIZE = 16; + + /* Possible reference types we can serialize. */ + private final short REFVAR_NULL = 1; + private final short REFVAR_OBJECT = 2; + private final short REFVAR_VM_NULL = 3; + private final short REFVAR_VM_INT = 4; + private final short REFVAR_VM_NUM = 5; + private final short REFVAR_VM_STR = 6; + private final short REFVAR_VM_ARR_VAR = 7; + private final short REFVAR_VM_ARR_STR = 8; + private final short REFVAR_VM_ARR_INT = 9; + private final short REFVAR_VM_HASH_STR_VAR = 10; + private final short REFVAR_STATIC_CODEREF = 11; + private final short REFVAR_CLONED_CODEREF = 12; +// +// /* Starting state. */ +// private ThreadContext tc; + private SerializationContext sc; + + private String[] sh; + +// private CodeRef[] cr; +// private int crCount; +// private CallFrame[] contexts; + + private ByteBuffer orig; + + /* The version of the serialization format we're currently reading. */ + public int version; + + /* Various table offsets and entry counts. */ + private int depTableOffset; + private int depTableEntries; + private int stTableOffset; + private int stTableEntries; + private int stDataOffset; + private int objTableOffset; + private int objTableEntries; + private int objDataOffset; + private int closureTableOffset; + private int closureTableEntries; + private int contextTableOffset; + private int contextTableEntries; + private int contextDataOffset; + private int reposTableOffset; + private int reposTableEntries; + private int stringHeapOffset; + private int stringHeapEntries; + +// /* Serialization contexts we depend on. */ +// SerializationContext[] dependentSCs; +// +// /* The object we're currently deserializing. */ +// SixModelObject curObject; +// + +// CodeRef[] cr, int crCount, + + public SerializationReader(SerializationContext sc, String[] sh, ByteBuffer orig) { + this.sc = sc; + this.sh = sh; +// this.cr = cr; +// this.crCount = crCount; + this.orig = orig; + } + + public void deserialize() { + // Serialized data is always little endian. + orig.order(ByteOrder.LITTLE_ENDIAN); +// + // Split the input into the various segments. + checkAndDisectInput(); +// +// deserializeStringHeap(); +// +// resolveDependencies(); +// +// // Put code refs in place. +// for (int i = 0; i < crCount; i++) { +// cr[i].isStaticCodeRef = true; +// cr[i].sc = sc; +// sc.addCodeRef(cr[i]); +// } +// +// // Handle any STable repossessions, then stub STables. +// sc.initSTableList(stTableEntries); +// if (reposTableEntries > 0) +// repossess(1); +// stubSTables(); +// +// // Handle any object repossessions, then stub objects. +// sc.initObjectList(objTableEntries); +// if (reposTableEntries > 0) +// repossess(0); +// stubObjects(); +// +// // Do first step of deserializing any closures. +// deserializeClosures(); +// +// // Second passes over STables and objects. +// deserializeSTables(); +// deserializeObjects(); +// +// // Finish up contexts and closures. +// deserializeContexts(); +// attachClosureOuters(crCount); +// attachContextOuters(); +// fixupContextOuters(); + } +// +// /* Checks the header looks sane and all of the places it points to make sense. +// * Also disects the input string into the tables and data segments and populates +// * the reader data structure more fully. */ + private void checkAndDisectInput() { + int prov_pos = 0; + int data_len = orig.limit(); + + /* Ensure that we have enough space to read a version number and check it. */ + if (data_len < 4) + throw new RuntimeException("Serialized data too short to read a version number (< 4 bytes)"); + version = orig.getInt(); + if (version < MIN_VERSION || version > CURRENT_VERSION) + throw new RuntimeException("Unknown serialization format version " + version); + + /* Ensure that the data is at least as long as the header is expected to be. */ + int headerSize = version >= 11 ? HEADER_SIZE : V10_HEADER_SIZE; + if (data_len < headerSize) + throw new RuntimeException("Serialized data shorter than header (< " + headerSize + " bytes)"); + prov_pos += headerSize; + + /* Get size and location of dependencies table. */ + depTableOffset = orig.getInt(); + depTableEntries = orig.getInt(); + if (depTableOffset < prov_pos) + throw new RuntimeException("Corruption detected (dependencies table starts before header ends)"); + prov_pos += depTableEntries * DEP_TABLE_ENTRY_SIZE; + if (prov_pos > data_len) + throw new RuntimeException("Corruption detected (dependencies table overruns end of data)"); + + /* Get size and location of STables table. */ + stTableOffset = orig.getInt(); + stTableEntries = orig.getInt(); + if (stTableOffset < prov_pos) + throw new RuntimeException("Corruption detected (STables table starts before dependencies table ends)"); + prov_pos += stTableEntries * STABLES_TABLE_ENTRY_SIZE; + if (prov_pos > data_len) + throw new RuntimeException("Corruption detected (STables table overruns end of data)"); + + /* Get location of STables data. */ + stDataOffset = orig.getInt(); + if (stDataOffset < prov_pos) + throw new RuntimeException("Corruption detected (STables data starts before STables table ends)"); + prov_pos = stDataOffset; + if (stDataOffset > data_len) + throw new RuntimeException("Corruption detected (STables data starts after end of data)"); + + /* Get size and location of objects table. */ + objTableOffset = orig.getInt(); + objTableEntries = orig.getInt(); + if (objTableOffset < prov_pos) + throw new RuntimeException("Corruption detected (objects table starts before STables data ends)"); + prov_pos = objTableOffset + objTableEntries * OBJECTS_TABLE_ENTRY_SIZE; + if (prov_pos > data_len) + throw new RuntimeException("Corruption detected (objects table overruns end of data)"); + + /* Get location of objects data. */ + objDataOffset = orig.getInt(); + if (objDataOffset < prov_pos) + throw new RuntimeException("Corruption detected (objects data starts before objects table ends)"); + prov_pos = objDataOffset; + if (prov_pos > data_len) + throw new RuntimeException("Corruption detected (objects data starts after end of data)"); + + /* Get size and location of closures table. */ + closureTableOffset = orig.getInt(); + closureTableEntries = orig.getInt(); + if (closureTableOffset < prov_pos) + throw new RuntimeException("Corruption detected (Closures table starts before objects data ends)"); + prov_pos = closureTableOffset + closureTableEntries * CLOSURES_TABLE_ENTRY_SIZE; + if (prov_pos > data_len) + throw new RuntimeException("Corruption detected (Closures table overruns end of data)"); + + /* Get size and location of contexts table. */ + contextTableOffset = orig.getInt(); + contextTableEntries = orig.getInt(); + if (contextTableOffset < prov_pos) + throw new RuntimeException("Corruption detected (contexts table starts before closures table ends)"); + prov_pos = contextTableOffset + contextTableEntries * CONTEXTS_TABLE_ENTRY_SIZE; + if (prov_pos > data_len) + throw new RuntimeException("Corruption detected (contexts table overruns end of data)"); + + /* Get location of contexts data. */ + contextDataOffset = orig.getInt(); + if (contextDataOffset < prov_pos) + throw new RuntimeException("Corruption detected (contexts data starts before contexts table ends)"); + prov_pos = contextDataOffset; + if (prov_pos > data_len) + throw new RuntimeException("Corruption detected (contexts data starts after end of data)"); + + /* Get size and location of repossessions table. */ + reposTableOffset = orig.getInt(); + reposTableEntries = orig.getInt(); + if (reposTableOffset < prov_pos) + throw new RuntimeException("Corruption detected (repossessions table starts before contexts data ends)"); + prov_pos = reposTableOffset + reposTableEntries * REPOS_TABLE_ENTRY_SIZE; + if (prov_pos > data_len) + throw new RuntimeException("Corruption detected (repossessions table overruns end of data)"); + + if (version >= 11) { + /* Get size and location of string heap. */ + stringHeapOffset = orig.getInt(); + stringHeapEntries = orig.getInt(); + if (stringHeapOffset < prov_pos) + throw new RuntimeException("Corruption detected (string table starts before repossessions tabke ends)"); + prov_pos = stringHeapOffset; + if (prov_pos > data_len) + throw new RuntimeException("Corruption detected (string table starts after end of data)"); + } + } + + private void deserializeStringHeap() { + if (version >= 11) { + sh = new String[stringHeapEntries + 1]; + sh[0] = null; + + orig.position(stringHeapOffset); + for (int i = 1; i <= stringHeapEntries; i++) { + int len = orig.getInt(); + byte[] bytes = new byte[len]; + orig.get(bytes, 0, len); + + try { + sh[i] = new String(bytes, "utf-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("Failed to decode a utf-8 encoded string heap entry"); + } + } + } + } + +// private void resolveDependencies() { +// dependentSCs = new SerializationContext[depTableEntries]; +// orig.position(depTableOffset); +// for (int i = 0; i < depTableEntries; i++) { +// String handle = lookupString(orig.getInt()); +// String desc = lookupString(orig.getInt()); +// SerializationContext sc = tc.gc.scs.get(handle); +// if (sc == null) { +// if (desc == null) +// desc = handle; +// throw new RuntimeException( +// "Missing or wrong version of dependency '" + desc + "'"); +// } +// dependentSCs[i] = sc; +// } +// } +// +// /* Repossess an object or STable. */ +// private void repossess(int chosenType) { +// for (int i = 0; i < reposTableEntries; i++) { +// /* Go to table row. */ +// orig.position(reposTableOffset + i * REPOS_TABLE_ENTRY_SIZE); +// +// /* Do appropriate type of repossession. */ +// int repoType = orig.getInt(); +// if (repoType != chosenType) +// continue; +// int objIdx = orig.getInt(); +// int origSCIdx = orig.getInt(); +// int origObjIdx = orig.getInt(); +// if (repoType == 0) { +// /* Get object to repossess. */ +// SerializationContext origSC = locateSC(origSCIdx); +// SixModelObject origObj = origSC.getObject(origObjIdx); +// +// /* Ensure we aren't already trying to repossess the object. */ +// /* XXX TODO */ +// +// /* Put it into objects root set at the appropriate slot. */ +// sc.addObject(origObj, objIdx); +// origObj.sc = sc; +// +// /* The object's STable may have changed as a result of the +// * repossession (perhaps due to mixing in to it), so put the +// * STable it should now have in place. */ +// orig.position(objTableOffset + objIdx * OBJECTS_TABLE_ENTRY_SIZE); +// origObj.st = lookupSTable(orig.getInt(), orig.getInt()); +// } +// else if (repoType == 1) { +// /* Get STable to repossess. */ +// SerializationContext origSC = locateSC(origSCIdx); +// STable origST = origSC.getSTable(origObjIdx); +// +// /* Ensure we aren't already trying to repossess the STable. */ +// /* XXX TODO */ +// +// /* Put it into STables root set at the apporpriate slot. */ +// sc.setSTable(objIdx, origST); +// origST.sc = sc; +// } +// else { +// throw new RuntimeException("Unknown repossession type"); +// } +// } +// } +// +// private void stubSTables() { +// for (int i = 0; i < stTableEntries; i++) { +// // May already have it, due to repossession. +// if (sc.getSTable(i) != null) +// continue; +// +// // Look up representation. +// orig.position(stTableOffset + i * STABLES_TABLE_ENTRY_SIZE); +// REPR repr = REPRRegistry.getByName(lookupString(orig.getInt())); +// +// // Create STable stub and add it to the root STable set. +// STable st = new STable(repr, null); +// st.sc = sc; +// sc.setSTable(i, st); +// } +// } +// +// private void stubObjects() { +// for (int i = 0; i < objTableEntries; i++) { +// // May already have it, due to repossession. +// if (sc.getObject(i) != null) +// continue; +// +// // Look up STable. +// orig.position(objTableOffset + i * OBJECTS_TABLE_ENTRY_SIZE); +// STable st = lookupSTable(orig.getInt(), orig.getInt()); +// +// // Now go by object flags. +// SixModelObject stubObj; +// orig.position(orig.position() + 4); +// int flags = orig.getInt(); +// if (flags == 0) { +// // Type object. +// stubObj = new TypeObject(); +// stubObj.st = st; +// } +// else { +// // Concrete object; defer to the REPR. +// stubObj = st.REPR.deserialize_stub(tc, st); +// } +// +// // Place object in SC root set. +// stubObj.sc = sc; +// sc.addObject(stubObj, i); +// } +// } +// +// private void deserializeClosures() { +// for (int i = 0; i < closureTableEntries; i++) { +// /* Seek to the closure's table row. */ +// orig.position(closureTableOffset + i * CLOSURES_TABLE_ENTRY_SIZE); +// +// /* Resolve the reference to the static code object. */ +// CodeRef staticCode = readCodeRef(); +// +// /* Clone it and add it to this SC's code refs list. */ +// CodeRef closure = (CodeRef)staticCode.clone(tc); +// closure.sc = sc; +// sc.addCodeRef(closure); +// +// /* See if there's a code object we need to attach. */ +// orig.position(orig.position() + 4); +// if (orig.getInt() != 0) +// closure.codeObject = readObjRef(); +// } +// } +// +// private void deserializeSTables() { +// for (int i = 0; i < stTableEntries; i++) { +// // Seek to the right position in the data chunk. +// orig.position(stTableOffset + i * STABLES_TABLE_ENTRY_SIZE + 4); +// orig.position(stDataOffset + orig.getInt()); +// +// // Get the STable we need to deserialize into. +// STable st = sc.getSTable(i); +// +// // Read the HOW, WHAT and WHO. +// st.HOW = readObjRef(); +// st.WHAT = readObjRef(); +// st.WHO = readRef(); +// +// /* Method cache and v-table. */ +// SixModelObject methodCache = readRef(); +// if (methodCache != null) +// st.MethodCache = ((VMHashInstance)methodCache).storage; +// st.VTable = new SixModelObject[(int)orig.getLong()]; +// for (int j = 0; j < st.VTable.length; j++) +// st.VTable[j] = readRef(); +// +// /* Type check cache. */ +// int tcCacheSize = (int)orig.getLong(); +// if (tcCacheSize > 0) { +// st.TypeCheckCache = new SixModelObject[tcCacheSize]; +// for (int j = 0; j < st.TypeCheckCache.length; j++) +// st.TypeCheckCache[j] = readRef(); +// } +// +// /* Mode flags. */ +// st.ModeFlags = (int)orig.getLong(); +// +// /* Boolification spec. */ +// if (orig.getLong() != 0) { +// st.BoolificationSpec = new BoolificationSpec(); +// st.BoolificationSpec.Mode = (int)orig.getLong(); +// st.BoolificationSpec.Method = readRef(); +// } +// +// /* Container spec. */ +// if (orig.getLong() != 0) { +// if (version >= 5) { +// String ccName = readStr(); +// ContainerConfigurer cc = tc.gc.contConfigs.get(ccName); +// if (cc == null) +// throw new RuntimeException("Unknown container config " + ccName); +// cc.setContainerSpec(tc, st); +// st.ContainerSpec.deserialize(tc, st, this); +// } +// else { +// throw new RuntimeException("Unable to deserialize old container spec format"); +// } +// } +// +// /* Invocation spec. */ +// if (version >= 5) { +// if (orig.getLong() != 0) { +// st.InvocationSpec = new InvocationSpec(); +// st.InvocationSpec.ClassHandle = readRef(); +// st.InvocationSpec.AttrName = lookupString(orig.getInt()); +// st.InvocationSpec.Hint = (int)orig.getLong(); +// st.InvocationSpec.InvocationHandler = readRef(); +// } +// } +// +// /* HLL stuff. */ +// if (version >= 6) { +// st.hllOwner = tc.gc.getHLLConfigFor(readStr()); +// st.hllRole = orig.getLong(); +// } +// +// /* Type parametricity. */ +// if (version >= 9) { +// long paraFlag = orig.getLong(); +// /* If it's a parametric type... */ +// if (paraFlag == 1) { +// ParametricType pt = new ParametricType(); +// pt.parameterizer = readRef(); +// pt.lookup = new ArrayList>(); +// st.parametricity = pt; +// } +// else if (paraFlag == 2) { +// ParameterizedType pt = new ParameterizedType(); +// pt.parametricType = readObjRef(); +// SixModelObject BOOTArray = tc.gc.BOOTArray; +// pt.parameters = BOOTArray.st.REPR.allocate(tc, BOOTArray.st); +// int elems = orig.getInt(); +// for (int j = 0; j < elems; j++) +// pt.parameters.bind_pos_boxed(tc, j, readRef()); +// st.parametricity = pt; +// } +// else if (paraFlag != 0) { +// throw new RuntimeException("Unknown STable parametricity flag"); +// } +// } +// +// /* If the REPR has a function to deserialize representation data, call it. */ +// st.REPR.deserialize_repr_data(tc, st, this); +// } +// } +// +// private void deserializeObjects() { +// for (int i = 0; i < objTableEntries; i++) { +// // Can skip if it's a type object. +// SixModelObject obj = sc.getObject(i); +// if (obj instanceof TypeObject) +// continue; +// +// // Seek reader to object data offset. +// orig.position(objTableOffset + i * OBJECTS_TABLE_ENTRY_SIZE + 8); +// orig.position(objDataOffset + orig.getInt()); +// +// // Complete the object's deserialization. +// this.curObject = obj; +// obj.st.REPR.deserialize_finish(tc, obj.st, this, obj); +// this.curObject = null; +// } +// } +// +// private void deserializeContexts() { +// contexts = new CallFrame[contextTableEntries]; +// for (int i = 0; i < contextTableEntries; i++) { +// /* Seek to the context's table row. */ +// orig.position(contextTableOffset + i * CONTEXTS_TABLE_ENTRY_SIZE); +// +// /* Resolve the reference to the static code object this context is for. */ +// CodeRef staticCode = readCodeRef(); +// +// /* Create a context and set it up. */ +// CallFrame ctx = new CallFrame(); +// ctx.tc = tc; +// ctx.codeRef = staticCode; +// StaticCodeInfo sci = staticCode.staticInfo; +// if (sci.oLexicalNames != null) +// ctx.oLex = sci.oLexStatic.clone(); +// if (sci.iLexicalNames != null) +// ctx.iLex = new long[sci.iLexicalNames.length]; +// if (sci.nLexicalNames != null) +// ctx.nLex = new double[sci.nLexicalNames.length]; +// if (sci.sLexicalNames != null) +// ctx.sLex = new String[sci.sLexicalNames.length]; +// +// /* Set context data read position, and set current read buffer to the correct thing. */ +// orig.position(contextDataOffset + orig.getInt()); +// +// /* Deserialize lexicals. */ +// long syms = orig.getLong(); +// for (long j = 0; j < syms; j++) { +// String sym = readStr(); +// Integer idx; +// if ((idx = sci.oTryGetLexicalIdx(sym)) != null) +// ctx.oLex[idx] = readRef(); +// else if ((idx = sci.iTryGetLexicalIdx(sym)) != null) +// ctx.iLex[idx] = orig.getLong(); +// else if ((idx = sci.nTryGetLexicalIdx(sym)) != null) +// ctx.nLex[idx] = orig.getDouble(); +// else if ((idx = sci.sTryGetLexicalIdx(sym)) != null) +// ctx.sLex[idx] = readStr(); +// else +// throw new RuntimeException("Failed to deserialize lexical " + sym); +// } +// +// /* Put context in place. */ +// contexts[i] = ctx; +// } +// } +// +// private void attachClosureOuters(int closureBaseIdx) { +// for (int i = 0; i < closureTableEntries; i++) { +// orig.position(closureTableOffset + i * CLOSURES_TABLE_ENTRY_SIZE + 8); +// int idx = orig.getInt(); +// if (idx > 0) +// sc.getCodeRef(closureBaseIdx + i).outer = contexts[idx - 1]; +// } +// } +// +// private void attachContextOuters() { +// for (int i = 0; i < contextTableEntries; i++) { +// orig.position(contextTableOffset + i * CONTEXTS_TABLE_ENTRY_SIZE + 12); +// int idx = orig.getInt(); +// if (idx > 0) +// contexts[i].outer = contexts[idx - 1]; +// } +// } +// +// private void fixupContextOuters() { +// for (int i = 0; i < contextTableEntries; i++) { +// if (contexts[i].outer == null && +// contexts[i].codeRef.staticInfo.priorInvocation != null && +// contexts[i].codeRef.staticInfo.priorInvocation.outer != null) +// contexts[i].outer = contexts[i].codeRef.staticInfo.priorInvocation.outer; +// } +// } +// +// public SixModelObject readRef() { +// short discrim = orig.getShort(); +// int elems; +// switch (discrim) { +// case REFVAR_NULL: +// case REFVAR_VM_NULL: +// return null; +// case REFVAR_OBJECT: +// return readObjRef(); +// case REFVAR_VM_INT: +// SixModelObject BOOTInt = tc.gc.BOOTInt; +// SixModelObject iResult = BOOTInt.st.REPR.allocate(tc, BOOTInt.st); +// iResult.set_int(tc, orig.getLong()); +// return iResult; +// case REFVAR_VM_NUM: +// SixModelObject BOOTNum = tc.gc.BOOTNum; +// SixModelObject nResult = BOOTNum.st.REPR.allocate(tc, BOOTNum.st); +// nResult.set_num(tc, orig.getDouble()); +// return nResult; +// case REFVAR_VM_STR: +// SixModelObject BOOTStr = tc.gc.BOOTStr; +// SixModelObject sResult = BOOTStr.st.REPR.allocate(tc, BOOTStr.st); +// sResult.set_str(tc, lookupString(orig.getInt())); +// return sResult; +// case REFVAR_VM_ARR_VAR: { +// SixModelObject BOOTArray = tc.gc.BOOTArray; +// SixModelObject resArray = BOOTArray.st.REPR.allocate(tc, BOOTArray.st); +// elems = orig.getInt(); +// for (int i = 0; i < elems; i++) +// resArray.bind_pos_boxed(tc, i, readRef()); +// if (this.curObject != null) { +// resArray.sc = sc; +// sc.owned_objects.put(resArray, this.curObject); +// } +// return resArray; +// } +// case REFVAR_VM_ARR_STR: { +// SixModelObject BOOTStrArray = tc.gc.BOOTStrArray; +// SixModelObject resArray = BOOTStrArray.st.REPR.allocate(tc, BOOTStrArray.st); +// elems = orig.getInt(); +// for (int i = 0; i < elems; i++) { +// tc.native_s = readStr(); +// resArray.bind_pos_native(tc, i); +// } +// return resArray; +// } +// case REFVAR_VM_ARR_INT: { +// SixModelObject BOOTIntArray = tc.gc.BOOTIntArray; +// SixModelObject resArray = BOOTIntArray.st.REPR.allocate(tc, BOOTIntArray.st); +// elems = orig.getInt(); +// for (int i = 0; i < elems; i++) { +// tc.native_i = readLong(); +// resArray.bind_pos_native(tc, i); +// } +// return resArray; +// } +// case REFVAR_VM_HASH_STR_VAR: +// SixModelObject BOOTHash = tc.gc.BOOTHash; +// SixModelObject resHash = BOOTHash.st.REPR.allocate(tc, BOOTHash.st); +// elems = orig.getInt(); +// for (int i = 0; i < elems; i++) { +// String key = lookupString(orig.getInt()); +// resHash.bind_key_boxed(tc, key, readRef()); +// } +// if (this.curObject != null) { +// resHash.sc = sc; +// sc.owned_objects.put(resHash, this.curObject); +// } +// return resHash; +// case REFVAR_STATIC_CODEREF: +// case REFVAR_CLONED_CODEREF: +// return readCodeRef(); +// default: +// throw new RuntimeException("Unimplemented case of read_ref"); +// } +// } +// +// public SixModelObject readObjRef() { +// SerializationContext sc = locateSC(orig.getInt()); +// int idx = orig.getInt(); +// if (idx < 0 || idx >= sc.objectCount()) +// throw new RuntimeException("Invalid SC object index " + idx); +// return sc.getObject(idx); +// } +// +// public STable readSTableRef() { +// return lookupSTable(orig.getInt(), orig.getInt()); +// } +// +// public CodeRef readCodeRef() { +// SerializationContext sc = locateSC(orig.getInt()); +// int idx = orig.getInt(); +// if (idx < 0 || idx >= sc.coderefCount()) +// throw new RuntimeException("Invalid SC code index " + idx); +// return sc.getCodeRef(idx); +// } +// +// public long readLong() { +// return orig.getLong(); +// } +// +// public int readInt32() { +// return orig.getInt(); +// } +// +// public double readDouble() { +// return orig.getDouble(); +// } +// +// public String readStr() { +// return lookupString(orig.getInt()); +// } +// +// private STable lookupSTable(int scIdx, int idx) { +// SerializationContext sc = locateSC(scIdx); +// if (idx < 0 || idx >= sc.stableCount()) +// throw new RuntimeException("Invalid STable index (scIdx=" + scIdx + ",idx=" + idx + ")"); +// return sc.getSTable(idx); +// } +// +// private SerializationContext locateSC(int scIdx) { +// if (scIdx == 0) +// return sc; +// if (scIdx < 1 || scIdx > dependentSCs.length) +// throw new RuntimeException("Invalid dependencies table index encountered (index " + scIdx + ")"); +// return dependentSCs[scIdx - 1]; +// } +// +// private String lookupString(int idx) { +// if (idx >= sh.length) +// throw new RuntimeException("Attempt to read past end of string heap (index " + idx + ")"); +// return sh[idx]; +// } +} diff --git a/tools/build/Makefile-JVM.in b/tools/build/Makefile-JVM.in index fcbd2a50b1..ac0390e26b 100644 --- a/tools/build/Makefile-JVM.in +++ b/tools/build/Makefile-JVM.in @@ -12,6 +12,7 @@ TRUFFLE_JAVAS = \ src/vm/jvm/runtime/org/perl6/nqp/truffle/runtime/*.java \ src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/*.java \ src/vm/jvm/runtime/org/perl6/nqp/truffle/nodes/*/*.java \ + src/vm/jvm/runtime/org/perl6/nqp/truffle/sixmodel/*.java \ src/vm/jvm/runtime/org/perl6/nqp/truffle/*.java \ RUNTIME_JAVAS = \