From 1336ac327e0938a0861dc04c3c80b87f8655cc9f Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 26 Aug 2021 18:07:13 +0100 Subject: [PATCH 1/4] Implemented #to:do: block inlining This adds the DUP_SECOND, JUMP_IF_GREATER, and JUMP2_IF_GREATER bytecodes. Signed-off-by: Stefan Marr --- src/trufflesom/compiler/ParserBc.java | 29 ++-- .../compiler/bc/BytecodeGenerator.java | 21 ++- .../compiler/bc/BytecodeMethodGenContext.java | 58 +++++++- src/trufflesom/compiler/bc/Disassembler.java | 6 +- src/trufflesom/interpreter/LexicalScope.java | 7 + src/trufflesom/interpreter/Method.java | 10 ++ src/trufflesom/interpreter/bc/Bytecodes.java | 136 ++++++++++-------- .../nodes/NonLocalVariableNode.java | 4 + .../nodes/bc/BytecodeLoopNode.java | 132 +++++++++++++++-- tests/trufflesom/tests/AstInliningTests.java | 37 +++++ .../trufflesom/tests/BytecodeMethodTests.java | 97 +++++++++---- 11 files changed, 414 insertions(+), 123 deletions(-) diff --git a/src/trufflesom/compiler/ParserBc.java b/src/trufflesom/compiler/ParserBc.java index ee68b0880..deb455883 100644 --- a/src/trufflesom/compiler/ParserBc.java +++ b/src/trufflesom/compiler/ParserBc.java @@ -279,25 +279,34 @@ private void keywordMessage(final BytecodeMethodGenContext mgenc) boolean isSuperSend = superSend; superSend = false; + int numArgs = 0; StringBuilder kw = new StringBuilder(); do { kw.append(keyword()); formula(mgenc); + numArgs += 1; } while (sym == Keyword); String kwStr = kw.toString(); if (!isSuperSend) { - if (("ifTrue:".equals(kwStr) && mgenc.inlineIfTrueOrIfFalse(this, true)) || - ("ifFalse:".equals(kwStr) && mgenc.inlineIfTrueOrIfFalse(this, false)) || - ("ifTrue:ifFalse:".equals(kwStr) && mgenc.inlineIfTrueIfFalse(this, true)) || - ("ifFalse:ifTrue:".equals(kwStr) && mgenc.inlineIfTrueIfFalse(this, false)) || - ("whileTrue:".equals(kwStr) && mgenc.inlineWhileTrueOrFalse(this, true)) || - ("whileFalse:".equals(kwStr) && mgenc.inlineWhileTrueOrFalse(this, false)) || - ("or:".equals(kwStr) && mgenc.inlineAndOr(this, true)) || - ("and:".equals(kwStr) && mgenc.inlineAndOr(this, false))) { - // all done - return; + if (numArgs == 1) { + if (("ifTrue:".equals(kwStr) && mgenc.inlineIfTrueOrIfFalse(this, true)) || + ("ifFalse:".equals(kwStr) && mgenc.inlineIfTrueOrIfFalse(this, false)) || + ("whileTrue:".equals(kwStr) && mgenc.inlineWhileTrueOrFalse(this, true)) || + ("whileFalse:".equals(kwStr) && mgenc.inlineWhileTrueOrFalse(this, false)) || + ("or:".equals(kwStr) && mgenc.inlineAndOr(this, true)) || + ("and:".equals(kwStr) && mgenc.inlineAndOr(this, false))) { + // all done + return; + } + } else if (numArgs == 2) { + if (("ifTrue:ifFalse:".equals(kwStr) && mgenc.inlineIfTrueIfFalse(this, true)) || + ("ifFalse:ifTrue:".equals(kwStr) && mgenc.inlineIfTrueIfFalse(this, false)) || + ("to:do:".equals(kwStr) && mgenc.inlineToDo(this))) { + // all done + return; + } } } diff --git a/src/trufflesom/compiler/bc/BytecodeGenerator.java b/src/trufflesom/compiler/bc/BytecodeGenerator.java index 90e5da6aa..4b8acbbf6 100644 --- a/src/trufflesom/compiler/bc/BytecodeGenerator.java +++ b/src/trufflesom/compiler/bc/BytecodeGenerator.java @@ -26,6 +26,7 @@ import static trufflesom.interpreter.bc.Bytecodes.DEC; import static trufflesom.interpreter.bc.Bytecodes.DUP; +import static trufflesom.interpreter.bc.Bytecodes.DUP_SECOND; import static trufflesom.interpreter.bc.Bytecodes.HALT; import static trufflesom.interpreter.bc.Bytecodes.INC; import static trufflesom.interpreter.bc.Bytecodes.INC_FIELD_PUSH; @@ -33,6 +34,7 @@ import static trufflesom.interpreter.bc.Bytecodes.JUMP2; import static trufflesom.interpreter.bc.Bytecodes.JUMP2_BACKWARDS; import static trufflesom.interpreter.bc.Bytecodes.JUMP_BACKWARDS; +import static trufflesom.interpreter.bc.Bytecodes.JUMP_IF_GREATER; import static trufflesom.interpreter.bc.Bytecodes.JUMP_ON_FALSE_POP; import static trufflesom.interpreter.bc.Bytecodes.JUMP_ON_FALSE_TOP_NIL; import static trufflesom.interpreter.bc.Bytecodes.JUMP_ON_TRUE_POP; @@ -94,6 +96,14 @@ public static void emitHALT(final BytecodeMethodGenContext mgenc) { emit1(mgenc, HALT, 0); } + public static void emitDUP(final BytecodeMethodGenContext mgenc) { + emit1(mgenc, DUP, 1); + } + + public static void emitDUPSECOND(final BytecodeMethodGenContext mgenc) { + emit1(mgenc, DUP_SECOND, 1); + } + public static void emitINC(final BytecodeMethodGenContext mgenc) { emit1(mgenc, INC, 0); } @@ -163,10 +173,6 @@ public static void emitRETURNFIELD(final BytecodeMethodGenContext mgenc, final b throw new IllegalArgumentException("RETURN_FIELD bytecode does not support idx=" + idx); } - public static void emitDUP(final BytecodeMethodGenContext mgenc) { - emit1(mgenc, DUP, 1); - } - public static void emitPUSHBLOCK(final BytecodeMethodGenContext mgenc, final SMethod blockMethod, final boolean withContext) { byte litIdx = mgenc.findLiteralIndex(blockMethod); @@ -369,6 +375,13 @@ public static void emitJumpWithOffset(final BytecodeMethodGenContext mgenc, emit3(mgenc, offset2 == 0 ? JUMP : JUMP2, offset1, offset2, 0); } + public static int emitJumpIfGreaterWithDummyOffset(final BytecodeMethodGenContext mgenc) { + emit1(mgenc, JUMP_IF_GREATER, 0); + int idx = mgenc.addBytecodeArgumentAndGetIndex((byte) 0); + mgenc.addBytecodeArgument((byte) 0); + return idx; + } + public static void emitJumpBackwardsWithOffset(final BytecodeMethodGenContext mgenc, final byte offset1, final byte offset2) { emit3(mgenc, offset2 == 0 ? JUMP_BACKWARDS : JUMP2_BACKWARDS, offset1, offset2, 0); diff --git a/src/trufflesom/compiler/bc/BytecodeMethodGenContext.java b/src/trufflesom/compiler/bc/BytecodeMethodGenContext.java index b2f9e72b0..9c352958f 100644 --- a/src/trufflesom/compiler/bc/BytecodeMethodGenContext.java +++ b/src/trufflesom/compiler/bc/BytecodeMethodGenContext.java @@ -1,9 +1,14 @@ package trufflesom.compiler.bc; +import static trufflesom.compiler.bc.BytecodeGenerator.emitDUP; +import static trufflesom.compiler.bc.BytecodeGenerator.emitDUPSECOND; +import static trufflesom.compiler.bc.BytecodeGenerator.emitINC; import static trufflesom.compiler.bc.BytecodeGenerator.emitJumpBackwardsWithOffset; +import static trufflesom.compiler.bc.BytecodeGenerator.emitJumpIfGreaterWithDummyOffset; import static trufflesom.compiler.bc.BytecodeGenerator.emitJumpOnBoolWithDummyOffset; import static trufflesom.compiler.bc.BytecodeGenerator.emitJumpWithDummyOffset; import static trufflesom.compiler.bc.BytecodeGenerator.emitPOP; +import static trufflesom.compiler.bc.BytecodeGenerator.emitPOPLOCAL; import static trufflesom.compiler.bc.BytecodeGenerator.emitPUSHCONSTANT; import static trufflesom.interpreter.bc.Bytecodes.DUP; import static trufflesom.interpreter.bc.Bytecodes.INC; @@ -69,6 +74,7 @@ import trufflesom.compiler.Variable; import trufflesom.compiler.Variable.Argument; import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.Method; import trufflesom.interpreter.bc.Bytecodes; import trufflesom.interpreter.nodes.ArgumentReadNode.LocalArgumentReadNode; import trufflesom.interpreter.nodes.ExpressionNode; @@ -326,7 +332,7 @@ public void updateLiteral(final SAbstractObject oldVal, final byte index, literals.set(index, newVal); } - private byte getPositionIn(final Local local, final LinkedHashMap map) { + private byte getPositionIn(final Variable local, final LinkedHashMap map) { byte i = 0; for (Local l : map.values()) { if (l.equals(local)) { @@ -337,6 +343,10 @@ private byte getPositionIn(final Local local, final LinkedHashMap bytecodes, final String indent, case JUMP_ON_FALSE_TOP_NIL: case JUMP_ON_TRUE_POP: case JUMP_ON_FALSE_POP: + case JUMP_IF_GREATER: case JUMP2: case JUMP2_ON_TRUE_TOP_NIL: case JUMP2_ON_FALSE_TOP_NIL: case JUMP2_ON_TRUE_POP: - case JUMP2_ON_FALSE_POP: { + case JUMP2_ON_FALSE_POP: + case JUMP2_IF_GREATER: { int offset = getJumpOffset(bytecodes.get(b + 1), bytecodes.get(b + 2)); Universe.errorPrintln( diff --git a/src/trufflesom/interpreter/LexicalScope.java b/src/trufflesom/interpreter/LexicalScope.java index 196cb21c0..9c50e34e9 100644 --- a/src/trufflesom/interpreter/LexicalScope.java +++ b/src/trufflesom/interpreter/LexicalScope.java @@ -159,6 +159,13 @@ public Variable[] getVariables() { return variables; } + public Variable getVariable(final int idx, final int ctxLevel) { + if (ctxLevel == 0) { + return variables[idx]; + } + return outerScope.getVariable(idx, ctxLevel - 1); + } + @Override public LexicalScope getScope(final Method method) { if (method.equals(this.method)) { diff --git a/src/trufflesom/interpreter/Method.java b/src/trufflesom/interpreter/Method.java index 91c8a790b..8c4eb9c71 100644 --- a/src/trufflesom/interpreter/Method.java +++ b/src/trufflesom/interpreter/Method.java @@ -118,6 +118,16 @@ public ExpressionNode inline(final MethodGenerationContext mgenc, getLanguage(SomLanguage.class)); } + public void mergeScopeInto(final MethodGenerationContext mgenc, final SMethod toBeInlined) { + mgenc.mergeIntoScope(currentLexicalScope, toBeInlined); + } + + public ExpressionNode inlineScopeAlreadyMerged(final MethodGenerationContext mgenc, + final SMethod toBeInlined) { + return ScopeAdaptationVisitor.adapt(uninitializedBody, mgenc, 0, true, + getLanguage(SomLanguage.class)); + } + @Override public boolean isTrivial() { if (currentLexicalScope.isBlock()) { diff --git a/src/trufflesom/interpreter/bc/Bytecodes.java b/src/trufflesom/interpreter/bc/Bytecodes.java index 6a8fb3885..9ecbc5d1b 100644 --- a/src/trufflesom/interpreter/bc/Bytecodes.java +++ b/src/trufflesom/interpreter/bc/Bytecodes.java @@ -33,89 +33,93 @@ public class Bytecodes { // Bytecodes used by the simple object machine public static final byte HALT = 0; - public static final byte DUP = 1; - public static final byte PUSH_LOCAL = 2; - public static final byte PUSH_LOCAL_0 = 3; - public static final byte PUSH_LOCAL_1 = 4; - public static final byte PUSH_LOCAL_2 = 5; + public static final byte DUP = 1; + public static final byte DUP_SECOND = 2; - public static final byte PUSH_ARGUMENT = 6; - public static final byte PUSH_SELF = 7; - public static final byte PUSH_ARG1 = 8; - public static final byte PUSH_ARG2 = 9; + public static final byte PUSH_LOCAL = 3; + public static final byte PUSH_LOCAL_0 = 4; + public static final byte PUSH_LOCAL_1 = 5; + public static final byte PUSH_LOCAL_2 = 6; - public static final byte PUSH_FIELD = 10; - public static final byte PUSH_FIELD_0 = 11; - public static final byte PUSH_FIELD_1 = 12; + public static final byte PUSH_ARGUMENT = 7; + public static final byte PUSH_SELF = 8; + public static final byte PUSH_ARG1 = 9; + public static final byte PUSH_ARG2 = 10; - public static final byte PUSH_BLOCK = 13; - public static final byte PUSH_BLOCK_NO_CTX = 14; + public static final byte PUSH_FIELD = 11; + public static final byte PUSH_FIELD_0 = 12; + public static final byte PUSH_FIELD_1 = 13; - public static final byte PUSH_CONSTANT = 15; - public static final byte PUSH_CONSTANT_0 = 16; - public static final byte PUSH_CONSTANT_1 = 17; - public static final byte PUSH_CONSTANT_2 = 18; + public static final byte PUSH_BLOCK = 14; + public static final byte PUSH_BLOCK_NO_CTX = 15; - public static final byte PUSH_0 = 19; - public static final byte PUSH_1 = 20; - public static final byte PUSH_NIL = 21; + public static final byte PUSH_CONSTANT = 16; + public static final byte PUSH_CONSTANT_0 = 17; + public static final byte PUSH_CONSTANT_1 = 18; + public static final byte PUSH_CONSTANT_2 = 19; - public static final byte PUSH_GLOBAL = 22; + public static final byte PUSH_0 = 20; + public static final byte PUSH_1 = 21; + public static final byte PUSH_NIL = 22; - public static final byte POP = 23; + public static final byte PUSH_GLOBAL = 23; - public static final byte POP_LOCAL = 24; - public static final byte POP_LOCAL_0 = 25; - public static final byte POP_LOCAL_1 = 26; - public static final byte POP_LOCAL_2 = 27; + public static final byte POP = 24; - public static final byte POP_ARGUMENT = 28; + public static final byte POP_LOCAL = 25; + public static final byte POP_LOCAL_0 = 26; + public static final byte POP_LOCAL_1 = 27; + public static final byte POP_LOCAL_2 = 28; - public static final byte POP_FIELD = 29; - public static final byte POP_FIELD_0 = 30; - public static final byte POP_FIELD_1 = 31; + public static final byte POP_ARGUMENT = 29; - public static final byte SEND = 32; - public static final byte SUPER_SEND = 33; + public static final byte POP_FIELD = 30; + public static final byte POP_FIELD_0 = 31; + public static final byte POP_FIELD_1 = 32; - public static final byte RETURN_LOCAL = 34; - public static final byte RETURN_NON_LOCAL = 35; - public static final byte RETURN_SELF = 36; + public static final byte SEND = 33; + public static final byte SUPER_SEND = 34; - public static final byte RETURN_FIELD_0 = 37; - public static final byte RETURN_FIELD_1 = 38; - public static final byte RETURN_FIELD_2 = 39; + public static final byte RETURN_LOCAL = 35; + public static final byte RETURN_NON_LOCAL = 36; + public static final byte RETURN_SELF = 37; - public static final byte INC = 40; - public static final byte DEC = 41; + public static final byte RETURN_FIELD_0 = 38; + public static final byte RETURN_FIELD_1 = 39; + public static final byte RETURN_FIELD_2 = 40; - public static final byte INC_FIELD = 42; - public static final byte INC_FIELD_PUSH = 43; + public static final byte INC = 41; + public static final byte DEC = 42; - public static final byte JUMP = 44; - public static final byte JUMP_ON_TRUE_TOP_NIL = 45; - public static final byte JUMP_ON_FALSE_TOP_NIL = 46; - public static final byte JUMP_ON_TRUE_POP = 47; - public static final byte JUMP_ON_FALSE_POP = 48; - public static final byte JUMP_BACKWARDS = 49; + public static final byte INC_FIELD = 43; + public static final byte INC_FIELD_PUSH = 44; - public static final byte JUMP2 = 50; - public static final byte JUMP2_ON_TRUE_TOP_NIL = 51; - public static final byte JUMP2_ON_FALSE_TOP_NIL = 52; - public static final byte JUMP2_ON_TRUE_POP = 53; - public static final byte JUMP2_ON_FALSE_POP = 54; - public static final byte JUMP2_BACKWARDS = 55; + public static final byte JUMP = 45; + public static final byte JUMP_ON_TRUE_TOP_NIL = 46; + public static final byte JUMP_ON_FALSE_TOP_NIL = 47; + public static final byte JUMP_ON_TRUE_POP = 48; + public static final byte JUMP_ON_FALSE_POP = 49; + public static final byte JUMP_IF_GREATER = 50; + public static final byte JUMP_BACKWARDS = 51; - public static final byte Q_PUSH_GLOBAL = 56; - public static final byte Q_SEND = 57; - public static final byte Q_SEND_1 = 58; - public static final byte Q_SEND_2 = 59; - public static final byte Q_SEND_3 = 60; + public static final byte JUMP2 = 52; + public static final byte JUMP2_ON_TRUE_TOP_NIL = 53; + public static final byte JUMP2_ON_FALSE_TOP_NIL = 54; + public static final byte JUMP2_ON_TRUE_POP = 55; + public static final byte JUMP2_ON_FALSE_POP = 56; + public static final byte JUMP2_IF_GREATER = 57; + public static final byte JUMP2_BACKWARDS = 58; + + public static final byte Q_PUSH_GLOBAL = 59; + public static final byte Q_SEND = 60; + public static final byte Q_SEND_1 = 61; + public static final byte Q_SEND_2 = 62; + public static final byte Q_SEND_3 = 63; public static final byte INVALID = -1; - public static final byte NUM_1_BYTE_JUMP_BYTECODES = 6; + public static final byte NUM_1_BYTE_JUMP_BYTECODES = 7; private static final String[] PADDED_BYTECODE_NAMES; private static final String[] BYTECODE_NAMES; @@ -147,9 +151,9 @@ public static int getBytecodeLength(final byte bytecode) { public static final byte[] JUMP_BYTECODES = new byte[] { JUMP, JUMP_ON_TRUE_TOP_NIL, JUMP_ON_TRUE_POP, - JUMP_ON_FALSE_TOP_NIL, JUMP_ON_FALSE_POP, JUMP_BACKWARDS, + JUMP_ON_FALSE_TOP_NIL, JUMP_ON_FALSE_POP, JUMP_IF_GREATER, JUMP_BACKWARDS, JUMP2, JUMP2_ON_TRUE_TOP_NIL, JUMP2_ON_TRUE_POP, - JUMP2_ON_FALSE_TOP_NIL, JUMP2_ON_FALSE_POP, JUMP_BACKWARDS + JUMP2_ON_FALSE_TOP_NIL, JUMP2_ON_FALSE_POP, JUMP2_IF_GREATER, JUMP_BACKWARDS }; public static final boolean isOneOf(final byte bytecode, final byte[] arr) { @@ -167,6 +171,7 @@ public static final boolean isOneOf(final byte bytecode, final byte[] arr) { PADDED_BYTECODE_NAMES = new String[] { "HALT ", "DUP ", + "DUP_SECOND ", "PUSH_LOCAL ", "PUSH_LOCAL_0 ", @@ -229,6 +234,7 @@ public static final boolean isOneOf(final byte bytecode, final byte[] arr) { "JUMP_ON_FALSE_TOP_NIL", "JUMP_ON_TRUE_POP", "JUMP_ON_FALSE_POP", + "JUMP_IF_GREATER ", "JUMP_BACKWARDS ", "JUMP2 ", @@ -236,6 +242,7 @@ public static final boolean isOneOf(final byte bytecode, final byte[] arr) { "JUMP2_ON_FALSE_TOP_NIL", "JUMP2_ON_TRUE_POP", "JUMP2_ON_FALSE_POP", + "JUMP2_IF_GREATER", "JUMP2_BACKWARDS ", "Q_PUSH_GLOBAL ", @@ -252,6 +259,7 @@ public static final boolean isOneOf(final byte bytecode, final byte[] arr) { BYTECODE_LENGTH = new int[] { 1, // HALT 1, // DUP + 1, // DUP_SECOND 3, // PUSH_LOCAL 1, // PUSH_LOCAL_0 @@ -311,6 +319,7 @@ public static final boolean isOneOf(final byte bytecode, final byte[] arr) { 3, // JUMP_ON_FALSE_TOP_NIL 3, // JUMP_ON_TRUE_POP 3, // JUMP_ON_FALSE_POP + 3, // JUMP_IF_GREATER 3, // JUMP_BACKWARDS 3, // JUMP2 @@ -318,6 +327,7 @@ public static final boolean isOneOf(final byte bytecode, final byte[] arr) { 3, // JUMP2_ON_FALSE_TOP_NIL 3, // JUMP2_ON_TRUE_POP 3, // JUMP2_ON_FALSE_POP + 3, // JUMP2_IF_GREATER 3, // JUMP2_BACKWARDS 2, // Q_PUSH_GLOBAL diff --git a/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java b/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java index 0e0a5f94d..cc0c8cbfd 100644 --- a/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java +++ b/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java @@ -37,6 +37,10 @@ public SSymbol getInvocationIdentifier() { return local.name; } + public Object getSlotIdentifier() { + return slot.getIdentifier(); + } + public abstract static class NonLocalVariableReadNode extends NonLocalVariableNode { public NonLocalVariableReadNode(final int contextLevel, final Local local) { diff --git a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java index 97c031ba0..d5ee76c50 100644 --- a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java +++ b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java @@ -4,12 +4,14 @@ import static trufflesom.compiler.bc.BytecodeGenerator.emit3; import static trufflesom.compiler.bc.BytecodeGenerator.emit3WithDummy; import static trufflesom.compiler.bc.BytecodeGenerator.emitPOP; +import static trufflesom.compiler.bc.BytecodeGenerator.emitPOPLOCAL; import static trufflesom.compiler.bc.BytecodeGenerator.emitPOPFIELD; import static trufflesom.compiler.bc.BytecodeGenerator.emitPUSHARGUMENT; import static trufflesom.compiler.bc.BytecodeGenerator.emitPUSHBLOCK; import static trufflesom.compiler.bc.BytecodeGenerator.emitPUSHCONSTANT; import static trufflesom.compiler.bc.BytecodeGenerator.emitPUSHFIELD; import static trufflesom.compiler.bc.BytecodeGenerator.emitPUSHGLOBAL; +import static trufflesom.compiler.bc.BytecodeGenerator.emitPUSHLOCAL; import static trufflesom.compiler.bc.BytecodeGenerator.emitRETURNLOCAL; import static trufflesom.compiler.bc.BytecodeGenerator.emitRETURNNONLOCAL; import static trufflesom.compiler.bc.BytecodeGenerator.emitSEND; @@ -17,6 +19,7 @@ import static trufflesom.compiler.bc.BytecodeMethodGenContext.getJumpOffset; import static trufflesom.interpreter.bc.Bytecodes.DEC; import static trufflesom.interpreter.bc.Bytecodes.DUP; +import static trufflesom.interpreter.bc.Bytecodes.DUP_SECOND; import static trufflesom.interpreter.bc.Bytecodes.HALT; import static trufflesom.interpreter.bc.Bytecodes.INC; import static trufflesom.interpreter.bc.Bytecodes.INC_FIELD; @@ -24,11 +27,13 @@ import static trufflesom.interpreter.bc.Bytecodes.JUMP; import static trufflesom.interpreter.bc.Bytecodes.JUMP2; import static trufflesom.interpreter.bc.Bytecodes.JUMP2_BACKWARDS; +import static trufflesom.interpreter.bc.Bytecodes.JUMP2_IF_GREATER; import static trufflesom.interpreter.bc.Bytecodes.JUMP2_ON_FALSE_POP; import static trufflesom.interpreter.bc.Bytecodes.JUMP2_ON_FALSE_TOP_NIL; import static trufflesom.interpreter.bc.Bytecodes.JUMP2_ON_TRUE_POP; import static trufflesom.interpreter.bc.Bytecodes.JUMP2_ON_TRUE_TOP_NIL; import static trufflesom.interpreter.bc.Bytecodes.JUMP_BACKWARDS; +import static trufflesom.interpreter.bc.Bytecodes.JUMP_IF_GREATER; import static trufflesom.interpreter.bc.Bytecodes.JUMP_ON_FALSE_POP; import static trufflesom.interpreter.bc.Bytecodes.JUMP_ON_FALSE_TOP_NIL; import static trufflesom.interpreter.bc.Bytecodes.JUMP_ON_TRUE_POP; @@ -105,11 +110,13 @@ import bd.primitives.Specializer; import bd.primitives.nodes.PreevaluatedExpression; import trufflesom.compiler.Parser.ParseError; +import trufflesom.compiler.Variable.Argument; import trufflesom.compiler.Variable.Local; import trufflesom.compiler.bc.BytecodeMethodGenContext; import trufflesom.interpreter.EscapedBlockException; import trufflesom.interpreter.FrameOnStackMarker; import trufflesom.interpreter.Invokable; +import trufflesom.interpreter.LexicalScope; import trufflesom.interpreter.Method; import trufflesom.interpreter.ReturnException; import trufflesom.interpreter.SArguments; @@ -147,9 +154,10 @@ public class BytecodeLoopNode extends ExpressionNode implements ScopeReference { private static final ValueProfile frameType = ValueProfile.createClassProfile(); private static final LiteralNode dummyNode = new IntegerLiteralNode(0); - @CompilationFinal(dimensions = 1) private final byte[] bytecodes; - @CompilationFinal(dimensions = 1) private final FrameSlot[] localsAndOuters; - @CompilationFinal(dimensions = 1) private final Object[] literalsAndConstants; + @CompilationFinal(dimensions = 1) private final byte[] bytecodes; + @CompilationFinal(dimensions = 1) private final Object[] literalsAndConstants; + + @CompilationFinal(dimensions = 1) private FrameSlot[] localsAndOuters; @CompilationFinal(dimensions = 1) private final BackJump[] inlinedLoops; @@ -161,16 +169,19 @@ public class BytecodeLoopNode extends ExpressionNode implements ScopeReference { private final FrameSlot frameOnStackMarker; + private final LexicalScope scope; + public BytecodeLoopNode(final byte[] bytecodes, final int numLocals, final FrameSlot[] localsAndOuters, final Object[] literals, final int maxStackDepth, final FrameSlot frameOnStackMarker, final BackJump[] inlinedLoops, - final Universe universe) { + final LexicalScope scope, final Universe universe) { this.bytecodes = bytecodes; this.numLocals = numLocals; this.localsAndOuters = localsAndOuters; this.literalsAndConstants = literals; this.maxStackDepth = maxStackDepth; this.inlinedLoops = inlinedLoops; + this.scope = scope; this.universe = universe; this.frameOnStackMarker = frameOnStackMarker; @@ -182,7 +193,8 @@ public BytecodeLoopNode(final byte[] bytecodes, final int numLocals, public Node deepCopy() { return new BytecodeLoopNode( bytecodes.clone(), numLocals, localsAndOuters, literalsAndConstants, - maxStackDepth, frameOnStackMarker, inlinedLoops, universe).initialize(sourceSection); + maxStackDepth, frameOnStackMarker, inlinedLoops, scope, universe).initialize( + sourceSection); } public String getNameOfLocal(final int idx) { @@ -263,6 +275,13 @@ public Object executeGeneric(final VirtualFrame frame) { break; } + case DUP_SECOND: { + Object second = stack[stackPointer - 1]; + stackPointer += 1; + stack[stackPointer] = second; + break; + } + case PUSH_LOCAL: { byte localIdx = bytecodes[bytecodeIndex + 1]; byte contextIdx = bytecodes[bytecodeIndex + 2]; @@ -877,6 +896,19 @@ public Object executeGeneric(final VirtualFrame frame) { break; } + case JUMP_IF_GREATER: { + long top = (Long) stack[stackPointer]; + long top2 = (Long) stack[stackPointer - 1]; + + if (top > top2) { + stackPointer -= 2; + int offset = Byte.toUnsignedInt(bytecodes[bytecodeIndex + 1]); + nextBytecodeIndex = bytecodeIndex + offset; + } + + break; + } + case JUMP_BACKWARDS: { int offset = Byte.toUnsignedInt(bytecodes[bytecodeIndex + 1]); nextBytecodeIndex = bytecodeIndex - offset; @@ -942,6 +974,20 @@ public Object executeGeneric(final VirtualFrame frame) { break; } + case JUMP2_IF_GREATER: { + long top = (Long) stack[stackPointer]; + long top2 = (Long) stack[stackPointer - 1]; + + if (top > top2) { + stackPointer -= 2; + int offset = Byte.toUnsignedInt(bytecodes[bytecodeIndex + 1]) + + (Byte.toUnsignedInt(bytecodes[bytecodeIndex + 2]) << 8); + nextBytecodeIndex = bytecodeIndex + offset; + } + + break; + } + case JUMP2_BACKWARDS: { int offset = Byte.toUnsignedInt(bytecodes[bytecodeIndex + 1]) + (Byte.toUnsignedInt(bytecodes[bytecodeIndex + 2]) << 8); @@ -1274,7 +1320,8 @@ private void inlineInto(final BytecodeMethodGenContext mgenc, final int targetCo switch (bytecode) { case HALT: - case DUP: { + case DUP: + case DUP_SECOND: { emit1(mgenc, bytecode, bytecode == HALT ? 0 : 1); break; } @@ -1311,8 +1358,14 @@ private void inlineInto(final BytecodeMethodGenContext mgenc, final int targetCo break; } + case PUSH_ARG1: { + Argument arg1 = (Argument) scope.getVariable(1, 0); + byte varIdx = mgenc.getVarIndex(arg1); + emitPUSHLOCAL(mgenc, varIdx, (byte) 0); + break; + } + case PUSH_SELF: - case PUSH_ARG1: case PUSH_ARG2: case PUSH_FIELD_0: case PUSH_FIELD_1: { @@ -1390,8 +1443,20 @@ private void inlineInto(final BytecodeMethodGenContext mgenc, final int targetCo case POP_ARGUMENT: { byte argIdx = bytecodes[i + 1]; - byte contextIdx = bytecodes[i + 2]; - emit3(mgenc, bytecode, argIdx, (byte) (contextIdx - 1), -1); + byte ctxLevel = bytecodes[i + 2]; + + if (ctxLevel > 0) { + emit3(mgenc, bytecode, argIdx, (byte) (ctxLevel - 1), -1); + } else { + assert ctxLevel == 0; + // ok, we are currently inlining a block, and we try to store into an argument + // well, we only have the to:do: blocks, that have arguments in the first place + // and there's only one + assert argIdx == 1 : "Don't support storing to any other than the loop index argument"; + Argument arg1 = (Argument) scope.getVariable(1, 0); + byte varIdx = mgenc.getVarIndex(arg1); + emitPOPLOCAL(mgenc, varIdx, (byte) 0); + } break; } @@ -1468,7 +1533,9 @@ private void inlineInto(final BytecodeMethodGenContext mgenc, final int targetCo case JUMP_ON_TRUE_TOP_NIL: case JUMP2_ON_TRUE_TOP_NIL: case JUMP_ON_FALSE_TOP_NIL: - case JUMP2_ON_FALSE_TOP_NIL: { + case JUMP2_ON_FALSE_TOP_NIL: + case JUMP_IF_GREATER: + case JUMP2_IF_GREATER: { int offset = getJumpOffset(bytecodes[i + 1], bytecodes[i + 2]); int idxOffset = emit3WithDummy(mgenc, bytecode, 0); @@ -1508,6 +1575,7 @@ private void inlineInto(final BytecodeMethodGenContext mgenc, final int targetCo private void adapt(final ScopeAdaptationVisitor inliner, final boolean requiresChangesToContextLevels) { + CompilerAsserts.neverPartOfCompilation("Not a run-time thing, a parse time thing..."); FrameSlot[] oldLocalsAndOuters = Arrays.copyOf(localsAndOuters, localsAndOuters.length); int i = 0; @@ -1517,7 +1585,8 @@ private void adapt(final ScopeAdaptationVisitor inliner, switch (bytecode) { case HALT: - case DUP: { + case DUP: + case DUP_SECOND: { break; } @@ -1544,7 +1613,44 @@ private void adapt(final ScopeAdaptationVisitor inliner, } case PUSH_ARGUMENT: { - adaptContextIdx(inliner, i, requiresChangesToContextLevels); + byte argIdx = bytecodes[i + 1]; + byte ctxLevel = bytecodes[i + 2]; + if (ctxLevel == inliner.contextLevel) { + if (argIdx == 1) { + // at this point, because of the context level, + // we know we refer to a block that got inlined + // the only time we could possibly refer to the argument + // for an inlined block is when inlining #to:do: + // so, there's only the one argument, everything else + // would mean we have a terrible bug... + Argument arg1 = (Argument) scope.getVariable(1, ctxLevel); + ScopeElement se = inliner.getAdaptedVar(arg1); + + assert se.contextLevel == ctxLevel; + FrameSlot slot = ((Local) se.var).getSlot(); + + int foundIdx = -1; + for (int j = 0; j < localsAndOuters.length; j += 1) { + if (localsAndOuters[j] == slot) { + foundIdx = j; + break; + } + } + + if (foundIdx == -1) { + foundIdx = localsAndOuters.length; + localsAndOuters = Arrays.copyOf(localsAndOuters, localsAndOuters.length + 1); + } + + localsAndOuters[foundIdx] = slot; + bytecodes[i] = Bytecodes.PUSH_LOCAL; + bytecodes[i + 1] = (byte) foundIdx; + } else { + throw new RuntimeException("This should really never happen"); + } + } else { + adaptContextIdx(inliner, i, requiresChangesToContextLevels); + } break; } @@ -1664,12 +1770,14 @@ private void adapt(final ScopeAdaptationVisitor inliner, case JUMP_ON_FALSE_TOP_NIL: case JUMP_ON_TRUE_POP: case JUMP_ON_FALSE_POP: + case JUMP_IF_GREATER: case JUMP_BACKWARDS: case JUMP2: case JUMP2_ON_TRUE_TOP_NIL: case JUMP2_ON_FALSE_TOP_NIL: case JUMP2_ON_TRUE_POP: case JUMP2_ON_FALSE_POP: + case JUMP2_IF_GREATER: case JUMP2_BACKWARDS: { break; } diff --git a/tests/trufflesom/tests/AstInliningTests.java b/tests/trufflesom/tests/AstInliningTests.java index 36094431b..f351a62b8 100644 --- a/tests/trufflesom/tests/AstInliningTests.java +++ b/tests/trufflesom/tests/AstInliningTests.java @@ -2,6 +2,7 @@ import static org.hamcrest.core.IsInstanceOf.instanceOf; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static trufflesom.vm.SymbolTable.symSelf; @@ -24,6 +25,7 @@ import trufflesom.interpreter.nodes.GlobalNode.NilGlobalNode; import trufflesom.interpreter.nodes.GlobalNode.TrueGlobalNode; import trufflesom.interpreter.nodes.GlobalNode.UninitializedGlobalReadNode; +import trufflesom.interpreter.nodes.LocalVariableNode.LocalVariableReadNode; import trufflesom.interpreter.nodes.LocalVariableNode.LocalVariableWriteNode; import trufflesom.interpreter.nodes.NonLocalVariableNode.NonLocalVariableReadNode; import trufflesom.interpreter.nodes.NonLocalVariableNode.NonLocalVariableWriteNode; @@ -464,4 +466,39 @@ public void testInliningOfToDo() { (IntToDoInlinedLiteralsNode) read(seq, "expressions", 0); assertEquals("i", toDo.getIndexName()); } + + @Test + public void testInliningOfToDoWithNestedBlocks() { + SequenceNode seq = (SequenceNode) parseMethod( + "test = ( 1 to: 2 do: [:i |\n" + + " i := i + 1.\n" + + " [ i := i + 1 ].\n" + + " true ifTrue: [ i := i + 1. ]\n" + + "] )"); + IntToDoInlinedLiteralsNode toDo = + (IntToDoInlinedLiteralsNode) read(seq, "expressions", 0); + assertEquals("i", toDo.getIndexName()); + + SequenceNode loopSeq = read(toDo, "body", SequenceNode.class); + BlockNodeWithContext block = (BlockNodeWithContext) read(loopSeq, "expressions", 1); + IfInlinedLiteralNode ifNode = (IfInlinedLiteralNode) read(loopSeq, "expressions", 2); + + LocalVariableWriteNode writeI = (LocalVariableWriteNode) read(loopSeq, "expressions", 0); + IntIncrementNode incNode = (IntIncrementNode) writeI.getExp(); + LocalVariableReadNode readI = (LocalVariableReadNode) incNode.getRcvr(); + assertSame(writeI.getSlotIdentifier(), readI.getSlotIdentifier()); + + NonLocalVariableWriteNode writeI2 = read(block.getMethod().getInvokable(), + "expressionOrSequence", NonLocalVariableWriteNode.class); + incNode = (IntIncrementNode) writeI2.getExp(); + NonLocalVariableReadNode readI2 = (NonLocalVariableReadNode) incNode.getRcvr(); + assertSame(writeI.getSlotIdentifier(), writeI2.getSlotIdentifier()); + assertSame(writeI2.getSlotIdentifier(), readI2.getSlotIdentifier()); + + writeI = read(ifNode, "bodyNode", LocalVariableWriteNode.class); + incNode = (IntIncrementNode) writeI.getExp(); + readI = (LocalVariableReadNode) incNode.getRcvr(); + assertSame(writeI.getSlotIdentifier(), readI.getSlotIdentifier()); + assertSame(writeI.getSlotIdentifier(), writeI2.getSlotIdentifier()); + } } diff --git a/tests/trufflesom/tests/BytecodeMethodTests.java b/tests/trufflesom/tests/BytecodeMethodTests.java index 9ec9480dc..beae45d47 100644 --- a/tests/trufflesom/tests/BytecodeMethodTests.java +++ b/tests/trufflesom/tests/BytecodeMethodTests.java @@ -2,7 +2,6 @@ import static org.junit.Assert.assertEquals; -import org.junit.Ignore; import org.junit.Test; import com.oracle.truffle.api.source.Source; @@ -845,7 +844,6 @@ private void inliningOfOr(final String sel) { byte[] bytecodes = methodToBytecodes( "test = ( true " + sel + " [ #val ] )"); - dump(); assertEquals(10, bytecodes.length); check(bytecodes, Bytecodes.PUSH_CONSTANT_0, @@ -884,32 +882,61 @@ public void testFieldReadInlining() { Bytecodes.RETURN_SELF); } - @Ignore("TODO") @Test public void testInliningOfToDo() { byte[] bytecodes = methodToBytecodes( "test = ( 1 to: 2 do: [:i | i ] )"); - assertEquals(21, bytecodes.length); check(bytecodes, - Bytecodes.PUSH_CONSTANT, - Bytecodes.PUSH_CONSTANT, - -1, // TODO: Bytecodes.DUP_SECOND, // stack: Top[1, 2, 1] - -1, // TODO new BC(Bytecodes.jump_if_greater, 17), // consume only on jump + Bytecodes.PUSH_1, + Bytecodes.PUSH_CONSTANT_0, + Bytecodes.DUP_SECOND, // stack: Top[1, 2, 1] + new BC(Bytecodes.JUMP_IF_GREATER, 11), // consume only on jump Bytecodes.DUP, - new BC(Bytecodes.POP_LOCAL, 0, 0), // store the i into the local (arg becomes local - // after inlining) - new BC(Bytecodes.PUSH_LOCAL, 0, 0), // push the local on the stack as part of the - // block's code + Bytecodes.POP_LOCAL_0, // store the i into the local (arg becomes local + // after inlining) + Bytecodes.PUSH_LOCAL_0, // push the local on the stack as part of the + // block's code Bytecodes.POP, // cleanup after block. Bytecodes.INC, // increment top, the iteration counter - -1, // TODO: Bytecodes.nil_local, - new BC(Bytecodes.JUMP_BACKWARDS, 14), // jump back to the jump_if_greater bytecode + new BC(Bytecodes.JUMP_BACKWARDS, 8), // jump back to the jump_if_greater bytecode // jump_if_greater target Bytecodes.RETURN_SELF); } - @Ignore("TODO") + @Test + public void testInliningOfToDoWithNestedBlocks() { + byte[] bytecodes = methodToBytecodes( + "test = ( 1 to: 2 do: [:i |\n" + + " i := i + 1.\n" + + " [ i := i + 1 ].\n" + + " true ifTrue: [ i := i + 1. ]\n" + + "] )"); + + check(bytecodes, + Bytecodes.PUSH_1, + Bytecodes.PUSH_CONSTANT_0, + Bytecodes.DUP_SECOND, + new BC(Bytecodes.JUMP_IF_GREATER, 25), + Bytecodes.DUP, + Bytecodes.POP_LOCAL_0, + Bytecodes.PUSH_LOCAL_0, + Bytecodes.INC, + Bytecodes.POP_LOCAL_0, + Bytecodes.PUSH_BLOCK, + Bytecodes.POP, + Bytecodes.PUSH_CONSTANT, + new BC(Bytecodes.JUMP_ON_FALSE_TOP_NIL, 7), + Bytecodes.PUSH_LOCAL_0, + Bytecodes.INC, + Bytecodes.DUP, + Bytecodes.POP_LOCAL_0, + Bytecodes.POP, + Bytecodes.INC, + new BC(Bytecodes.JUMP_BACKWARDS, 22), + Bytecodes.RETURN_SELF); + } + @Test public void testToDoBlockBlockInlinedSelf() { addField("field"); @@ -923,34 +950,42 @@ public void testToDoBlockBlockInlinedSelf() { + " l2 := l2 + 1 ] ] ]\n" + ")"); - assertEquals(25, bytecodes.length); + assertEquals(19, bytecodes.length); check(bytecodes, - Bytecodes.PUSH_CONSTANT, - Bytecodes.PUSH_CONSTANT, - -1, // TODO: Bytecodes.DUP_SECOND, // stack: Top[1, 2, 1] - -1, // TODO new BC(Bytecodes.jump_if_greater, 21), // consume only on jump + Bytecodes.PUSH_1, + Bytecodes.PUSH_CONSTANT_0, + Bytecodes.DUP_SECOND, // stack: Top[1, 2, 1] + new BC(Bytecodes.JUMP_IF_GREATER, 15), // consume only on jump Bytecodes.DUP, - new BC(Bytecodes.POP_LOCAL, 2, 0), // store the i into the local (arg becomes local - // after inlining) - new BC(Bytecodes.PUSH_LOCAL, 0, 0), // push the local on the stack as part of the - // block's code + Bytecodes.POP_LOCAL_2, // store the i into the local (arg becomes local + // after inlining) + Bytecodes.PUSH_LOCAL_0, // push the local on the stack as part of the + // block's code new BC(Bytecodes.PUSH_BLOCK, 2), Bytecodes.SEND, Bytecodes.POP, // cleanup after block. Bytecodes.INC, // increment top, the iteration counter - -1, // TODO: Bytecodes.nil_local, - new BC(Bytecodes.JUMP_BACKWARDS, 10), // jump back to the jump_if_greater bytecode + new BC(Bytecodes.JUMP_BACKWARDS, 12), // jump back to the jump_if_greater bytecode // jump_if_greater target Bytecodes.RETURN_SELF); - // TODO: fix bcIdx to the PUSH_BLOCK bc - SMethod blockMethod = (SMethod) mgenc.getConstant(-1); - + // the #do: block + SMethod blockMethod = (SMethod) mgenc.getConstant(9); check( read(blockMethod.getInvokable(), "expressionOrSequence", BytecodeLoopNode.class).getBytecodeArray(), - t(6, new BC(Bytecodes.PUSH_LOCAL, 2, 1, "local b")), - Bytecodes.POP); + Bytecodes.PUSH_ARG1, + new BC(Bytecodes.JUMP_ON_FALSE_TOP_NIL, 15), + + // read a (it's now a local, because we inlined the block + new BC(Bytecodes.PUSH_LOCAL, 1, 1), + + Bytecodes.POP, + new BC(Bytecodes.PUSH_LOCAL, 0, 1, "read local l2"), + Bytecodes.INC, + Bytecodes.DUP, + new BC(Bytecodes.POP_LOCAL, 0, 1, "store local l2"), + Bytecodes.RETURN_LOCAL); } private void returnFieldTrivial(final String fieldName, final byte bytecode) { From 2d2fd382aaaa4a918959b6a1839d0456a6844951 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 26 Aug 2021 18:44:48 +0100 Subject: [PATCH 2/4] Fix adapting things on splitting, here we don't need to change from arg to local Signed-off-by: Stefan Marr --- src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java index d5ee76c50..11ccf920c 100644 --- a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java +++ b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java @@ -4,8 +4,8 @@ import static trufflesom.compiler.bc.BytecodeGenerator.emit3; import static trufflesom.compiler.bc.BytecodeGenerator.emit3WithDummy; import static trufflesom.compiler.bc.BytecodeGenerator.emitPOP; -import static trufflesom.compiler.bc.BytecodeGenerator.emitPOPLOCAL; import static trufflesom.compiler.bc.BytecodeGenerator.emitPOPFIELD; +import static trufflesom.compiler.bc.BytecodeGenerator.emitPOPLOCAL; import static trufflesom.compiler.bc.BytecodeGenerator.emitPUSHARGUMENT; import static trufflesom.compiler.bc.BytecodeGenerator.emitPUSHBLOCK; import static trufflesom.compiler.bc.BytecodeGenerator.emitPUSHCONSTANT; @@ -1615,7 +1615,7 @@ private void adapt(final ScopeAdaptationVisitor inliner, case PUSH_ARGUMENT: { byte argIdx = bytecodes[i + 1]; byte ctxLevel = bytecodes[i + 2]; - if (ctxLevel == inliner.contextLevel) { + if (ctxLevel == inliner.contextLevel && requiresChangesToContextLevels) { if (argIdx == 1) { // at this point, because of the context level, // we know we refer to a block that got inlined @@ -1648,9 +1648,9 @@ private void adapt(final ScopeAdaptationVisitor inliner, } else { throw new RuntimeException("This should really never happen"); } - } else { - adaptContextIdx(inliner, i, requiresChangesToContextLevels); + break; } + adaptContextIdx(inliner, i, requiresChangesToContextLevels); break; } From 4149dfb37726c54861eeccc8825b52a7e5100996 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 26 Aug 2021 23:56:09 +0100 Subject: [PATCH 3/4] Add frame slot specialization in bytecode interpreter - simplify guards in ast interpreter, move them to Local Signed-off-by: Stefan Marr # Conflicts: # src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java --- src/trufflesom/compiler/Variable.java | 45 +++++++ .../compiler/bc/BytecodeMethodGenContext.java | 8 +- .../interpreter/nodes/LocalVariableNode.java | 104 ++++------------ .../nodes/NonLocalVariableNode.java | 113 ++++------------- .../nodes/bc/BytecodeLoopNode.java | 115 +++++++++++------- .../interpreter/nodes/bc/LocalNode.java | 82 +++++++++++++ 6 files changed, 242 insertions(+), 225 deletions(-) create mode 100644 src/trufflesom/interpreter/nodes/bc/LocalNode.java diff --git a/src/trufflesom/compiler/Variable.java b/src/trufflesom/compiler/Variable.java index 9ace9be74..9a8eaaa66 100644 --- a/src/trufflesom/compiler/Variable.java +++ b/src/trufflesom/compiler/Variable.java @@ -17,6 +17,7 @@ import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.FrameSlotKind; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.source.SourceSection; import bd.inlining.NodeState; @@ -163,6 +164,50 @@ public void init(final FrameSlot slot, final FrameDescriptor descriptor) { this.descriptor = descriptor; } + public boolean isBoolKind(final VirtualFrame frame) { + FrameSlotKind kind = descriptor.getFrameSlotKind(slot); + if (kind == FrameSlotKind.Boolean) { + return true; + } + if (kind == FrameSlotKind.Illegal) { + descriptor.setFrameSlotKind(slot, FrameSlotKind.Boolean); + return true; + } + return false; + } + + public boolean isLongKind(final VirtualFrame frame) { + FrameSlotKind kind = descriptor.getFrameSlotKind(slot); + if (kind == FrameSlotKind.Long) { + return true; + } + if (kind == FrameSlotKind.Illegal) { + descriptor.setFrameSlotKind(slot, FrameSlotKind.Long); + return true; + } + return false; + } + + public boolean isDoubleKind(final VirtualFrame frame) { + FrameSlotKind kind = descriptor.getFrameSlotKind(slot); + if (kind == FrameSlotKind.Double) { + return true; + } + if (kind == FrameSlotKind.Illegal) { + descriptor.setFrameSlotKind(slot, FrameSlotKind.Double); + return true; + } + return false; + } + + public boolean isUninitialized(final VirtualFrame frame) { + return descriptor.getFrameSlotKind(slot) == FrameSlotKind.Illegal; + } + + public void makeObject() { + descriptor.setFrameSlotKind(slot, FrameSlotKind.Object); + } + @Override public ExpressionNode getReadNode(final int contextLevel, final SourceSection source) { transferToInterpreterAndInvalidate("Variable.getReadNode"); diff --git a/src/trufflesom/compiler/bc/BytecodeMethodGenContext.java b/src/trufflesom/compiler/bc/BytecodeMethodGenContext.java index 9c352958f..783fec3f9 100644 --- a/src/trufflesom/compiler/bc/BytecodeMethodGenContext.java +++ b/src/trufflesom/compiler/bc/BytecodeMethodGenContext.java @@ -383,13 +383,7 @@ private BytecodeLoopNode constructBytecodeBody(final SourceSection sourceSection byte[] bytecodes = getBytecodeArray(); Object[] literalsArr = literals.toArray(); - FrameSlot[] localsAndOuters = new FrameSlot[localAndOuterVars.size()]; - - int i = 0; - for (Local l : localAndOuterVars.values()) { - localsAndOuters[i] = l.getSlot(); - i += 1; - } + Local[] localsAndOuters = localAndOuterVars.values().toArray(new Local[0]); FrameSlot frameOnStackMarker = throwsNonLocalReturn ? getFrameOnStackMarker(sourceSection).getSlot() : null; diff --git a/src/trufflesom/interpreter/nodes/LocalVariableNode.java b/src/trufflesom/interpreter/nodes/LocalVariableNode.java index 52663d48e..547daf153 100644 --- a/src/trufflesom/interpreter/nodes/LocalVariableNode.java +++ b/src/trufflesom/interpreter/nodes/LocalVariableNode.java @@ -2,9 +2,6 @@ import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.frame.FrameDescriptor; -import com.oracle.truffle.api.frame.FrameSlot; -import com.oracle.truffle.api.frame.FrameSlotKind; import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.VirtualFrame; @@ -17,21 +14,17 @@ public abstract class LocalVariableNode extends ExpressionNode implements Invocation { - protected final FrameSlot slot; - protected final FrameDescriptor descriptor; - protected final Local local; + protected final Local local; // TODO: We currently assume that there is a 1:1 mapping between lexical contexts // and frame descriptors, which is apparently not strictly true anymore in Truffle 1.0.0. // Generally, we also need to revise everything in this area and address issue SOMns#240. private LocalVariableNode(final Local local) { this.local = local; - this.slot = local.getSlot(); - this.descriptor = local.getFrameDescriptor(); } public final Object getSlotIdentifier() { - return slot.getIdentifier(); + return local.getSlot().getIdentifier(); } @Override @@ -49,51 +42,34 @@ public LocalVariableReadNode(final LocalVariableReadNode node) { this(node.local); } - @Specialization(guards = "isUninitialized(frame)") + @Specialization(guards = "local.isUninitialized(frame)") public final SObject doNil(final VirtualFrame frame) { return Nil.nilObject; } - protected boolean isBoolean(final VirtualFrame frame) { - return frame.isBoolean(slot); - } - - protected boolean isLong(final VirtualFrame frame) { - return frame.isLong(slot); - } - - protected boolean isDouble(final VirtualFrame frame) { - return frame.isDouble(slot); - } - - protected boolean isObject(final VirtualFrame frame) { - return frame.isObject(slot); - } - - @Specialization(guards = {"isBoolean(frame)"}, rewriteOn = {FrameSlotTypeException.class}) + @Specialization(guards = {"frame.isBoolean(local.getSlot())"}, + rewriteOn = {FrameSlotTypeException.class}) public final boolean doBoolean(final VirtualFrame frame) throws FrameSlotTypeException { - return frame.getBoolean(slot); + return frame.getBoolean(local.getSlot()); } - @Specialization(guards = {"isLong(frame)"}, rewriteOn = {FrameSlotTypeException.class}) + @Specialization(guards = {"frame.isLong(local.getSlot())"}, + rewriteOn = {FrameSlotTypeException.class}) public final long doLong(final VirtualFrame frame) throws FrameSlotTypeException { - return frame.getLong(slot); + return frame.getLong(local.getSlot()); } - @Specialization(guards = {"isDouble(frame)"}, rewriteOn = {FrameSlotTypeException.class}) + @Specialization(guards = {"frame.isDouble(local.getSlot())"}, + rewriteOn = {FrameSlotTypeException.class}) public final double doDouble(final VirtualFrame frame) throws FrameSlotTypeException { - return frame.getDouble(slot); + return frame.getDouble(local.getSlot()); } - @Specialization(guards = {"isObject(frame)"}, + @Specialization(guards = {"frame.isObject(local.getSlot())"}, replaces = {"doBoolean", "doLong", "doDouble"}, rewriteOn = {FrameSlotTypeException.class}) public final Object doObject(final VirtualFrame frame) throws FrameSlotTypeException { - return frame.getObject(slot); - } - - protected final boolean isUninitialized(final VirtualFrame frame) { - return descriptor.getFrameSlotKind(slot) == FrameSlotKind.Illegal; + return frame.getObject(local.getSlot()); } @Override @@ -115,67 +91,31 @@ public LocalVariableWriteNode(final LocalVariableWriteNode node) { public abstract ExpressionNode getExp(); - @Specialization(guards = "isBoolKind(expValue)") + @Specialization(guards = "local.isBoolKind(frame)") public final boolean writeBoolean(final VirtualFrame frame, final boolean expValue) { - frame.setBoolean(slot, expValue); + frame.setBoolean(local.getSlot(), expValue); return expValue; } - @Specialization(guards = "isLongKind(expValue)") + @Specialization(guards = "local.isLongKind(frame)") public final long writeLong(final VirtualFrame frame, final long expValue) { - frame.setLong(slot, expValue); + frame.setLong(local.getSlot(), expValue); return expValue; } - @Specialization(guards = "isDoubleKind(expValue)") + @Specialization(guards = "local.isDoubleKind(frame)") public final double writeDouble(final VirtualFrame frame, final double expValue) { - frame.setDouble(slot, expValue); + frame.setDouble(local.getSlot(), expValue); return expValue; } @Specialization(replaces = {"writeBoolean", "writeLong", "writeDouble"}) public final Object writeGeneric(final VirtualFrame frame, final Object expValue) { - descriptor.setFrameSlotKind(slot, FrameSlotKind.Object); - frame.setObject(slot, expValue); + local.makeObject(); + frame.setObject(local.getSlot(), expValue); return expValue; } - // uses expValue to make sure guard is not converted to assertion - protected final boolean isBoolKind(final boolean expValue) { - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Boolean) { - return true; - } - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Illegal) { - descriptor.setFrameSlotKind(slot, FrameSlotKind.Boolean); - return true; - } - return false; - } - - // uses expValue to make sure guard is not converted to assertion - protected final boolean isLongKind(final long expValue) { - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Long) { - return true; - } - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Illegal) { - descriptor.setFrameSlotKind(slot, FrameSlotKind.Long); - return true; - } - return false; - } - - // uses expValue to make sure guard is not converted to assertion - protected final boolean isDoubleKind(final double expValue) { - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Double) { - return true; - } - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Illegal) { - descriptor.setFrameSlotKind(slot, FrameSlotKind.Double); - return true; - } - return false; - } - @Override public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { inliner.updateWrite(local, this, getExp(), 0); diff --git a/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java b/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java index cc0c8cbfd..7f3439984 100644 --- a/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java +++ b/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java @@ -1,12 +1,7 @@ package trufflesom.interpreter.nodes; -import static trufflesom.interpreter.TruffleCompiler.transferToInterpreter; - import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.frame.FrameDescriptor; -import com.oracle.truffle.api.frame.FrameSlot; -import com.oracle.truffle.api.frame.FrameSlotKind; import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.VirtualFrame; @@ -21,15 +16,11 @@ public abstract class NonLocalVariableNode extends ContextualNode implements Invocation { - protected final FrameSlot slot; - protected final Local local; - protected final FrameDescriptor descriptor; + protected final Local local; private NonLocalVariableNode(final int contextLevel, final Local local) { super(contextLevel); this.local = local; - this.descriptor = local.getFrameDescriptor(); - this.slot = local.getSlot(); } @Override @@ -38,7 +29,7 @@ public SSymbol getInvocationIdentifier() { } public Object getSlotIdentifier() { - return slot.getIdentifier(); + return local.getSlot().getIdentifier(); } public abstract static class NonLocalVariableReadNode extends NonLocalVariableNode { @@ -47,51 +38,34 @@ public NonLocalVariableReadNode(final int contextLevel, final Local local) { super(contextLevel, local); } - @Specialization(guards = "isUninitialized(frame)") + @Specialization(guards = "local.isUninitialized(frame)") public final SObject doNil(final VirtualFrame frame) { return Nil.nilObject; } - protected boolean isBoolean(final VirtualFrame frame) { - return determineContext(frame).isBoolean(slot); - } - - protected boolean isLong(final VirtualFrame frame) { - return determineContext(frame).isLong(slot); - } - - protected boolean isDouble(final VirtualFrame frame) { - return determineContext(frame).isDouble(slot); - } - - protected boolean isObject(final VirtualFrame frame) { - return determineContext(frame).isObject(slot); - } - - @Specialization(guards = {"isBoolean(frame)"}, rewriteOn = {FrameSlotTypeException.class}) + @Specialization(guards = {"determineContext(frame).isBoolean(local.getSlot())"}, + rewriteOn = {FrameSlotTypeException.class}) public final boolean doBoolean(final VirtualFrame frame) throws FrameSlotTypeException { - return determineContext(frame).getBoolean(slot); + return determineContext(frame).getBoolean(local.getSlot()); } - @Specialization(guards = {"isLong(frame)"}, rewriteOn = {FrameSlotTypeException.class}) + @Specialization(guards = {"determineContext(frame).isLong(local.getSlot())"}, + rewriteOn = {FrameSlotTypeException.class}) public final long doLong(final VirtualFrame frame) throws FrameSlotTypeException { - return determineContext(frame).getLong(slot); + return determineContext(frame).getLong(local.getSlot()); } - @Specialization(guards = {"isDouble(frame)"}, rewriteOn = {FrameSlotTypeException.class}) + @Specialization(guards = {"determineContext(frame).isDouble(local.getSlot())"}, + rewriteOn = {FrameSlotTypeException.class}) public final double doDouble(final VirtualFrame frame) throws FrameSlotTypeException { - return determineContext(frame).getDouble(slot); + return determineContext(frame).getDouble(local.getSlot()); } - @Specialization(guards = {"isObject(frame)"}, + @Specialization(guards = {"determineContext(frame).isObject(local.getSlot())"}, replaces = {"doBoolean", "doLong", "doDouble"}, rewriteOn = {FrameSlotTypeException.class}) public final Object doObject(final VirtualFrame frame) throws FrameSlotTypeException { - return determineContext(frame).getObject(slot); - } - - protected final boolean isUninitialized(final VirtualFrame frame) { - return descriptor.getFrameSlotKind(slot) == FrameSlotKind.Illegal; + return determineContext(frame).getObject(local.getSlot()); } @Override @@ -109,74 +83,31 @@ public NonLocalVariableWriteNode(final int contextLevel, final Local local) { public abstract ExpressionNode getExp(); - @Specialization(guards = "isBoolKind(frame)") + @Specialization(guards = "local.isBoolKind(frame)") public final boolean writeBoolean(final VirtualFrame frame, final boolean expValue) { - determineContext(frame).setBoolean(slot, expValue); + determineContext(frame).setBoolean(local.getSlot(), expValue); return expValue; } - @Specialization(guards = "isLongKind(frame)") + @Specialization(guards = "local.isLongKind(frame)") public final long writeLong(final VirtualFrame frame, final long expValue) { - determineContext(frame).setLong(slot, expValue); + determineContext(frame).setLong(local.getSlot(), expValue); return expValue; } - @Specialization(guards = "isDoubleKind(frame)") + @Specialization(guards = "local.isDoubleKind(frame)") public final double writeDouble(final VirtualFrame frame, final double expValue) { - determineContext(frame).setDouble(slot, expValue); + determineContext(frame).setDouble(local.getSlot(), expValue); return expValue; } @Specialization(replaces = {"writeBoolean", "writeLong", "writeDouble"}) public final Object writeGeneric(final VirtualFrame frame, final Object expValue) { - ensureObjectKind(); - determineContext(frame).setObject(slot, expValue); + local.makeObject(); + determineContext(frame).setObject(local.getSlot(), expValue); return expValue; } - protected final boolean isBoolKind(final VirtualFrame frame) { - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Boolean) { - return true; - } - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Illegal) { - transferToInterpreter("LocalVar.writeBoolToUninit"); - descriptor.setFrameSlotKind(slot, FrameSlotKind.Boolean); - return true; - } - return false; - } - - protected final boolean isLongKind(final VirtualFrame frame) { - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Long) { - return true; - } - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Illegal) { - transferToInterpreter("LocalVar.writeIntToUninit"); - descriptor.setFrameSlotKind(slot, FrameSlotKind.Long); - return true; - } - return false; - } - - protected final boolean isDoubleKind(final VirtualFrame frame) { - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Double) { - return true; - } - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Illegal) { - transferToInterpreter("LocalVar.writeDoubleToUninit"); - descriptor.setFrameSlotKind(slot, FrameSlotKind.Double); - return true; - } - return false; - } - - protected final void ensureObjectKind() { - if (descriptor.getFrameSlotKind(slot) != FrameSlotKind.Object) { - transferToInterpreter("LocalVar.writeObjectToUninit"); - descriptor.setFrameSlotKind(slot, FrameSlotKind.Object); - } - } - @Override public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { inliner.updateWrite(local, this, getExp(), contextLevel); diff --git a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java index 11ccf920c..e309633ef 100644 --- a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java +++ b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java @@ -128,6 +128,10 @@ import trufflesom.interpreter.nodes.MessageSendNode; import trufflesom.interpreter.nodes.MessageSendNode.AbstractMessageSendNode; import trufflesom.interpreter.nodes.MessageSendNode.GenericMessageSendNode; +import trufflesom.interpreter.nodes.bc.LocalNode.LocalPop; +import trufflesom.interpreter.nodes.bc.LocalNode.LocalPush; +import trufflesom.interpreter.nodes.bc.LocalNodeFactory.LocalPopNodeGen; +import trufflesom.interpreter.nodes.bc.LocalNodeFactory.LocalPushNodeGen; import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; import trufflesom.interpreter.nodes.literals.LiteralNode; import trufflesom.interpreter.nodes.nary.BinaryExpressionNode; @@ -157,7 +161,7 @@ public class BytecodeLoopNode extends ExpressionNode implements ScopeReference { @CompilationFinal(dimensions = 1) private final byte[] bytecodes; @CompilationFinal(dimensions = 1) private final Object[] literalsAndConstants; - @CompilationFinal(dimensions = 1) private FrameSlot[] localsAndOuters; + @CompilationFinal(dimensions = 1) private Local[] localsAndOuters; @CompilationFinal(dimensions = 1) private final BackJump[] inlinedLoops; @@ -172,7 +176,7 @@ public class BytecodeLoopNode extends ExpressionNode implements ScopeReference { private final LexicalScope scope; public BytecodeLoopNode(final byte[] bytecodes, final int numLocals, - final FrameSlot[] localsAndOuters, final Object[] literals, final int maxStackDepth, + final Local[] localsAndOuters, final Object[] literals, final int maxStackDepth, final FrameSlot frameOnStackMarker, final BackJump[] inlinedLoops, final LexicalScope scope, final Universe universe) { this.bytecodes = bytecodes; @@ -191,14 +195,13 @@ public BytecodeLoopNode(final byte[] bytecodes, final int numLocals, @Override public Node deepCopy() { - return new BytecodeLoopNode( - bytecodes.clone(), numLocals, localsAndOuters, literalsAndConstants, - maxStackDepth, frameOnStackMarker, inlinedLoops, scope, universe).initialize( - sourceSection); + return new BytecodeLoopNode(bytecodes.clone(), numLocals, localsAndOuters, + literalsAndConstants, maxStackDepth, frameOnStackMarker, inlinedLoops, scope, + universe).initialize(sourceSection); } public String getNameOfLocal(final int idx) { - Local l = (Local) localsAndOuters[idx].getIdentifier(); + Local l = localsAndOuters[idx]; return l.name.getString(); } @@ -283,6 +286,9 @@ public Object executeGeneric(final VirtualFrame frame) { } case PUSH_LOCAL: { + if (quickened[bytecodeIndex] == null) { + quickened[bytecodeIndex] = LocalPushNodeGen.create(); + } byte localIdx = bytecodes[bytecodeIndex + 1]; byte contextIdx = bytecodes[bytecodeIndex + 2]; @@ -290,27 +296,41 @@ public Object executeGeneric(final VirtualFrame frame) { if (contextIdx > 0) { currentOrContext = determineContext(currentOrContext, contextIdx); } - FrameSlot slot = localsAndOuters[localIdx]; - Object value = currentOrContext.getValue(slot); stackPointer += 1; - stack[stackPointer] = value; + stack[stackPointer] = ((LocalPush) quickened[bytecodeIndex]).execute( + currentOrContext, localsAndOuters[localIdx]); break; } case PUSH_LOCAL_0: { + if (quickened[bytecodeIndex] == null) { + quickened[bytecodeIndex] = LocalPushNodeGen.create(); + } + stackPointer += 1; - stack[stackPointer] = frame.getValue(localsAndOuters[0]); + stack[stackPointer] = + ((LocalPush) quickened[bytecodeIndex]).execute(frame, localsAndOuters[0]); break; } case PUSH_LOCAL_1: { + if (quickened[bytecodeIndex] == null) { + quickened[bytecodeIndex] = LocalPushNodeGen.create(); + } + stackPointer += 1; - stack[stackPointer] = frame.getValue(localsAndOuters[1]); + stack[stackPointer] = + ((LocalPush) quickened[bytecodeIndex]).execute(frame, localsAndOuters[1]); break; } case PUSH_LOCAL_2: { + if (quickened[bytecodeIndex] == null) { + quickened[bytecodeIndex] = LocalPushNodeGen.create(); + } + stackPointer += 1; - stack[stackPointer] = frame.getValue(localsAndOuters[2]); + stack[stackPointer] = + ((LocalPush) quickened[bytecodeIndex]).execute(frame, localsAndOuters[2]); break; } @@ -474,6 +494,10 @@ public Object executeGeneric(final VirtualFrame frame) { } case POP_LOCAL: { + if (quickened[bytecodeIndex] == null) { + quickened[bytecodeIndex] = LocalPopNodeGen.create(); + } + byte localIdx = bytecodes[bytecodeIndex + 1]; byte contextIdx = bytecodes[bytecodeIndex + 2]; @@ -482,27 +506,39 @@ public Object executeGeneric(final VirtualFrame frame) { currentOrContext = determineContext(currentOrContext, contextIdx); } - FrameSlot slot = localsAndOuters[localIdx]; - - Object value = stack[stackPointer]; + ((LocalPop) quickened[bytecodeIndex]).execute(currentOrContext, + localsAndOuters[localIdx], stack[stackPointer]); stackPointer -= 1; - - currentOrContext.setObject(slot, value); break; } case POP_LOCAL_0: { - frame.setObject(localsAndOuters[0], stack[stackPointer]); + if (quickened[bytecodeIndex] == null) { + quickened[bytecodeIndex] = LocalPopNodeGen.create(); + } + + ((LocalPop) quickened[bytecodeIndex]).execute(frame, localsAndOuters[0], + stack[stackPointer]); stackPointer -= 1; break; } case POP_LOCAL_1: { - frame.setObject(localsAndOuters[1], stack[stackPointer]); + if (quickened[bytecodeIndex] == null) { + quickened[bytecodeIndex] = LocalPopNodeGen.create(); + } + + ((LocalPop) quickened[bytecodeIndex]).execute(frame, localsAndOuters[1], + stack[stackPointer]); stackPointer -= 1; break; } case POP_LOCAL_2: { - frame.setObject(localsAndOuters[2], stack[stackPointer]); + if (quickened[bytecodeIndex] == null) { + quickened[bytecodeIndex] = LocalPopNodeGen.create(); + } + + ((LocalPop) quickened[bytecodeIndex]).execute(frame, localsAndOuters[2], + stack[stackPointer]); stackPointer -= 1; break; } @@ -1328,9 +1364,7 @@ private void inlineInto(final BytecodeMethodGenContext mgenc, final int targetCo case PUSH_LOCAL: { byte localIdx = bytecodes[i + 1]; - FrameSlot frameSlot = localsAndOuters[localIdx]; - Local local = (Local) frameSlot.getIdentifier(); - local.emitPush(mgenc); + localsAndOuters[localIdx].emitPush(mgenc); break; } @@ -1338,9 +1372,7 @@ private void inlineInto(final BytecodeMethodGenContext mgenc, final int targetCo case PUSH_LOCAL_1: case PUSH_LOCAL_2: { byte localIdx = (byte) (bytecode - PUSH_LOCAL_0); - FrameSlot frameSlot = localsAndOuters[localIdx]; - Local local = (Local) frameSlot.getIdentifier(); - local.emitPush(mgenc); + localsAndOuters[localIdx].emitPush(mgenc); break; } @@ -1425,9 +1457,7 @@ private void inlineInto(final BytecodeMethodGenContext mgenc, final int targetCo case POP_LOCAL: { byte localIdx = bytecodes[i + 1]; - FrameSlot frameSlot = localsAndOuters[localIdx]; - Local local = (Local) frameSlot.getIdentifier(); - local.emitPop(mgenc); + localsAndOuters[localIdx].emitPop(mgenc); break; } @@ -1435,9 +1465,7 @@ private void inlineInto(final BytecodeMethodGenContext mgenc, final int targetCo case POP_LOCAL_1: case POP_LOCAL_2: { byte localIdx = (byte) (bytecode - POP_LOCAL_0); - FrameSlot frameSlot = localsAndOuters[localIdx]; - Local local = (Local) frameSlot.getIdentifier(); - local.emitPop(mgenc); + localsAndOuters[localIdx].emitPop(mgenc); break; } @@ -1576,7 +1604,7 @@ private void inlineInto(final BytecodeMethodGenContext mgenc, final int targetCo private void adapt(final ScopeAdaptationVisitor inliner, final boolean requiresChangesToContextLevels) { CompilerAsserts.neverPartOfCompilation("Not a run-time thing, a parse time thing..."); - FrameSlot[] oldLocalsAndOuters = Arrays.copyOf(localsAndOuters, localsAndOuters.length); + Local[] oldLocalsAndOuters = Arrays.copyOf(localsAndOuters, localsAndOuters.length); int i = 0; while (i < bytecodes.length) { @@ -1600,15 +1628,14 @@ private void adapt(final ScopeAdaptationVisitor inliner, } else { localIdx = (byte) (bytecode - PUSH_LOCAL_0); } - FrameSlot frameSlot = oldLocalsAndOuters[localIdx]; - Local local = (Local) frameSlot.getIdentifier(); - ScopeElement se = inliner.getAdaptedVar(local); + ScopeElement se = + inliner.getAdaptedVar(oldLocalsAndOuters[localIdx]); if (bytecode == PUSH_LOCAL) { bytecodes[i + 2] = (byte) se.contextLevel; assert bytecodes[i + 2] >= 0; } - localsAndOuters[localIdx] = ((Local) se.var).getSlot(); + localsAndOuters[localIdx] = (Local) se.var; break; } @@ -1627,11 +1654,10 @@ private void adapt(final ScopeAdaptationVisitor inliner, ScopeElement se = inliner.getAdaptedVar(arg1); assert se.contextLevel == ctxLevel; - FrameSlot slot = ((Local) se.var).getSlot(); int foundIdx = -1; for (int j = 0; j < localsAndOuters.length; j += 1) { - if (localsAndOuters[j] == slot) { + if (localsAndOuters[j].equals(se.var)) { foundIdx = j; break; } @@ -1642,7 +1668,7 @@ private void adapt(final ScopeAdaptationVisitor inliner, localsAndOuters = Arrays.copyOf(localsAndOuters, localsAndOuters.length + 1); } - localsAndOuters[foundIdx] = slot; + localsAndOuters[foundIdx] = (Local) se.var; bytecodes[i] = Bytecodes.PUSH_LOCAL; bytecodes[i + 1] = (byte) foundIdx; } else { @@ -1708,15 +1734,14 @@ private void adapt(final ScopeAdaptationVisitor inliner, } else { localIdx = (byte) (bytecode - POP_LOCAL_0); } - FrameSlot frameSlot = oldLocalsAndOuters[localIdx]; - Local local = (Local) frameSlot.getIdentifier(); - ScopeElement se = inliner.getAdaptedVar(local); + ScopeElement se = + inliner.getAdaptedVar(oldLocalsAndOuters[localIdx]); if (bytecode == POP_LOCAL) { bytecodes[i + 2] = (byte) se.contextLevel; assert bytecodes[i + 2] >= 0; } - localsAndOuters[localIdx] = ((Local) se.var).getSlot(); + localsAndOuters[localIdx] = (Local) se.var; break; } diff --git a/src/trufflesom/interpreter/nodes/bc/LocalNode.java b/src/trufflesom/interpreter/nodes/bc/LocalNode.java new file mode 100644 index 000000000..c8108b8e9 --- /dev/null +++ b/src/trufflesom/interpreter/nodes/bc/LocalNode.java @@ -0,0 +1,82 @@ +package trufflesom.interpreter.nodes.bc; + +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.FrameSlotTypeException; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; + +import trufflesom.compiler.Variable.Local; +import trufflesom.vm.constants.Nil; +import trufflesom.vmobjects.SObject; + + +public abstract class LocalNode { + public abstract static class LocalPush extends Node { + public abstract Object execute(VirtualFrame frame, Local local); + + @Specialization(guards = "local.isUninitialized(frame)") + public final SObject doNil(final VirtualFrame frame, final Local local) { + return Nil.nilObject; + } + + @Specialization(guards = {"frame.isBoolean(local.getSlot())"}, + rewriteOn = {FrameSlotTypeException.class}) + public final boolean doBoolean(final VirtualFrame frame, final Local local) + throws FrameSlotTypeException { + return frame.getBoolean(local.getSlot()); + } + + @Specialization(guards = {"frame.isLong(local.getSlot())"}, + rewriteOn = {FrameSlotTypeException.class}) + public final long doLong(final VirtualFrame frame, final Local local) + throws FrameSlotTypeException { + return frame.getLong(local.getSlot()); + } + + @Specialization(guards = {"frame.isDouble(local.getSlot())"}, + rewriteOn = {FrameSlotTypeException.class}) + public final double doDouble(final VirtualFrame frame, final Local local) + throws FrameSlotTypeException { + return frame.getDouble(local.getSlot()); + } + + @Specialization(guards = {"frame.isObject(local.getSlot())"}, + replaces = {"doBoolean", "doLong", "doDouble"}, + rewriteOn = {FrameSlotTypeException.class}) + public final Object doObject(final VirtualFrame frame, final Local local) + throws FrameSlotTypeException { + return frame.getObject(local.getSlot()); + } + } + + public abstract static class LocalPop extends Node { + + public abstract void execute(VirtualFrame frame, Local local, Object value); + + @Specialization(guards = "local.isBoolKind(frame)") + public final void writeBoolean(final VirtualFrame frame, final Local local, + final Boolean expValue) { + frame.setBoolean(local.getSlot(), expValue); + } + + @Specialization(guards = "local.isLongKind(frame)") + public final void writeLong(final VirtualFrame frame, final Local local, + final Long expValue) { + frame.setLong(local.getSlot(), expValue); + } + + @Specialization(guards = "local.isDoubleKind(frame)") + public final void writeDouble(final VirtualFrame frame, final Local local, + final Double expValue) { + frame.setDouble(local.getSlot(), expValue); + } + + @Specialization(replaces = {"writeBoolean", "writeLong", "writeDouble"}) + public final void writeGeneric(final VirtualFrame frame, final Local local, + final Object expValue) { + local.makeObject(); + frame.setObject(local.getSlot(), expValue); + } + + } +} From c6a8ab5d84aec13a06ae661f1a5dd780c5dfe4a9 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 27 Aug 2021 00:05:10 +0100 Subject: [PATCH 4/4] Fix native image building Signed-off-by: Stefan Marr --- src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java index e309633ef..305f12a8d 100644 --- a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java +++ b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java @@ -287,6 +287,7 @@ public Object executeGeneric(final VirtualFrame frame) { case PUSH_LOCAL: { if (quickened[bytecodeIndex] == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); quickened[bytecodeIndex] = LocalPushNodeGen.create(); } byte localIdx = bytecodes[bytecodeIndex + 1]; @@ -305,6 +306,7 @@ public Object executeGeneric(final VirtualFrame frame) { case PUSH_LOCAL_0: { if (quickened[bytecodeIndex] == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); quickened[bytecodeIndex] = LocalPushNodeGen.create(); } @@ -315,6 +317,7 @@ public Object executeGeneric(final VirtualFrame frame) { } case PUSH_LOCAL_1: { if (quickened[bytecodeIndex] == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); quickened[bytecodeIndex] = LocalPushNodeGen.create(); } @@ -325,6 +328,7 @@ public Object executeGeneric(final VirtualFrame frame) { } case PUSH_LOCAL_2: { if (quickened[bytecodeIndex] == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); quickened[bytecodeIndex] = LocalPushNodeGen.create(); } @@ -495,6 +499,7 @@ public Object executeGeneric(final VirtualFrame frame) { case POP_LOCAL: { if (quickened[bytecodeIndex] == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); quickened[bytecodeIndex] = LocalPopNodeGen.create(); } @@ -514,6 +519,7 @@ public Object executeGeneric(final VirtualFrame frame) { case POP_LOCAL_0: { if (quickened[bytecodeIndex] == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); quickened[bytecodeIndex] = LocalPopNodeGen.create(); } @@ -524,6 +530,7 @@ public Object executeGeneric(final VirtualFrame frame) { } case POP_LOCAL_1: { if (quickened[bytecodeIndex] == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); quickened[bytecodeIndex] = LocalPopNodeGen.create(); } @@ -534,6 +541,7 @@ public Object executeGeneric(final VirtualFrame frame) { } case POP_LOCAL_2: { if (quickened[bytecodeIndex] == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); quickened[bytecodeIndex] = LocalPopNodeGen.create(); }