From e6f1708e3a468467c4216bb1ab784a52cfb39cd0 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 4 Oct 2024 16:44:23 +0100 Subject: [PATCH] Implement more supernodes for incrementing/decrementing - generalize existing nodes to work with arbitrary values, support decrementing, and match new naming scheme All nodes now supported: - IncExpWithValue: adds or subtracts a constant value to/from a subexpression - [Uninit]IncFieldWithValueNode: increment or decrement a field by a constant value - [Uninit]IncFieldWithExpNode: increment or decrement a field with a value from a subexpression - Inc[Non]LocalVarWithExpNode: increment or decrement a local with a value from a subexpression - Inc[Non]LocalVarWithValueNode: increment or decrement a local by a constant value - SomSom's parser also has `text := text + self currentChar.` where `text` is a field in the lexer, this is supported too --- .../compiler/MethodGenerationContext.java | 33 +++- .../src/trufflesom/compiler/ParserAst.java | 13 +- .../src/trufflesom/compiler/Variable.java | 62 ++++++- .../interpreter/nodes/FieldNode.java | 88 --------- .../nodes/bc/BytecodeLoopNode.java | 5 +- .../objectstorage/FieldAccessorNode.java | 12 +- .../objectstorage/StorageLocation.java | 10 +- .../supernodes/IntIncrementNode.java | 41 ----- .../supernodes/inc/IncExpWithValueNode.java | 116 ++++++++++++ .../supernodes/inc/IncFieldWithExpNode.java | 57 ++++++ .../supernodes/inc/IncFieldWithValueNode.java | 46 +++++ .../inc/IncLocalVarWithExpNode.java | 71 ++++++++ .../inc/IncLocalVarWithValueNode.java | 47 +++++ .../inc/IncNonLocalVarWithExpNode.java | 102 +++++++++++ .../inc/IncNonLocalVarWithValueNode.java | 56 ++++++ .../inc/UninitIncFieldWithExpNode.java | 95 ++++++++++ .../inc/UninitIncFieldWithValueNode.java | 67 +++++++ .../supernodes/IncrementOpTests.java | 170 ++++++++++++++++++ tests/trufflesom/tests/AstInliningTests.java | 25 ++- 19 files changed, 942 insertions(+), 174 deletions(-) delete mode 100644 src/trufflesom/src/trufflesom/interpreter/supernodes/IntIncrementNode.java create mode 100644 src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncExpWithValueNode.java create mode 100644 src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncFieldWithExpNode.java create mode 100644 src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncFieldWithValueNode.java create mode 100644 src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncLocalVarWithExpNode.java create mode 100644 src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncLocalVarWithValueNode.java create mode 100644 src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncNonLocalVarWithExpNode.java create mode 100644 src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncNonLocalVarWithValueNode.java create mode 100644 src/trufflesom/src/trufflesom/interpreter/supernodes/inc/UninitIncFieldWithExpNode.java create mode 100644 src/trufflesom/src/trufflesom/interpreter/supernodes/inc/UninitIncFieldWithValueNode.java create mode 100644 tests/trufflesom/supernodes/IncrementOpTests.java diff --git a/src/trufflesom/src/trufflesom/compiler/MethodGenerationContext.java b/src/trufflesom/src/trufflesom/compiler/MethodGenerationContext.java index 3295f6090..df4d93f56 100644 --- a/src/trufflesom/src/trufflesom/compiler/MethodGenerationContext.java +++ b/src/trufflesom/src/trufflesom/compiler/MethodGenerationContext.java @@ -50,15 +50,16 @@ import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.FieldNode; import trufflesom.interpreter.nodes.FieldNode.FieldReadNode; -import trufflesom.interpreter.nodes.FieldNode.UninitFieldIncNode; import trufflesom.interpreter.nodes.FieldNodeFactory.FieldWriteNodeGen; import trufflesom.interpreter.nodes.ReturnNonLocalNode; import trufflesom.interpreter.nodes.ReturnNonLocalNode.CatchNonLocalReturnNode; import trufflesom.interpreter.nodes.literals.BlockNode; -import trufflesom.interpreter.supernodes.IntIncrementNode; +import trufflesom.interpreter.supernodes.inc.IncExpWithValueNode; import trufflesom.interpreter.supernodes.LocalVariableSquareNode; import trufflesom.interpreter.supernodes.NonLocalVariableSquareNode; +import trufflesom.interpreter.supernodes.inc.UninitIncFieldWithExpNode; import trufflesom.primitives.Primitives; +import trufflesom.primitives.arithmetic.AdditionPrim; import trufflesom.vmobjects.SClass; import trufflesom.vmobjects.SInvokable; import trufflesom.vmobjects.SInvokable.SMethod; @@ -405,6 +406,10 @@ public ExpressionNode getLocalWriteNode(final Variable variable, final ExpressionNode valExpr, final long coord) { int ctxLevel = getContextLevel(variable); + if (valExpr instanceof IncExpWithValueNode inc && inc.doesAccessVariable(variable)) { + return inc.createIncVarNode((Local) variable, ctxLevel); + } + if (valExpr instanceof LocalVariableSquareNode l) { return variable.getReadSquareWriteNode(ctxLevel, coord, l.getLocal(), 0); } @@ -450,8 +455,9 @@ public FieldReadNode getObjectFieldRead(final SSymbol fieldName, return null; } - return new FieldReadNode(getSelfRead(coord), - holderGenc.getFieldIndex(fieldName)).initialize(coord); + byte fieldIndex = holderGenc.getFieldIndex(fieldName); + ExpressionNode selfNode = getSelfRead(coord); + return new FieldReadNode(selfNode, fieldIndex).initialize(coord); } public FieldNode getObjectFieldWrite(final SSymbol fieldName, final ExpressionNode exp, @@ -460,11 +466,22 @@ public FieldNode getObjectFieldWrite(final SSymbol fieldName, final ExpressionNo return null; } - int fieldIndex = holderGenc.getFieldIndex(fieldName); + byte fieldIndex = holderGenc.getFieldIndex(fieldName); ExpressionNode self = getSelfRead(coord); - if (exp instanceof IntIncrementNode - && ((IntIncrementNode) exp).doesAccessField(fieldIndex)) { - return new UninitFieldIncNode(self, fieldIndex, coord); + if (exp instanceof IncExpWithValueNode incNode && incNode.doesAccessField(fieldIndex)) { + return incNode.createIncFieldNode(self, fieldIndex, coord); + } + + if (exp instanceof AdditionPrim add) { + ExpressionNode rcvr = add.getReceiver(); + ExpressionNode arg = add.getArgument(); + + if (rcvr instanceof FieldReadNode fr && fieldIndex == fr.getFieldIndex()) { + return new UninitIncFieldWithExpNode(self, arg, true, fieldIndex, coord); + } + if (arg instanceof FieldReadNode fr && fieldIndex == fr.getFieldIndex()) { + return new UninitIncFieldWithExpNode(self, rcvr, false, fieldIndex, coord); + } } return FieldWriteNodeGen.create(fieldIndex, self, exp).initialize(coord); diff --git a/src/trufflesom/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/src/trufflesom/compiler/ParserAst.java index d17ceb579..30945c57e 100644 --- a/src/trufflesom/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/src/trufflesom/compiler/ParserAst.java @@ -45,12 +45,12 @@ import trufflesom.interpreter.nodes.literals.GenericLiteralNode; import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; import trufflesom.interpreter.nodes.literals.LiteralNode; -import trufflesom.interpreter.supernodes.IntIncrementNodeGen; import trufflesom.interpreter.supernodes.LocalFieldStringEqualsNode; import trufflesom.interpreter.supernodes.LocalVariableSquareNodeGen; import trufflesom.interpreter.supernodes.NonLocalFieldStringEqualsNode; import trufflesom.interpreter.supernodes.NonLocalVariableSquareNodeGen; import trufflesom.interpreter.supernodes.StringEqualsNodeGen; +import trufflesom.interpreter.supernodes.inc.IncExpWithValueNodeGen; import trufflesom.primitives.Primitives; import trufflesom.vm.Globals; import trufflesom.vm.NotYetImplementedException; @@ -325,6 +325,12 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, rcvr.getContextLevel(), rcvr.getLocal()).initialize(coordWithL); } } + } else if (msg == SymbolTable.symPlus && operand instanceof IntegerLiteralNode lit) { + long litValue = lit.executeLong(null); + return IncExpWithValueNodeGen.create(litValue, false, receiver).initialize(coordWithL); + } else if (msg == SymbolTable.symMinus && operand instanceof IntegerLiteralNode lit) { + long litValue = lit.executeLong(null); + return IncExpWithValueNodeGen.create(-litValue, true, receiver).initialize(coordWithL); } ExpressionNode inlined = @@ -334,11 +340,6 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, return inlined; } - if (msg == SymbolTable.symPlus && operand instanceof IntegerLiteralNode lit) { - if (lit.executeLong(null) == 1) { - return IntIncrementNodeGen.create(receiver); - } - } return MessageSendNode.create(msg, args, coordWithL); } diff --git a/src/trufflesom/src/trufflesom/compiler/Variable.java b/src/trufflesom/src/trufflesom/compiler/Variable.java index 8d85dd09b..da7cac2c3 100644 --- a/src/trufflesom/src/trufflesom/compiler/Variable.java +++ b/src/trufflesom/src/trufflesom/compiler/Variable.java @@ -6,9 +6,6 @@ import static trufflesom.compiler.bc.BytecodeGenerator.emitPUSHLOCAL; import static trufflesom.vm.SymbolTable.strBlockSelf; import static trufflesom.vm.SymbolTable.strSelf; -import static trufflesom.vm.SymbolTable.symBlockSelf; -import static trufflesom.vm.SymbolTable.symSelf; -import static trufflesom.vm.SymbolTable.symbolFor; import java.util.Objects; @@ -23,16 +20,22 @@ import trufflesom.interpreter.nodes.ArgumentReadNode.NonLocalArgumentReadNode; import trufflesom.interpreter.nodes.ArgumentReadNode.NonLocalArgumentWriteNode; import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.LocalVariableNode.LocalVariableReadNode; import trufflesom.interpreter.nodes.LocalVariableNodeFactory.LocalVariableReadNodeGen; import trufflesom.interpreter.nodes.LocalVariableNodeFactory.LocalVariableWriteNodeGen; +import trufflesom.interpreter.nodes.NonLocalVariableNode.NonLocalVariableReadNode; import trufflesom.interpreter.nodes.NonLocalVariableNodeFactory.NonLocalVariableReadNodeGen; import trufflesom.interpreter.nodes.NonLocalVariableNodeFactory.NonLocalVariableWriteNodeGen; import trufflesom.interpreter.supernodes.LocalVariableReadSquareWriteNodeGen; import trufflesom.interpreter.supernodes.LocalVariableSquareNodeGen; import trufflesom.interpreter.supernodes.NonLocalVariableReadSquareWriteNodeGen; import trufflesom.interpreter.supernodes.NonLocalVariableSquareNodeGen; +import trufflesom.interpreter.supernodes.inc.IncLocalVarWithExpNodeGen; +import trufflesom.interpreter.supernodes.inc.IncLocalVarWithValueNodeGen; +import trufflesom.interpreter.supernodes.inc.IncNonLocalVarWithExpNodeGen; +import trufflesom.interpreter.supernodes.inc.IncNonLocalVarWithValueNodeGen; +import trufflesom.primitives.arithmetic.AdditionPrim; import trufflesom.vm.NotYetImplementedException; -import trufflesom.vmobjects.SSymbol; public abstract class Variable { @@ -68,6 +71,8 @@ public abstract ExpressionNode getWriteNode( public abstract ExpressionNode getReadSquareWriteNode(int writeContextLevel, long coord, Local readLocal, int readContextLevel); + public abstract ExpressionNode getIncNode(int contextLevel, long incValue, long coord); + protected abstract void emitPop(BytecodeMethodGenContext mgenc); protected abstract void emitPush(BytecodeMethodGenContext mgenc); @@ -156,6 +161,12 @@ public ExpressionNode getReadSquareWriteNode(final int writeContextLevel, final throw new NotYetImplementedException(); } + @Override + public ExpressionNode getIncNode(final int contextLevel, final long incValue, + final long coord) { + throw new NotYetImplementedException(); + } + @Override public void emitPop(final BytecodeMethodGenContext mgenc) { emitPOPARGUMENT(mgenc, (byte) index, (byte) mgenc.getContextLevel(this)); @@ -215,6 +226,16 @@ public ExpressionNode getReadSquareWriteNode(final int writeContextLevel, final return LocalVariableReadSquareWriteNodeGen.create(this, readLocal).initialize(coord); } + @Override + public ExpressionNode getIncNode(final int contextLevel, final long incValue, + final long coord) { + if (contextLevel > 0) { + return IncNonLocalVarWithValueNodeGen.create(contextLevel, this, incValue) + .initialize(coord); + } + return IncLocalVarWithValueNodeGen.create(this, incValue).initialize(coord); + } + public final int getIndex() { return slotIndex; } @@ -231,6 +252,31 @@ public Local splitToMergeIntoOuterScope(final int newSlotIndex) { public ExpressionNode getWriteNode(final int contextLevel, final ExpressionNode valueExpr, final long coordinate) { + if (valueExpr instanceof AdditionPrim add) { + ExpressionNode rcvr = add.getReceiver(); + ExpressionNode arg = add.getArgument(); + + if (contextLevel > 0) { + if (rcvr instanceof NonLocalVariableReadNode nl && nl.getLocal() == this) { + return IncNonLocalVarWithExpNodeGen.create(contextLevel, this, arg) + .initialize(coord); + } + + if (arg instanceof NonLocalVariableReadNode nl && nl.getLocal() == this) { + return IncNonLocalVarWithExpNodeGen.create(contextLevel, this, rcvr) + .initialize(coord); + } + } else { + if (rcvr instanceof LocalVariableReadNode l && l.getLocal() == this) { + return IncLocalVarWithExpNodeGen.create(this, arg).initialize(coord); + } + + if (arg instanceof LocalVariableReadNode l && l.getLocal() == this) { + return IncLocalVarWithExpNodeGen.create(this, rcvr).initialize(coord); + } + } + } + if (contextLevel > 0) { return NonLocalVariableWriteNodeGen.create(contextLevel, this, valueExpr) .initialize(coordinate); @@ -286,6 +332,14 @@ public ExpressionNode getReadSquareWriteNode(final int readContextLevel, final l "There shouldn't be any language-level square nodes for internal slots. "); } + @Override + public ExpressionNode getIncNode(final int contextLevel, final long incValue, + final long coord) { + throw new UnsupportedOperationException( + "There shouldn't be any language-level inc nodes for internal slots. " + + "They are used directly by other nodes."); + } + @Override public Internal split() { return new Internal(name, coord, slotIndex); diff --git a/src/trufflesom/src/trufflesom/interpreter/nodes/FieldNode.java b/src/trufflesom/src/trufflesom/interpreter/nodes/FieldNode.java index cbed026a4..461410667 100644 --- a/src/trufflesom/src/trufflesom/interpreter/nodes/FieldNode.java +++ b/src/trufflesom/src/trufflesom/interpreter/nodes/FieldNode.java @@ -246,94 +246,6 @@ public static ExpressionNode createForMethod(final int fieldIdx, final Argument } } - public static final class UninitFieldIncNode extends FieldNode { - - @Child private ExpressionNode self; - private final int fieldIndex; - - public UninitFieldIncNode(final ExpressionNode self, final int fieldIndex, - final long coord) { - this.self = self; - this.fieldIndex = fieldIndex; - this.sourceCoord = coord; - } - - public int getFieldIndex() { - return fieldIndex; - } - - @Override - public ExpressionNode getSelf() { - return self; - } - - @Override - public Object doPreEvaluated(final VirtualFrame frame, final Object[] arguments) { - CompilerDirectives.transferToInterpreter(); - throw new UnsupportedOperationException(); - } - - @Override - public Object executeGeneric(final VirtualFrame frame) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - SObject obj = (SObject) self.executeGeneric(frame); - - Object val = obj.getField(fieldIndex); - if (!(val instanceof Long)) { - throw new NotYetImplementedException(); - } - - long longVal = 0; - try { - longVal = Math.addExact((Long) val, 1); - obj.setField(fieldIndex, longVal); - } catch (ArithmeticException e) { - throw new NotYetImplementedException(); - } - - IncrementLongFieldNode node = FieldAccessorNode.createIncrement(fieldIndex, obj); - IncFieldNode incNode = new IncFieldNode(self, node, sourceCoord); - replace(incNode); - node.notifyAsInserted(); - - return longVal; - } - } - - private static final class IncFieldNode extends FieldNode { - @Child private ExpressionNode self; - @Child private IncrementLongFieldNode inc; - - IncFieldNode(final ExpressionNode self, final IncrementLongFieldNode inc, - final long coord) { - initialize(coord); - this.self = self; - this.inc = inc; - } - - @Override - public ExpressionNode getSelf() { - return self; - } - - @Override - public Object doPreEvaluated(final VirtualFrame frame, final Object[] arguments) { - CompilerDirectives.transferToInterpreter(); - throw new UnsupportedOperationException(); - } - - @Override - public Object executeGeneric(final VirtualFrame frame) { - return executeLong(frame); - } - - @Override - public long executeLong(final VirtualFrame frame) { - SObject obj = (SObject) self.executeGeneric(frame); - return inc.increment(obj); - } - } - public static final class WriteAndReturnSelf extends ExpressionNode implements PreevaluatedExpression { @Child ExpressionNode write; diff --git a/src/trufflesom/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java b/src/trufflesom/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java index 5cb7e0ffa..545ef87dd 100644 --- a/src/trufflesom/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java +++ b/src/trufflesom/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java @@ -99,7 +99,6 @@ import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; -import com.oracle.truffle.api.profiles.ValueProfile; import trufflesom.bdt.inlining.ScopeAdaptationVisitor; import trufflesom.bdt.inlining.nodes.ScopeReference; @@ -866,7 +865,7 @@ public Object executeGeneric(final VirtualFrame frame) { break; } - ((IncrementLongFieldNode) node).increment(obj); + ((IncrementLongFieldNode) node).increment(obj, 1); bytecodeIndex += Bytecodes.LEN_TWO_ARGS; break; } @@ -890,7 +889,7 @@ public Object executeGeneric(final VirtualFrame frame) { break; } - long value = ((IncrementLongFieldNode) node).increment(obj); + long value = ((IncrementLongFieldNode) node).increment(obj, 1); stackPointer += 1; stack[stackPointer] = value; bytecodeIndex += Bytecodes.LEN_TWO_ARGS; diff --git a/src/trufflesom/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java b/src/trufflesom/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java index 95a4185c4..efaefaa42 100644 --- a/src/trufflesom/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java +++ b/src/trufflesom/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java @@ -432,24 +432,24 @@ private boolean hasExpectedLayout(final SObject obj) return layout == obj.getObjectLayout(); } - public long increment(final SObject obj) { + public long increment(final SObject obj, final long incValue) { try { if (hasExpectedLayout(obj)) { - return storage.increment(obj); + return storage.increment(obj, incValue); } else { ensureNext(obj); - return nextInCache.increment(obj); + return nextInCache.increment(obj, incValue); } } catch (InvalidAssumptionException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); ensureNext(obj); - return dropAndIncrementNext(obj); + return dropAndIncrementNext(obj, incValue); } } @InliningCutoff - private long dropAndIncrementNext(final SObject obj) { - return replace(SOMNode.unwrapIfNeeded(nextInCache)).increment(obj); + private long dropAndIncrementNext(final SObject obj, final long incValue) { + return replace(SOMNode.unwrapIfNeeded(nextInCache)).increment(obj, incValue); } @InliningCutoff diff --git a/src/trufflesom/src/trufflesom/interpreter/objectstorage/StorageLocation.java b/src/trufflesom/src/trufflesom/interpreter/objectstorage/StorageLocation.java index a08c95020..e132fad53 100644 --- a/src/trufflesom/src/trufflesom/interpreter/objectstorage/StorageLocation.java +++ b/src/trufflesom/src/trufflesom/interpreter/objectstorage/StorageLocation.java @@ -38,7 +38,7 @@ public interface LongStorageLocation { void writeLong(SObject obj, long value); - long increment(SObject obj); + long increment(SObject obj, long incValue); } public interface DoubleStorageLocation { @@ -364,9 +364,9 @@ public long readLongSet(final SObject obj) { } @Override - public long increment(final SObject obj) { + public long increment(final SObject obj, final long incValue) { long val = unsafe.getLong(obj, fieldMemoryOffset); - long result = Math.addExact(val, 1); + long result = Math.addExact(val, incValue); unsafe.putLong(obj, fieldMemoryOffset, result); return result; } @@ -453,9 +453,9 @@ public long readLongSet(final SObject obj) { } @Override - public long increment(final SObject obj) { + public long increment(final SObject obj, final long incValue) { long val = obj.getExtendedPrimFields()[extensionIndex]; - long result = Math.addExact(val, 1); + long result = Math.addExact(val, incValue); obj.getExtendedPrimFields()[extensionIndex] = result; return result; } diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/IntIncrementNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/IntIncrementNode.java deleted file mode 100644 index ff0cc2163..000000000 --- a/src/trufflesom/src/trufflesom/interpreter/supernodes/IntIncrementNode.java +++ /dev/null @@ -1,41 +0,0 @@ -package trufflesom.interpreter.supernodes; - -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.frame.VirtualFrame; - -import trufflesom.interpreter.nodes.ExpressionNode; -import trufflesom.interpreter.nodes.FieldNode.FieldReadNode; - - -@NodeChild(value = "rcvr", type = ExpressionNode.class) -public abstract class IntIncrementNode extends ExpressionNode { - @Specialization(rewriteOn = ArithmeticException.class) - public static long doInc(final long rcvr) { - return Math.addExact(rcvr, 1); - } - - @Specialization - public static double doInc(final double rcvr) { - return rcvr + 1; - } - - public abstract Object executeEvaluated(Object rcvr); - - @Override - public final Object doPreEvaluated(final VirtualFrame frame, final Object[] args) { - return executeEvaluated(args[0]); - } - - public abstract ExpressionNode getRcvr(); - - public boolean doesAccessField(final int fieldIdx) { - ExpressionNode rcvr = getRcvr(); - if (rcvr instanceof FieldReadNode) { - FieldReadNode r = (FieldReadNode) rcvr; - return r.getFieldIndex() == fieldIdx; - } - - return false; - } -} diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncExpWithValueNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncExpWithValueNode.java new file mode 100644 index 000000000..e056f1b6c --- /dev/null +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncExpWithValueNode.java @@ -0,0 +1,116 @@ +package trufflesom.interpreter.supernodes.inc; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.NodeChild; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; + +import trufflesom.compiler.Variable; +import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.AbstractMessageSendNode; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.FieldNode; +import trufflesom.interpreter.nodes.FieldNode.FieldReadNode; +import trufflesom.interpreter.nodes.GenericMessageSendNode; +import trufflesom.interpreter.nodes.LocalVariableNode; +import trufflesom.interpreter.nodes.MessageSendNode; +import trufflesom.interpreter.nodes.NonLocalVariableNode; +import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; +import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; +import trufflesom.vm.SymbolTable; +import trufflesom.vm.VmSettings; +import trufflesom.vmobjects.SSymbol; + + +@NodeChild(value = "rcvr", type = ExpressionNode.class) +public abstract class IncExpWithValueNode extends ExpressionNode { + protected final long incValue; + protected final boolean isMinusAndValueNegated; + + public IncExpWithValueNode(long incValue, boolean isMinusAndValueNegated) { + this.incValue = incValue; + this.isMinusAndValueNegated = isMinusAndValueNegated; + } + + public abstract Object executeEvaluated(VirtualFrame frame, Object rcvr); + + @Override + public final Object doPreEvaluated(final VirtualFrame frame, final Object[] args) { + return executeEvaluated(frame, args[0]); + } + + public abstract ExpressionNode getRcvr(); + + @Specialization(rewriteOn = ArithmeticException.class) + public long doInc(final long rcvr) { + return Math.addExact(rcvr, incValue); + } + + @Specialization + public double doInc(final double rcvr) { + return rcvr + incValue; + } + + @Fallback + public final Object makeGenericSend(final VirtualFrame frame, final Object rcvr) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + return makeGenericSend().doPreEvaluated(frame, + new Object[] {rcvr, isMinusAndValueNegated ? -incValue : incValue}); + } + + public boolean doesAccessField(final int fieldIdx) { + ExpressionNode rcvr = getRcvr(); + if (rcvr instanceof FieldReadNode r) { + return r.getFieldIndex() == fieldIdx; + } + + return false; + } + + public final boolean doesAccessVariable(final Variable var) { + ExpressionNode rcvr = getRcvr(); + if (rcvr instanceof LocalVariableNode r) { + return r.getLocal().equals(var); + } + + if (rcvr instanceof NonLocalVariableNode nl) { + return nl.getLocal().equals(var); + } + + return false; + } + + public final GenericMessageSendNode makeGenericSend() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + + SSymbol selector = isMinusAndValueNegated ? SymbolTable.symMinus : SymbolTable.symPlus; + GenericMessageSendNode send = MessageSendNode.createGeneric(selector, + new ExpressionNode[] {getRcvr(), + new IntegerLiteralNode(isMinusAndValueNegated ? -incValue : incValue)}, + sourceCoord); + + if (VmSettings.UseAstInterp) { + replace(send); + send.notifyDispatchInserted(); + return send; + } + + assert getParent() instanceof BytecodeLoopNode : "This node was expected to be a direct child of a `BytecodeLoopNode`."; + throw new RespecializeException(send); + } + + public FieldNode createIncFieldNode(final ExpressionNode self, final byte fieldIndex, + final long coord) { + return new UninitIncFieldWithValueNode(self, fieldIndex, coord, incValue); + } + + public final ExpressionNode createIncVarNode(final Local local, final int ctxLevel) { + if (ctxLevel == 0) { + return IncLocalVarWithValueNodeGen.create(local, incValue).initialize(sourceCoord); + } + return IncNonLocalVarWithValueNodeGen.create(ctxLevel, local, incValue) + .initialize(sourceCoord); + } +} diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncFieldWithExpNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncFieldWithExpNode.java new file mode 100644 index 000000000..ef24d6537 --- /dev/null +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncFieldWithExpNode.java @@ -0,0 +1,57 @@ +package trufflesom.interpreter.supernodes.inc; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.FieldNode; +import trufflesom.interpreter.objectstorage.FieldAccessorNode.IncrementLongFieldNode; +import trufflesom.vm.NotYetImplementedException; +import trufflesom.vmobjects.SObject; + + +public final class IncFieldWithExpNode extends FieldNode { + @Child private ExpressionNode self; + @Child private ExpressionNode valueExpr; + @Child private IncrementLongFieldNode inc; + + IncFieldWithExpNode(final ExpressionNode self, final ExpressionNode valueExpr, + final IncrementLongFieldNode inc, final long coord) { + initialize(coord); + this.self = self; + this.valueExpr = valueExpr; + this.inc = inc; + } + + @Override + public ExpressionNode getSelf() { + return self; + } + + @Override + public Object doPreEvaluated(final VirtualFrame frame, final Object[] arguments) { + CompilerDirectives.transferToInterpreter(); + throw new UnsupportedOperationException(); + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + return executeLong(frame); + } + + @Override + public long executeLong(final VirtualFrame frame) { + SObject obj = (SObject) self.executeGeneric(frame); + long incValue; + + try { + incValue = valueExpr.executeLong(frame); + } catch (UnexpectedResultException e) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw new NotYetImplementedException(); + } + + return inc.increment(obj, incValue); + } + +} diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncFieldWithValueNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncFieldWithValueNode.java new file mode 100644 index 000000000..761381b0b --- /dev/null +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncFieldWithValueNode.java @@ -0,0 +1,46 @@ +package trufflesom.interpreter.supernodes.inc; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.FieldNode; +import trufflesom.interpreter.objectstorage.FieldAccessorNode.IncrementLongFieldNode; +import trufflesom.vmobjects.SObject; + + +public class IncFieldWithValueNode extends FieldNode { + @Child private ExpressionNode self; + @Child private IncrementLongFieldNode inc; + + private final long incValue; + + IncFieldWithValueNode(final ExpressionNode self, final IncrementLongFieldNode inc, + final long coord, final long incValue) { + initialize(coord); + this.self = self; + this.inc = inc; + this.incValue = incValue; + } + + @Override + public ExpressionNode getSelf() { + return self; + } + + @Override + public Object doPreEvaluated(final VirtualFrame frame, final Object[] arguments) { + CompilerDirectives.transferToInterpreter(); + throw new UnsupportedOperationException(); + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + return executeLong(frame); + } + + @Override + public long executeLong(final VirtualFrame frame) { + SObject obj = (SObject) self.executeGeneric(frame); + return inc.increment(obj, incValue); + } +} diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncLocalVarWithExpNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncLocalVarWithExpNode.java new file mode 100644 index 000000000..118ab92d6 --- /dev/null +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncLocalVarWithExpNode.java @@ -0,0 +1,71 @@ +package trufflesom.interpreter.supernodes.inc; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.NodeChild; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.FrameSlotTypeException; +import com.oracle.truffle.api.frame.VirtualFrame; +import trufflesom.bdt.inlining.ScopeAdaptationVisitor; +import trufflesom.bdt.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.LocalVariableNode; + + +@NodeChild(value = "value", type = ExpressionNode.class) +public abstract class IncLocalVarWithExpNode extends LocalVariableNode { + public IncLocalVarWithExpNode(final Local variable) { + super(variable); + } + + public abstract ExpressionNode getValue(); + + @Specialization(guards = "frame.isLong(slotIndex)", + rewriteOn = {FrameSlotTypeException.class}) + public final long doLong(final VirtualFrame frame, final long value) + throws FrameSlotTypeException { + long current = frame.getLong(slotIndex); + long result = Math.addExact(current, value); + frame.setLong(slotIndex, result); + return result; + } + + @Specialization(guards = "frame.isDouble(slotIndex)", + rewriteOn = {FrameSlotTypeException.class}) + public final double doDouble(final VirtualFrame frame, final double value) + throws FrameSlotTypeException { + double current = frame.getDouble(slotIndex); + double result = current + value; + frame.setDouble(slotIndex, result); + return result; + } + + @Specialization(guards = "frame.isObject(slotIndex)", + rewriteOn = {FrameSlotTypeException.class}) + public final Object doString(final VirtualFrame frame, final String value) + throws FrameSlotTypeException { + String current = (String) frame.getObject(slotIndex); + String result = concat(current, value); + frame.setObject(slotIndex, result); + return result; + } + + @TruffleBoundary + private static String concat(final String a, final String b) { + return a.concat(b); + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + ScopeElement se = inliner.getAdaptedVar(local); + if (se.var != local || se.contextLevel < 0) { + IncLocalVarWithExpNode newNode = + IncLocalVarWithExpNodeGen.create((Local) se.var, getValue()); + newNode.initialize(sourceCoord); + replace(newNode); + } else { + assert 0 == se.contextLevel; + } + } + +} diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncLocalVarWithValueNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncLocalVarWithValueNode.java new file mode 100644 index 000000000..2d771db95 --- /dev/null +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncLocalVarWithValueNode.java @@ -0,0 +1,47 @@ +package trufflesom.interpreter.supernodes.inc; + +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.FrameSlotTypeException; +import com.oracle.truffle.api.frame.VirtualFrame; +import trufflesom.bdt.inlining.ScopeAdaptationVisitor; +import trufflesom.bdt.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.nodes.LocalVariableNode; + + +public abstract class IncLocalVarWithValueNode extends LocalVariableNode { + private final long incValue; + + public IncLocalVarWithValueNode(final Local variable, final long incValue) { + super(variable); + this.incValue = incValue; + } + + @Specialization(guards = "frame.isLong(slotIndex)", + rewriteOn = {FrameSlotTypeException.class}) + public final long doLong(final VirtualFrame frame) throws FrameSlotTypeException { + long current = frame.getLong(slotIndex); + long result = Math.addExact(current, incValue); + frame.setLong(slotIndex, result); + return result; + } + + @Specialization(guards = "frame.isDouble(slotIndex)", + rewriteOn = {FrameSlotTypeException.class}) + public final double doDouble(final VirtualFrame frame) throws FrameSlotTypeException { + double current = frame.getDouble(slotIndex); + double result = current + incValue; + frame.setDouble(slotIndex, result); + return result; + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + ScopeElement se = inliner.getAdaptedVar(local); + if (se.var != local || se.contextLevel < 0) { + replace(se.var.getIncNode(se.contextLevel, incValue, sourceCoord)); + } else { + assert 0 == se.contextLevel; + } + } +} diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncNonLocalVarWithExpNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncNonLocalVarWithExpNode.java new file mode 100644 index 000000000..9f9b1292d --- /dev/null +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncNonLocalVarWithExpNode.java @@ -0,0 +1,102 @@ +package trufflesom.interpreter.supernodes.inc; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.NodeChild; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.FrameSlotTypeException; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.frame.VirtualFrame; +import trufflesom.bdt.inlining.ScopeAdaptationVisitor; +import trufflesom.bdt.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.NonLocalVariableNode; +import trufflesom.primitives.arithmetic.AdditionPrim; +import trufflesom.primitives.arithmetic.AdditionPrimFactory; + + +@NodeChild(value = "value", type = ExpressionNode.class) +public abstract class IncNonLocalVarWithExpNode extends NonLocalVariableNode { + + protected IncNonLocalVarWithExpNode(final int contextLevel, final Local local) { + super(contextLevel, local); + } + + public abstract ExpressionNode getValue(); + + @Specialization(guards = "ctx.isLong(slotIndex)", rewriteOn = {FrameSlotTypeException.class}) + public final long doLong(final VirtualFrame frame, final long value, + @Bind("determineContext(frame)") final MaterializedFrame ctx) + throws FrameSlotTypeException { + long current = ctx.getLong(slotIndex); + long result = Math.addExact(current, value); + ctx.setLong(slotIndex, result); + return result; + } + + @Specialization(guards = "ctx.isDouble(slotIndex)", + rewriteOn = {FrameSlotTypeException.class}) + public final double doDouble(final VirtualFrame frame, final double value, + @Bind("determineContext(frame)") final MaterializedFrame ctx) + throws FrameSlotTypeException { + double current = ctx.getDouble(slotIndex); + double result = current + value; + ctx.setDouble(slotIndex, result); + return result; + } + + @Specialization(guards = "ctx.isObject(slotIndex)", + rewriteOn = {FrameSlotTypeException.class}) + public final Object doString(final VirtualFrame frame, final String value, + @Bind("determineContext(frame)") final MaterializedFrame ctx) + throws FrameSlotTypeException { + String current = (String) ctx.getObject(slotIndex); + String result = concat(current, value); + ctx.setObject(slotIndex, result); + return result; + } + + @TruffleBoundary + private static String concat(final String a, final String b) { + return a.concat(b); + } + + @Fallback + public final Object fallback(final VirtualFrame frame, final Object value) { + MaterializedFrame ctx = determineContext(frame); + CompilerDirectives.transferToInterpreterAndInvalidate(); + + AdditionPrim add = + AdditionPrimFactory.create(local.getReadNode(contextLevel, sourceCoord), getValue()); + add.initialize(sourceCoord); + + replace(local.getWriteNode(contextLevel, add, sourceCoord)).adoptChildren(); + + Object preIncValue = ctx.getValue(slotIndex); + Object result = add.executeEvaluated(null, preIncValue, value); + ctx.setObject(slotIndex, result); + return result; + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + ScopeElement se = inliner.getAdaptedVar(local); + if (se.var != local || se.contextLevel < contextLevel) { + ExpressionNode node; + if (se.contextLevel == 0) { + node = IncLocalVarWithExpNodeGen.create((Local) se.var, getValue()); + } else { + node = + IncNonLocalVarWithExpNodeGen.create(se.contextLevel, (Local) se.var, getValue()); + } + node.initialize(sourceCoord); + + replace(node); + } else { + assert contextLevel == se.contextLevel; + } + } +} diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncNonLocalVarWithValueNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncNonLocalVarWithValueNode.java new file mode 100644 index 000000000..54c7974c9 --- /dev/null +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/IncNonLocalVarWithValueNode.java @@ -0,0 +1,56 @@ +package trufflesom.interpreter.supernodes.inc; + +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.NodeChild; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.FrameSlotTypeException; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.frame.VirtualFrame; + +import trufflesom.bdt.inlining.ScopeAdaptationVisitor; +import trufflesom.bdt.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.NonLocalVariableNode; + + +public abstract class IncNonLocalVarWithValueNode extends NonLocalVariableNode { + protected final long incValue; + + public IncNonLocalVarWithValueNode(final int contextLevel, final Local local, + final long incValue) { + super(contextLevel, local); + this.incValue = incValue; + } + + @Specialization(guards = "ctx.isLong(slotIndex)", rewriteOn = {FrameSlotTypeException.class}) + public final long doLong(final VirtualFrame frame, + @Bind("determineContext(frame)") final MaterializedFrame ctx) + throws FrameSlotTypeException { + long current = ctx.getLong(slotIndex); + long result = Math.addExact(current, incValue); + ctx.setLong(slotIndex, result); + return result; + } + + @Specialization(guards = "ctx.isDouble(slotIndex)", + rewriteOn = {FrameSlotTypeException.class}) + public final double doDouble(final VirtualFrame frame, + @Bind("determineContext(frame)") final MaterializedFrame ctx) + throws FrameSlotTypeException { + double current = ctx.getDouble(slotIndex); + double result = current + incValue; + ctx.setDouble(slotIndex, result); + return result; + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + ScopeElement se = inliner.getAdaptedVar(local); + if (se.var != local || se.contextLevel < contextLevel) { + replace(se.var.getIncNode(se.contextLevel, incValue, sourceCoord)); + } else { + assert contextLevel == se.contextLevel; + } + } +} diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/UninitIncFieldWithExpNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/UninitIncFieldWithExpNode.java new file mode 100644 index 000000000..c5ddda5db --- /dev/null +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/UninitIncFieldWithExpNode.java @@ -0,0 +1,95 @@ +package trufflesom.interpreter.supernodes.inc; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.FieldNode; +import trufflesom.interpreter.nodes.FieldNodeFactory.FieldWriteNodeGen; +import trufflesom.interpreter.objectstorage.FieldAccessorNode; +import trufflesom.interpreter.objectstorage.FieldAccessorNode.IncrementLongFieldNode; +import trufflesom.primitives.arithmetic.AdditionPrim; +import trufflesom.primitives.arithmetic.AdditionPrimFactory; +import trufflesom.vm.NotYetImplementedException; +import trufflesom.vmobjects.SObject; + + +public final class UninitIncFieldWithExpNode extends FieldNode { + + @Child private ExpressionNode self; + @Child private ExpressionNode valueExpr; + + private final int fieldIndex; + private final boolean valueExprIsArg; + + public UninitIncFieldWithExpNode(final ExpressionNode self, final ExpressionNode valueExpr, + final boolean valueExprIsArg, final int fieldIndex, final long coord) { + this.self = self; + this.valueExpr = valueExpr; + this.valueExprIsArg = valueExprIsArg; + this.fieldIndex = fieldIndex; + this.sourceCoord = coord; + } + + @Override + public ExpressionNode getSelf() { + return self; + } + + @Override + public Object doPreEvaluated(final VirtualFrame frame, final Object[] arguments) { + CompilerDirectives.transferToInterpreter(); + throw new UnsupportedOperationException(); + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + SObject obj = (SObject) self.executeGeneric(frame); + + long incValue; + try { + incValue = valueExpr.executeLong(frame); + } catch (UnexpectedResultException e1) { + AdditionPrim add; + if (valueExprIsArg) { + add = AdditionPrimFactory.create( + new FieldReadNode((ExpressionNode) self.copy(), fieldIndex), + valueExpr); + } else { + add = AdditionPrimFactory.create( + valueExpr, + new FieldReadNode((ExpressionNode) self.copy(), fieldIndex)); + } + add.initialize(sourceCoord); + + replace(FieldWriteNodeGen.create(fieldIndex, self, add) + .initialize(sourceCoord)).adoptChildren(); + + Object preIncValue = obj.getField(fieldIndex); + Object result = add.executeEvaluated(frame, preIncValue, e1.getResult()); + obj.setField(fieldIndex, result); + return result; + } + + Object val = obj.getField(fieldIndex); + if (!(val instanceof Long)) { + throw new NotYetImplementedException(); + } + + long longVal = 0; + try { + longVal = Math.addExact((Long) val, incValue); + obj.setField(fieldIndex, longVal); + } catch (ArithmeticException e) { + throw new NotYetImplementedException(); + } + + IncrementLongFieldNode node = FieldAccessorNode.createIncrement(fieldIndex, obj); + IncFieldWithExpNode incNode = new IncFieldWithExpNode(self, valueExpr, node, sourceCoord); + replace(incNode); + node.notifyAsInserted(); + + return longVal; + } +} diff --git a/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/UninitIncFieldWithValueNode.java b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/UninitIncFieldWithValueNode.java new file mode 100644 index 000000000..860d23596 --- /dev/null +++ b/src/trufflesom/src/trufflesom/interpreter/supernodes/inc/UninitIncFieldWithValueNode.java @@ -0,0 +1,67 @@ +package trufflesom.interpreter.supernodes.inc; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.FieldNode; +import trufflesom.interpreter.objectstorage.FieldAccessorNode; +import trufflesom.interpreter.objectstorage.FieldAccessorNode.IncrementLongFieldNode; +import trufflesom.vm.NotYetImplementedException; +import trufflesom.vmobjects.SObject; + + +public class UninitIncFieldWithValueNode extends FieldNode { + @Child private ExpressionNode self; + private final int fieldIndex; + private final long incValue; + + public UninitIncFieldWithValueNode(final ExpressionNode self, final int fieldIndex, + final long coord, long incValue) { + this.self = self; + this.fieldIndex = fieldIndex; + this.sourceCoord = coord; + this.incValue = incValue; + } + + public int getFieldIndex() { + return fieldIndex; + } + + @Override + public ExpressionNode getSelf() { + return self; + } + + @Override + public Object doPreEvaluated(final VirtualFrame frame, final Object[] arguments) { + CompilerDirectives.transferToInterpreter(); + throw new UnsupportedOperationException(); + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + SObject obj = (SObject) self.executeGeneric(frame); + + Object val = obj.getField(fieldIndex); + if (!(val instanceof Long)) { + throw new NotYetImplementedException(); + } + + long longVal = 0; + try { + longVal = Math.addExact((Long) val, incValue); + obj.setField(fieldIndex, longVal); + } catch (ArithmeticException e) { + throw new NotYetImplementedException(); + } + + IncrementLongFieldNode node = FieldAccessorNode.createIncrement(fieldIndex, obj); + IncFieldWithValueNode incNode = + new IncFieldWithValueNode(self, node, sourceCoord, incValue); + replace(incNode); + node.notifyAsInserted(); + + return longVal; + } +} diff --git a/tests/trufflesom/supernodes/IncrementOpTests.java b/tests/trufflesom/supernodes/IncrementOpTests.java new file mode 100644 index 000000000..490e5aff8 --- /dev/null +++ b/tests/trufflesom/supernodes/IncrementOpTests.java @@ -0,0 +1,170 @@ +package trufflesom.supernodes; + +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.Test; + +import trufflesom.interpreter.nodes.ArgumentReadNode.LocalArgumentReadNode; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.SequenceNode; +import trufflesom.interpreter.nodes.literals.BlockNode; +import trufflesom.interpreter.nodes.specialized.IfInlinedLiteralNode; +import trufflesom.interpreter.supernodes.inc.IncExpWithValueNode; +import trufflesom.interpreter.supernodes.inc.IncLocalVarWithExpNode; +import trufflesom.interpreter.supernodes.inc.IncLocalVarWithValueNode; +import trufflesom.interpreter.supernodes.inc.IncNonLocalVarWithExpNode; +import trufflesom.interpreter.supernodes.inc.IncNonLocalVarWithValueNode; +import trufflesom.interpreter.supernodes.inc.UninitIncFieldWithExpNode; +import trufflesom.interpreter.supernodes.inc.UninitIncFieldWithValueNode; +import trufflesom.tests.AstTestSetup; + + +public class IncrementOpTests extends AstTestSetup { + + private void basicAddOrSubtract(final String test, final long literalValue, + final Class nodeType) { + addField("field"); + SequenceNode seq = (SequenceNode) parseMethod( + "test: arg = ( | var | \n" + test + " )"); + + ExpressionNode testExpr = read(seq, "expressions", 0); + assertThat(testExpr, instanceOf(nodeType)); + long value = read(testExpr, "incValue", Long.class); + assertEquals(literalValue, value); + } + + @Test + public void testBasicAddOrSubtract() { + // int const + int const + basicAddOrSubtract("1 + 1", 1, IncExpWithValueNode.class); + basicAddOrSubtract("1 + 2", 2, IncExpWithValueNode.class); + basicAddOrSubtract("1 + 150", 150, IncExpWithValueNode.class); + + // int const - int const + basicAddOrSubtract("1 - 1", -1, IncExpWithValueNode.class); + basicAddOrSubtract("1 - 2", -2, IncExpWithValueNode.class); + basicAddOrSubtract("1 - 150", -150, IncExpWithValueNode.class); + + // int expr + int const + basicAddOrSubtract("(3 / 4) + 1", 1, IncExpWithValueNode.class); + basicAddOrSubtract("(3 / 5) + 2", 2, IncExpWithValueNode.class); + basicAddOrSubtract("(4 / 4) + 150", 150, IncExpWithValueNode.class); + + // int expr - int const + basicAddOrSubtract("(3 / 4) - 1", -1, IncExpWithValueNode.class); + basicAddOrSubtract("(3 / 5) - 2", -2, IncExpWithValueNode.class); + basicAddOrSubtract("(4 / 4) - 150", -150, IncExpWithValueNode.class); + + basicAddOrSubtract("arg + 123", 123, IncExpWithValueNode.class); + basicAddOrSubtract("var + 245", 245, IncExpWithValueNode.class); + basicAddOrSubtract("field + 645", 645, IncExpWithValueNode.class); + + basicAddOrSubtract("arg - 123", -123, IncExpWithValueNode.class); + basicAddOrSubtract("var - 245", -245, IncExpWithValueNode.class); + basicAddOrSubtract("field - 645", -645, IncExpWithValueNode.class); + } + + @Test + public void testIfTrueAndIncArg() { + SequenceNode seq = (SequenceNode) parseMethod( + "test: arg = (\n" + + "#start.\n" + + "(self key: 5) ifTrue: [ arg + 1 ]. #end )"); + + IfInlinedLiteralNode ifNode = (IfInlinedLiteralNode) read(seq, "expressions", 1); + + IncExpWithValueNode inc = read(ifNode, "bodyNode", IncExpWithValueNode.class); + LocalArgumentReadNode arg = (LocalArgumentReadNode) inc.getRcvr(); + assertEquals(1, arg.argumentIndex); + assertEquals("arg", arg.getInvocationIdentifier()); + } + + @Test + public void testFieldInc() { + basicAddOrSubtract("field := field + 1", 1, UninitIncFieldWithValueNode.class); + basicAddOrSubtract("field := field - 1", -1, UninitIncFieldWithValueNode.class); + basicAddOrSubtract("field := field + 1123", 1123, UninitIncFieldWithValueNode.class); + basicAddOrSubtract("field := field - 234234", -234234, UninitIncFieldWithValueNode.class); + } + + private void incWithExpr(final String test, final Class nodeType) { + addField("field"); + SequenceNode seq = (SequenceNode) parseMethod( + "test: arg = ( | var | \n" + test + " )"); + + ExpressionNode testExpr = read(seq, "expressions", 0); + assertThat(testExpr, instanceOf(nodeType)); + } + + @Test + public void testFieldIncWithExpression() { + incWithExpr("field := field + (23 + 434)", UninitIncFieldWithExpNode.class); + incWithExpr("field := field + var", UninitIncFieldWithExpNode.class); + incWithExpr("field := field + arg", UninitIncFieldWithExpNode.class); + } + + @Test + public void testLocalIncWithExpression() { + incWithExpr("var := var + (23 + 434)", IncLocalVarWithExpNode.class); + incWithExpr("var := var + var", IncLocalVarWithExpNode.class); + incWithExpr("var := var + arg", IncLocalVarWithExpNode.class); + + incWithExpr("var := (23 + 434) + var", IncLocalVarWithExpNode.class); + incWithExpr("var := var + var", IncLocalVarWithExpNode.class); + incWithExpr("var := arg + var", IncLocalVarWithExpNode.class); + } + + @Test + public void testLocalInc() { + basicAddOrSubtract("var := var + 1", 1, IncLocalVarWithValueNode.class); + basicAddOrSubtract("var := var - 1", -1, IncLocalVarWithValueNode.class); + basicAddOrSubtract("var := var + 1123", 1123, IncLocalVarWithValueNode.class); + basicAddOrSubtract("var := var - 234234", -234234, IncLocalVarWithValueNode.class); + } + + private void inBlock(final String test, final long literalValue, + final Class nodeType) { + addField("field"); + SequenceNode seq = (SequenceNode) parseMethod( + "test: arg = ( | var | \n" + test + " )"); + + BlockNode block = (BlockNode) read(seq, "expressions", 0); + ExpressionNode testExpr = + read(block.getMethod().getInvokable(), "body", ExpressionNode.class); + assertThat(testExpr, instanceOf(nodeType)); + long value = read(testExpr, "incValue", Long.class); + assertEquals(literalValue, value); + } + + @Test + public void testNonLocalInc() { + inBlock("[ var := var + 1 ]", 1, IncNonLocalVarWithValueNode.class); + inBlock("[ var := var - 1 ]", -1, IncNonLocalVarWithValueNode.class); + inBlock("[ var := var + 1123 ]", 1123, IncNonLocalVarWithValueNode.class); + inBlock("[ var := var - 234234 ]", -234234, IncNonLocalVarWithValueNode.class); + } + + private void incWithExprInBlock(final String test, final Class nodeType) { + addField("field"); + SequenceNode seq = (SequenceNode) parseMethod( + "test: arg = ( | var | \n" + test + " )"); + + BlockNode block = (BlockNode) read(seq, "expressions", 0); + ExpressionNode testExpr = + read(block.getMethod().getInvokable(), "body", ExpressionNode.class); + assertThat(testExpr, instanceOf(nodeType)); + } + + @Test + public void testNonLocalIncWithExpression() { + incWithExprInBlock("[ var := var + (23 + 434) ]", IncNonLocalVarWithExpNode.class); + incWithExprInBlock("[ var := var + var ]", IncNonLocalVarWithExpNode.class); + incWithExprInBlock("[ var := var + arg ]", IncNonLocalVarWithExpNode.class); + + incWithExprInBlock("[ var := (23 + 434) + var ]", IncNonLocalVarWithExpNode.class); + incWithExprInBlock("[ var := var + var ]", IncNonLocalVarWithExpNode.class); + incWithExprInBlock("[ var := arg + var ]", IncNonLocalVarWithExpNode.class); + } +} diff --git a/tests/trufflesom/tests/AstInliningTests.java b/tests/trufflesom/tests/AstInliningTests.java index b7c0bc04b..b7c20a229 100644 --- a/tests/trufflesom/tests/AstInliningTests.java +++ b/tests/trufflesom/tests/AstInliningTests.java @@ -13,7 +13,6 @@ import trufflesom.interpreter.nodes.ArgumentReadNode.NonLocalArgumentReadNode; import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.FieldNode.FieldReadNode; -import trufflesom.interpreter.nodes.FieldNode.UninitFieldIncNode; import trufflesom.interpreter.nodes.GlobalNode.FalseGlobalNode; import trufflesom.interpreter.nodes.GlobalNode.NilGlobalNode; import trufflesom.interpreter.nodes.GlobalNode.TrueGlobalNode; @@ -35,7 +34,9 @@ import trufflesom.interpreter.nodes.specialized.IfTrueIfFalseInlinedLiteralsNode.TrueIfElseLiteralNode; import trufflesom.interpreter.nodes.specialized.IntToDoInlinedLiteralsNode; import trufflesom.interpreter.nodes.specialized.whileloops.WhileInlinedLiteralsNode; -import trufflesom.interpreter.supernodes.IntIncrementNode; +import trufflesom.interpreter.supernodes.inc.IncExpWithValueNode; +import trufflesom.interpreter.supernodes.inc.IncNonLocalVarWithValueNode; +import trufflesom.interpreter.supernodes.inc.UninitIncFieldWithValueNode; import trufflesom.primitives.arithmetic.SubtractionPrim; import trufflesom.primitives.arrays.DoPrim; @@ -144,7 +145,8 @@ public void testIfTrueAndIncField() { + "(self key: 5) ifTrue: [ field := field + 1 ]. #end )"); IfInlinedLiteralNode ifNode = (IfInlinedLiteralNode) read(seq, "expressions", 1); - UninitFieldIncNode incNode = read(ifNode, "bodyNode", UninitFieldIncNode.class); + UninitIncFieldWithValueNode incNode = + read(ifNode, "bodyNode", UninitIncFieldWithValueNode.class); int fieldIdx = read(incNode, "fieldIndex", Integer.class); assertEquals(0, fieldIdx); @@ -162,7 +164,7 @@ public void testIfTrueAndIncArg() { IfInlinedLiteralNode ifNode = (IfInlinedLiteralNode) read(seq, "expressions", 1); - IntIncrementNode inc = read(ifNode, "bodyNode", IntIncrementNode.class); + IncExpWithValueNode inc = read(ifNode, "bodyNode", IncExpWithValueNode.class); LocalArgumentReadNode arg = (LocalArgumentReadNode) inc.getRcvr(); assertEquals(1, arg.argumentIndex); assertEquals("arg", arg.getInvocationIdentifier()); @@ -359,7 +361,8 @@ public void testBlockBlockInlinedSelf() { assertEquals("b", readB.getInvocationIdentifier()); assertEquals(1, readB.argumentIndex); - UninitFieldIncNode incNode = read(blockBIfTrue, "bodyNode", UninitFieldIncNode.class); + UninitIncFieldWithValueNode incNode = + read(blockBIfTrue, "bodyNode", UninitIncFieldWithValueNode.class); NonLocalArgumentReadNode selfNode = (NonLocalArgumentReadNode) incNode.getSelf(); assertEquals(2, selfNode.getContextLevel()); assertEquals(0, (int) read(incNode, "fieldIndex", Integer.class)); @@ -389,14 +392,10 @@ public void testToDoBlockBlockInlinedSelf() { assertEquals("b", readNode.getInvocationIdentifier()); assertEquals(1, readNode.argumentIndex); - NonLocalVariableWriteNode writeNode = - read(blockBIfTrue, "bodyNode", NonLocalVariableWriteNode.class); - assertEquals(1, writeNode.getContextLevel()); - assertEquals("l2", writeNode.getInvocationIdentifier()); - - IntIncrementNode incNode = (IntIncrementNode) writeNode.getExp(); - NonLocalVariableReadNode readL2 = (NonLocalVariableReadNode) incNode.getRcvr(); - assertEquals("l2", readL2.getInvocationIdentifier()); + IncNonLocalVarWithValueNode incNode = + read(blockBIfTrue, "bodyNode", IncNonLocalVarWithValueNode.class); + assertEquals(1, incNode.getContextLevel()); + assertEquals("l2", incNode.getInvocationIdentifier()); } @Test