From f7fbb14b4449b5445546d5e710baa2f8de9bf44e Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 21 Nov 2021 14:09:07 +0000 Subject: [PATCH 01/38] Add specialized n-ary send nodes that send to an argument The most common version of this is sending to self. Signed-off-by: Stefan Marr --- .../interpreter/nodes/MessageSendNode.java | 67 +++++++++++++++-- .../nodes/UninitializedMessageSendNode.java | 24 +++++-- .../nodes/bc/BytecodeLoopNode.java | 5 +- .../nodes/nary/BinaryExpressionNode.java | 16 ++--- .../nodes/nary/QuaternaryExpressionNode.java | 16 ++--- .../nodes/nary/TernaryExpressionNode.java | 16 ++--- .../nodes/nary/UnaryExpressionNode.java | 15 ++-- .../supernodes/BinaryArgSendNode.java | 63 ++++++++++++++++ .../supernodes/QuatArgSendNode.java | 71 +++++++++++++++++++ .../supernodes/TernaryArgSendNode.java | 68 ++++++++++++++++++ .../supernodes/UnaryArgSendNode.java | 58 +++++++++++++++ 11 files changed, 363 insertions(+), 56 deletions(-) create mode 100644 src/trufflesom/interpreter/supernodes/BinaryArgSendNode.java create mode 100644 src/trufflesom/interpreter/supernodes/QuatArgSendNode.java create mode 100644 src/trufflesom/interpreter/supernodes/TernaryArgSendNode.java create mode 100644 src/trufflesom/interpreter/supernodes/UnaryArgSendNode.java diff --git a/src/trufflesom/interpreter/nodes/MessageSendNode.java b/src/trufflesom/interpreter/nodes/MessageSendNode.java index 2834767f1..522d1e4af 100644 --- a/src/trufflesom/interpreter/nodes/MessageSendNode.java +++ b/src/trufflesom/interpreter/nodes/MessageSendNode.java @@ -1,5 +1,6 @@ package trufflesom.interpreter.nodes; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; @@ -7,6 +8,10 @@ import bdt.primitives.Specializer; import bdt.primitives.nodes.PreevaluatedExpression; import trufflesom.interpreter.nodes.dispatch.UninitializedDispatchNode; +import trufflesom.interpreter.supernodes.BinaryArgSendNode; +import trufflesom.interpreter.supernodes.QuatArgSendNode; +import trufflesom.interpreter.supernodes.TernaryArgSendNode; +import trufflesom.interpreter.supernodes.UnaryArgSendNode; import trufflesom.primitives.Primitives; import trufflesom.vm.NotYetImplementedException; import trufflesom.vmobjects.SClass; @@ -34,10 +39,64 @@ public static AbstractMessageSendNode createForPerformNodes(final SSymbol select return new UninitializedMessageSendNode(selector, NO_ARGS).initialize(coord); } - public static GenericMessageSendNode createGeneric(final SSymbol selector, + public static AbstractMessageSendNode createGenericUnary(final SSymbol selector, + final ExpressionNode rcvrNode, final long coord) { + UninitializedDispatchNode dispatch = new UninitializedDispatchNode(selector); + if (rcvrNode != null && rcvrNode instanceof LocalArgumentReadNode) { + int argIdx = ((LocalArgumentReadNode) rcvrNode).argumentIndex; + return new UnaryArgSendNode(argIdx, selector, dispatch).initialize(coord); + } + + return new GenericMessageSendNode( + selector, new ExpressionNode[] {rcvrNode}, dispatch).initialize(coord); + } + + public static AbstractMessageSendNode createGenericBinary(final SSymbol selector, + final ExpressionNode rcvrNode, final ExpressionNode arg1, final long coord) { + UninitializedDispatchNode dispatch = new UninitializedDispatchNode(selector); + if (rcvrNode != null && rcvrNode instanceof LocalArgumentReadNode) { + int argIdx = ((LocalArgumentReadNode) rcvrNode).argumentIndex; + return new BinaryArgSendNode(argIdx, arg1, selector, dispatch).initialize(coord); + } + + return new GenericMessageSendNode( + selector, new ExpressionNode[] {rcvrNode, arg1}, dispatch).initialize(coord); + } + + public static AbstractMessageSendNode createGenericTernary(final SSymbol selector, + final ExpressionNode rcvrNode, final ExpressionNode arg1, final ExpressionNode arg2, + final long coord) { + UninitializedDispatchNode dispatch = new UninitializedDispatchNode(selector); + if (rcvrNode != null && rcvrNode instanceof LocalArgumentReadNode) { + int argIdx = ((LocalArgumentReadNode) rcvrNode).argumentIndex; + return new TernaryArgSendNode(argIdx, arg1, arg2, selector, dispatch).initialize(coord); + } + + return new GenericMessageSendNode( + selector, new ExpressionNode[] {rcvrNode, arg1, arg2}, dispatch).initialize(coord); + } + + public static AbstractMessageSendNode createGenericQuat(final SSymbol selector, + final ExpressionNode rcvrNode, final ExpressionNode arg1, final ExpressionNode arg2, + final ExpressionNode arg3, final long coord) { + UninitializedDispatchNode dispatch = new UninitializedDispatchNode(selector); + if (rcvrNode != null && rcvrNode instanceof LocalArgumentReadNode) { + int argIdx = ((LocalArgumentReadNode) rcvrNode).argumentIndex; + return new QuatArgSendNode(argIdx, arg1, arg2, arg3, selector, dispatch).initialize( + coord); + } + + return new GenericMessageSendNode( + selector, new ExpressionNode[] {rcvrNode, arg1, arg2, arg3}, dispatch).initialize( + coord); + } + + public static AbstractMessageSendNode createGenericNary(final SSymbol selector, final ExpressionNode[] argumentNodes, final long coord) { - return new GenericMessageSendNode(selector, argumentNodes, - new UninitializedDispatchNode(selector)).initialize(coord); + assert argumentNodes == null || argumentNodes.length > 4; + UninitializedDispatchNode dispatch = new UninitializedDispatchNode(selector); + return new GenericMessageSendNode( + selector, argumentNodes, dispatch).initialize(coord); } public static AbstractMessageSendNode createSuperSend(final SClass superClass, @@ -49,7 +108,7 @@ public static AbstractMessageSendNode createSuperSend(final SClass superClass, "Currently #dnu with super sent is not yet implemented. "); } - PreevaluatedExpression node = method.copyTrivialNode(); + PreevaluatedExpression node = method.copyTrivialNode(); if (node != null) { return new SuperExprNode(selector, arguments, node).initialize(coord); } diff --git a/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java b/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java index 18c44a27f..2ca25f67e 100644 --- a/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java +++ b/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java @@ -55,12 +55,26 @@ private PreevaluatedExpression specialize(final Object[] arguments) { return makeGenericSend(); } - private GenericMessageSendNode makeGenericSend() { - AbstractDispatchNode dispatch = new UninitializedDispatchNode(selector); - GenericMessageSendNode send = new GenericMessageSendNode(selector, argumentNodes, - dispatch).initialize(sourceCoord); + private AbstractMessageSendNode makeGenericSend() { + int numArgs = argumentNodes.length; + AbstractMessageSendNode send; + if (numArgs == 1) { + send = MessageSendNode.createGenericUnary(selector, argumentNodes[0], sourceCoord); + } else if (numArgs == 2) { + send = MessageSendNode.createGenericBinary(selector, argumentNodes[0], argumentNodes[1], + sourceCoord); + } else if (numArgs == 3) { + send = MessageSendNode.createGenericTernary(selector, argumentNodes[0], argumentNodes[1], + argumentNodes[2], sourceCoord); + } else if (numArgs == 4) { + send = MessageSendNode.createGenericQuat(selector, argumentNodes[0], argumentNodes[1], + argumentNodes[2], argumentNodes[3], sourceCoord); + } else { + send = new GenericMessageSendNode(selector, argumentNodes, + new UninitializedDispatchNode(selector)).initialize(sourceCoord); + } replace(send); - dispatch.notifyAsInserted(); + send.notifyDispatchInserted(); return send; } diff --git a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java index fcbb475d4..2b3352bed 100644 --- a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java +++ b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java @@ -117,7 +117,6 @@ import trufflesom.interpreter.bc.RestartLoopException; import trufflesom.interpreter.nodes.AbstractMessageSendNode; import trufflesom.interpreter.nodes.ExpressionNode; -import trufflesom.interpreter.nodes.GenericMessageSendNode; import trufflesom.interpreter.nodes.GlobalNode; import trufflesom.interpreter.nodes.MessageSendNode; import trufflesom.interpreter.nodes.NoPreEvalExprNode; @@ -1180,8 +1179,8 @@ public Object specializeSendBytecode(final VirtualFrame frame, final int bytecod } if (!done) { - GenericMessageSendNode quick = - MessageSendNode.createGeneric(signature, null, sourceCoord); + AbstractMessageSendNode quick = + MessageSendNode.createGenericNary(signature, null, sourceCoord); quickenBytecode(bytecodeIndex, Q_SEND, quick); result = quick.doPreEvaluated(frame, callArgs); diff --git a/src/trufflesom/interpreter/nodes/nary/BinaryExpressionNode.java b/src/trufflesom/interpreter/nodes/nary/BinaryExpressionNode.java index 0214cfe18..435a15172 100644 --- a/src/trufflesom/interpreter/nodes/nary/BinaryExpressionNode.java +++ b/src/trufflesom/interpreter/nodes/nary/BinaryExpressionNode.java @@ -6,8 +6,8 @@ import bdt.primitives.nodes.PreevaluatedExpression; import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.AbstractMessageSendNode; import trufflesom.interpreter.nodes.ExpressionNode; -import trufflesom.interpreter.nodes.GenericMessageSendNode; import trufflesom.interpreter.nodes.MessageSendNode; import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; import trufflesom.vm.VmSettings; @@ -32,17 +32,11 @@ public final Object doPreEvaluated(final VirtualFrame frame, return executeEvaluated(frame, arguments[0], arguments[1]); } - protected GenericMessageSendNode makeGenericSend(final SSymbol selector) { + protected AbstractMessageSendNode makeGenericSend(final SSymbol selector) { CompilerDirectives.transferToInterpreterAndInvalidate(); - ExpressionNode[] children; - if (VmSettings.UseAstInterp) { - children = new ExpressionNode[] {getReceiver(), getArgument()}; - } else { - children = null; - } - - GenericMessageSendNode send = - MessageSendNode.createGeneric(selector, children, sourceCoord); + AbstractMessageSendNode send = + MessageSendNode.createGenericBinary(selector, getReceiver(), getArgument(), + sourceCoord); if (VmSettings.UseAstInterp) { replace(send); diff --git a/src/trufflesom/interpreter/nodes/nary/QuaternaryExpressionNode.java b/src/trufflesom/interpreter/nodes/nary/QuaternaryExpressionNode.java index 13b5d3b1a..9e266b780 100644 --- a/src/trufflesom/interpreter/nodes/nary/QuaternaryExpressionNode.java +++ b/src/trufflesom/interpreter/nodes/nary/QuaternaryExpressionNode.java @@ -6,8 +6,8 @@ import com.oracle.truffle.api.frame.VirtualFrame; import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.AbstractMessageSendNode; import trufflesom.interpreter.nodes.ExpressionNode; -import trufflesom.interpreter.nodes.GenericMessageSendNode; import trufflesom.interpreter.nodes.MessageSendNode; import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; import trufflesom.vm.VmSettings; @@ -38,17 +38,11 @@ public final Object doPreEvaluated(final VirtualFrame frame, return executeEvaluated(frame, arguments[0], arguments[1], arguments[2], arguments[3]); } - protected GenericMessageSendNode makeGenericSend(final SSymbol selector) { + protected AbstractMessageSendNode makeGenericSend(final SSymbol selector) { CompilerDirectives.transferToInterpreterAndInvalidate(); - ExpressionNode[] children; - if (VmSettings.UseAstInterp) { - children = new ExpressionNode[] {getReceiver(), getArg1(), getArg2(), getArg3()}; - } else { - children = null; - } - - GenericMessageSendNode send = - MessageSendNode.createGeneric(selector, children, sourceCoord); + AbstractMessageSendNode send = + MessageSendNode.createGenericQuat(selector, getReceiver(), getArg1(), getArg2(), + getArg3(), sourceCoord); if (VmSettings.UseAstInterp) { replace(send); diff --git a/src/trufflesom/interpreter/nodes/nary/TernaryExpressionNode.java b/src/trufflesom/interpreter/nodes/nary/TernaryExpressionNode.java index 87ee5ce5e..f18a5237b 100644 --- a/src/trufflesom/interpreter/nodes/nary/TernaryExpressionNode.java +++ b/src/trufflesom/interpreter/nodes/nary/TernaryExpressionNode.java @@ -5,8 +5,8 @@ import com.oracle.truffle.api.frame.VirtualFrame; import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.AbstractMessageSendNode; import trufflesom.interpreter.nodes.ExpressionNode; -import trufflesom.interpreter.nodes.GenericMessageSendNode; import trufflesom.interpreter.nodes.MessageSendNode; import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; import trufflesom.vm.VmSettings; @@ -33,17 +33,11 @@ public final Object doPreEvaluated(final VirtualFrame frame, return executeEvaluated(frame, arguments[0], arguments[1], arguments[2]); } - protected GenericMessageSendNode makeGenericSend(final SSymbol selector) { + protected AbstractMessageSendNode makeGenericSend(final SSymbol selector) { CompilerDirectives.transferToInterpreterAndInvalidate(); - ExpressionNode[] children; - if (VmSettings.UseAstInterp) { - children = new ExpressionNode[] {getReceiver(), getArg1(), getArg2()}; - } else { - children = null; - } - - GenericMessageSendNode send = - MessageSendNode.createGeneric(selector, children, sourceCoord); + AbstractMessageSendNode send = + MessageSendNode.createGenericTernary(selector, getReceiver(), getArg1(), getArg2(), + sourceCoord); if (VmSettings.UseAstInterp) { replace(send); diff --git a/src/trufflesom/interpreter/nodes/nary/UnaryExpressionNode.java b/src/trufflesom/interpreter/nodes/nary/UnaryExpressionNode.java index 922f425ed..1ae4abd28 100644 --- a/src/trufflesom/interpreter/nodes/nary/UnaryExpressionNode.java +++ b/src/trufflesom/interpreter/nodes/nary/UnaryExpressionNode.java @@ -5,8 +5,8 @@ import com.oracle.truffle.api.frame.VirtualFrame; import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.AbstractMessageSendNode; import trufflesom.interpreter.nodes.ExpressionNode; -import trufflesom.interpreter.nodes.GenericMessageSendNode; import trufflesom.interpreter.nodes.MessageSendNode; import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; import trufflesom.vm.VmSettings; @@ -26,17 +26,10 @@ public final Object doPreEvaluated(final VirtualFrame frame, return executeEvaluated(frame, arguments[0]); } - protected GenericMessageSendNode makeGenericSend(final SSymbol selector) { + protected AbstractMessageSendNode makeGenericSend(final SSymbol selector) { CompilerDirectives.transferToInterpreterAndInvalidate(); - ExpressionNode[] children; - if (VmSettings.UseAstInterp) { - children = new ExpressionNode[] {getReceiver()}; - } else { - children = null; - } - - GenericMessageSendNode send = - MessageSendNode.createGeneric(selector, children, sourceCoord); + AbstractMessageSendNode send = + MessageSendNode.createGenericUnary(selector, getReceiver(), sourceCoord); if (VmSettings.UseAstInterp) { replace(send); diff --git a/src/trufflesom/interpreter/supernodes/BinaryArgSendNode.java b/src/trufflesom/interpreter/supernodes/BinaryArgSendNode.java new file mode 100644 index 000000000..56d48cf0c --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/BinaryArgSendNode.java @@ -0,0 +1,63 @@ +package trufflesom.interpreter.supernodes; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.frame.VirtualFrame; + +import trufflesom.interpreter.nodes.AbstractMessageSendNode; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode; +import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; +import trufflesom.vmobjects.SSymbol; + + +public class BinaryArgSendNode extends AbstractMessageSendNode { + private final int argIdx; + private final SSymbol selector; + @Child private AbstractDispatchNode dispatchNode; + @Child private ExpressionNode arg1; + + public BinaryArgSendNode(final int argIdx, final ExpressionNode arg1, final SSymbol selector, + final AbstractDispatchNode dispatchNode) { + super(null); + this.argIdx = argIdx; + this.selector = selector; + this.dispatchNode = dispatchNode; + this.arg1 = arg1; + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + Object[] arguments = new Object[] { + frame.getArguments()[argIdx], + arg1.executeGeneric(frame)}; + return doPreEvaluated(frame, arguments); + } + + @Override + public Object doPreEvaluated(final VirtualFrame frame, + final Object[] arguments) { + return dispatchNode.executeDispatch(frame, arguments); + } + + @Override + public SSymbol getInvocationIdentifier() { + return selector; + } + + @Override + public int getNumberOfArguments() { + return 2; + } + + @Override + public void replaceDispatchListHead( + final GenericDispatchNode replacement) { + CompilerAsserts.neverPartOfCompilation(); + dispatchNode.replace(replacement); + } + + @Override + public void notifyDispatchInserted() { + dispatchNode.notifyAsInserted(); + } +} diff --git a/src/trufflesom/interpreter/supernodes/QuatArgSendNode.java b/src/trufflesom/interpreter/supernodes/QuatArgSendNode.java new file mode 100644 index 000000000..994b603f8 --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/QuatArgSendNode.java @@ -0,0 +1,71 @@ +package trufflesom.interpreter.supernodes; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.frame.VirtualFrame; + +import trufflesom.interpreter.nodes.AbstractMessageSendNode; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode; +import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; +import trufflesom.vmobjects.SSymbol; + + +public class QuatArgSendNode extends AbstractMessageSendNode { + private final int argIdx; + private final SSymbol selector; + @Child private AbstractDispatchNode dispatchNode; + @Child private ExpressionNode arg1; + @Child private ExpressionNode arg2; + @Child private ExpressionNode arg3; + + public QuatArgSendNode(final int argIdx, final ExpressionNode arg1, + final ExpressionNode arg2, + final ExpressionNode arg3, final SSymbol selector, + final AbstractDispatchNode dispatchNode) { + super(null); + this.argIdx = argIdx; + this.selector = selector; + this.dispatchNode = dispatchNode; + this.arg1 = arg1; + this.arg2 = arg2; + this.arg3 = arg3; + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + Object[] arguments = new Object[] { + frame.getArguments()[argIdx], + arg1.executeGeneric(frame), + arg2.executeGeneric(frame), + arg3.executeGeneric(frame)}; + return doPreEvaluated(frame, arguments); + } + + @Override + public Object doPreEvaluated(final VirtualFrame frame, + final Object[] arguments) { + return dispatchNode.executeDispatch(frame, arguments); + } + + @Override + public SSymbol getInvocationIdentifier() { + return selector; + } + + @Override + public int getNumberOfArguments() { + return 4; + } + + @Override + public void replaceDispatchListHead( + final GenericDispatchNode replacement) { + CompilerAsserts.neverPartOfCompilation(); + dispatchNode.replace(replacement); + } + + @Override + public void notifyDispatchInserted() { + dispatchNode.notifyAsInserted(); + } +} diff --git a/src/trufflesom/interpreter/supernodes/TernaryArgSendNode.java b/src/trufflesom/interpreter/supernodes/TernaryArgSendNode.java new file mode 100644 index 000000000..199d9a7f2 --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/TernaryArgSendNode.java @@ -0,0 +1,68 @@ +package trufflesom.interpreter.supernodes; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.frame.VirtualFrame; + +import trufflesom.interpreter.nodes.AbstractMessageSendNode; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode; +import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; +import trufflesom.vmobjects.SSymbol; + + +public class TernaryArgSendNode extends AbstractMessageSendNode { + private final int argIdx; + private final SSymbol selector; + @Child private AbstractDispatchNode dispatchNode; + @Child private ExpressionNode arg1; + @Child private ExpressionNode arg2; + + public TernaryArgSendNode(final int argIdx, final ExpressionNode arg1, + final ExpressionNode arg2, + final SSymbol selector, + final AbstractDispatchNode dispatchNode) { + super(null); + this.argIdx = argIdx; + this.selector = selector; + this.dispatchNode = dispatchNode; + this.arg1 = arg1; + this.arg2 = arg2; + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + Object[] arguments = new Object[] { + frame.getArguments()[argIdx], + arg1.executeGeneric(frame), + arg2.executeGeneric(frame)}; + return doPreEvaluated(frame, arguments); + } + + @Override + public Object doPreEvaluated(final VirtualFrame frame, + final Object[] arguments) { + return dispatchNode.executeDispatch(frame, arguments); + } + + @Override + public SSymbol getInvocationIdentifier() { + return selector; + } + + @Override + public int getNumberOfArguments() { + return 3; + } + + @Override + public void replaceDispatchListHead( + final GenericDispatchNode replacement) { + CompilerAsserts.neverPartOfCompilation(); + dispatchNode.replace(replacement); + } + + @Override + public void notifyDispatchInserted() { + dispatchNode.notifyAsInserted(); + } +} diff --git a/src/trufflesom/interpreter/supernodes/UnaryArgSendNode.java b/src/trufflesom/interpreter/supernodes/UnaryArgSendNode.java new file mode 100644 index 000000000..6a80c632e --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/UnaryArgSendNode.java @@ -0,0 +1,58 @@ +package trufflesom.interpreter.supernodes; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.frame.VirtualFrame; + +import trufflesom.interpreter.nodes.AbstractMessageSendNode; +import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode; +import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; +import trufflesom.vmobjects.SSymbol; + + +public final class UnaryArgSendNode extends AbstractMessageSendNode { + private final int argIdx; + private final SSymbol selector; + @Child private AbstractDispatchNode dispatchNode; + + public UnaryArgSendNode(final int argIdx, final SSymbol selector, + final AbstractDispatchNode dispatchNode) { + super(null); + this.argIdx = argIdx; + this.selector = selector; + this.dispatchNode = dispatchNode; + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + Object[] arguments = new Object[] {frame.getArguments()[argIdx]}; + return doPreEvaluated(frame, arguments); + } + + @Override + public Object doPreEvaluated(final VirtualFrame frame, + final Object[] arguments) { + return dispatchNode.executeDispatch(frame, arguments); + } + + @Override + public SSymbol getInvocationIdentifier() { + return selector; + } + + @Override + public int getNumberOfArguments() { + return 1; + } + + @Override + public void replaceDispatchListHead( + final GenericDispatchNode replacement) { + CompilerAsserts.neverPartOfCompilation(); + dispatchNode.replace(replacement); + } + + @Override + public void notifyDispatchInserted() { + dispatchNode.notifyAsInserted(); + } +} From 741fc3c56d358a309929bde178c5fe82e675d625 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 21 Jan 2022 22:13:41 +0000 Subject: [PATCH 02/38] Implement IntIncrementNode and needed field access/storage support This also adds the support in the bytecode interpreter (this is mostly incidental, since I had to remove it completely, too) Signed-off-by: Stefan Marr --- src/trufflesom/compiler/ParserAst.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/compiler/ParserAst.java index 17e32464a..1dcafd7d0 100644 --- a/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/compiler/ParserAst.java @@ -253,6 +253,11 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, if (isSuperSend) { return MessageSendNode.createSuperSend( mgenc.getHolder().getSuperClass(), msg, args, coordWithL); + } else if (msg.getString().equals("+") && operand instanceof IntegerLiteralNode) { + IntegerLiteralNode lit = (IntegerLiteralNode) operand; + if (lit.executeLong(null) == 1) { + return IntIncrementNodeGen.create(receiver); + } } ExpressionNode inlined = From 9377f1d0e202b7d211e06e3c23f23b6fe72e19df Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sat, 22 Jan 2022 18:50:58 +0000 Subject: [PATCH 03/38] Generalize the IncOperationNode to arbitary values - also supports `-` as operator in parser - add tests - add fallback support Signed-off-by: Stefan Marr --- src/trufflesom/compiler/ParserAst.java | 11 ++- .../interpreter/nodes/FieldNode.java | 8 +- .../nodes/specialized/IntIncrementNode.java | 76 ++++++++++++++++-- .../objectstorage/FieldAccessorNode.java | 13 ++-- .../objectstorage/StorageLocation.java | 10 +-- .../supernodes/IncrementOpTests.java | 77 +++++++++++++++++++ tests/trufflesom/tests/AstInliningTests.java | 15 ---- 7 files changed, 174 insertions(+), 36 deletions(-) create mode 100644 tests/trufflesom/supernodes/IncrementOpTests.java diff --git a/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/compiler/ParserAst.java index 1dcafd7d0..88babb9e9 100644 --- a/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/compiler/ParserAst.java @@ -253,10 +253,15 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, if (isSuperSend) { return MessageSendNode.createSuperSend( mgenc.getHolder().getSuperClass(), msg, args, coordWithL); - } else if (msg.getString().equals("+") && operand instanceof IntegerLiteralNode) { + } else if (operand instanceof IntegerLiteralNode) { IntegerLiteralNode lit = (IntegerLiteralNode) operand; - if (lit.executeLong(null) == 1) { - return IntIncrementNodeGen.create(receiver); + if (msg.getString().equals("+")) { + return IntIncrementNodeGen.create(lit.executeLong(null), false, receiver) + .initialize(coordWithL); + } + if (msg.getString().equals("-")) { + return IntIncrementNodeGen.create(-lit.executeLong(null), true, receiver) + .initialize(coordWithL); } } diff --git a/src/trufflesom/interpreter/nodes/FieldNode.java b/src/trufflesom/interpreter/nodes/FieldNode.java index 5853a742f..11b0c9de8 100644 --- a/src/trufflesom/interpreter/nodes/FieldNode.java +++ b/src/trufflesom/interpreter/nodes/FieldNode.java @@ -252,12 +252,14 @@ public static final class UninitFieldIncNode extends FieldNode { @Child private ExpressionNode self; private final int fieldIndex; + private final long value; public UninitFieldIncNode(final ExpressionNode self, final int fieldIndex, - final long coord) { + final long coord, final long value) { this.self = self; this.fieldIndex = fieldIndex; this.sourceCoord = coord; + this.value = value; } public int getFieldIndex() { @@ -287,13 +289,13 @@ public Object executeGeneric(final VirtualFrame frame) { long longVal = 0; try { - longVal = Math.addExact((Long) val, 1); + longVal = Math.addExact((Long) val, value); obj.setField(fieldIndex, longVal); } catch (ArithmeticException e) { throw new NotYetImplementedException(); } - IncrementLongFieldNode node = FieldAccessorNode.createIncrement(fieldIndex, obj); + IncrementLongFieldNode node = FieldAccessorNode.createIncrement(fieldIndex, obj, value); IncFieldNode incNode = new IncFieldNode(self, node, sourceCoord); replace(incNode); node.notifyAsInserted(); diff --git a/src/trufflesom/interpreter/nodes/specialized/IntIncrementNode.java b/src/trufflesom/interpreter/nodes/specialized/IntIncrementNode.java index 88f1335a3..0336345e9 100644 --- a/src/trufflesom/interpreter/nodes/specialized/IntIncrementNode.java +++ b/src/trufflesom/interpreter/nodes/specialized/IntIncrementNode.java @@ -1,23 +1,53 @@ package trufflesom.interpreter.nodes.specialized; +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.interpreter.bc.RespecializeException; 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.GenericMessageSendNode; +import trufflesom.interpreter.nodes.MessageSendNode; +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 IntIncrementNode extends ExpressionNode { + + protected final long value; + protected final boolean isMinusAndValueNegated; + + public IntIncrementNode(final long value, final boolean isMinusAndValueNegated) { + this.value = value; + 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 static long doInc(final long rcvr) { - return Math.addExact(rcvr, 1); + public long doInc(final long rcvr) { + return Math.addExact(rcvr, value); } @Specialization - public static double doInc(final double rcvr) { - return rcvr + 1; + public double doInc(final double rcvr) { + return rcvr + value; } public abstract Object executeEvaluated(Object rcvr); @@ -27,7 +57,12 @@ public final Object doPreEvaluated(final VirtualFrame frame, final Object[] args return executeEvaluated(args[0]); } - public abstract ExpressionNode getRcvr(); + @Fallback + public final Object makeGenericSend(final VirtualFrame frame, final Object rcvr) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + return makeGenericSend().doPreEvaluated(frame, + new Object[] {rcvr, isMinusAndValueNegated ? -value : value}); + } public boolean doesAccessField(final int fieldIdx) { ExpressionNode rcvr = getRcvr(); @@ -38,4 +73,35 @@ public boolean doesAccessField(final int fieldIdx) { return false; } + + protected GenericMessageSendNode makeGenericSend() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + ExpressionNode[] children; + if (VmSettings.UseAstInterp) { + children = new ExpressionNode[] {getRcvr(), + new IntegerLiteralNode(isMinusAndValueNegated ? -value : value)}; + } else { + children = null; + } + + SSymbol selector = + isMinusAndValueNegated ? SymbolTable.symbolFor("-") : SymbolTable.symbolFor("+"); + GenericMessageSendNode send = + MessageSendNode.createGeneric(selector, children, 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 createFieldIncNode(final ExpressionNode self, final int fieldIndex, + final long coord) { + return new UninitFieldIncNode(self, fieldIndex, coord, value); + } + } diff --git a/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java b/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java index ee5e93856..1b5b71429 100644 --- a/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java +++ b/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java @@ -31,9 +31,9 @@ public static AbstractWriteFieldNode createWrite(final int fieldIndex) { @InliningCutoff public static IncrementLongFieldNode createIncrement(final int fieldIndex, - final SObject obj) { + final SObject obj, final long incValue) { final ObjectLayout layout = obj.getObjectLayout(); - return new IncrementLongFieldNode(fieldIndex, layout); + return new IncrementLongFieldNode(fieldIndex, layout, incValue); } private FieldAccessorNode(final int fieldIndex) { @@ -324,13 +324,16 @@ protected final boolean hasExpectedLayout(final SObject obj) public static final class IncrementLongFieldNode extends FieldAccessorNode { protected final ObjectLayout layout; private final LongStorageLocation storage; + private final long incValue; @Child protected IncrementLongFieldNode nextInCache; - public IncrementLongFieldNode(final int fieldIndex, final ObjectLayout layout) { + public IncrementLongFieldNode(final int fieldIndex, final ObjectLayout layout, + final long incValue) { super(fieldIndex); this.layout = layout; this.storage = (LongStorageLocation) layout.getStorageLocation(fieldIndex); + this.incValue = incValue; } protected boolean hasExpectedLayout(final SObject obj) @@ -342,7 +345,7 @@ protected boolean hasExpectedLayout(final SObject obj) public long increment(final SObject obj) { try { if (hasExpectedLayout(obj)) { - return storage.increment(obj); + return storage.increment(obj, incValue); } else { ensureNext(obj); return nextInCache.increment(obj); @@ -363,7 +366,7 @@ private long dropAndIncrementNext(final SObject obj) { private void ensureNext(final SObject obj) { if (nextInCache == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - nextInCache = new IncrementLongFieldNode(fieldIndex, obj.getObjectLayout()); + nextInCache = new IncrementLongFieldNode(fieldIndex, obj.getObjectLayout(), incValue); } } } diff --git a/src/trufflesom/interpreter/objectstorage/StorageLocation.java b/src/trufflesom/interpreter/objectstorage/StorageLocation.java index 4ebf85a92..871bb6f8b 100644 --- a/src/trufflesom/interpreter/objectstorage/StorageLocation.java +++ b/src/trufflesom/interpreter/objectstorage/StorageLocation.java @@ -33,7 +33,7 @@ public interface LongStorageLocation { void writeLong(SObject obj, long value); - long increment(SObject obj); + long increment(SObject obj, long incValue); } public interface DoubleStorageLocation { @@ -343,9 +343,9 @@ public long readLong(final SObject obj) throws UnexpectedResultException { } @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; } @@ -425,9 +425,9 @@ public long readLong(final SObject obj) throws UnexpectedResultException { } @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/tests/trufflesom/supernodes/IncrementOpTests.java b/tests/trufflesom/supernodes/IncrementOpTests.java new file mode 100644 index 000000000..81735de54 --- /dev/null +++ b/tests/trufflesom/supernodes/IncrementOpTests.java @@ -0,0 +1,77 @@ +package trufflesom.supernodes; + +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.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.specialized.IfInlinedLiteralNode; +import trufflesom.interpreter.nodes.specialized.IntIncrementNode; +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, "value", Long.class); + assertEquals(literalValue, value); + } + + @Test + public void testBasicAddOrSubtract() { + // int const + int const + basicAddOrSubtract("1 + 1", 1, IntIncrementNode.class); + basicAddOrSubtract("1 + 2", 2, IntIncrementNode.class); + basicAddOrSubtract("1 + 150", 150, IntIncrementNode.class); + + // int const - int const + basicAddOrSubtract("1 - 1", -1, IntIncrementNode.class); + basicAddOrSubtract("1 - 2", -2, IntIncrementNode.class); + basicAddOrSubtract("1 - 150", -150, IntIncrementNode.class); + + // int expr + int const + basicAddOrSubtract("(3 / 4) + 1", 1, IntIncrementNode.class); + basicAddOrSubtract("(3 / 5) + 2", 2, IntIncrementNode.class); + basicAddOrSubtract("(4 / 4) + 150", 150, IntIncrementNode.class); + + // int expr - int const + basicAddOrSubtract("(3 / 4) - 1", -1, IntIncrementNode.class); + basicAddOrSubtract("(3 / 5) - 2", -2, IntIncrementNode.class); + basicAddOrSubtract("(4 / 4) - 150", -150, IntIncrementNode.class); + + basicAddOrSubtract("arg + 123", 123, IntIncrementNode.class); + basicAddOrSubtract("var + 245", 245, IntIncrementNode.class); + basicAddOrSubtract("field + 645", 645, IntIncrementNode.class); + + basicAddOrSubtract("arg - 123", -123, IntIncrementNode.class); + basicAddOrSubtract("var - 245", -245, IntIncrementNode.class); + basicAddOrSubtract("field - 645", -645, IntIncrementNode.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); + + IntIncrementNode inc = read(ifNode, "bodyNode", IntIncrementNode.class); + LocalArgumentReadNode arg = (LocalArgumentReadNode) inc.getRcvr(); + assertEquals(1, arg.argumentIndex); + assertEquals("arg", arg.getInvocationIdentifier().getString()); + } + +} diff --git a/tests/trufflesom/tests/AstInliningTests.java b/tests/trufflesom/tests/AstInliningTests.java index 38c360015..f30cbed4a 100644 --- a/tests/trufflesom/tests/AstInliningTests.java +++ b/tests/trufflesom/tests/AstInliningTests.java @@ -153,21 +153,6 @@ public void testIfTrueAndIncField() { assertTrue(selfNode.isSelfRead()); } - @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); - - IntIncrementNode inc = read(ifNode, "bodyNode", IntIncrementNode.class); - LocalArgumentReadNode arg = (LocalArgumentReadNode) inc.getRcvr(); - assertEquals(1, arg.argumentIndex); - assertEquals("arg", arg.getInvocationIdentifier().getString()); - } - @Test public void testNestedIf() { addField("field"); From 51e9a6a5ed87b90f3b21c7a257902df84c2f72a2 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sat, 22 Jan 2022 20:48:34 +0000 Subject: [PATCH 04/38] Rename field to more consistent and explicit incValue Signed-off-by: Stefan Marr --- src/trufflesom/interpreter/nodes/FieldNode.java | 8 ++++---- .../nodes/specialized/IntIncrementNode.java | 14 +++++++------- tests/trufflesom/supernodes/IncrementOpTests.java | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/trufflesom/interpreter/nodes/FieldNode.java b/src/trufflesom/interpreter/nodes/FieldNode.java index 11b0c9de8..2a29570a1 100644 --- a/src/trufflesom/interpreter/nodes/FieldNode.java +++ b/src/trufflesom/interpreter/nodes/FieldNode.java @@ -252,14 +252,14 @@ public static final class UninitFieldIncNode extends FieldNode { @Child private ExpressionNode self; private final int fieldIndex; - private final long value; + private final long incValue; public UninitFieldIncNode(final ExpressionNode self, final int fieldIndex, final long coord, final long value) { this.self = self; this.fieldIndex = fieldIndex; this.sourceCoord = coord; - this.value = value; + this.incValue = value; } public int getFieldIndex() { @@ -289,13 +289,13 @@ public Object executeGeneric(final VirtualFrame frame) { long longVal = 0; try { - longVal = Math.addExact((Long) val, value); + longVal = Math.addExact((Long) val, incValue); obj.setField(fieldIndex, longVal); } catch (ArithmeticException e) { throw new NotYetImplementedException(); } - IncrementLongFieldNode node = FieldAccessorNode.createIncrement(fieldIndex, obj, value); + IncrementLongFieldNode node = FieldAccessorNode.createIncrement(fieldIndex, obj, incValue); IncFieldNode incNode = new IncFieldNode(self, node, sourceCoord); replace(incNode); node.notifyAsInserted(); diff --git a/src/trufflesom/interpreter/nodes/specialized/IntIncrementNode.java b/src/trufflesom/interpreter/nodes/specialized/IntIncrementNode.java index 0336345e9..22514d022 100644 --- a/src/trufflesom/interpreter/nodes/specialized/IntIncrementNode.java +++ b/src/trufflesom/interpreter/nodes/specialized/IntIncrementNode.java @@ -23,11 +23,11 @@ @NodeChild(value = "rcvr", type = ExpressionNode.class) public abstract class IntIncrementNode extends ExpressionNode { - protected final long value; + protected final long incValue; protected final boolean isMinusAndValueNegated; public IntIncrementNode(final long value, final boolean isMinusAndValueNegated) { - this.value = value; + this.incValue = value; this.isMinusAndValueNegated = isMinusAndValueNegated; } @@ -42,12 +42,12 @@ public final Object doPreEvaluated(final VirtualFrame frame, final Object[] args @Specialization(rewriteOn = ArithmeticException.class) public long doInc(final long rcvr) { - return Math.addExact(rcvr, value); + return Math.addExact(rcvr, incValue); } @Specialization public double doInc(final double rcvr) { - return rcvr + value; + return rcvr + incValue; } public abstract Object executeEvaluated(Object rcvr); @@ -61,7 +61,7 @@ public final Object doPreEvaluated(final VirtualFrame frame, final Object[] args public final Object makeGenericSend(final VirtualFrame frame, final Object rcvr) { CompilerDirectives.transferToInterpreterAndInvalidate(); return makeGenericSend().doPreEvaluated(frame, - new Object[] {rcvr, isMinusAndValueNegated ? -value : value}); + new Object[] {rcvr, isMinusAndValueNegated ? -incValue : incValue}); } public boolean doesAccessField(final int fieldIdx) { @@ -79,7 +79,7 @@ protected GenericMessageSendNode makeGenericSend() { ExpressionNode[] children; if (VmSettings.UseAstInterp) { children = new ExpressionNode[] {getRcvr(), - new IntegerLiteralNode(isMinusAndValueNegated ? -value : value)}; + new IntegerLiteralNode(isMinusAndValueNegated ? -incValue : incValue)}; } else { children = null; } @@ -101,7 +101,7 @@ protected GenericMessageSendNode makeGenericSend() { public FieldNode createFieldIncNode(final ExpressionNode self, final int fieldIndex, final long coord) { - return new UninitFieldIncNode(self, fieldIndex, coord, value); + return new UninitFieldIncNode(self, fieldIndex, coord, incValue); } } diff --git a/tests/trufflesom/supernodes/IncrementOpTests.java b/tests/trufflesom/supernodes/IncrementOpTests.java index 81735de54..cdd14bf84 100644 --- a/tests/trufflesom/supernodes/IncrementOpTests.java +++ b/tests/trufflesom/supernodes/IncrementOpTests.java @@ -24,7 +24,7 @@ private void basicAddOrSubtract(final String test, final long literalValue, ExpressionNode testExpr = read(seq, "expressions", 0); assertThat(testExpr, instanceOf(nodeType)); - long value = read(testExpr, "value", Long.class); + long value = read(testExpr, "incValue", Long.class); assertEquals(literalValue, value); } From 9a2483ce9abd65ebca588c5e403752c2739ea996 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sat, 22 Jan 2022 20:49:35 +0000 Subject: [PATCH 05/38] Added LocalVariableIncNode and NonLocalVariableIncNode Signed-off-by: Stefan Marr --- src/bdt/inlining/Variable.java | 2 + .../compiler/MethodGenerationContext.java | 11 +++- src/trufflesom/compiler/ParserAst.java | 2 +- src/trufflesom/compiler/Variable.java | 27 ++++++++ .../interpreter/nodes/LocalVariableNode.java | 5 +- .../nodes/NonLocalVariableNode.java | 2 +- .../interpreter/supernodes/IncFieldNode.java | 44 +++++++++++++ .../IntIncrementNode.java | 43 +++++++++---- .../supernodes/LocalVariableIncNode.java | 49 ++++++++++++++ .../supernodes/NonLocalVariableIncNode.java | 55 ++++++++++++++++ .../supernodes/UninitFieldIncNode.java | 64 +++++++++++++++++++ .../supernodes/IncrementOpTests.java | 44 ++++++++++++- tests/trufflesom/tests/AstInliningTests.java | 12 ++-- 13 files changed, 333 insertions(+), 27 deletions(-) create mode 100644 src/trufflesom/interpreter/supernodes/IncFieldNode.java rename src/trufflesom/interpreter/{nodes/specialized => supernodes}/IntIncrementNode.java (70%) create mode 100644 src/trufflesom/interpreter/supernodes/LocalVariableIncNode.java create mode 100644 src/trufflesom/interpreter/supernodes/NonLocalVariableIncNode.java create mode 100644 src/trufflesom/interpreter/supernodes/UninitFieldIncNode.java diff --git a/src/bdt/inlining/Variable.java b/src/bdt/inlining/Variable.java index 526454e59..27eaef658 100644 --- a/src/bdt/inlining/Variable.java +++ b/src/bdt/inlining/Variable.java @@ -37,6 +37,8 @@ public interface Variable { */ N getReadNode(int contextLevel, long coord); + N getIncNode(int contextLevel, long incValue, long coord); + /** * Create a node to write to this variable. * diff --git a/src/trufflesom/compiler/MethodGenerationContext.java b/src/trufflesom/compiler/MethodGenerationContext.java index a0d6768a6..0e413783f 100644 --- a/src/trufflesom/compiler/MethodGenerationContext.java +++ b/src/trufflesom/compiler/MethodGenerationContext.java @@ -55,7 +55,7 @@ import trufflesom.interpreter.nodes.ReturnNonLocalNode; import trufflesom.interpreter.nodes.ReturnNonLocalNode.CatchNonLocalReturnNode; import trufflesom.interpreter.nodes.literals.BlockNode; -import trufflesom.interpreter.nodes.specialized.IntIncrementNode; +import trufflesom.interpreter.supernodes.IntIncrementNode; import trufflesom.primitives.Primitives; import trufflesom.vmobjects.SClass; import trufflesom.vmobjects.SInvokable; @@ -401,7 +401,14 @@ public ExpressionNode getLocalReadNode(final Variable variable, final long coord public ExpressionNode getLocalWriteNode(final Variable variable, final ExpressionNode valExpr, final long coord) { - return variable.getWriteNode(getContextLevel(variable), valExpr, coord); + int ctxLevel = getContextLevel(variable); + + if (valExpr instanceof IntIncrementNode + && ((IntIncrementNode) valExpr).doesAccessVariable(variable)) { + return ((IntIncrementNode) valExpr).createIncNode((Local) variable, ctxLevel); + } + + return variable.getWriteNode(ctxLevel, valExpr, coord); } protected Local getLocal(final SSymbol varName) { diff --git a/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/compiler/ParserAst.java index 88babb9e9..bb9bc25a8 100644 --- a/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/compiler/ParserAst.java @@ -38,7 +38,7 @@ import trufflesom.interpreter.nodes.literals.GenericLiteralNode; import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; import trufflesom.interpreter.nodes.literals.LiteralNode; -import trufflesom.interpreter.nodes.specialized.IntIncrementNodeGen; +import trufflesom.interpreter.supernodes.IntIncrementNodeGen; import trufflesom.primitives.Primitives; import trufflesom.vm.Globals; import trufflesom.vmobjects.SArray; diff --git a/src/trufflesom/compiler/Variable.java b/src/trufflesom/compiler/Variable.java index 2205e9d53..73e785fe0 100644 --- a/src/trufflesom/compiler/Variable.java +++ b/src/trufflesom/compiler/Variable.java @@ -26,6 +26,8 @@ import trufflesom.interpreter.nodes.LocalVariableNodeFactory.LocalVariableWriteNodeGen; import trufflesom.interpreter.nodes.NonLocalVariableNodeFactory.NonLocalVariableReadNodeGen; import trufflesom.interpreter.nodes.NonLocalVariableNodeFactory.NonLocalVariableWriteNodeGen; +import trufflesom.interpreter.supernodes.LocalVariableIncNodeGen; +import trufflesom.interpreter.supernodes.NonLocalVariableIncNodeGen; import trufflesom.vm.NotYetImplementedException; import trufflesom.vmobjects.SSymbol; @@ -125,6 +127,12 @@ public ExpressionNode getReadNode(final int contextLevel, final long coord) { } } + @Override + public ExpressionNode getIncNode(final int contextLevel, final long incValue, + final long coord) { + throw new NotYetImplementedException(); + } + @Override public ExpressionNode getWriteNode(final int contextLevel, final ExpressionNode valueExpr, final long coord) { @@ -178,6 +186,17 @@ public ExpressionNode getReadNode(final int contextLevel, final long coord) { return LocalVariableReadNodeGen.create(this).initialize(coord); } + @Override + public ExpressionNode getIncNode(final int contextLevel, final long incValue, + final long coord) { + transferToInterpreterAndInvalidate("Variable.getReadNode"); + if (contextLevel > 0) { + return NonLocalVariableIncNodeGen.create(contextLevel, this, incValue) + .initialize(coord); + } + return LocalVariableIncNodeGen.create(this, incValue).initialize(coord); + } + public final int getIndex() { return slotIndex; } @@ -238,6 +257,14 @@ public ExpressionNode getReadNode(final int contextLevel, final long coord) { + "They are used directly by other nodes."); } + @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/interpreter/nodes/LocalVariableNode.java b/src/trufflesom/interpreter/nodes/LocalVariableNode.java index b710288e1..f42a64520 100644 --- a/src/trufflesom/interpreter/nodes/LocalVariableNode.java +++ b/src/trufflesom/interpreter/nodes/LocalVariableNode.java @@ -14,14 +14,15 @@ import trufflesom.vmobjects.SSymbol; -public abstract class LocalVariableNode extends NoPreEvalExprNode implements Invocation { +public abstract class LocalVariableNode extends NoPreEvalExprNode + implements Invocation { protected final int slotIndex; 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) { + protected LocalVariableNode(final Local local) { this.local = local; this.slotIndex = local.getIndex(); } diff --git a/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java b/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java index e8df39ca7..245729e5e 100644 --- a/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java +++ b/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java @@ -24,7 +24,7 @@ public abstract class NonLocalVariableNode extends ContextualNode protected final int slotIndex; protected final Local local; - private NonLocalVariableNode(final int contextLevel, final Local local) { + protected NonLocalVariableNode(final int contextLevel, final Local local) { super(contextLevel); this.local = local; this.slotIndex = local.getIndex(); diff --git a/src/trufflesom/interpreter/supernodes/IncFieldNode.java b/src/trufflesom/interpreter/supernodes/IncFieldNode.java new file mode 100644 index 000000000..8534b1390 --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/IncFieldNode.java @@ -0,0 +1,44 @@ +package trufflesom.interpreter.supernodes; + +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; + + +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); + } +} diff --git a/src/trufflesom/interpreter/nodes/specialized/IntIncrementNode.java b/src/trufflesom/interpreter/supernodes/IntIncrementNode.java similarity index 70% rename from src/trufflesom/interpreter/nodes/specialized/IntIncrementNode.java rename to src/trufflesom/interpreter/supernodes/IntIncrementNode.java index 22514d022..dd7fb16fd 100644 --- a/src/trufflesom/interpreter/nodes/specialized/IntIncrementNode.java +++ b/src/trufflesom/interpreter/supernodes/IntIncrementNode.java @@ -1,4 +1,4 @@ -package trufflesom.interpreter.nodes.specialized; +package trufflesom.interpreter.supernodes; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Fallback; @@ -6,13 +6,16 @@ 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.FieldNode.UninitFieldIncNode; -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; @@ -74,20 +77,28 @@ public boolean doesAccessField(final int fieldIdx) { return false; } - protected GenericMessageSendNode makeGenericSend() { - CompilerDirectives.transferToInterpreterAndInvalidate(); - ExpressionNode[] children; - if (VmSettings.UseAstInterp) { - children = new ExpressionNode[] {getRcvr(), - new IntegerLiteralNode(isMinusAndValueNegated ? -incValue : incValue)}; + public boolean doesAccessVariable(final Variable var) { + ExpressionNode rcvr = getRcvr(); + Local local; + if (rcvr instanceof LocalVariableNode) { + local = ((LocalVariableNode) rcvr).getLocal(); + } else if (rcvr instanceof NonLocalVariableNode) { + local = ((NonLocalVariableNode) rcvr).getLocal(); } else { - children = null; + return false; } + return local.equals(var); + } + + protected AbstractMessageSendNode makeGenericSend() { + CompilerDirectives.transferToInterpreterAndInvalidate(); SSymbol selector = isMinusAndValueNegated ? SymbolTable.symbolFor("-") : SymbolTable.symbolFor("+"); - GenericMessageSendNode send = - MessageSendNode.createGeneric(selector, children, sourceCoord); + AbstractMessageSendNode send = + MessageSendNode.createGenericBinary(selector, getRcvr(), + new IntegerLiteralNode(isMinusAndValueNegated ? -incValue : incValue), + sourceCoord); if (VmSettings.UseAstInterp) { replace(send); @@ -104,4 +115,12 @@ public FieldNode createFieldIncNode(final ExpressionNode self, final int fieldIn return new UninitFieldIncNode(self, fieldIndex, coord, incValue); } + public ExpressionNode createIncNode(final Local local, final int ctxLevel) { + if (ctxLevel == 0) { + return LocalVariableIncNodeGen.create(local, incValue).initialize(sourceCoord); + } + return NonLocalVariableIncNodeGen.create(ctxLevel, local, incValue) + .initialize(sourceCoord); + } + } diff --git a/src/trufflesom/interpreter/supernodes/LocalVariableIncNode.java b/src/trufflesom/interpreter/supernodes/LocalVariableIncNode.java new file mode 100644 index 000000000..c346b5305 --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/LocalVariableIncNode.java @@ -0,0 +1,49 @@ +package trufflesom.interpreter.supernodes; + +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 bd.inlining.ScopeAdaptationVisitor; +import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.nodes.LocalVariableNode; + + +public abstract class LocalVariableIncNode extends LocalVariableNode { + + private final long incValue; + + public LocalVariableIncNode(final Local variable, final long incValue) { + super(variable); + this.incValue = incValue; + } + + @Specialization(guards = "frame.isLong(slot)", rewriteOn = {FrameSlotTypeException.class}) + public final long doLong(final VirtualFrame frame) throws FrameSlotTypeException { + long current = frame.getLong(slot); + long result = Math.addExact(current, incValue); + frame.setLong(slot, result); + return result; + } + + @Specialization(guards = "frame.isDouble(slot)", + rewriteOn = {FrameSlotTypeException.class}) + public final double doDouble(final VirtualFrame frame) throws FrameSlotTypeException { + double current = frame.getDouble(slot); + double result = current + incValue; + frame.setDouble(slot, 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/interpreter/supernodes/NonLocalVariableIncNode.java b/src/trufflesom/interpreter/supernodes/NonLocalVariableIncNode.java new file mode 100644 index 000000000..3f945f3e9 --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/NonLocalVariableIncNode.java @@ -0,0 +1,55 @@ +package trufflesom.interpreter.supernodes; + +import com.oracle.truffle.api.dsl.Bind; +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 com.oracle.truffle.api.nodes.Node; + +import bd.inlining.ScopeAdaptationVisitor; +import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.nodes.NonLocalVariableNode; + + +public abstract class NonLocalVariableIncNode extends NonLocalVariableNode { + + private final long incValue; + + public NonLocalVariableIncNode(final int contextLevel, final Local local, + final long incValue) { + super(contextLevel, local); + this.incValue = incValue; + } + + @Specialization(guards = "ctx.isLong(slot)", rewriteOn = {FrameSlotTypeException.class}) + public final long doLong(final VirtualFrame frame, + @Bind("determineContext(frame)") final MaterializedFrame ctx) + throws FrameSlotTypeException { + long current = ctx.getLong(slot); + long result = Math.addExact(current, incValue); + ctx.setLong(slot, result); + return result; + } + + @Specialization(guards = "ctx.isDouble(slot)", rewriteOn = {FrameSlotTypeException.class}) + public final double doDouble(final VirtualFrame frame, + @Bind("determineContext(frame)") final MaterializedFrame ctx) + throws FrameSlotTypeException { + double current = ctx.getDouble(slot); + double result = current + incValue; + ctx.setDouble(slot, 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/interpreter/supernodes/UninitFieldIncNode.java b/src/trufflesom/interpreter/supernodes/UninitFieldIncNode.java new file mode 100644 index 000000000..44d688ce4 --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/UninitFieldIncNode.java @@ -0,0 +1,64 @@ +package trufflesom.interpreter.supernodes; + +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 final class UninitFieldIncNode extends FieldNode { + + @Child private ExpressionNode self; + private final int fieldIndex; + private final long incValue; + + public UninitFieldIncNode(final ExpressionNode self, final int fieldIndex, + final long coord, final long value) { + this.self = self; + this.fieldIndex = fieldIndex; + this.sourceCoord = coord; + this.incValue = value; + } + + @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, incValue); + IncFieldNode incNode = new IncFieldNode(self, node, sourceCoord); + replace(incNode); + node.notifyAsInserted(); + + return longVal; + } +} diff --git a/tests/trufflesom/supernodes/IncrementOpTests.java b/tests/trufflesom/supernodes/IncrementOpTests.java index cdd14bf84..9f721dc84 100644 --- a/tests/trufflesom/supernodes/IncrementOpTests.java +++ b/tests/trufflesom/supernodes/IncrementOpTests.java @@ -9,8 +9,12 @@ 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.nodes.specialized.IntIncrementNode; +import trufflesom.interpreter.supernodes.IntIncrementNode; +import trufflesom.interpreter.supernodes.LocalVariableIncNode; +import trufflesom.interpreter.supernodes.NonLocalVariableIncNode; +import trufflesom.interpreter.supernodes.UninitFieldIncNode; import trufflesom.tests.AstTestSetup; @@ -74,4 +78,42 @@ public void testIfTrueAndIncArg() { assertEquals("arg", arg.getInvocationIdentifier().getString()); } + @Test + public void testFieldInc() { + basicAddOrSubtract("field := field + 1", 1, UninitFieldIncNode.class); + basicAddOrSubtract("field := field - 1", -1, UninitFieldIncNode.class); + basicAddOrSubtract("field := field + 1123", 1123, UninitFieldIncNode.class); + basicAddOrSubtract("field := field - 234234", -234234, UninitFieldIncNode.class); + } + + @Test + public void testLocalInc() { + basicAddOrSubtract("var := var + 1", 1, LocalVariableIncNode.class); + basicAddOrSubtract("var := var - 1", -1, LocalVariableIncNode.class); + basicAddOrSubtract("var := var + 1123", 1123, LocalVariableIncNode.class); + basicAddOrSubtract("var := var - 234234", -234234, LocalVariableIncNode.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(), "expressionOrSequence", 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, NonLocalVariableIncNode.class); + inBlock("[ var := var - 1 ]", -1, NonLocalVariableIncNode.class); + inBlock("[ var := var + 1123 ]", 1123, NonLocalVariableIncNode.class); + inBlock("[ var := var - 234234 ]", -234234, NonLocalVariableIncNode.class); + } + } diff --git a/tests/trufflesom/tests/AstInliningTests.java b/tests/trufflesom/tests/AstInliningTests.java index f30cbed4a..d8d0a5596 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; @@ -33,9 +32,10 @@ import trufflesom.interpreter.nodes.specialized.IfInlinedLiteralNode; import trufflesom.interpreter.nodes.specialized.IfTrueIfFalseInlinedLiteralsNode.FalseIfElseLiteralNode; import trufflesom.interpreter.nodes.specialized.IfTrueIfFalseInlinedLiteralsNode.TrueIfElseLiteralNode; -import trufflesom.interpreter.nodes.specialized.IntIncrementNode; import trufflesom.interpreter.nodes.specialized.IntToDoInlinedLiteralsNode; import trufflesom.interpreter.nodes.specialized.whileloops.WhileInlinedLiteralsNode; +import trufflesom.interpreter.supernodes.NonLocalVariableIncNode; +import trufflesom.interpreter.supernodes.UninitFieldIncNode; import trufflesom.primitives.arithmetic.SubtractionPrim; import trufflesom.primitives.arrays.DoPrim; @@ -374,14 +374,10 @@ public void testToDoBlockBlockInlinedSelf() { assertEquals("b", readNode.getInvocationIdentifier().getString()); assertEquals(1, readNode.argumentIndex); - NonLocalVariableWriteNode writeNode = - read(blockBIfTrue, "bodyNode", NonLocalVariableWriteNode.class); + NonLocalVariableIncNode writeNode = + read(blockBIfTrue, "bodyNode", NonLocalVariableIncNode.class); assertEquals(1, writeNode.getContextLevel()); assertEquals("l2", writeNode.getInvocationIdentifier().getString()); - - IntIncrementNode incNode = (IntIncrementNode) writeNode.getExp(); - NonLocalVariableReadNode readL2 = (NonLocalVariableReadNode) incNode.getRcvr(); - assertEquals("l2", readL2.getInvocationIdentifier().getString()); } @Test From 9931e1adb6dec40b1fd237621a563b6cf8d0c1c7 Mon Sep 17 00:00:00 2001 From: Octave Larose Date: Sun, 23 Jan 2022 00:11:21 +0000 Subject: [PATCH 06/38] Add AssignLocalSquareToLocalNode Cherry-picked from supernodes branch --- .../AssignLocalSquareToLocalNode.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/trufflesom/interpreter/nodes/supernodes/AssignLocalSquareToLocalNode.java diff --git a/src/trufflesom/interpreter/nodes/supernodes/AssignLocalSquareToLocalNode.java b/src/trufflesom/interpreter/nodes/supernodes/AssignLocalSquareToLocalNode.java new file mode 100644 index 000000000..226cdf4ec --- /dev/null +++ b/src/trufflesom/interpreter/nodes/supernodes/AssignLocalSquareToLocalNode.java @@ -0,0 +1,106 @@ +package trufflesom.interpreter.nodes.supernodes; + +import bd.inlining.ScopeAdaptationVisitor; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.FrameSlot; +import com.oracle.truffle.api.frame.FrameSlotTypeException; +import com.oracle.truffle.api.frame.VirtualFrame; +import trufflesom.compiler.Variable; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.LocalVariableNode; +import trufflesom.primitives.arithmetic.MultiplicationPrim; + +/** + * Matches the following AST: + *
+ * LocalVariableWriteNode
+ *     LocalVariableReadNode
+ *     LocalVariableReadNode (same as the previous read)
+ *     MultiplicationPrim
+ * 
+ * + * ...and replaces it with: + *
+ * AssignLocalSquareToLocalNode
+ * 
+ */ +public abstract class AssignLocalSquareToLocalNode extends LocalVariableNode { + private final FrameSlot squaredVarSlot; + private final LocalVariableNode originalSubtree; + + public AssignLocalSquareToLocalNode(final Variable.Local variable, + final Variable.Local squaredVar, + final LocalVariableNode originalSubtree) { + super(variable); + this.squaredVarSlot = squaredVar.getSlot(); + this.originalSubtree = originalSubtree; + } + + @Specialization(rewriteOn = {FrameSlotTypeException.class, ArithmeticException.class}) + public final long writeLong(final VirtualFrame frame) throws FrameSlotTypeException { + long localVarValue = frame.getLong(this.squaredVarSlot); + long newValue = Math.multiplyExact(localVarValue, localVarValue); + frame.setLong(slot, newValue); + return newValue; + } + + @Specialization(rewriteOn = {FrameSlotTypeException.class, ArithmeticException.class}) + public final double writeDouble(final VirtualFrame frame) throws FrameSlotTypeException { + double localVarValue = frame.getDouble(this.squaredVarSlot); + double newValue = localVarValue * localVarValue; + frame.setDouble(slot, newValue); + return newValue; + } + + @Specialization(replaces = {"writeLong", "writeDouble"}) + public final Object writeGeneric(final VirtualFrame frame) { + Object result = originalSubtree.executeGeneric(frame); + replace(originalSubtree); + return result; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "[ " + local.name + " ]"; + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + /* + * This should never happen because ``replaceAfterScopeChange`` is only called in the + * parsing stage, whereas the ``IncrementOperationNode`` superinstruction is only inserted + * into the AST *after* parsing. + */ + throw new RuntimeException("replaceAfterScopeChange: This should never happen!"); + } + + /** + * Check if the AST subtree has the shape of an increment operation. + */ + public static boolean isSquareAssignmentOperation(ExpressionNode exp) { + if (exp instanceof MultiplicationPrim) { + MultiplicationPrim mulPrim = (MultiplicationPrim) exp; + if (mulPrim.getReceiver() instanceof LocalVariableReadNode + && mulPrim.getArgument() instanceof LocalVariableReadNode) { + LocalVariableReadNode var1 = (LocalVariableReadNode) mulPrim.getReceiver(); + LocalVariableReadNode var2 = (LocalVariableReadNode) mulPrim.getArgument(); + return var1.getLocal().equals(var2.getLocal()); + } + } + return false; + } + + /** + * Replace ``node`` with a superinstruction. Assumes that the AST subtree has the correct shape. + */ + public static void replaceNode(final LocalVariableWriteNode node) { + MultiplicationPrim mulPrim = (MultiplicationPrim) node.getExp(); + if (mulPrim.getArgument() instanceof LocalVariableReadNode) { + LocalVariableReadNode localVarNode = (LocalVariableReadNode) mulPrim.getArgument(); + AssignLocalSquareToLocalNode newNode = AssignLocalSquareToLocalNodeGen + .create(node.getLocal(), localVarNode.getLocal(), node) + .initialize(node.getSourceCoordinate()); + node.replace(newNode); + } + } +} From 6526cc604ca47fd202ccb7ada9862a9a58e6d062 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 23 Jan 2022 00:31:47 +0000 Subject: [PATCH 07/38] Added initial tests, the todo list Signed-off-by: Stefan Marr --- tests/trufflesom/supernodes/SquareTests.java | 58 ++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 tests/trufflesom/supernodes/SquareTests.java diff --git a/tests/trufflesom/supernodes/SquareTests.java b/tests/trufflesom/supernodes/SquareTests.java new file mode 100644 index 000000000..514b17204 --- /dev/null +++ b/tests/trufflesom/supernodes/SquareTests.java @@ -0,0 +1,58 @@ +package trufflesom.supernodes; + +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertThat; + +import org.junit.Test; + +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.LocalVariableNode.LocalVariableWriteNode; +import trufflesom.interpreter.nodes.SequenceNode; +import trufflesom.interpreter.nodes.supernodes.AssignLocalSquareToLocalNode; +import trufflesom.primitives.arithmetic.MultiplicationPrim; +import trufflesom.tests.AstTestSetup; + + +public class SquareTests extends AstTestSetup { + private ExpressionNode assertThatMainNodeIs(final String test, final Class expectedNode) { + SequenceNode seq = (SequenceNode) parseMethod( + "test = ( | l1 l2 l3 l4 | \n" + test + " )"); + + ExpressionNode testExpr = read(seq, "expressions", 0); + assertThat(testExpr, instanceOf(expectedNode)); + return testExpr; + } + + @Test + public void testJustSquareLocals() { + assertThatMainNodeIs("l2 * l2.", AssignLocalSquareToLocalNode.class); + assertThatMainNodeIs("l1 * l1.", AssignLocalSquareToLocalNode.class); + + assertThatMainNodeIs("l1 * l3.", MultiplicationPrim.class); + } + + @Test + public void testJustSquareNoneLocals() { + assertThatMainNodeIs("[ l2 * l2 ]", AssignLocalSquareToLocalNode.class); + assertThatMainNodeIs("[ l1 * l1 ]", AssignLocalSquareToLocalNode.class); + + assertThatMainNodeIs("[ l1 * l3 ]", MultiplicationPrim.class); + } + + @Test + public void testSquareAndAssignLocal() { + assertThatMainNodeIs("l1 := l2 * l2.", AssignLocalSquareToLocalNode.class); + assertThatMainNodeIs("l2 := l2 * l2.", AssignLocalSquareToLocalNode.class); + + assertThatMainNodeIs("l3 := l1 * l2.", LocalVariableWriteNode.class); + } + + @Test + public void testSquareAndAssignNonLocal() { + assertThatMainNodeIs("[ l1 := l2 * l2 ]", AssignLocalSquareToLocalNode.class); + assertThatMainNodeIs("[ l2 := l2 * l2 ]", AssignLocalSquareToLocalNode.class); + + assertThatMainNodeIs("[ l3 := l1 * l2 ]", LocalVariableWriteNode.class); + } + +} From 89377b2b70a2bb91a821daf26a16a2b242c4e057 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 23 Jan 2022 01:01:34 +0000 Subject: [PATCH 08/38] Added [Non]LocalVariableSquareNode Signed-off-by: Stefan Marr --- src/bdt/inlining/Variable.java | 2 + src/trufflesom/compiler/ParserAst.java | 25 +++++++++- src/trufflesom/compiler/Variable.java | 22 +++++++++ .../supernodes/LocalVariableSquareNode.java | 42 +++++++++++++++++ .../NonLocalVariableSquareNode.java | 47 +++++++++++++++++++ tests/trufflesom/supernodes/SquareTests.java | 41 ++++++++++++---- 6 files changed, 170 insertions(+), 9 deletions(-) create mode 100644 src/trufflesom/interpreter/nodes/supernodes/LocalVariableSquareNode.java create mode 100644 src/trufflesom/interpreter/nodes/supernodes/NonLocalVariableSquareNode.java diff --git a/src/bdt/inlining/Variable.java b/src/bdt/inlining/Variable.java index 27eaef658..4f8284301 100644 --- a/src/bdt/inlining/Variable.java +++ b/src/bdt/inlining/Variable.java @@ -39,6 +39,8 @@ public interface Variable { N getIncNode(int contextLevel, long incValue, long coord); + N getSquareNode(int contextLevel, long coord); + /** * Create a node to write to this variable. * diff --git a/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/compiler/ParserAst.java index bb9bc25a8..e81c622a0 100644 --- a/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/compiler/ParserAst.java @@ -30,14 +30,17 @@ import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.FieldNode; import trufflesom.interpreter.nodes.GlobalNode; +import trufflesom.interpreter.nodes.LocalVariableNode.LocalVariableReadNode; import trufflesom.interpreter.nodes.MessageSendNode; -import trufflesom.interpreter.nodes.SequenceNode; +import trufflesom.interpreter.nodes.NonLocalVariableNode.NonLocalVariableReadNode; import trufflesom.interpreter.nodes.literals.BlockNode; import trufflesom.interpreter.nodes.literals.BlockNode.BlockNodeWithContext; import trufflesom.interpreter.nodes.literals.DoubleLiteralNode; import trufflesom.interpreter.nodes.literals.GenericLiteralNode; import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; import trufflesom.interpreter.nodes.literals.LiteralNode; +import trufflesom.interpreter.nodes.supernodes.LocalVariableSquareNodeGen; +import trufflesom.interpreter.nodes.supernodes.NonLocalVariableSquareNodeGen; import trufflesom.interpreter.supernodes.IntIncrementNodeGen; import trufflesom.primitives.Primitives; import trufflesom.vm.Globals; @@ -253,6 +256,26 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, if (isSuperSend) { return MessageSendNode.createSuperSend( mgenc.getHolder().getSuperClass(), msg, args, coordWithL); + } else if (msg.getString().equals("*")) { + if (receiver instanceof LocalVariableReadNode + && operand instanceof LocalVariableReadNode) { + Local rcvrLocal = ((LocalVariableReadNode) receiver).getLocal(); + Local opLocal = ((LocalVariableReadNode) operand).getLocal(); + if (rcvrLocal.equals(opLocal)) { + return LocalVariableSquareNodeGen.create(rcvrLocal).initialize(coordWithL); + } + } else if (receiver instanceof NonLocalVariableReadNode + && operand instanceof NonLocalVariableReadNode) { + Local rcvrLocal = ((NonLocalVariableReadNode) receiver).getLocal(); + Local opLocal = ((NonLocalVariableReadNode) operand).getLocal(); + + assert ((NonLocalVariableReadNode) receiver).getContextLevel() == ((NonLocalVariableReadNode) operand).getContextLevel(); + if (rcvrLocal.equals(opLocal)) { + return NonLocalVariableSquareNodeGen.create( + ((NonLocalVariableReadNode) receiver).getContextLevel(), rcvrLocal) + .initialize(coordWithL); + } + } } else if (operand instanceof IntegerLiteralNode) { IntegerLiteralNode lit = (IntegerLiteralNode) operand; if (msg.getString().equals("+")) { diff --git a/src/trufflesom/compiler/Variable.java b/src/trufflesom/compiler/Variable.java index 73e785fe0..9dfd58211 100644 --- a/src/trufflesom/compiler/Variable.java +++ b/src/trufflesom/compiler/Variable.java @@ -26,6 +26,8 @@ import trufflesom.interpreter.nodes.LocalVariableNodeFactory.LocalVariableWriteNodeGen; import trufflesom.interpreter.nodes.NonLocalVariableNodeFactory.NonLocalVariableReadNodeGen; import trufflesom.interpreter.nodes.NonLocalVariableNodeFactory.NonLocalVariableWriteNodeGen; +import trufflesom.interpreter.nodes.supernodes.LocalVariableSquareNodeGen; +import trufflesom.interpreter.nodes.supernodes.NonLocalVariableSquareNodeGen; import trufflesom.interpreter.supernodes.LocalVariableIncNodeGen; import trufflesom.interpreter.supernodes.NonLocalVariableIncNodeGen; import trufflesom.vm.NotYetImplementedException; @@ -133,6 +135,11 @@ public ExpressionNode getIncNode(final int contextLevel, final long incValue, throw new NotYetImplementedException(); } + @Override + public ExpressionNode getSquareNode(final int contextLevel, final long coord) { + throw new NotYetImplementedException(); + } + @Override public ExpressionNode getWriteNode(final int contextLevel, final ExpressionNode valueExpr, final long coord) { @@ -197,6 +204,15 @@ public ExpressionNode getIncNode(final int contextLevel, final long incValue, return LocalVariableIncNodeGen.create(this, incValue).initialize(coord); } + @Override + public ExpressionNode getSquareNode(final int contextLevel, final long coord) { + transferToInterpreterAndInvalidate("Variable.getReadNode"); + if (contextLevel > 0) { + return NonLocalVariableSquareNodeGen.create(contextLevel, this).initialize(coord); + } + return LocalVariableSquareNodeGen.create(this).initialize(coord); + } + public final int getIndex() { return slotIndex; } @@ -265,6 +281,12 @@ public ExpressionNode getIncNode(final int contextLevel, final long incValue, + "They are used directly by other nodes."); } + @Override + public ExpressionNode getSquareNode(final int contextLevel, final long coord) { + throw new UnsupportedOperationException( + "There shouldn't be any language-level square nodes for internal slots. "); + } + @Override public Internal split() { return new Internal(name, coord, slotIndex); diff --git a/src/trufflesom/interpreter/nodes/supernodes/LocalVariableSquareNode.java b/src/trufflesom/interpreter/nodes/supernodes/LocalVariableSquareNode.java new file mode 100644 index 000000000..945c3d07b --- /dev/null +++ b/src/trufflesom/interpreter/nodes/supernodes/LocalVariableSquareNode.java @@ -0,0 +1,42 @@ +package trufflesom.interpreter.nodes.supernodes; + +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 bd.inlining.ScopeAdaptationVisitor; +import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.nodes.LocalVariableNode; + + +public abstract class LocalVariableSquareNode extends LocalVariableNode { + + public LocalVariableSquareNode(final Local variable) { + super(variable); + } + + @Specialization(guards = {"frame.isLong(slot)"}, rewriteOn = {FrameSlotTypeException.class}) + public final long doLong(final VirtualFrame frame) throws FrameSlotTypeException { + long value = frame.getLong(slot); + return Math.multiplyExact(value, value); + } + + @Specialization(guards = {"frame.isDouble(slot)"}, + rewriteOn = {FrameSlotTypeException.class}) + public final double doDouble(final VirtualFrame frame) throws FrameSlotTypeException { + double value = frame.getDouble(slot); + return value * value; + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + ScopeElement se = inliner.getAdaptedVar(local); + if (se.var != local || se.contextLevel < 0) { + replace(se.var.getSquareNode(se.contextLevel, sourceCoord)); + } else { + assert 0 == se.contextLevel; + } + } +} diff --git a/src/trufflesom/interpreter/nodes/supernodes/NonLocalVariableSquareNode.java b/src/trufflesom/interpreter/nodes/supernodes/NonLocalVariableSquareNode.java new file mode 100644 index 000000000..38ccfd252 --- /dev/null +++ b/src/trufflesom/interpreter/nodes/supernodes/NonLocalVariableSquareNode.java @@ -0,0 +1,47 @@ +package trufflesom.interpreter.nodes.supernodes; + +import com.oracle.truffle.api.dsl.Bind; +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 com.oracle.truffle.api.nodes.Node; + +import bd.inlining.ScopeAdaptationVisitor; +import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.nodes.NonLocalVariableNode; + + +public abstract class NonLocalVariableSquareNode extends NonLocalVariableNode { + + public NonLocalVariableSquareNode(final int contextLevel, final Local local) { + super(contextLevel, local); + } + + @Specialization(guards = {"ctx.isLong(slot)"}, rewriteOn = {FrameSlotTypeException.class}) + public final long doLong(final VirtualFrame frame, + @Bind("determineContext(frame)") final MaterializedFrame ctx) + throws FrameSlotTypeException { + long current = ctx.getLong(slot); + return Math.multiplyExact(current, current); + } + + @Specialization(guards = {"ctx.isDouble(slot)"}, rewriteOn = {FrameSlotTypeException.class}) + public final double doDouble(final VirtualFrame frame, + @Bind("determineContext(frame)") final MaterializedFrame ctx) + throws FrameSlotTypeException { + double current = ctx.getDouble(slot); + return current * current; + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + ScopeElement se = inliner.getAdaptedVar(local); + if (se.var != local || se.contextLevel < contextLevel) { + replace(se.var.getSquareNode(se.contextLevel, sourceCoord)); + } else { + assert contextLevel == se.contextLevel; + } + } +} diff --git a/tests/trufflesom/supernodes/SquareTests.java b/tests/trufflesom/supernodes/SquareTests.java index 514b17204..18a08a49d 100644 --- a/tests/trufflesom/supernodes/SquareTests.java +++ b/tests/trufflesom/supernodes/SquareTests.java @@ -1,6 +1,7 @@ package trufflesom.supernodes; import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import org.junit.Test; @@ -8,35 +9,59 @@ import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.LocalVariableNode.LocalVariableWriteNode; import trufflesom.interpreter.nodes.SequenceNode; +import trufflesom.interpreter.nodes.literals.BlockNode; import trufflesom.interpreter.nodes.supernodes.AssignLocalSquareToLocalNode; +import trufflesom.interpreter.nodes.supernodes.LocalVariableSquareNode; +import trufflesom.interpreter.nodes.supernodes.NonLocalVariableSquareNode; import trufflesom.primitives.arithmetic.MultiplicationPrim; import trufflesom.tests.AstTestSetup; public class SquareTests extends AstTestSetup { - private ExpressionNode assertThatMainNodeIs(final String test, final Class expectedNode) { + @SuppressWarnings("unchecked") + private T assertThatMainNodeIs(final String test, final Class expectedNode) { SequenceNode seq = (SequenceNode) parseMethod( "test = ( | l1 l2 l3 l4 | \n" + test + " )"); ExpressionNode testExpr = read(seq, "expressions", 0); assertThat(testExpr, instanceOf(expectedNode)); - return testExpr; + return (T) testExpr; } @Test public void testJustSquareLocals() { - assertThatMainNodeIs("l2 * l2.", AssignLocalSquareToLocalNode.class); - assertThatMainNodeIs("l1 * l1.", AssignLocalSquareToLocalNode.class); + LocalVariableSquareNode s = + assertThatMainNodeIs("l2 * l2.", LocalVariableSquareNode.class); + assertEquals(s.getLocal().name.getString(), "l2"); + + s = assertThatMainNodeIs("l1 * l1.", LocalVariableSquareNode.class); + assertEquals(s.getLocal().name.getString(), "l1"); assertThatMainNodeIs("l1 * l3.", MultiplicationPrim.class); } + @SuppressWarnings("unchecked") + private T inBlock(final String test, final Class expectedNode) { + addField("field"); + SequenceNode seq = (SequenceNode) parseMethod( + "test: arg = ( | l1 l2 l3 l4 | \n" + test + " )"); + + BlockNode block = (BlockNode) read(seq, "expressions", 0); + ExpressionNode testExpr = + read(block.getMethod().getInvokable(), "expressionOrSequence", ExpressionNode.class); + assertThat(testExpr, instanceOf(expectedNode)); + return (T) testExpr; + } + @Test - public void testJustSquareNoneLocals() { - assertThatMainNodeIs("[ l2 * l2 ]", AssignLocalSquareToLocalNode.class); - assertThatMainNodeIs("[ l1 * l1 ]", AssignLocalSquareToLocalNode.class); + public void testJustSquareNonLocals() { + NonLocalVariableSquareNode s = inBlock("[ l2 * l2 ]", NonLocalVariableSquareNode.class); + assertEquals(s.getLocal().name.getString(), "l2"); + + s = inBlock("[ l1 * l1 ]", NonLocalVariableSquareNode.class); + assertEquals(s.getLocal().name.getString(), "l1"); - assertThatMainNodeIs("[ l1 * l3 ]", MultiplicationPrim.class); + inBlock("[ l1 * l3 ]", MultiplicationPrim.class); } @Test From e72ba5bd2dbdce9d0f2797889918bf220f5af28c Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 23 Jan 2022 11:35:12 +0000 Subject: [PATCH 09/38] Add [Non]LocalVariableReadSquareWriteNode - do specialization in the parser to do it as early as possible - remove AssignLocalSquareToLocalNode which is the run-time specialization version Signed-off-by: Stefan Marr --- src/bdt/inlining/Variable.java | 4 + .../compiler/MethodGenerationContext.java | 26 ++++- src/trufflesom/compiler/Variable.java | 25 +++++ .../AssignLocalSquareToLocalNode.java | 106 ------------------ .../LocalVariableReadSquareWriteNode.java | 85 ++++++++++++++ .../NonLocalVariableReadSquareWriteNode.java | 97 ++++++++++++++++ tests/trufflesom/supernodes/SquareTests.java | 14 ++- 7 files changed, 244 insertions(+), 113 deletions(-) delete mode 100644 src/trufflesom/interpreter/nodes/supernodes/AssignLocalSquareToLocalNode.java create mode 100644 src/trufflesom/interpreter/nodes/supernodes/LocalVariableReadSquareWriteNode.java create mode 100644 src/trufflesom/interpreter/nodes/supernodes/NonLocalVariableReadSquareWriteNode.java diff --git a/src/bdt/inlining/Variable.java b/src/bdt/inlining/Variable.java index 4f8284301..bf519f9ea 100644 --- a/src/bdt/inlining/Variable.java +++ b/src/bdt/inlining/Variable.java @@ -2,6 +2,8 @@ import com.oracle.truffle.api.nodes.Node; +import trufflesom.compiler.Variable.Local; + /** * A {@link Variable} represents a variable most often in the user code, or sometimes internal @@ -41,6 +43,8 @@ public interface Variable { N getSquareNode(int contextLevel, long coord); + N getReadSquareWriteNode(int contextLevel, long coord, Local readLocal); + /** * Create a node to write to this variable. * diff --git a/src/trufflesom/compiler/MethodGenerationContext.java b/src/trufflesom/compiler/MethodGenerationContext.java index 0e413783f..04a10e76d 100644 --- a/src/trufflesom/compiler/MethodGenerationContext.java +++ b/src/trufflesom/compiler/MethodGenerationContext.java @@ -55,8 +55,12 @@ import trufflesom.interpreter.nodes.ReturnNonLocalNode; import trufflesom.interpreter.nodes.ReturnNonLocalNode.CatchNonLocalReturnNode; import trufflesom.interpreter.nodes.literals.BlockNode; +import trufflesom.interpreter.nodes.supernodes.LocalVariableSquareNode; +import trufflesom.interpreter.nodes.supernodes.NonLocalVariableSquareNode; import trufflesom.interpreter.supernodes.IntIncrementNode; import trufflesom.primitives.Primitives; +import trufflesom.vm.NotYetImplementedException; +import trufflesom.vm.constants.Nil; import trufflesom.vmobjects.SClass; import trufflesom.vmobjects.SInvokable; import trufflesom.vmobjects.SInvokable.SMethod; @@ -84,7 +88,7 @@ public class MethodGenerationContext protected final LinkedHashMap arguments; protected final LinkedHashMap locals; - private Internal frameOnStack; + private Internal frameOnStack; protected final LexicalScope currentScope; @@ -408,6 +412,26 @@ public ExpressionNode getLocalWriteNode(final Variable variable, return ((IntIncrementNode) valExpr).createIncNode((Local) variable, ctxLevel); } + if (ctxLevel == 0) { + if (valExpr instanceof LocalVariableSquareNode) { + return variable.getReadSquareWriteNode(ctxLevel, coord, + ((LocalVariableSquareNode) valExpr).getLocal()); + } + if (valExpr instanceof NonLocalVariableSquareNode) { + throw new NotYetImplementedException( + "a missing read/square/write combination, used in a benchmark?"); + } + } else { + if (valExpr instanceof NonLocalVariableSquareNode) { + return variable.getReadSquareWriteNode(ctxLevel, coord, + ((NonLocalVariableSquareNode) valExpr).getLocal()); + } + + if (valExpr instanceof LocalVariableSquareNode) { + return variable.getReadSquareWriteNode(ctxLevel, coord, + ((LocalVariableSquareNode) valExpr).getLocal()); + } + } return variable.getWriteNode(ctxLevel, valExpr, coord); } diff --git a/src/trufflesom/compiler/Variable.java b/src/trufflesom/compiler/Variable.java index 9dfd58211..119697c05 100644 --- a/src/trufflesom/compiler/Variable.java +++ b/src/trufflesom/compiler/Variable.java @@ -26,7 +26,9 @@ import trufflesom.interpreter.nodes.LocalVariableNodeFactory.LocalVariableWriteNodeGen; import trufflesom.interpreter.nodes.NonLocalVariableNodeFactory.NonLocalVariableReadNodeGen; import trufflesom.interpreter.nodes.NonLocalVariableNodeFactory.NonLocalVariableWriteNodeGen; +import trufflesom.interpreter.nodes.supernodes.LocalVariableReadSquareWriteNodeGen; import trufflesom.interpreter.nodes.supernodes.LocalVariableSquareNodeGen; +import trufflesom.interpreter.nodes.supernodes.NonLocalVariableReadSquareWriteNodeGen; import trufflesom.interpreter.nodes.supernodes.NonLocalVariableSquareNodeGen; import trufflesom.interpreter.supernodes.LocalVariableIncNodeGen; import trufflesom.interpreter.supernodes.NonLocalVariableIncNodeGen; @@ -140,6 +142,12 @@ public ExpressionNode getSquareNode(final int contextLevel, final long coord) { throw new NotYetImplementedException(); } + @Override + public ExpressionNode getReadSquareWriteNode(final int contextLevel, final long coord, + final Local readLocal) { + throw new NotYetImplementedException(); + } + @Override public ExpressionNode getWriteNode(final int contextLevel, final ExpressionNode valueExpr, final long coord) { @@ -213,6 +221,16 @@ public ExpressionNode getSquareNode(final int contextLevel, final long coord) { return LocalVariableSquareNodeGen.create(this).initialize(coord); } + @Override + public ExpressionNode getReadSquareWriteNode(final int contextLevel, final long coord, + final Local readLocal) { + if (contextLevel > 0) { + return NonLocalVariableReadSquareWriteNodeGen.create(contextLevel, this, readLocal) + .initialize(coord); + } + return LocalVariableReadSquareWriteNodeGen.create(this, readLocal).initialize(coord); + } + public final int getIndex() { return slotIndex; } @@ -287,6 +305,13 @@ public ExpressionNode getSquareNode(final int contextLevel, final long coord) { "There shouldn't be any language-level square nodes for internal slots. "); } + @Override + public ExpressionNode getReadSquareWriteNode(final int contextLevel, final long coord, + final Local readLocal) { + throw new UnsupportedOperationException( + "There shouldn't be any language-level square nodes for internal slots. "); + } + @Override public Internal split() { return new Internal(name, coord, slotIndex); diff --git a/src/trufflesom/interpreter/nodes/supernodes/AssignLocalSquareToLocalNode.java b/src/trufflesom/interpreter/nodes/supernodes/AssignLocalSquareToLocalNode.java deleted file mode 100644 index 226cdf4ec..000000000 --- a/src/trufflesom/interpreter/nodes/supernodes/AssignLocalSquareToLocalNode.java +++ /dev/null @@ -1,106 +0,0 @@ -package trufflesom.interpreter.nodes.supernodes; - -import bd.inlining.ScopeAdaptationVisitor; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.frame.FrameSlot; -import com.oracle.truffle.api.frame.FrameSlotTypeException; -import com.oracle.truffle.api.frame.VirtualFrame; -import trufflesom.compiler.Variable; -import trufflesom.interpreter.nodes.ExpressionNode; -import trufflesom.interpreter.nodes.LocalVariableNode; -import trufflesom.primitives.arithmetic.MultiplicationPrim; - -/** - * Matches the following AST: - *
- * LocalVariableWriteNode
- *     LocalVariableReadNode
- *     LocalVariableReadNode (same as the previous read)
- *     MultiplicationPrim
- * 
- * - * ...and replaces it with: - *
- * AssignLocalSquareToLocalNode
- * 
- */ -public abstract class AssignLocalSquareToLocalNode extends LocalVariableNode { - private final FrameSlot squaredVarSlot; - private final LocalVariableNode originalSubtree; - - public AssignLocalSquareToLocalNode(final Variable.Local variable, - final Variable.Local squaredVar, - final LocalVariableNode originalSubtree) { - super(variable); - this.squaredVarSlot = squaredVar.getSlot(); - this.originalSubtree = originalSubtree; - } - - @Specialization(rewriteOn = {FrameSlotTypeException.class, ArithmeticException.class}) - public final long writeLong(final VirtualFrame frame) throws FrameSlotTypeException { - long localVarValue = frame.getLong(this.squaredVarSlot); - long newValue = Math.multiplyExact(localVarValue, localVarValue); - frame.setLong(slot, newValue); - return newValue; - } - - @Specialization(rewriteOn = {FrameSlotTypeException.class, ArithmeticException.class}) - public final double writeDouble(final VirtualFrame frame) throws FrameSlotTypeException { - double localVarValue = frame.getDouble(this.squaredVarSlot); - double newValue = localVarValue * localVarValue; - frame.setDouble(slot, newValue); - return newValue; - } - - @Specialization(replaces = {"writeLong", "writeDouble"}) - public final Object writeGeneric(final VirtualFrame frame) { - Object result = originalSubtree.executeGeneric(frame); - replace(originalSubtree); - return result; - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "[ " + local.name + " ]"; - } - - @Override - public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { - /* - * This should never happen because ``replaceAfterScopeChange`` is only called in the - * parsing stage, whereas the ``IncrementOperationNode`` superinstruction is only inserted - * into the AST *after* parsing. - */ - throw new RuntimeException("replaceAfterScopeChange: This should never happen!"); - } - - /** - * Check if the AST subtree has the shape of an increment operation. - */ - public static boolean isSquareAssignmentOperation(ExpressionNode exp) { - if (exp instanceof MultiplicationPrim) { - MultiplicationPrim mulPrim = (MultiplicationPrim) exp; - if (mulPrim.getReceiver() instanceof LocalVariableReadNode - && mulPrim.getArgument() instanceof LocalVariableReadNode) { - LocalVariableReadNode var1 = (LocalVariableReadNode) mulPrim.getReceiver(); - LocalVariableReadNode var2 = (LocalVariableReadNode) mulPrim.getArgument(); - return var1.getLocal().equals(var2.getLocal()); - } - } - return false; - } - - /** - * Replace ``node`` with a superinstruction. Assumes that the AST subtree has the correct shape. - */ - public static void replaceNode(final LocalVariableWriteNode node) { - MultiplicationPrim mulPrim = (MultiplicationPrim) node.getExp(); - if (mulPrim.getArgument() instanceof LocalVariableReadNode) { - LocalVariableReadNode localVarNode = (LocalVariableReadNode) mulPrim.getArgument(); - AssignLocalSquareToLocalNode newNode = AssignLocalSquareToLocalNodeGen - .create(node.getLocal(), localVarNode.getLocal(), node) - .initialize(node.getSourceCoordinate()); - node.replace(newNode); - } - } -} diff --git a/src/trufflesom/interpreter/nodes/supernodes/LocalVariableReadSquareWriteNode.java b/src/trufflesom/interpreter/nodes/supernodes/LocalVariableReadSquareWriteNode.java new file mode 100644 index 000000000..d5542c74a --- /dev/null +++ b/src/trufflesom/interpreter/nodes/supernodes/LocalVariableReadSquareWriteNode.java @@ -0,0 +1,85 @@ +package trufflesom.interpreter.nodes.supernodes; + +import com.oracle.truffle.api.dsl.Specialization; +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; +import com.oracle.truffle.api.nodes.Node; + +import bd.inlining.ScopeAdaptationVisitor; +import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.nodes.LocalVariableNode; + + +public abstract class LocalVariableReadSquareWriteNode extends LocalVariableNode { + + protected final Local readLocal; + protected final FrameSlot readSlot; + + public LocalVariableReadSquareWriteNode(final Local writeLocal, final Local readLocal) { + super(writeLocal); + this.readLocal = readLocal; + this.readSlot = readLocal.getSlot(); + } + + @Specialization(guards = {"isLongKind(frame)", "frame.isLong(readSlot)"}, + rewriteOn = {FrameSlotTypeException.class}) + public final long writeLong(final VirtualFrame frame) throws FrameSlotTypeException { + long current = frame.getLong(readSlot); + long result = Math.multiplyExact(current, current); + frame.setLong(slot, result); + return result; + } + + @Specialization(guards = {"isDoubleKind(frame)", "frame.isDouble(readSlot)"}, + rewriteOn = {FrameSlotTypeException.class}) + public final double writeDouble(final VirtualFrame frame) throws FrameSlotTypeException { + double current = frame.getDouble(readSlot); + double result = current * current; + frame.setDouble(slot, result); + return result; + } + + // uses frame to make sure guard is not converted to assertion + protected final boolean isLongKind(final VirtualFrame frame) { + if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Long) { + return true; + } + if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Illegal) { + descriptor.setFrameSlotKind(slot, FrameSlotKind.Long); + return true; + } + return false; + } + + // uses frame to make sure guard is not converted to assertion + protected final boolean isDoubleKind(final VirtualFrame frame) { + 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) { + ScopeElement seWrite = inliner.getAdaptedVar(local); + ScopeElement seRead = inliner.getAdaptedVar(readLocal); + + assert seWrite.contextLevel == seRead.contextLevel; + + if (seWrite.var != local || seWrite.contextLevel < 0) { + assert seRead.var != readLocal || seRead.contextLevel < 0; + replace( + seWrite.var.getReadSquareWriteNode(seWrite.contextLevel, sourceCoord, + (Local) seRead.var)); + } else { + assert 0 == seWrite.contextLevel; + } + } +} diff --git a/src/trufflesom/interpreter/nodes/supernodes/NonLocalVariableReadSquareWriteNode.java b/src/trufflesom/interpreter/nodes/supernodes/NonLocalVariableReadSquareWriteNode.java new file mode 100644 index 000000000..081391b8a --- /dev/null +++ b/src/trufflesom/interpreter/nodes/supernodes/NonLocalVariableReadSquareWriteNode.java @@ -0,0 +1,97 @@ +package trufflesom.interpreter.nodes.supernodes; + +import static trufflesom.interpreter.TruffleCompiler.transferToInterpreter; + +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Specialization; +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.MaterializedFrame; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; + +import bd.inlining.ScopeAdaptationVisitor; +import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.nodes.NonLocalVariableNode; + + +public abstract class NonLocalVariableReadSquareWriteNode extends NonLocalVariableNode { + + protected final Local readLocal; + protected final FrameSlot readSlot; + + public NonLocalVariableReadSquareWriteNode(final int contextLevel, final Local writeLocal, + final Local readLocal) { + super(contextLevel, writeLocal); + this.readLocal = readLocal; + this.readSlot = readLocal.getSlot(); + } + + @Specialization(guards = {"isLongKind(ctx)", "ctx.isLong(readSlot)"}, + rewriteOn = {FrameSlotTypeException.class}) + public final long writeLong(final VirtualFrame frame, + @Bind("determineContext(frame)") final MaterializedFrame ctx) + throws FrameSlotTypeException { + long current = ctx.getLong(readSlot); + long result = Math.multiplyExact(current, current); + + ctx.setLong(slot, result); + + return result; + } + + @Specialization(guards = {"isDoubleKind(ctx)", "ctx.isDouble(readSlot)"}, + rewriteOn = {FrameSlotTypeException.class}) + public final double writeDouble(final VirtualFrame frame, + @Bind("determineContext(frame)") final MaterializedFrame ctx) + throws FrameSlotTypeException { + double current = ctx.getDouble(readSlot); + double result = current * current; + + ctx.setDouble(slot, result); + return result; + } + + 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; + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + ScopeElement seWrite = inliner.getAdaptedVar(local); + ScopeElement seRead = inliner.getAdaptedVar(readLocal); + + assert seWrite.contextLevel == seRead.contextLevel; + + if (seWrite.var != local || seWrite.contextLevel < contextLevel) { + assert seRead.var != readLocal || seRead.contextLevel < contextLevel; + replace( + seWrite.var.getReadSquareWriteNode(seWrite.contextLevel, sourceCoord, + (Local) seRead.var)); + } else { + assert contextLevel == seWrite.contextLevel; + } + } +} diff --git a/tests/trufflesom/supernodes/SquareTests.java b/tests/trufflesom/supernodes/SquareTests.java index 18a08a49d..23470781a 100644 --- a/tests/trufflesom/supernodes/SquareTests.java +++ b/tests/trufflesom/supernodes/SquareTests.java @@ -8,10 +8,12 @@ import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.LocalVariableNode.LocalVariableWriteNode; +import trufflesom.interpreter.nodes.NonLocalVariableNode.NonLocalVariableWriteNode; import trufflesom.interpreter.nodes.SequenceNode; import trufflesom.interpreter.nodes.literals.BlockNode; -import trufflesom.interpreter.nodes.supernodes.AssignLocalSquareToLocalNode; +import trufflesom.interpreter.nodes.supernodes.LocalVariableReadSquareWriteNode; import trufflesom.interpreter.nodes.supernodes.LocalVariableSquareNode; +import trufflesom.interpreter.nodes.supernodes.NonLocalVariableReadSquareWriteNode; import trufflesom.interpreter.nodes.supernodes.NonLocalVariableSquareNode; import trufflesom.primitives.arithmetic.MultiplicationPrim; import trufflesom.tests.AstTestSetup; @@ -66,18 +68,18 @@ public void testJustSquareNonLocals() { @Test public void testSquareAndAssignLocal() { - assertThatMainNodeIs("l1 := l2 * l2.", AssignLocalSquareToLocalNode.class); - assertThatMainNodeIs("l2 := l2 * l2.", AssignLocalSquareToLocalNode.class); + assertThatMainNodeIs("l1 := l2 * l2.", LocalVariableReadSquareWriteNode.class); + assertThatMainNodeIs("l2 := l2 * l2.", LocalVariableReadSquareWriteNode.class); assertThatMainNodeIs("l3 := l1 * l2.", LocalVariableWriteNode.class); } @Test public void testSquareAndAssignNonLocal() { - assertThatMainNodeIs("[ l1 := l2 * l2 ]", AssignLocalSquareToLocalNode.class); - assertThatMainNodeIs("[ l2 := l2 * l2 ]", AssignLocalSquareToLocalNode.class); + inBlock("[ l1 := l2 * l2 ]", NonLocalVariableReadSquareWriteNode.class); + inBlock("[ l2 := l2 * l2 ]", NonLocalVariableReadSquareWriteNode.class); - assertThatMainNodeIs("[ l3 := l1 * l2 ]", LocalVariableWriteNode.class); + inBlock("[ l3 := l1 * l2 ]", NonLocalVariableWriteNode.class); } } From bd3d369fbd0a7753e80e99f8586bd7b031cc6768 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 23 Jan 2022 16:31:38 +0000 Subject: [PATCH 10/38] Add StringEqualsNode, which is used for `expr = 'str'`, i.e. literal string comparions. For the nil case in the string comparison, we store `nil` in a local static field to avoid type restrictions of the DSL. Signed-off-by: Stefan Marr --- src/trufflesom/compiler/ParserAst.java | 26 ++++++- .../nodes/supernodes/StringEqualsNode.java | 73 +++++++++++++++++++ .../supernodes/StringEqualsTests.java | 39 ++++++++++ 3 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 src/trufflesom/interpreter/nodes/supernodes/StringEqualsNode.java create mode 100644 tests/trufflesom/supernodes/StringEqualsTests.java diff --git a/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/compiler/ParserAst.java index e81c622a0..fc257d7b0 100644 --- a/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/compiler/ParserAst.java @@ -41,6 +41,7 @@ import trufflesom.interpreter.nodes.literals.LiteralNode; import trufflesom.interpreter.nodes.supernodes.LocalVariableSquareNodeGen; import trufflesom.interpreter.nodes.supernodes.NonLocalVariableSquareNodeGen; +import trufflesom.interpreter.nodes.supernodes.StringEqualsNodeGen; import trufflesom.interpreter.supernodes.IntIncrementNodeGen; import trufflesom.primitives.Primitives; import trufflesom.vm.Globals; @@ -256,7 +257,11 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, if (isSuperSend) { return MessageSendNode.createSuperSend( mgenc.getHolder().getSuperClass(), msg, args, coordWithL); - } else if (msg.getString().equals("*")) { + } + + String binSelector = msg.getString(); + + if (binSelector.equals("*")) { if (receiver instanceof LocalVariableReadNode && operand instanceof LocalVariableReadNode) { Local rcvrLocal = ((LocalVariableReadNode) receiver).getLocal(); @@ -276,13 +281,28 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, .initialize(coordWithL); } } + } else if (binSelector.equals("=")) { + if (operand instanceof GenericLiteralNode) { + Object literal = operand.executeGeneric(null); + if (literal instanceof String) { + return StringEqualsNodeGen.create((String) literal, receiver) + .initialize(coordWithL); + } + } + if (receiver instanceof GenericLiteralNode) { + Object literal = receiver.executeGeneric(null); + if (literal instanceof String) { + return StringEqualsNodeGen.create((String) literal, operand) + .initialize(coordWithL); + } + } } else if (operand instanceof IntegerLiteralNode) { IntegerLiteralNode lit = (IntegerLiteralNode) operand; - if (msg.getString().equals("+")) { + if (binSelector.equals("+")) { return IntIncrementNodeGen.create(lit.executeLong(null), false, receiver) .initialize(coordWithL); } - if (msg.getString().equals("-")) { + if (binSelector.equals("-")) { return IntIncrementNodeGen.create(-lit.executeLong(null), true, receiver) .initialize(coordWithL); } diff --git a/src/trufflesom/interpreter/nodes/supernodes/StringEqualsNode.java b/src/trufflesom/interpreter/nodes/supernodes/StringEqualsNode.java new file mode 100644 index 000000000..b36bdf4a3 --- /dev/null +++ b/src/trufflesom/interpreter/nodes/supernodes/StringEqualsNode.java @@ -0,0 +1,73 @@ +package trufflesom.interpreter.nodes.supernodes; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; + +import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.GenericMessageSendNode; +import trufflesom.interpreter.nodes.MessageSendNode; +import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; +import trufflesom.interpreter.nodes.literals.GenericLiteralNode; +import trufflesom.interpreter.nodes.nary.UnaryExpressionNode; +import trufflesom.vm.SymbolTable; +import trufflesom.vm.VmSettings; +import trufflesom.vm.constants.Nil; +import trufflesom.vmobjects.SSymbol; + + +public abstract class StringEqualsNode extends UnaryExpressionNode { + private final String value; + + protected static final Object nil = Nil.nilObject; + + protected StringEqualsNode(final String value) { + this.value = value; + } + + @Override + public abstract ExpressionNode getReceiver(); + + @Specialization + public final boolean doString(final String rcvr) { + return value.equals(rcvr); + } + + @Specialization(guards = "rcvr == nil") + public final boolean doNil(final Object rcvr) { + return false; + } + + @Fallback + public final Object makeGenericSend(final VirtualFrame frame, + final Object receiver) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + return makeGenericSend(SymbolTable.symbolFor("=")).doPreEvaluated(frame, + new Object[] {receiver, value}); + } + + @Override + protected GenericMessageSendNode makeGenericSend(final SSymbol selector) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + ExpressionNode[] children; + if (VmSettings.UseAstInterp) { + children = new ExpressionNode[] {getReceiver(), new GenericLiteralNode(value)}; + } else { + children = null; + } + + GenericMessageSendNode send = + MessageSendNode.createGeneric(selector, children, 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); + } +} diff --git a/tests/trufflesom/supernodes/StringEqualsTests.java b/tests/trufflesom/supernodes/StringEqualsTests.java new file mode 100644 index 000000000..92b29e7b2 --- /dev/null +++ b/tests/trufflesom/supernodes/StringEqualsTests.java @@ -0,0 +1,39 @@ +package trufflesom.supernodes; + +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertThat; + +import org.junit.Test; + +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.SequenceNode; +import trufflesom.interpreter.nodes.supernodes.StringEqualsNode; +import trufflesom.tests.AstTestSetup; + + +public class StringEqualsTests extends AstTestSetup { + + @SuppressWarnings("unchecked") + private T assertThatMainNodeIs(final String test, final Class expectedNode) { + addField("field"); + SequenceNode seq = (SequenceNode) parseMethod( + "test: arg = ( | var | \n" + test + " )"); + + ExpressionNode testExpr = read(seq, "expressions", 0); + assertThat(testExpr, instanceOf(expectedNode)); + return (T) testExpr; + } + + @Test + public void testStringEqual() { + assertThatMainNodeIs("field = 'str'", StringEqualsNode.class); + assertThatMainNodeIs("arg = 'str'", StringEqualsNode.class); + assertThatMainNodeIs("var = 'str'", StringEqualsNode.class); + assertThatMainNodeIs("('s' + 'dd') = 'str'", StringEqualsNode.class); + + assertThatMainNodeIs("'str' = field", StringEqualsNode.class); + assertThatMainNodeIs("'str' = arg", StringEqualsNode.class); + assertThatMainNodeIs("'str' = var", StringEqualsNode.class); + assertThatMainNodeIs("'str' = ('s' + 'dd')", StringEqualsNode.class); + } +} From 107c989c3460cd39e2400e6f421d699d0f1467d9 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 23 Jan 2022 23:12:10 +0000 Subject: [PATCH 11/38] Add [Non]LocalFieldStringEqualsNode This node inlines the argument and field reading and does the string equal. There's theoretical an early abort for non-object fields. Though, we don't have those in our benchmarks. Well, perhaps uninitialized fields. Though, the structure of the lookup, and caching makes that tricky. Not sure it's worth optimizing that. Signed-off-by: Stefan Marr --- src/trufflesom/compiler/ParserAst.java | 40 ++++ .../interpreter/nodes/ArgumentReadNode.java | 8 + .../LocalFieldStringEqualsNode.java | 172 ++++++++++++++++++ .../NonLocalFieldStringEqualsNode.java | 165 +++++++++++++++++ .../objectstorage/FieldAccessorNode.java | 4 +- .../supernodes/StringEqualsTests.java | 5 +- 6 files changed, 390 insertions(+), 4 deletions(-) create mode 100644 src/trufflesom/interpreter/nodes/supernodes/LocalFieldStringEqualsNode.java create mode 100644 src/trufflesom/interpreter/nodes/supernodes/NonLocalFieldStringEqualsNode.java diff --git a/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/compiler/ParserAst.java index fc257d7b0..9ccd7bc16 100644 --- a/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/compiler/ParserAst.java @@ -29,6 +29,7 @@ import bdt.tools.structure.StructuralProbe; import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.FieldNode; +import trufflesom.interpreter.nodes.FieldNode.FieldReadNode; import trufflesom.interpreter.nodes.GlobalNode; import trufflesom.interpreter.nodes.LocalVariableNode.LocalVariableReadNode; import trufflesom.interpreter.nodes.MessageSendNode; @@ -39,12 +40,15 @@ import trufflesom.interpreter.nodes.literals.GenericLiteralNode; import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; import trufflesom.interpreter.nodes.literals.LiteralNode; +import trufflesom.interpreter.nodes.supernodes.LocalFieldStringEqualsNode; import trufflesom.interpreter.nodes.supernodes.LocalVariableSquareNodeGen; +import trufflesom.interpreter.nodes.supernodes.NonLocalFieldStringEqualsNode; import trufflesom.interpreter.nodes.supernodes.NonLocalVariableSquareNodeGen; import trufflesom.interpreter.nodes.supernodes.StringEqualsNodeGen; import trufflesom.interpreter.supernodes.IntIncrementNodeGen; import trufflesom.primitives.Primitives; import trufflesom.vm.Globals; +import trufflesom.vm.NotYetImplementedException; import trufflesom.vmobjects.SArray; import trufflesom.vmobjects.SClass; import trufflesom.vmobjects.SInvokable; @@ -285,13 +289,49 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, if (operand instanceof GenericLiteralNode) { Object literal = operand.executeGeneric(null); if (literal instanceof String) { + if (receiver instanceof FieldReadNode) { + FieldReadNode fieldRead = (FieldReadNode) receiver; + ExpressionNode self = fieldRead.getSelf(); + if (self instanceof LocalArgumentReadNode) { + return new LocalFieldStringEqualsNode(fieldRead.getFieldIndex(), + ((LocalArgumentReadNode) self).getArg(), (String) literal).initialize( + coordWithL); + } else if (self instanceof NonLocalArgumentReadNode) { + NonLocalArgumentReadNode arg = (NonLocalArgumentReadNode) self; + return new NonLocalFieldStringEqualsNode(fieldRead.getFieldIndex(), + arg.getArg(), arg.getContextLevel(), (String) literal).initialize( + coordWithL); + } else { + throw new NotYetImplementedException(); + } + + } + return StringEqualsNodeGen.create((String) literal, receiver) .initialize(coordWithL); } } + if (receiver instanceof GenericLiteralNode) { Object literal = receiver.executeGeneric(null); if (literal instanceof String) { + if (operand instanceof FieldReadNode) { + FieldReadNode fieldRead = (FieldReadNode) operand; + ExpressionNode self = fieldRead.getSelf(); + if (self instanceof LocalArgumentReadNode) { + return new LocalFieldStringEqualsNode(fieldRead.getFieldIndex(), + ((LocalArgumentReadNode) self).getArg(), (String) literal).initialize( + coordWithL); + } else if (self instanceof NonLocalArgumentReadNode) { + NonLocalArgumentReadNode arg = (NonLocalArgumentReadNode) self; + return new NonLocalFieldStringEqualsNode(fieldRead.getFieldIndex(), + arg.getArg(), arg.getContextLevel(), (String) literal).initialize( + coordWithL); + } else { + throw new NotYetImplementedException(); + } + } + return StringEqualsNodeGen.create((String) literal, operand) .initialize(coordWithL); } diff --git a/src/trufflesom/interpreter/nodes/ArgumentReadNode.java b/src/trufflesom/interpreter/nodes/ArgumentReadNode.java index 6cebf3f16..758e716d6 100644 --- a/src/trufflesom/interpreter/nodes/ArgumentReadNode.java +++ b/src/trufflesom/interpreter/nodes/ArgumentReadNode.java @@ -39,6 +39,10 @@ public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { inliner.updateRead(arg, this, 0); } + public Argument getArg() { + return arg; + } + @Override public SSymbol getInvocationIdentifier() { return arg.name; @@ -118,6 +122,10 @@ public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { inliner.updateRead(arg, this, contextLevel); } + public Argument getArg() { + return arg; + } + @Override public SSymbol getInvocationIdentifier() { return arg.name; diff --git a/src/trufflesom/interpreter/nodes/supernodes/LocalFieldStringEqualsNode.java b/src/trufflesom/interpreter/nodes/supernodes/LocalFieldStringEqualsNode.java new file mode 100644 index 000000000..f28078864 --- /dev/null +++ b/src/trufflesom/interpreter/nodes/supernodes/LocalFieldStringEqualsNode.java @@ -0,0 +1,172 @@ +package trufflesom.interpreter.nodes.supernodes; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.UnexpectedResultException; + +import bd.inlining.ScopeAdaptationVisitor; +import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Argument; +import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.ArgumentReadNode.LocalArgumentReadNode; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.FieldNode.FieldReadNode; +import trufflesom.interpreter.nodes.GenericMessageSendNode; +import trufflesom.interpreter.nodes.MessageSendNode; +import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; +import trufflesom.interpreter.nodes.literals.GenericLiteralNode; +import trufflesom.interpreter.objectstorage.FieldAccessorNode.AbstractReadFieldNode; +import trufflesom.interpreter.objectstorage.FieldAccessorNode.UninitializedReadFieldNode; +import trufflesom.interpreter.objectstorage.ObjectLayout; +import trufflesom.interpreter.objectstorage.StorageLocation; +import trufflesom.vm.SymbolTable; +import trufflesom.vm.VmSettings; +import trufflesom.vm.constants.Nil; +import trufflesom.vmobjects.SObject; + + +public final class LocalFieldStringEqualsNode extends ExpressionNode { + + private final int fieldIdx; + private final String value; + protected final Argument arg; + + @Child private AbstractReadFieldNode readFieldNode; + + @CompilationFinal private int state; + + public LocalFieldStringEqualsNode(final int fieldIdx, final Argument arg, + final String value) { + this.fieldIdx = fieldIdx; + this.arg = arg; + this.value = value; + + this.state = 0; + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + try { + SObject rcvr = (SObject) frame.getArguments()[0]; + return executeEvaluated(frame, rcvr); + } catch (UnexpectedResultException e) { + return e.getResult(); + } + } + + @Override + public Object doPreEvaluated(final VirtualFrame frame, final Object[] args) { + try { + return executeEvaluated(frame, (SObject) args[0]); + } catch (UnexpectedResultException e) { + return e.getResult(); + } + } + + public boolean executeEvaluated(final VirtualFrame frame, final SObject rcvr) + throws UnexpectedResultException { + int currentState = state; + + if (state == 0) { + // uninitialized + CompilerDirectives.transferToInterpreterAndInvalidate(); + final ObjectLayout layout = rcvr.getObjectLayout(); + StorageLocation location = layout.getStorageLocation(fieldIdx); + + readFieldNode = + insert(location.getReadNode(fieldIdx, layout, + new UninitializedReadFieldNode(fieldIdx))); + } + + Object result = readFieldNode.read(rcvr); + + if ((state & 0b1) != 0) { + // we saw a string before + if (result instanceof String) { + return ((String) result).equals(value); + } + } + + if ((state & 0b10) != 0) { + // we saw a nil before + if (result == Nil.nilObject) { + return false; + } + } + + CompilerDirectives.transferToInterpreterAndInvalidate(); + return specialize(frame, result, currentState); + } + + @Override + public boolean executeBoolean(final VirtualFrame frame) throws UnexpectedResultException { + SObject rcvr = (SObject) frame.getArguments()[0]; + + return executeEvaluated(frame, rcvr); + } + + private boolean specialize(final VirtualFrame frame, final Object result, + final int currentState) throws UnexpectedResultException { + if (result instanceof String) { + state = currentState | 0b1; + return value.equals(result); + } + + if (result == Nil.nilObject) { + state = currentState | 0b10; + return false; + } + + Object sendResult = + makeGenericSend(result).doPreEvaluated(frame, new Object[] {result, value}); + if (sendResult instanceof Boolean) { + return (Boolean) sendResult; + } + throw new UnexpectedResultException(sendResult); + } + + public final GenericMessageSendNode makeGenericSend(final Object receiver) { + ExpressionNode[] children; + if (VmSettings.UseAstInterp) { + children = + new ExpressionNode[] {new FieldReadNode(new LocalArgumentReadNode(arg), fieldIdx), + new GenericLiteralNode(value)}; + } else { + children = null; + } + + GenericMessageSendNode send = + MessageSendNode.createGeneric(SymbolTable.symbolFor("="), children, 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); + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + ScopeElement se = inliner.getAdaptedVar(arg); + if (se.var != arg || se.contextLevel < 0) { + Node newNode; + if (se.contextLevel == 0) { + newNode = + new LocalFieldStringEqualsNode(fieldIdx, (Argument) se.var, value).initialize( + fieldIdx); + } else { + newNode = new NonLocalFieldStringEqualsNode(fieldIdx, (Argument) se.var, + se.contextLevel, value).initialize(fieldIdx); + } + + replace(newNode); + } else { + assert 0 == se.contextLevel; + } + } +} diff --git a/src/trufflesom/interpreter/nodes/supernodes/NonLocalFieldStringEqualsNode.java b/src/trufflesom/interpreter/nodes/supernodes/NonLocalFieldStringEqualsNode.java new file mode 100644 index 000000000..96492c6f9 --- /dev/null +++ b/src/trufflesom/interpreter/nodes/supernodes/NonLocalFieldStringEqualsNode.java @@ -0,0 +1,165 @@ +package trufflesom.interpreter.nodes.supernodes; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.UnexpectedResultException; + +import bd.inlining.ScopeAdaptationVisitor; +import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Argument; +import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.ArgumentReadNode.NonLocalArgumentReadNode; +import trufflesom.interpreter.nodes.ContextualNode; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.FieldNode.FieldReadNode; +import trufflesom.interpreter.nodes.GenericMessageSendNode; +import trufflesom.interpreter.nodes.MessageSendNode; +import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; +import trufflesom.interpreter.nodes.literals.GenericLiteralNode; +import trufflesom.interpreter.objectstorage.FieldAccessorNode.AbstractReadFieldNode; +import trufflesom.interpreter.objectstorage.FieldAccessorNode.UninitializedReadFieldNode; +import trufflesom.interpreter.objectstorage.ObjectLayout; +import trufflesom.interpreter.objectstorage.StorageLocation; +import trufflesom.vm.SymbolTable; +import trufflesom.vm.VmSettings; +import trufflesom.vm.constants.Nil; +import trufflesom.vmobjects.SObject; + + +public class NonLocalFieldStringEqualsNode extends ContextualNode { + + private final int fieldIdx; + private final String value; + protected final Argument arg; + + @Child private AbstractReadFieldNode readFieldNode; + + @CompilationFinal private int state; + + public NonLocalFieldStringEqualsNode(final int fieldIdx, final Argument arg, + final int contextLevel, final String value) { + super(contextLevel); + this.fieldIdx = fieldIdx; + this.arg = arg; + this.value = value; + + this.state = 0; + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + try { + SObject rcvr = (SObject) determineContext(frame).getArguments()[0]; + return executeEvaluated(frame, rcvr); + } catch (UnexpectedResultException e) { + return e.getResult(); + } + } + + public boolean executeEvaluated(final VirtualFrame frame, final SObject rcvr) + throws UnexpectedResultException { + int currentState = state; + + if (state == 0) { + // uninitialized + CompilerDirectives.transferToInterpreterAndInvalidate(); + final ObjectLayout layout = rcvr.getObjectLayout(); + StorageLocation location = layout.getStorageLocation(fieldIdx); + + readFieldNode = + insert(location.getReadNode(fieldIdx, layout, + new UninitializedReadFieldNode(fieldIdx))); + } + + Object result = readFieldNode.read(rcvr); + + if ((state & 0b1) != 0) { + // we saw a string before + if (result instanceof String) { + return ((String) result).equals(value); + } + } + + if ((state & 0b10) != 0) { + // we saw a nil before + if (result == Nil.nilObject) { + return false; + } + } + + CompilerDirectives.transferToInterpreterAndInvalidate(); + return specialize(frame, result, currentState); + } + + @Override + public boolean executeBoolean(final VirtualFrame frame) throws UnexpectedResultException { + SObject rcvr = (SObject) determineContext(frame).getArguments()[0]; + + return executeEvaluated(frame, rcvr); + } + + private boolean specialize(final VirtualFrame frame, final Object result, + final int currentState) throws UnexpectedResultException { + if (result instanceof String) { + state = currentState | 0b1; + return value.equals(result); + } + + if (result == Nil.nilObject) { + state = currentState | 0b10; + } + + Object sendResult = + makeGenericSend(result).doPreEvaluated(frame, new Object[] {result, value}); + if (sendResult instanceof Boolean) { + return (Boolean) sendResult; + } + throw new UnexpectedResultException(sendResult); + } + + public final GenericMessageSendNode makeGenericSend(final Object receiver) { + ExpressionNode[] children; + if (VmSettings.UseAstInterp) { + children = + new ExpressionNode[] { + new FieldReadNode(new NonLocalArgumentReadNode(arg, contextLevel), fieldIdx), + new GenericLiteralNode(value)}; + } else { + children = null; + } + + GenericMessageSendNode send = + MessageSendNode.createGeneric(SymbolTable.symbolFor("="), children, 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); + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + ScopeElement se = inliner.getAdaptedVar(arg); + if (se.var != arg || se.contextLevel < contextLevel) { + Node newNode; + if (se.contextLevel == 0) { + newNode = + new LocalFieldStringEqualsNode(fieldIdx, (Argument) se.var, value).initialize( + fieldIdx); + } else { + newNode = new NonLocalFieldStringEqualsNode(fieldIdx, (Argument) se.var, + se.contextLevel, value).initialize(fieldIdx); + } + + replace(newNode); + } else { + assert contextLevel == se.contextLevel; + } + } +} diff --git a/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java b/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java index 1b5b71429..7d90c4794 100644 --- a/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java +++ b/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java @@ -84,9 +84,9 @@ protected final AbstractReadFieldNode specialize(final SObject obj, } } - private static final class UninitializedReadFieldNode extends AbstractReadFieldNode { + public static final class UninitializedReadFieldNode extends AbstractReadFieldNode { - UninitializedReadFieldNode(final int fieldIndex) { + public UninitializedReadFieldNode(final int fieldIndex) { super(fieldIndex); } diff --git a/tests/trufflesom/supernodes/StringEqualsTests.java b/tests/trufflesom/supernodes/StringEqualsTests.java index 92b29e7b2..cce01128d 100644 --- a/tests/trufflesom/supernodes/StringEqualsTests.java +++ b/tests/trufflesom/supernodes/StringEqualsTests.java @@ -7,6 +7,7 @@ import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.SequenceNode; +import trufflesom.interpreter.nodes.supernodes.LocalFieldStringEqualsNode; import trufflesom.interpreter.nodes.supernodes.StringEqualsNode; import trufflesom.tests.AstTestSetup; @@ -26,12 +27,12 @@ private T assertThatMainNodeIs(final String test, final Class expectedNod @Test public void testStringEqual() { - assertThatMainNodeIs("field = 'str'", StringEqualsNode.class); + assertThatMainNodeIs("field = 'str'", LocalFieldStringEqualsNode.class); assertThatMainNodeIs("arg = 'str'", StringEqualsNode.class); assertThatMainNodeIs("var = 'str'", StringEqualsNode.class); assertThatMainNodeIs("('s' + 'dd') = 'str'", StringEqualsNode.class); - assertThatMainNodeIs("'str' = field", StringEqualsNode.class); + assertThatMainNodeIs("'str' = field", LocalFieldStringEqualsNode.class); assertThatMainNodeIs("'str' = arg", StringEqualsNode.class); assertThatMainNodeIs("'str' = var", StringEqualsNode.class); assertThatMainNodeIs("'str' = ('s' + 'dd')", StringEqualsNode.class); From 57b868f2cb12c77d5771d0336943c156757bf775 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Mon, 24 Jan 2022 16:14:44 +0000 Subject: [PATCH 12/38] Adapt to use createGenericBinary Signed-off-by: Stefan Marr --- .../LocalFieldStringEqualsNode.java | 19 ++++++----------- .../NonLocalFieldStringEqualsNode.java | 21 ++++++------------- .../nodes/supernodes/StringEqualsNode.java | 16 +++++--------- 3 files changed, 17 insertions(+), 39 deletions(-) diff --git a/src/trufflesom/interpreter/nodes/supernodes/LocalFieldStringEqualsNode.java b/src/trufflesom/interpreter/nodes/supernodes/LocalFieldStringEqualsNode.java index f28078864..f88c775b3 100644 --- a/src/trufflesom/interpreter/nodes/supernodes/LocalFieldStringEqualsNode.java +++ b/src/trufflesom/interpreter/nodes/supernodes/LocalFieldStringEqualsNode.java @@ -10,10 +10,10 @@ import bd.inlining.ScopeAdaptationVisitor.ScopeElement; import trufflesom.compiler.Variable.Argument; import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.AbstractMessageSendNode; import trufflesom.interpreter.nodes.ArgumentReadNode.LocalArgumentReadNode; import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.FieldNode.FieldReadNode; -import trufflesom.interpreter.nodes.GenericMessageSendNode; import trufflesom.interpreter.nodes.MessageSendNode; import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; import trufflesom.interpreter.nodes.literals.GenericLiteralNode; @@ -127,18 +127,11 @@ private boolean specialize(final VirtualFrame frame, final Object result, throw new UnexpectedResultException(sendResult); } - public final GenericMessageSendNode makeGenericSend(final Object receiver) { - ExpressionNode[] children; - if (VmSettings.UseAstInterp) { - children = - new ExpressionNode[] {new FieldReadNode(new LocalArgumentReadNode(arg), fieldIdx), - new GenericLiteralNode(value)}; - } else { - children = null; - } - - GenericMessageSendNode send = - MessageSendNode.createGeneric(SymbolTable.symbolFor("="), children, sourceCoord); + public AbstractMessageSendNode makeGenericSend(final Object receiver) { + AbstractMessageSendNode send = + MessageSendNode.createGenericBinary(SymbolTable.symbolFor("="), + new FieldReadNode(new LocalArgumentReadNode(arg), fieldIdx), + new GenericLiteralNode(value), sourceCoord); if (VmSettings.UseAstInterp) { replace(send); diff --git a/src/trufflesom/interpreter/nodes/supernodes/NonLocalFieldStringEqualsNode.java b/src/trufflesom/interpreter/nodes/supernodes/NonLocalFieldStringEqualsNode.java index 96492c6f9..af4f5329f 100644 --- a/src/trufflesom/interpreter/nodes/supernodes/NonLocalFieldStringEqualsNode.java +++ b/src/trufflesom/interpreter/nodes/supernodes/NonLocalFieldStringEqualsNode.java @@ -10,11 +10,10 @@ import bd.inlining.ScopeAdaptationVisitor.ScopeElement; import trufflesom.compiler.Variable.Argument; import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.AbstractMessageSendNode; import trufflesom.interpreter.nodes.ArgumentReadNode.NonLocalArgumentReadNode; import trufflesom.interpreter.nodes.ContextualNode; -import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.FieldNode.FieldReadNode; -import trufflesom.interpreter.nodes.GenericMessageSendNode; import trufflesom.interpreter.nodes.MessageSendNode; import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; import trufflesom.interpreter.nodes.literals.GenericLiteralNode; @@ -119,19 +118,11 @@ private boolean specialize(final VirtualFrame frame, final Object result, throw new UnexpectedResultException(sendResult); } - public final GenericMessageSendNode makeGenericSend(final Object receiver) { - ExpressionNode[] children; - if (VmSettings.UseAstInterp) { - children = - new ExpressionNode[] { - new FieldReadNode(new NonLocalArgumentReadNode(arg, contextLevel), fieldIdx), - new GenericLiteralNode(value)}; - } else { - children = null; - } - - GenericMessageSendNode send = - MessageSendNode.createGeneric(SymbolTable.symbolFor("="), children, sourceCoord); + public final AbstractMessageSendNode makeGenericSend(final Object receiver) { + AbstractMessageSendNode send = + MessageSendNode.createGenericBinary(SymbolTable.symbolFor("="), + new FieldReadNode(new NonLocalArgumentReadNode(arg, contextLevel), fieldIdx), + new GenericLiteralNode(value), sourceCoord); if (VmSettings.UseAstInterp) { replace(send); diff --git a/src/trufflesom/interpreter/nodes/supernodes/StringEqualsNode.java b/src/trufflesom/interpreter/nodes/supernodes/StringEqualsNode.java index b36bdf4a3..5013c4363 100644 --- a/src/trufflesom/interpreter/nodes/supernodes/StringEqualsNode.java +++ b/src/trufflesom/interpreter/nodes/supernodes/StringEqualsNode.java @@ -6,8 +6,8 @@ import com.oracle.truffle.api.frame.VirtualFrame; import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.AbstractMessageSendNode; import trufflesom.interpreter.nodes.ExpressionNode; -import trufflesom.interpreter.nodes.GenericMessageSendNode; import trufflesom.interpreter.nodes.MessageSendNode; import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; import trufflesom.interpreter.nodes.literals.GenericLiteralNode; @@ -49,17 +49,11 @@ public final Object makeGenericSend(final VirtualFrame frame, } @Override - protected GenericMessageSendNode makeGenericSend(final SSymbol selector) { + protected AbstractMessageSendNode makeGenericSend(final SSymbol selector) { CompilerDirectives.transferToInterpreterAndInvalidate(); - ExpressionNode[] children; - if (VmSettings.UseAstInterp) { - children = new ExpressionNode[] {getReceiver(), new GenericLiteralNode(value)}; - } else { - children = null; - } - - GenericMessageSendNode send = - MessageSendNode.createGeneric(selector, children, sourceCoord); + AbstractMessageSendNode send = + MessageSendNode.createGenericBinary(selector, getReceiver(), + new GenericLiteralNode(value), sourceCoord); if (VmSettings.UseAstInterp) { replace(send); From e9a6922cbc02bbca0e4bb4e50635866034d05c86 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Mon, 24 Jan 2022 16:18:53 +0000 Subject: [PATCH 13/38] Move all supernodes to same package Signed-off-by: Stefan Marr --- src/trufflesom/compiler/MethodGenerationContext.java | 4 ++-- src/trufflesom/compiler/ParserAst.java | 10 +++++----- src/trufflesom/compiler/Variable.java | 8 ++++---- .../supernodes/LocalFieldStringEqualsNode.java | 2 +- .../supernodes/LocalVariableReadSquareWriteNode.java | 2 +- .../supernodes/LocalVariableSquareNode.java | 2 +- .../supernodes/NonLocalFieldStringEqualsNode.java | 2 +- .../NonLocalVariableReadSquareWriteNode.java | 2 +- .../supernodes/NonLocalVariableSquareNode.java | 2 +- .../{nodes => }/supernodes/StringEqualsNode.java | 2 +- tests/trufflesom/supernodes/SquareTests.java | 8 ++++---- tests/trufflesom/supernodes/StringEqualsTests.java | 4 ++-- 12 files changed, 24 insertions(+), 24 deletions(-) rename src/trufflesom/interpreter/{nodes => }/supernodes/LocalFieldStringEqualsNode.java (99%) rename src/trufflesom/interpreter/{nodes => }/supernodes/LocalVariableReadSquareWriteNode.java (98%) rename src/trufflesom/interpreter/{nodes => }/supernodes/LocalVariableSquareNode.java (96%) rename src/trufflesom/interpreter/{nodes => }/supernodes/NonLocalFieldStringEqualsNode.java (99%) rename src/trufflesom/interpreter/{nodes => }/supernodes/NonLocalVariableReadSquareWriteNode.java (98%) rename src/trufflesom/interpreter/{nodes => }/supernodes/NonLocalVariableSquareNode.java (97%) rename src/trufflesom/interpreter/{nodes => }/supernodes/StringEqualsNode.java (97%) diff --git a/src/trufflesom/compiler/MethodGenerationContext.java b/src/trufflesom/compiler/MethodGenerationContext.java index 04a10e76d..367f86b84 100644 --- a/src/trufflesom/compiler/MethodGenerationContext.java +++ b/src/trufflesom/compiler/MethodGenerationContext.java @@ -55,9 +55,9 @@ import trufflesom.interpreter.nodes.ReturnNonLocalNode; import trufflesom.interpreter.nodes.ReturnNonLocalNode.CatchNonLocalReturnNode; import trufflesom.interpreter.nodes.literals.BlockNode; -import trufflesom.interpreter.nodes.supernodes.LocalVariableSquareNode; -import trufflesom.interpreter.nodes.supernodes.NonLocalVariableSquareNode; import trufflesom.interpreter.supernodes.IntIncrementNode; +import trufflesom.interpreter.supernodes.LocalVariableSquareNode; +import trufflesom.interpreter.supernodes.NonLocalVariableSquareNode; import trufflesom.primitives.Primitives; import trufflesom.vm.NotYetImplementedException; import trufflesom.vm.constants.Nil; diff --git a/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/compiler/ParserAst.java index 9ccd7bc16..5cc593476 100644 --- a/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/compiler/ParserAst.java @@ -40,12 +40,12 @@ import trufflesom.interpreter.nodes.literals.GenericLiteralNode; import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; import trufflesom.interpreter.nodes.literals.LiteralNode; -import trufflesom.interpreter.nodes.supernodes.LocalFieldStringEqualsNode; -import trufflesom.interpreter.nodes.supernodes.LocalVariableSquareNodeGen; -import trufflesom.interpreter.nodes.supernodes.NonLocalFieldStringEqualsNode; -import trufflesom.interpreter.nodes.supernodes.NonLocalVariableSquareNodeGen; -import trufflesom.interpreter.nodes.supernodes.StringEqualsNodeGen; 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.primitives.Primitives; import trufflesom.vm.Globals; import trufflesom.vm.NotYetImplementedException; diff --git a/src/trufflesom/compiler/Variable.java b/src/trufflesom/compiler/Variable.java index 119697c05..149c22491 100644 --- a/src/trufflesom/compiler/Variable.java +++ b/src/trufflesom/compiler/Variable.java @@ -26,12 +26,12 @@ import trufflesom.interpreter.nodes.LocalVariableNodeFactory.LocalVariableWriteNodeGen; import trufflesom.interpreter.nodes.NonLocalVariableNodeFactory.NonLocalVariableReadNodeGen; import trufflesom.interpreter.nodes.NonLocalVariableNodeFactory.NonLocalVariableWriteNodeGen; -import trufflesom.interpreter.nodes.supernodes.LocalVariableReadSquareWriteNodeGen; -import trufflesom.interpreter.nodes.supernodes.LocalVariableSquareNodeGen; -import trufflesom.interpreter.nodes.supernodes.NonLocalVariableReadSquareWriteNodeGen; -import trufflesom.interpreter.nodes.supernodes.NonLocalVariableSquareNodeGen; import trufflesom.interpreter.supernodes.LocalVariableIncNodeGen; +import trufflesom.interpreter.supernodes.LocalVariableReadSquareWriteNodeGen; +import trufflesom.interpreter.supernodes.LocalVariableSquareNodeGen; import trufflesom.interpreter.supernodes.NonLocalVariableIncNodeGen; +import trufflesom.interpreter.supernodes.NonLocalVariableReadSquareWriteNodeGen; +import trufflesom.interpreter.supernodes.NonLocalVariableSquareNodeGen; import trufflesom.vm.NotYetImplementedException; import trufflesom.vmobjects.SSymbol; diff --git a/src/trufflesom/interpreter/nodes/supernodes/LocalFieldStringEqualsNode.java b/src/trufflesom/interpreter/supernodes/LocalFieldStringEqualsNode.java similarity index 99% rename from src/trufflesom/interpreter/nodes/supernodes/LocalFieldStringEqualsNode.java rename to src/trufflesom/interpreter/supernodes/LocalFieldStringEqualsNode.java index f88c775b3..b54569147 100644 --- a/src/trufflesom/interpreter/nodes/supernodes/LocalFieldStringEqualsNode.java +++ b/src/trufflesom/interpreter/supernodes/LocalFieldStringEqualsNode.java @@ -1,4 +1,4 @@ -package trufflesom.interpreter.nodes.supernodes; +package trufflesom.interpreter.supernodes; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; diff --git a/src/trufflesom/interpreter/nodes/supernodes/LocalVariableReadSquareWriteNode.java b/src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java similarity index 98% rename from src/trufflesom/interpreter/nodes/supernodes/LocalVariableReadSquareWriteNode.java rename to src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java index d5542c74a..c4c99eb57 100644 --- a/src/trufflesom/interpreter/nodes/supernodes/LocalVariableReadSquareWriteNode.java +++ b/src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java @@ -1,4 +1,4 @@ -package trufflesom.interpreter.nodes.supernodes; +package trufflesom.interpreter.supernodes; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.FrameSlot; diff --git a/src/trufflesom/interpreter/nodes/supernodes/LocalVariableSquareNode.java b/src/trufflesom/interpreter/supernodes/LocalVariableSquareNode.java similarity index 96% rename from src/trufflesom/interpreter/nodes/supernodes/LocalVariableSquareNode.java rename to src/trufflesom/interpreter/supernodes/LocalVariableSquareNode.java index 945c3d07b..01ba57411 100644 --- a/src/trufflesom/interpreter/nodes/supernodes/LocalVariableSquareNode.java +++ b/src/trufflesom/interpreter/supernodes/LocalVariableSquareNode.java @@ -1,4 +1,4 @@ -package trufflesom.interpreter.nodes.supernodes; +package trufflesom.interpreter.supernodes; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.FrameSlotTypeException; diff --git a/src/trufflesom/interpreter/nodes/supernodes/NonLocalFieldStringEqualsNode.java b/src/trufflesom/interpreter/supernodes/NonLocalFieldStringEqualsNode.java similarity index 99% rename from src/trufflesom/interpreter/nodes/supernodes/NonLocalFieldStringEqualsNode.java rename to src/trufflesom/interpreter/supernodes/NonLocalFieldStringEqualsNode.java index af4f5329f..71215b6ab 100644 --- a/src/trufflesom/interpreter/nodes/supernodes/NonLocalFieldStringEqualsNode.java +++ b/src/trufflesom/interpreter/supernodes/NonLocalFieldStringEqualsNode.java @@ -1,4 +1,4 @@ -package trufflesom.interpreter.nodes.supernodes; +package trufflesom.interpreter.supernodes; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; diff --git a/src/trufflesom/interpreter/nodes/supernodes/NonLocalVariableReadSquareWriteNode.java b/src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java similarity index 98% rename from src/trufflesom/interpreter/nodes/supernodes/NonLocalVariableReadSquareWriteNode.java rename to src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java index 081391b8a..57c061bf0 100644 --- a/src/trufflesom/interpreter/nodes/supernodes/NonLocalVariableReadSquareWriteNode.java +++ b/src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java @@ -1,4 +1,4 @@ -package trufflesom.interpreter.nodes.supernodes; +package trufflesom.interpreter.supernodes; import static trufflesom.interpreter.TruffleCompiler.transferToInterpreter; diff --git a/src/trufflesom/interpreter/nodes/supernodes/NonLocalVariableSquareNode.java b/src/trufflesom/interpreter/supernodes/NonLocalVariableSquareNode.java similarity index 97% rename from src/trufflesom/interpreter/nodes/supernodes/NonLocalVariableSquareNode.java rename to src/trufflesom/interpreter/supernodes/NonLocalVariableSquareNode.java index 38ccfd252..bc3ba183d 100644 --- a/src/trufflesom/interpreter/nodes/supernodes/NonLocalVariableSquareNode.java +++ b/src/trufflesom/interpreter/supernodes/NonLocalVariableSquareNode.java @@ -1,4 +1,4 @@ -package trufflesom.interpreter.nodes.supernodes; +package trufflesom.interpreter.supernodes; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Specialization; diff --git a/src/trufflesom/interpreter/nodes/supernodes/StringEqualsNode.java b/src/trufflesom/interpreter/supernodes/StringEqualsNode.java similarity index 97% rename from src/trufflesom/interpreter/nodes/supernodes/StringEqualsNode.java rename to src/trufflesom/interpreter/supernodes/StringEqualsNode.java index 5013c4363..b6ad44828 100644 --- a/src/trufflesom/interpreter/nodes/supernodes/StringEqualsNode.java +++ b/src/trufflesom/interpreter/supernodes/StringEqualsNode.java @@ -1,4 +1,4 @@ -package trufflesom.interpreter.nodes.supernodes; +package trufflesom.interpreter.supernodes; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Fallback; diff --git a/tests/trufflesom/supernodes/SquareTests.java b/tests/trufflesom/supernodes/SquareTests.java index 23470781a..54d8bb96a 100644 --- a/tests/trufflesom/supernodes/SquareTests.java +++ b/tests/trufflesom/supernodes/SquareTests.java @@ -11,10 +11,10 @@ import trufflesom.interpreter.nodes.NonLocalVariableNode.NonLocalVariableWriteNode; import trufflesom.interpreter.nodes.SequenceNode; import trufflesom.interpreter.nodes.literals.BlockNode; -import trufflesom.interpreter.nodes.supernodes.LocalVariableReadSquareWriteNode; -import trufflesom.interpreter.nodes.supernodes.LocalVariableSquareNode; -import trufflesom.interpreter.nodes.supernodes.NonLocalVariableReadSquareWriteNode; -import trufflesom.interpreter.nodes.supernodes.NonLocalVariableSquareNode; +import trufflesom.interpreter.supernodes.LocalVariableReadSquareWriteNode; +import trufflesom.interpreter.supernodes.LocalVariableSquareNode; +import trufflesom.interpreter.supernodes.NonLocalVariableReadSquareWriteNode; +import trufflesom.interpreter.supernodes.NonLocalVariableSquareNode; import trufflesom.primitives.arithmetic.MultiplicationPrim; import trufflesom.tests.AstTestSetup; diff --git a/tests/trufflesom/supernodes/StringEqualsTests.java b/tests/trufflesom/supernodes/StringEqualsTests.java index cce01128d..e35b4a070 100644 --- a/tests/trufflesom/supernodes/StringEqualsTests.java +++ b/tests/trufflesom/supernodes/StringEqualsTests.java @@ -7,8 +7,8 @@ import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.SequenceNode; -import trufflesom.interpreter.nodes.supernodes.LocalFieldStringEqualsNode; -import trufflesom.interpreter.nodes.supernodes.StringEqualsNode; +import trufflesom.interpreter.supernodes.LocalFieldStringEqualsNode; +import trufflesom.interpreter.supernodes.StringEqualsNode; import trufflesom.tests.AstTestSetup; From 348f90a2eeb9d6e1d6e4f52a70a0194dbd48c047 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Tue, 25 Jan 2022 23:54:37 +0000 Subject: [PATCH 14/38] Restructure the Increment super nodes to support field increment with some other expression Signed-off-by: Stefan Marr --- .../nodes/bc/BytecodeLoopNode.java | 2 +- .../objectstorage/FieldAccessorNode.java | 15 ++-- .../interpreter/supernodes/IncFieldNode.java | 19 ++++- .../supernodes/IntIncFieldNode.java | 47 ++++++++++++ .../supernodes/IntIncrementNode.java | 3 +- ...ncNode.java => IntUninitIncFieldNode.java} | 8 +- .../supernodes/UninitIncFieldNode.java | 74 +++++++++++++++++++ .../supernodes/IncrementOpTests.java | 28 +++++-- tests/trufflesom/tests/AstInliningTests.java | 6 +- 9 files changed, 175 insertions(+), 27 deletions(-) create mode 100644 src/trufflesom/interpreter/supernodes/IntIncFieldNode.java rename src/trufflesom/interpreter/supernodes/{UninitFieldIncNode.java => IntUninitIncFieldNode.java} (87%) create mode 100644 src/trufflesom/interpreter/supernodes/UninitIncFieldNode.java diff --git a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java index 2b3352bed..5b63a8e6c 100644 --- a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java +++ b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java @@ -874,7 +874,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_THREE_ARGS; diff --git a/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java b/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java index 7d90c4794..cdb8ba59a 100644 --- a/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java +++ b/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java @@ -31,9 +31,9 @@ public static AbstractWriteFieldNode createWrite(final int fieldIndex) { @InliningCutoff public static IncrementLongFieldNode createIncrement(final int fieldIndex, - final SObject obj, final long incValue) { + final SObject obj) { final ObjectLayout layout = obj.getObjectLayout(); - return new IncrementLongFieldNode(fieldIndex, layout, incValue); + return new IncrementLongFieldNode(fieldIndex, layout); } private FieldAccessorNode(final int fieldIndex) { @@ -324,16 +324,13 @@ protected final boolean hasExpectedLayout(final SObject obj) public static final class IncrementLongFieldNode extends FieldAccessorNode { protected final ObjectLayout layout; private final LongStorageLocation storage; - private final long incValue; @Child protected IncrementLongFieldNode nextInCache; - public IncrementLongFieldNode(final int fieldIndex, final ObjectLayout layout, - final long incValue) { + public IncrementLongFieldNode(final int fieldIndex, final ObjectLayout layout) { super(fieldIndex); this.layout = layout; this.storage = (LongStorageLocation) layout.getStorageLocation(fieldIndex); - this.incValue = incValue; } protected boolean hasExpectedLayout(final SObject obj) @@ -342,13 +339,13 @@ protected 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, incValue); } else { ensureNext(obj); - return nextInCache.increment(obj); + return nextInCache.increment(obj, incValue); } } catch (InvalidAssumptionException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -366,7 +363,7 @@ private long dropAndIncrementNext(final SObject obj) { private void ensureNext(final SObject obj) { if (nextInCache == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - nextInCache = new IncrementLongFieldNode(fieldIndex, obj.getObjectLayout(), incValue); + nextInCache = new IncrementLongFieldNode(fieldIndex, obj.getObjectLayout()); } } } diff --git a/src/trufflesom/interpreter/supernodes/IncFieldNode.java b/src/trufflesom/interpreter/supernodes/IncFieldNode.java index 8534b1390..f23d390b6 100644 --- a/src/trufflesom/interpreter/supernodes/IncFieldNode.java +++ b/src/trufflesom/interpreter/supernodes/IncFieldNode.java @@ -2,21 +2,25 @@ 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; final class IncFieldNode extends FieldNode { @Child private ExpressionNode self; + @Child private ExpressionNode valueExpr; @Child private IncrementLongFieldNode inc; - IncFieldNode(final ExpressionNode self, final IncrementLongFieldNode inc, - final long coord) { + IncFieldNode(final ExpressionNode self, final ExpressionNode valueExpr, + final IncrementLongFieldNode inc, final long coord) { initialize(coord); this.self = self; + this.valueExpr = valueExpr; this.inc = inc; } @@ -39,6 +43,15 @@ public Object executeGeneric(final VirtualFrame frame) { @Override public long executeLong(final VirtualFrame frame) { SObject obj = (SObject) self.executeGeneric(frame); - return inc.increment(obj); + 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/interpreter/supernodes/IntIncFieldNode.java b/src/trufflesom/interpreter/supernodes/IntIncFieldNode.java new file mode 100644 index 000000000..fdb680154 --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/IntIncFieldNode.java @@ -0,0 +1,47 @@ +package trufflesom.interpreter.supernodes; + +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; + + +final class IntIncFieldNode extends FieldNode { + @Child private ExpressionNode self; + @Child private IncrementLongFieldNode inc; + + private final long incValue; + + IntIncFieldNode(final ExpressionNode self, final IncrementLongFieldNode inc, + final long incValue, final long coord) { + 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/interpreter/supernodes/IntIncrementNode.java b/src/trufflesom/interpreter/supernodes/IntIncrementNode.java index dd7fb16fd..4fc016c84 100644 --- a/src/trufflesom/interpreter/supernodes/IntIncrementNode.java +++ b/src/trufflesom/interpreter/supernodes/IntIncrementNode.java @@ -112,7 +112,7 @@ protected AbstractMessageSendNode makeGenericSend() { public FieldNode createFieldIncNode(final ExpressionNode self, final int fieldIndex, final long coord) { - return new UninitFieldIncNode(self, fieldIndex, coord, incValue); + return new IntUninitIncFieldNode(self, fieldIndex, coord, incValue); } public ExpressionNode createIncNode(final Local local, final int ctxLevel) { @@ -122,5 +122,4 @@ public ExpressionNode createIncNode(final Local local, final int ctxLevel) { return NonLocalVariableIncNodeGen.create(ctxLevel, local, incValue) .initialize(sourceCoord); } - } diff --git a/src/trufflesom/interpreter/supernodes/UninitFieldIncNode.java b/src/trufflesom/interpreter/supernodes/IntUninitIncFieldNode.java similarity index 87% rename from src/trufflesom/interpreter/supernodes/UninitFieldIncNode.java rename to src/trufflesom/interpreter/supernodes/IntUninitIncFieldNode.java index 44d688ce4..4337a0909 100644 --- a/src/trufflesom/interpreter/supernodes/UninitFieldIncNode.java +++ b/src/trufflesom/interpreter/supernodes/IntUninitIncFieldNode.java @@ -11,13 +11,13 @@ import trufflesom.vmobjects.SObject; -public final class UninitFieldIncNode extends FieldNode { +public final class IntUninitIncFieldNode extends FieldNode { @Child private ExpressionNode self; private final int fieldIndex; private final long incValue; - public UninitFieldIncNode(final ExpressionNode self, final int fieldIndex, + public IntUninitIncFieldNode(final ExpressionNode self, final int fieldIndex, final long coord, final long value) { this.self = self; this.fieldIndex = fieldIndex; @@ -54,8 +54,8 @@ public Object executeGeneric(final VirtualFrame frame) { throw new NotYetImplementedException(); } - IncrementLongFieldNode node = FieldAccessorNode.createIncrement(fieldIndex, obj, incValue); - IncFieldNode incNode = new IncFieldNode(self, node, sourceCoord); + IncrementLongFieldNode node = FieldAccessorNode.createIncrement(fieldIndex, obj); + IntIncFieldNode incNode = new IntIncFieldNode(self, node, incValue, sourceCoord); replace(incNode); node.notifyAsInserted(); diff --git a/src/trufflesom/interpreter/supernodes/UninitIncFieldNode.java b/src/trufflesom/interpreter/supernodes/UninitIncFieldNode.java new file mode 100644 index 000000000..308a885fa --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/UninitIncFieldNode.java @@ -0,0 +1,74 @@ +package trufflesom.interpreter.supernodes; + +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; +import trufflesom.interpreter.objectstorage.FieldAccessorNode.IncrementLongFieldNode; +import trufflesom.vm.NotYetImplementedException; +import trufflesom.vmobjects.SObject; + + +public final class UninitIncFieldNode extends FieldNode { + + @Child private ExpressionNode self; + @Child private ExpressionNode valueExpr; + + private final int fieldIndex; + + public UninitIncFieldNode(final ExpressionNode self, final ExpressionNode valueExpr, + final int fieldIndex, + final long coord) { + this.self = self; + this.valueExpr = valueExpr; + 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) { + throw new NotYetImplementedException(); + } + + 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); + IncFieldNode incNode = new IncFieldNode(self, valueExpr, node, sourceCoord); + replace(incNode); + node.notifyAsInserted(); + + return longVal; + } +} diff --git a/tests/trufflesom/supernodes/IncrementOpTests.java b/tests/trufflesom/supernodes/IncrementOpTests.java index 9f721dc84..9f9762161 100644 --- a/tests/trufflesom/supernodes/IncrementOpTests.java +++ b/tests/trufflesom/supernodes/IncrementOpTests.java @@ -12,9 +12,10 @@ import trufflesom.interpreter.nodes.literals.BlockNode; import trufflesom.interpreter.nodes.specialized.IfInlinedLiteralNode; import trufflesom.interpreter.supernodes.IntIncrementNode; +import trufflesom.interpreter.supernodes.IntUninitIncFieldNode; import trufflesom.interpreter.supernodes.LocalVariableIncNode; import trufflesom.interpreter.supernodes.NonLocalVariableIncNode; -import trufflesom.interpreter.supernodes.UninitFieldIncNode; +import trufflesom.interpreter.supernodes.UninitIncFieldNode; import trufflesom.tests.AstTestSetup; @@ -80,10 +81,27 @@ public void testIfTrueAndIncArg() { @Test public void testFieldInc() { - basicAddOrSubtract("field := field + 1", 1, UninitFieldIncNode.class); - basicAddOrSubtract("field := field - 1", -1, UninitFieldIncNode.class); - basicAddOrSubtract("field := field + 1123", 1123, UninitFieldIncNode.class); - basicAddOrSubtract("field := field - 234234", -234234, UninitFieldIncNode.class); + basicAddOrSubtract("field := field + 1", 1, IntUninitIncFieldNode.class); + basicAddOrSubtract("field := field - 1", -1, IntUninitIncFieldNode.class); + basicAddOrSubtract("field := field + 1123", 1123, IntUninitIncFieldNode.class); + basicAddOrSubtract("field := field - 234234", -234234, IntUninitIncFieldNode.class); + + } + + private void fieldIncWithExpr(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() { + fieldIncWithExpr("field := field + (23 + 434)", UninitIncFieldNode.class); + fieldIncWithExpr("field := field + var", UninitIncFieldNode.class); + fieldIncWithExpr("field := field + arg", UninitIncFieldNode.class); } @Test diff --git a/tests/trufflesom/tests/AstInliningTests.java b/tests/trufflesom/tests/AstInliningTests.java index d8d0a5596..c8d759845 100644 --- a/tests/trufflesom/tests/AstInliningTests.java +++ b/tests/trufflesom/tests/AstInliningTests.java @@ -35,7 +35,7 @@ import trufflesom.interpreter.nodes.specialized.IntToDoInlinedLiteralsNode; import trufflesom.interpreter.nodes.specialized.whileloops.WhileInlinedLiteralsNode; import trufflesom.interpreter.supernodes.NonLocalVariableIncNode; -import trufflesom.interpreter.supernodes.UninitFieldIncNode; +import trufflesom.interpreter.supernodes.IntUninitIncFieldNode; import trufflesom.primitives.arithmetic.SubtractionPrim; import trufflesom.primitives.arrays.DoPrim; @@ -144,7 +144,7 @@ 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); + IntUninitIncFieldNode incNode = read(ifNode, "bodyNode", IntUninitIncFieldNode.class); int fieldIdx = read(incNode, "fieldIndex", Integer.class); assertEquals(0, fieldIdx); @@ -344,7 +344,7 @@ public void testBlockBlockInlinedSelf() { assertEquals("b", readB.getInvocationIdentifier().getString()); assertEquals(1, readB.argumentIndex); - UninitFieldIncNode incNode = read(blockBIfTrue, "bodyNode", UninitFieldIncNode.class); + IntUninitIncFieldNode incNode = read(blockBIfTrue, "bodyNode", IntUninitIncFieldNode.class); NonLocalArgumentReadNode selfNode = (NonLocalArgumentReadNode) incNode.getSelf(); assertEquals(2, selfNode.getContextLevel()); assertEquals(0, (int) read(incNode, "fieldIndex", Integer.class)); From e004beae51d90c28ac53fcdb9e226a31623badb0 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 26 Jan 2022 00:36:00 +0000 Subject: [PATCH 15/38] Add fallback code for UninitIncFieldNode, SomSom needs it... SomSom's parser also has `text := text + self currentChar.` where `text` is a field in the lexer. Signed-off-by: Stefan Marr --- .../supernodes/UninitIncFieldNode.java | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/trufflesom/interpreter/supernodes/UninitIncFieldNode.java b/src/trufflesom/interpreter/supernodes/UninitIncFieldNode.java index 308a885fa..5ed2f8772 100644 --- a/src/trufflesom/interpreter/supernodes/UninitIncFieldNode.java +++ b/src/trufflesom/interpreter/supernodes/UninitIncFieldNode.java @@ -6,8 +6,11 @@ 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; @@ -17,13 +20,14 @@ public final class UninitIncFieldNode extends FieldNode { @Child private ExpressionNode self; @Child private ExpressionNode valueExpr; - private final int fieldIndex; + private final int fieldIndex; + private final boolean valueExprIsArg; public UninitIncFieldNode(final ExpressionNode self, final ExpressionNode valueExpr, - final int fieldIndex, - final long coord) { + final boolean valueExprIsArg, final int fieldIndex, final long coord) { this.self = self; this.valueExpr = valueExpr; + this.valueExprIsArg = valueExprIsArg; this.fieldIndex = fieldIndex; this.sourceCoord = coord; } @@ -48,7 +52,25 @@ public Object executeGeneric(final VirtualFrame frame) { try { incValue = valueExpr.executeLong(frame); } catch (UnexpectedResultException e1) { - throw new NotYetImplementedException(); + 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); From 19bb759953f520e196b9315ffffde5b78c22b129 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 26 Jan 2022 10:47:41 +0000 Subject: [PATCH 16/38] Rename increment nodes for variables that use an int constant Signed-off-by: Stefan Marr --- ...Node.java => IntIncLocalVariableNode.java} | 4 ++-- ...e.java => IntIncNonLocalVariableNode.java} | 4 ++-- .../supernodes/IntIncrementNode.java | 6 +++--- .../supernodes/IncrementOpTests.java | 20 +++++++++---------- tests/trufflesom/tests/AstInliningTests.java | 6 +++--- 5 files changed, 20 insertions(+), 20 deletions(-) rename src/trufflesom/interpreter/supernodes/{LocalVariableIncNode.java => IntIncLocalVariableNode.java} (91%) rename src/trufflesom/interpreter/supernodes/{NonLocalVariableIncNode.java => IntIncNonLocalVariableNode.java} (91%) diff --git a/src/trufflesom/interpreter/supernodes/LocalVariableIncNode.java b/src/trufflesom/interpreter/supernodes/IntIncLocalVariableNode.java similarity index 91% rename from src/trufflesom/interpreter/supernodes/LocalVariableIncNode.java rename to src/trufflesom/interpreter/supernodes/IntIncLocalVariableNode.java index c346b5305..e02479241 100644 --- a/src/trufflesom/interpreter/supernodes/LocalVariableIncNode.java +++ b/src/trufflesom/interpreter/supernodes/IntIncLocalVariableNode.java @@ -11,11 +11,11 @@ import trufflesom.interpreter.nodes.LocalVariableNode; -public abstract class LocalVariableIncNode extends LocalVariableNode { +public abstract class IntIncLocalVariableNode extends LocalVariableNode { private final long incValue; - public LocalVariableIncNode(final Local variable, final long incValue) { + public IntIncLocalVariableNode(final Local variable, final long incValue) { super(variable); this.incValue = incValue; } diff --git a/src/trufflesom/interpreter/supernodes/NonLocalVariableIncNode.java b/src/trufflesom/interpreter/supernodes/IntIncNonLocalVariableNode.java similarity index 91% rename from src/trufflesom/interpreter/supernodes/NonLocalVariableIncNode.java rename to src/trufflesom/interpreter/supernodes/IntIncNonLocalVariableNode.java index 3f945f3e9..df7a13505 100644 --- a/src/trufflesom/interpreter/supernodes/NonLocalVariableIncNode.java +++ b/src/trufflesom/interpreter/supernodes/IntIncNonLocalVariableNode.java @@ -13,11 +13,11 @@ import trufflesom.interpreter.nodes.NonLocalVariableNode; -public abstract class NonLocalVariableIncNode extends NonLocalVariableNode { +public abstract class IntIncNonLocalVariableNode extends NonLocalVariableNode { private final long incValue; - public NonLocalVariableIncNode(final int contextLevel, final Local local, + public IntIncNonLocalVariableNode(final int contextLevel, final Local local, final long incValue) { super(contextLevel, local); this.incValue = incValue; diff --git a/src/trufflesom/interpreter/supernodes/IntIncrementNode.java b/src/trufflesom/interpreter/supernodes/IntIncrementNode.java index 4fc016c84..000c07e11 100644 --- a/src/trufflesom/interpreter/supernodes/IntIncrementNode.java +++ b/src/trufflesom/interpreter/supernodes/IntIncrementNode.java @@ -117,9 +117,9 @@ public FieldNode createFieldIncNode(final ExpressionNode self, final int fieldIn public ExpressionNode createIncNode(final Local local, final int ctxLevel) { if (ctxLevel == 0) { - return LocalVariableIncNodeGen.create(local, incValue).initialize(sourceCoord); + return IntIncLocalVariableNodeGen.create(local, incValue).initialize(sourceCoord); } - return NonLocalVariableIncNodeGen.create(ctxLevel, local, incValue) - .initialize(sourceCoord); + return IntIncNonLocalVariableNodeGen.create(ctxLevel, local, incValue) + .initialize(sourceCoord); } } diff --git a/tests/trufflesom/supernodes/IncrementOpTests.java b/tests/trufflesom/supernodes/IncrementOpTests.java index 9f9762161..8ff70dd8c 100644 --- a/tests/trufflesom/supernodes/IncrementOpTests.java +++ b/tests/trufflesom/supernodes/IncrementOpTests.java @@ -13,8 +13,8 @@ import trufflesom.interpreter.nodes.specialized.IfInlinedLiteralNode; import trufflesom.interpreter.supernodes.IntIncrementNode; import trufflesom.interpreter.supernodes.IntUninitIncFieldNode; -import trufflesom.interpreter.supernodes.LocalVariableIncNode; -import trufflesom.interpreter.supernodes.NonLocalVariableIncNode; +import trufflesom.interpreter.supernodes.IntIncLocalVariableNode; +import trufflesom.interpreter.supernodes.IntIncNonLocalVariableNode; import trufflesom.interpreter.supernodes.UninitIncFieldNode; import trufflesom.tests.AstTestSetup; @@ -106,10 +106,10 @@ public void testFieldIncWithExpression() { @Test public void testLocalInc() { - basicAddOrSubtract("var := var + 1", 1, LocalVariableIncNode.class); - basicAddOrSubtract("var := var - 1", -1, LocalVariableIncNode.class); - basicAddOrSubtract("var := var + 1123", 1123, LocalVariableIncNode.class); - basicAddOrSubtract("var := var - 234234", -234234, LocalVariableIncNode.class); + basicAddOrSubtract("var := var + 1", 1, IntIncLocalVariableNode.class); + basicAddOrSubtract("var := var - 1", -1, IntIncLocalVariableNode.class); + basicAddOrSubtract("var := var + 1123", 1123, IntIncLocalVariableNode.class); + basicAddOrSubtract("var := var - 234234", -234234, IntIncLocalVariableNode.class); } private void inBlock(final String test, final long literalValue, @@ -128,10 +128,10 @@ private void inBlock(final String test, final long literalValue, @Test public void testNonLocalInc() { - inBlock("[ var := var + 1 ]", 1, NonLocalVariableIncNode.class); - inBlock("[ var := var - 1 ]", -1, NonLocalVariableIncNode.class); - inBlock("[ var := var + 1123 ]", 1123, NonLocalVariableIncNode.class); - inBlock("[ var := var - 234234 ]", -234234, NonLocalVariableIncNode.class); + inBlock("[ var := var + 1 ]", 1, IntIncNonLocalVariableNode.class); + inBlock("[ var := var - 1 ]", -1, IntIncNonLocalVariableNode.class); + inBlock("[ var := var + 1123 ]", 1123, IntIncNonLocalVariableNode.class); + inBlock("[ var := var - 234234 ]", -234234, IntIncNonLocalVariableNode.class); } } diff --git a/tests/trufflesom/tests/AstInliningTests.java b/tests/trufflesom/tests/AstInliningTests.java index c8d759845..3ff857df5 100644 --- a/tests/trufflesom/tests/AstInliningTests.java +++ b/tests/trufflesom/tests/AstInliningTests.java @@ -34,7 +34,7 @@ import trufflesom.interpreter.nodes.specialized.IfTrueIfFalseInlinedLiteralsNode.TrueIfElseLiteralNode; import trufflesom.interpreter.nodes.specialized.IntToDoInlinedLiteralsNode; import trufflesom.interpreter.nodes.specialized.whileloops.WhileInlinedLiteralsNode; -import trufflesom.interpreter.supernodes.NonLocalVariableIncNode; +import trufflesom.interpreter.supernodes.IntIncNonLocalVariableNode; import trufflesom.interpreter.supernodes.IntUninitIncFieldNode; import trufflesom.primitives.arithmetic.SubtractionPrim; import trufflesom.primitives.arrays.DoPrim; @@ -374,8 +374,8 @@ public void testToDoBlockBlockInlinedSelf() { assertEquals("b", readNode.getInvocationIdentifier().getString()); assertEquals(1, readNode.argumentIndex); - NonLocalVariableIncNode writeNode = - read(blockBIfTrue, "bodyNode", NonLocalVariableIncNode.class); + IntIncNonLocalVariableNode writeNode = + read(blockBIfTrue, "bodyNode", IntIncNonLocalVariableNode.class); assertEquals(1, writeNode.getContextLevel()); assertEquals("l2", writeNode.getInvocationIdentifier().getString()); } From f15d40b0f63b3c23655d522a8b0a15cf0e856f2c Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 26 Jan 2022 12:22:17 +0000 Subject: [PATCH 17/38] Add Inc[Non]LocalVariableNode Signed-off-by: Stefan Marr --- src/trufflesom/compiler/Variable.java | 57 ++++++++-- .../supernodes/IncLocalVariableNode.java | 72 +++++++++++++ .../supernodes/IncNonLocalVariableNode.java | 101 ++++++++++++++++++ .../supernodes/IncrementOpTests.java | 46 ++++++-- 4 files changed, 263 insertions(+), 13 deletions(-) create mode 100644 src/trufflesom/interpreter/supernodes/IncLocalVariableNode.java create mode 100644 src/trufflesom/interpreter/supernodes/IncNonLocalVariableNode.java diff --git a/src/trufflesom/compiler/Variable.java b/src/trufflesom/compiler/Variable.java index 149c22491..b8b21cfda 100644 --- a/src/trufflesom/compiler/Variable.java +++ b/src/trufflesom/compiler/Variable.java @@ -22,16 +22,21 @@ 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.LocalVariableIncNodeGen; +import trufflesom.interpreter.supernodes.IncLocalVariableNodeGen; +import trufflesom.interpreter.supernodes.IncNonLocalVariableNodeGen; +import trufflesom.interpreter.supernodes.IntIncLocalVariableNodeGen; +import trufflesom.interpreter.supernodes.IntIncNonLocalVariableNodeGen; import trufflesom.interpreter.supernodes.LocalVariableReadSquareWriteNodeGen; import trufflesom.interpreter.supernodes.LocalVariableSquareNodeGen; -import trufflesom.interpreter.supernodes.NonLocalVariableIncNodeGen; import trufflesom.interpreter.supernodes.NonLocalVariableReadSquareWriteNodeGen; import trufflesom.interpreter.supernodes.NonLocalVariableSquareNodeGen; +import trufflesom.primitives.arithmetic.AdditionPrim; import trufflesom.vm.NotYetImplementedException; import trufflesom.vmobjects.SSymbol; @@ -204,17 +209,17 @@ public ExpressionNode getReadNode(final int contextLevel, final long coord) { @Override public ExpressionNode getIncNode(final int contextLevel, final long incValue, final long coord) { - transferToInterpreterAndInvalidate("Variable.getReadNode"); + transferToInterpreterAndInvalidate(); if (contextLevel > 0) { - return NonLocalVariableIncNodeGen.create(contextLevel, this, incValue) - .initialize(coord); + return IntIncNonLocalVariableNodeGen.create(contextLevel, this, incValue) + .initialize(coord); } - return LocalVariableIncNodeGen.create(this, incValue).initialize(coord); + return IntIncLocalVariableNodeGen.create(this, incValue).initialize(coord); } @Override public ExpressionNode getSquareNode(final int contextLevel, final long coord) { - transferToInterpreterAndInvalidate("Variable.getReadNode"); + transferToInterpreterAndInvalidate(); if (contextLevel > 0) { return NonLocalVariableSquareNodeGen.create(contextLevel, this).initialize(coord); } @@ -249,10 +254,48 @@ public Local splitToMergeIntoOuterScope(final int newSlotIndex) { public ExpressionNode getWriteNode(final int contextLevel, final ExpressionNode valueExpr, final long coord) { transferToInterpreterAndInvalidate(); + if (contextLevel > 0) { + if (valueExpr instanceof AdditionPrim) { + AdditionPrim add = (AdditionPrim) valueExpr; + ExpressionNode rcvr = add.getReceiver(); + ExpressionNode arg = add.getArgument(); + + if (rcvr instanceof NonLocalVariableReadNode + && ((NonLocalVariableReadNode) rcvr).getLocal() == this) { + return IncNonLocalVariableNodeGen.create(contextLevel, this, arg) + .initialize(coord); + } + + if (arg instanceof NonLocalVariableReadNode + && ((NonLocalVariableReadNode) arg).getLocal() == this) { + return IncNonLocalVariableNodeGen.create(contextLevel, this, rcvr) + .initialize(coord); + } + } + return NonLocalVariableWriteNodeGen.create(contextLevel, this, valueExpr) .initialize(coord); } + + if (valueExpr instanceof AdditionPrim) { + AdditionPrim add = (AdditionPrim) valueExpr; + ExpressionNode rcvr = add.getReceiver(); + ExpressionNode arg = add.getArgument(); + + if (rcvr instanceof LocalVariableReadNode + && ((LocalVariableReadNode) rcvr).getLocal() == this) { + return IncLocalVariableNodeGen.create(this, arg) + .initialize(coord); + } + + if (arg instanceof LocalVariableReadNode + && ((LocalVariableReadNode) arg).getLocal() == this) { + return IncLocalVariableNodeGen.create(this, rcvr) + .initialize(coord); + } + } + return LocalVariableWriteNodeGen.create(this, valueExpr).initialize(coord); } diff --git a/src/trufflesom/interpreter/supernodes/IncLocalVariableNode.java b/src/trufflesom/interpreter/supernodes/IncLocalVariableNode.java new file mode 100644 index 000000000..4e54c6749 --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/IncLocalVariableNode.java @@ -0,0 +1,72 @@ +package trufflesom.interpreter.supernodes; + +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 com.oracle.truffle.api.nodes.Node; + +import bd.inlining.ScopeAdaptationVisitor; +import bd.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 IncLocalVariableNode extends LocalVariableNode { + + protected IncLocalVariableNode(final Local variable) { + super(variable); + } + + public abstract ExpressionNode getValue(); + + @Specialization(guards = "frame.isLong(slot)", rewriteOn = {FrameSlotTypeException.class}) + public final long doLong(final VirtualFrame frame, final long value) + throws FrameSlotTypeException { + long current = frame.getLong(slot); + long result = Math.addExact(current, value); + frame.setLong(slot, result); + return result; + } + + @Specialization(guards = "frame.isDouble(slot)", + rewriteOn = {FrameSlotTypeException.class}) + public final double doDouble(final VirtualFrame frame, final double value) + throws FrameSlotTypeException { + double current = frame.getDouble(slot); + double result = current + value; + frame.setDouble(slot, result); + return result; + } + + @Specialization(guards = "frame.isObject(slot)", + rewriteOn = {FrameSlotTypeException.class}) + public final Object doString(final VirtualFrame frame, final String value) + throws FrameSlotTypeException { + String current = (String) frame.getObject(slot); + String result = concat(current, value); + frame.setObject(slot, 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) { + IncLocalVariableNode newNode = + IncLocalVariableNodeGen.create((Local) se.var, getValue()); + newNode.initialize(sourceCoord); + replace(newNode); + } else { + assert 0 == se.contextLevel; + } + } +} diff --git a/src/trufflesom/interpreter/supernodes/IncNonLocalVariableNode.java b/src/trufflesom/interpreter/supernodes/IncNonLocalVariableNode.java new file mode 100644 index 000000000..d28fc7084 --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/IncNonLocalVariableNode.java @@ -0,0 +1,101 @@ +package trufflesom.interpreter.supernodes; + +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 com.oracle.truffle.api.nodes.Node; + +import bd.inlining.ScopeAdaptationVisitor; +import bd.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 IncNonLocalVariableNode extends NonLocalVariableNode { + + protected IncNonLocalVariableNode(final int contextLevel, final Local local) { + super(contextLevel, local); + } + + public abstract ExpressionNode getValue(); + + @Specialization(guards = "ctx.isLong(slot)", 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(slot); + long result = Math.addExact(current, value); + ctx.setLong(slot, result); + return result; + } + + @Specialization(guards = "ctx.isDouble(slot)", 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(slot); + double result = current + value; + ctx.setDouble(slot, result); + return result; + } + + @Specialization(guards = "ctx.isObject(slot)", 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(slot); + String result = concat(current, value); + ctx.setObject(slot, 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(slot); + Object result = add.executeEvaluated(null, preIncValue, value); + ctx.setObject(slot, 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 = IncLocalVariableNodeGen.create((Local) se.var, getValue()); + } else { + node = IncNonLocalVariableNodeGen.create(se.contextLevel, (Local) se.var, getValue()); + } + node.initialize(sourceCoord); + + replace(node); + } else { + assert contextLevel == se.contextLevel; + } + } +} diff --git a/tests/trufflesom/supernodes/IncrementOpTests.java b/tests/trufflesom/supernodes/IncrementOpTests.java index 8ff70dd8c..da618337a 100644 --- a/tests/trufflesom/supernodes/IncrementOpTests.java +++ b/tests/trufflesom/supernodes/IncrementOpTests.java @@ -11,10 +11,12 @@ import trufflesom.interpreter.nodes.SequenceNode; import trufflesom.interpreter.nodes.literals.BlockNode; import trufflesom.interpreter.nodes.specialized.IfInlinedLiteralNode; -import trufflesom.interpreter.supernodes.IntIncrementNode; -import trufflesom.interpreter.supernodes.IntUninitIncFieldNode; +import trufflesom.interpreter.supernodes.IncLocalVariableNode; +import trufflesom.interpreter.supernodes.IncNonLocalVariableNode; import trufflesom.interpreter.supernodes.IntIncLocalVariableNode; import trufflesom.interpreter.supernodes.IntIncNonLocalVariableNode; +import trufflesom.interpreter.supernodes.IntIncrementNode; +import trufflesom.interpreter.supernodes.IntUninitIncFieldNode; import trufflesom.interpreter.supernodes.UninitIncFieldNode; import trufflesom.tests.AstTestSetup; @@ -88,7 +90,7 @@ public void testFieldInc() { } - private void fieldIncWithExpr(final String test, final Class nodeType) { + private void incWithExpr(final String test, final Class nodeType) { addField("field"); SequenceNode seq = (SequenceNode) parseMethod( "test: arg = ( | var | \n" + test + " )"); @@ -99,9 +101,20 @@ private void fieldIncWithExpr(final String test, final Class nodeType) { @Test public void testFieldIncWithExpression() { - fieldIncWithExpr("field := field + (23 + 434)", UninitIncFieldNode.class); - fieldIncWithExpr("field := field + var", UninitIncFieldNode.class); - fieldIncWithExpr("field := field + arg", UninitIncFieldNode.class); + incWithExpr("field := field + (23 + 434)", UninitIncFieldNode.class); + incWithExpr("field := field + var", UninitIncFieldNode.class); + incWithExpr("field := field + arg", UninitIncFieldNode.class); + } + + @Test + public void testLocalIncWithExpression() { + incWithExpr("var := var + (23 + 434)", IncLocalVariableNode.class); + incWithExpr("var := var + var", IncLocalVariableNode.class); + incWithExpr("var := var + arg", IncLocalVariableNode.class); + + incWithExpr("var := (23 + 434) + var", IncLocalVariableNode.class); + incWithExpr("var := var + var", IncLocalVariableNode.class); + incWithExpr("var := arg + var", IncLocalVariableNode.class); } @Test @@ -134,4 +147,25 @@ public void testNonLocalInc() { inBlock("[ var := var - 234234 ]", -234234, IntIncNonLocalVariableNode.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(), "expressionOrSequence", ExpressionNode.class); + assertThat(testExpr, instanceOf(nodeType)); + } + + @Test + public void testNonLocalIncWithExpression() { + incWithExprInBlock("[ var := var + (23 + 434) ]", IncNonLocalVariableNode.class); + incWithExprInBlock("[ var := var + var ]", IncNonLocalVariableNode.class); + incWithExprInBlock("[ var := var + arg ]", IncNonLocalVariableNode.class); + + incWithExprInBlock("[ var := (23 + 434) + var ]", IncNonLocalVariableNode.class); + incWithExprInBlock("[ var := var + var ]", IncNonLocalVariableNode.class); + incWithExprInBlock("[ var := arg + var ]", IncNonLocalVariableNode.class); + } } From 87d590c29c77808e7400cc04d21c2dfc60ee4a9e Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Tue, 15 Feb 2022 10:49:21 +0000 Subject: [PATCH 18/38] Fix test regression after Invokable changes being merged in Signed-off-by: Stefan Marr --- tests/trufflesom/supernodes/IncrementOpTests.java | 4 ++-- tests/trufflesom/supernodes/SquareTests.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/trufflesom/supernodes/IncrementOpTests.java b/tests/trufflesom/supernodes/IncrementOpTests.java index da618337a..99ef54e1c 100644 --- a/tests/trufflesom/supernodes/IncrementOpTests.java +++ b/tests/trufflesom/supernodes/IncrementOpTests.java @@ -133,7 +133,7 @@ private void inBlock(final String test, final long literalValue, BlockNode block = (BlockNode) read(seq, "expressions", 0); ExpressionNode testExpr = - read(block.getMethod().getInvokable(), "expressionOrSequence", ExpressionNode.class); + read(block.getMethod().getInvokable(), "body", ExpressionNode.class); assertThat(testExpr, instanceOf(nodeType)); long value = read(testExpr, "incValue", Long.class); assertEquals(literalValue, value); @@ -154,7 +154,7 @@ private void incWithExprInBlock(final String test, final Class nodeType) { BlockNode block = (BlockNode) read(seq, "expressions", 0); ExpressionNode testExpr = - read(block.getMethod().getInvokable(), "expressionOrSequence", ExpressionNode.class); + read(block.getMethod().getInvokable(), "body", ExpressionNode.class); assertThat(testExpr, instanceOf(nodeType)); } diff --git a/tests/trufflesom/supernodes/SquareTests.java b/tests/trufflesom/supernodes/SquareTests.java index 54d8bb96a..e14747ea6 100644 --- a/tests/trufflesom/supernodes/SquareTests.java +++ b/tests/trufflesom/supernodes/SquareTests.java @@ -50,7 +50,7 @@ private T inBlock(final String test, final Class expectedNode) { BlockNode block = (BlockNode) read(seq, "expressions", 0); ExpressionNode testExpr = - read(block.getMethod().getInvokable(), "expressionOrSequence", ExpressionNode.class); + read(block.getMethod().getInvokable(), "body", ExpressionNode.class); assertThat(testExpr, instanceOf(expectedNode)); return (T) testExpr; } From 8192c978f2d301c7bf3423287b9f121ed4c91e5f Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Tue, 22 Feb 2022 18:42:22 +0000 Subject: [PATCH 19/38] Adapt to use of frame slot index instead of FrameSlot Signed-off-by: Stefan Marr --- .../supernodes/IncLocalVariableNode.java | 19 +++++----- .../supernodes/IncNonLocalVariableNode.java | 24 ++++++------ .../supernodes/IntIncLocalVariableNode.java | 13 ++++--- .../IntIncNonLocalVariableNode.java | 13 ++++--- .../LocalVariableReadSquareWriteNode.java | 34 +++++++++-------- .../supernodes/LocalVariableSquareNode.java | 9 +++-- .../NonLocalVariableReadSquareWriteNode.java | 38 +++++++++---------- .../NonLocalVariableSquareNode.java | 10 +++-- 8 files changed, 84 insertions(+), 76 deletions(-) diff --git a/src/trufflesom/interpreter/supernodes/IncLocalVariableNode.java b/src/trufflesom/interpreter/supernodes/IncLocalVariableNode.java index 4e54c6749..3a53660ee 100644 --- a/src/trufflesom/interpreter/supernodes/IncLocalVariableNode.java +++ b/src/trufflesom/interpreter/supernodes/IncLocalVariableNode.java @@ -23,32 +23,33 @@ protected IncLocalVariableNode(final Local variable) { public abstract ExpressionNode getValue(); - @Specialization(guards = "frame.isLong(slot)", rewriteOn = {FrameSlotTypeException.class}) + @Specialization(guards = "frame.isLong(slotIndex)", + rewriteOn = {FrameSlotTypeException.class}) public final long doLong(final VirtualFrame frame, final long value) throws FrameSlotTypeException { - long current = frame.getLong(slot); + long current = frame.getLong(slotIndex); long result = Math.addExact(current, value); - frame.setLong(slot, result); + frame.setLong(slotIndex, result); return result; } - @Specialization(guards = "frame.isDouble(slot)", + @Specialization(guards = "frame.isDouble(slotIndex)", rewriteOn = {FrameSlotTypeException.class}) public final double doDouble(final VirtualFrame frame, final double value) throws FrameSlotTypeException { - double current = frame.getDouble(slot); + double current = frame.getDouble(slotIndex); double result = current + value; - frame.setDouble(slot, result); + frame.setDouble(slotIndex, result); return result; } - @Specialization(guards = "frame.isObject(slot)", + @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(slot); + String current = (String) frame.getObject(slotIndex); String result = concat(current, value); - frame.setObject(slot, result); + frame.setObject(slotIndex, result); return result; } diff --git a/src/trufflesom/interpreter/supernodes/IncNonLocalVariableNode.java b/src/trufflesom/interpreter/supernodes/IncNonLocalVariableNode.java index d28fc7084..feb938f1f 100644 --- a/src/trufflesom/interpreter/supernodes/IncNonLocalVariableNode.java +++ b/src/trufflesom/interpreter/supernodes/IncNonLocalVariableNode.java @@ -29,33 +29,35 @@ protected IncNonLocalVariableNode(final int contextLevel, final Local local) { public abstract ExpressionNode getValue(); - @Specialization(guards = "ctx.isLong(slot)", rewriteOn = {FrameSlotTypeException.class}) + @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(slot); + long current = ctx.getLong(slotIndex); long result = Math.addExact(current, value); - ctx.setLong(slot, result); + ctx.setLong(slotIndex, result); return result; } - @Specialization(guards = "ctx.isDouble(slot)", rewriteOn = {FrameSlotTypeException.class}) + @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(slot); + double current = ctx.getDouble(slotIndex); double result = current + value; - ctx.setDouble(slot, result); + ctx.setDouble(slotIndex, result); return result; } - @Specialization(guards = "ctx.isObject(slot)", rewriteOn = {FrameSlotTypeException.class}) + @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(slot); + String current = (String) ctx.getObject(slotIndex); String result = concat(current, value); - ctx.setObject(slot, result); + ctx.setObject(slotIndex, result); return result; } @@ -75,9 +77,9 @@ public final Object fallback(final VirtualFrame frame, final Object value) { replace(local.getWriteNode(contextLevel, add, sourceCoord)).adoptChildren(); - Object preIncValue = ctx.getValue(slot); + Object preIncValue = ctx.getValue(slotIndex); Object result = add.executeEvaluated(null, preIncValue, value); - ctx.setObject(slot, result); + ctx.setObject(slotIndex, result); return result; } diff --git a/src/trufflesom/interpreter/supernodes/IntIncLocalVariableNode.java b/src/trufflesom/interpreter/supernodes/IntIncLocalVariableNode.java index e02479241..6e6083b25 100644 --- a/src/trufflesom/interpreter/supernodes/IntIncLocalVariableNode.java +++ b/src/trufflesom/interpreter/supernodes/IntIncLocalVariableNode.java @@ -20,20 +20,21 @@ public IntIncLocalVariableNode(final Local variable, final long incValue) { this.incValue = incValue; } - @Specialization(guards = "frame.isLong(slot)", rewriteOn = {FrameSlotTypeException.class}) + @Specialization(guards = "frame.isLong(slotIndex)", + rewriteOn = {FrameSlotTypeException.class}) public final long doLong(final VirtualFrame frame) throws FrameSlotTypeException { - long current = frame.getLong(slot); + long current = frame.getLong(slotIndex); long result = Math.addExact(current, incValue); - frame.setLong(slot, result); + frame.setLong(slotIndex, result); return result; } - @Specialization(guards = "frame.isDouble(slot)", + @Specialization(guards = "frame.isDouble(slotIndex)", rewriteOn = {FrameSlotTypeException.class}) public final double doDouble(final VirtualFrame frame) throws FrameSlotTypeException { - double current = frame.getDouble(slot); + double current = frame.getDouble(slotIndex); double result = current + incValue; - frame.setDouble(slot, result); + frame.setDouble(slotIndex, result); return result; } diff --git a/src/trufflesom/interpreter/supernodes/IntIncNonLocalVariableNode.java b/src/trufflesom/interpreter/supernodes/IntIncNonLocalVariableNode.java index df7a13505..278bc9621 100644 --- a/src/trufflesom/interpreter/supernodes/IntIncNonLocalVariableNode.java +++ b/src/trufflesom/interpreter/supernodes/IntIncNonLocalVariableNode.java @@ -23,23 +23,24 @@ public IntIncNonLocalVariableNode(final int contextLevel, final Local local, this.incValue = incValue; } - @Specialization(guards = "ctx.isLong(slot)", rewriteOn = {FrameSlotTypeException.class}) + @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(slot); + long current = ctx.getLong(slotIndex); long result = Math.addExact(current, incValue); - ctx.setLong(slot, result); + ctx.setLong(slotIndex, result); return result; } - @Specialization(guards = "ctx.isDouble(slot)", rewriteOn = {FrameSlotTypeException.class}) + @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(slot); + double current = ctx.getDouble(slotIndex); double result = current + incValue; - ctx.setDouble(slot, result); + ctx.setDouble(slotIndex, result); return result; } diff --git a/src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java b/src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java index c4c99eb57..db4e864f8 100644 --- a/src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java +++ b/src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java @@ -1,7 +1,7 @@ package trufflesom.interpreter.supernodes; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.frame.FrameSlot; +import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.FrameSlotKind; import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.VirtualFrame; @@ -15,40 +15,41 @@ public abstract class LocalVariableReadSquareWriteNode extends LocalVariableNode { - protected final Local readLocal; - protected final FrameSlot readSlot; + protected final Local readLocal; + protected final int readIndex; public LocalVariableReadSquareWriteNode(final Local writeLocal, final Local readLocal) { super(writeLocal); this.readLocal = readLocal; - this.readSlot = readLocal.getSlot(); + this.readIndex = readLocal.getIndex(); } - @Specialization(guards = {"isLongKind(frame)", "frame.isLong(readSlot)"}, + @Specialization(guards = {"isLongKind(frame)", "frame.isLong(readIndex)"}, rewriteOn = {FrameSlotTypeException.class}) public final long writeLong(final VirtualFrame frame) throws FrameSlotTypeException { - long current = frame.getLong(readSlot); + long current = frame.getLong(readIndex); long result = Math.multiplyExact(current, current); - frame.setLong(slot, result); + frame.setLong(slotIndex, result); return result; } - @Specialization(guards = {"isDoubleKind(frame)", "frame.isDouble(readSlot)"}, + @Specialization(guards = {"isDoubleKind(frame)", "frame.isDouble(readIndex)"}, rewriteOn = {FrameSlotTypeException.class}) public final double writeDouble(final VirtualFrame frame) throws FrameSlotTypeException { - double current = frame.getDouble(readSlot); + double current = frame.getDouble(readIndex); double result = current * current; - frame.setDouble(slot, result); + frame.setDouble(slotIndex, result); return result; } // uses frame to make sure guard is not converted to assertion protected final boolean isLongKind(final VirtualFrame frame) { - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Long) { + FrameDescriptor descriptor = local.getFrameDescriptor(); + if (descriptor.getSlotKind(slotIndex) == FrameSlotKind.Long) { return true; } - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Illegal) { - descriptor.setFrameSlotKind(slot, FrameSlotKind.Long); + if (descriptor.getSlotKind(slotIndex) == FrameSlotKind.Illegal) { + descriptor.setSlotKind(slotIndex, FrameSlotKind.Long); return true; } return false; @@ -56,11 +57,12 @@ protected final boolean isLongKind(final VirtualFrame frame) { // uses frame to make sure guard is not converted to assertion protected final boolean isDoubleKind(final VirtualFrame frame) { - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Double) { + FrameDescriptor descriptor = local.getFrameDescriptor(); + if (descriptor.getSlotKind(slotIndex) == FrameSlotKind.Double) { return true; } - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Illegal) { - descriptor.setFrameSlotKind(slot, FrameSlotKind.Double); + if (descriptor.getSlotKind(slotIndex) == FrameSlotKind.Illegal) { + descriptor.setSlotKind(slotIndex, FrameSlotKind.Double); return true; } return false; diff --git a/src/trufflesom/interpreter/supernodes/LocalVariableSquareNode.java b/src/trufflesom/interpreter/supernodes/LocalVariableSquareNode.java index 01ba57411..c3992bf1c 100644 --- a/src/trufflesom/interpreter/supernodes/LocalVariableSquareNode.java +++ b/src/trufflesom/interpreter/supernodes/LocalVariableSquareNode.java @@ -17,16 +17,17 @@ public LocalVariableSquareNode(final Local variable) { super(variable); } - @Specialization(guards = {"frame.isLong(slot)"}, rewriteOn = {FrameSlotTypeException.class}) + @Specialization(guards = {"frame.isLong(slotIndex)"}, + rewriteOn = {FrameSlotTypeException.class}) public final long doLong(final VirtualFrame frame) throws FrameSlotTypeException { - long value = frame.getLong(slot); + long value = frame.getLong(slotIndex); return Math.multiplyExact(value, value); } - @Specialization(guards = {"frame.isDouble(slot)"}, + @Specialization(guards = {"frame.isDouble(slotIndex)"}, rewriteOn = {FrameSlotTypeException.class}) public final double doDouble(final VirtualFrame frame) throws FrameSlotTypeException { - double value = frame.getDouble(slot); + double value = frame.getDouble(slotIndex); return value * value; } diff --git a/src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java b/src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java index 57c061bf0..a23988dc3 100644 --- a/src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java +++ b/src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java @@ -1,10 +1,8 @@ package trufflesom.interpreter.supernodes; -import static trufflesom.interpreter.TruffleCompiler.transferToInterpreter; - import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.frame.FrameSlot; +import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.FrameSlotKind; import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.MaterializedFrame; @@ -19,60 +17,60 @@ public abstract class NonLocalVariableReadSquareWriteNode extends NonLocalVariableNode { - protected final Local readLocal; - protected final FrameSlot readSlot; + protected final Local readLocal; + protected final int readIndex; public NonLocalVariableReadSquareWriteNode(final int contextLevel, final Local writeLocal, final Local readLocal) { super(contextLevel, writeLocal); this.readLocal = readLocal; - this.readSlot = readLocal.getSlot(); + this.readIndex = readLocal.getIndex(); } - @Specialization(guards = {"isLongKind(ctx)", "ctx.isLong(readSlot)"}, + @Specialization(guards = {"isLongKind(ctx)", "ctx.isLong(readIndex)"}, rewriteOn = {FrameSlotTypeException.class}) public final long writeLong(final VirtualFrame frame, @Bind("determineContext(frame)") final MaterializedFrame ctx) throws FrameSlotTypeException { - long current = ctx.getLong(readSlot); + long current = ctx.getLong(readIndex); long result = Math.multiplyExact(current, current); - ctx.setLong(slot, result); + ctx.setLong(slotIndex, result); return result; } - @Specialization(guards = {"isDoubleKind(ctx)", "ctx.isDouble(readSlot)"}, + @Specialization(guards = {"isDoubleKind(ctx)", "ctx.isDouble(readIndex)"}, rewriteOn = {FrameSlotTypeException.class}) public final double writeDouble(final VirtualFrame frame, @Bind("determineContext(frame)") final MaterializedFrame ctx) throws FrameSlotTypeException { - double current = ctx.getDouble(readSlot); + double current = ctx.getDouble(readIndex); double result = current * current; - ctx.setDouble(slot, result); + ctx.setDouble(slotIndex, result); return result; } protected final boolean isLongKind(final VirtualFrame frame) { - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Long) { + FrameDescriptor descriptor = local.getFrameDescriptor(); + if (descriptor.getSlotKind(slotIndex) == FrameSlotKind.Long) { return true; } - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Illegal) { - transferToInterpreter("LocalVar.writeIntToUninit"); - descriptor.setFrameSlotKind(slot, FrameSlotKind.Long); + if (descriptor.getSlotKind(slotIndex) == FrameSlotKind.Illegal) { + descriptor.setSlotKind(slotIndex, FrameSlotKind.Long); return true; } return false; } protected final boolean isDoubleKind(final VirtualFrame frame) { - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Double) { + FrameDescriptor descriptor = local.getFrameDescriptor(); + if (descriptor.getSlotKind(slotIndex) == FrameSlotKind.Double) { return true; } - if (descriptor.getFrameSlotKind(slot) == FrameSlotKind.Illegal) { - transferToInterpreter("LocalVar.writeDoubleToUninit"); - descriptor.setFrameSlotKind(slot, FrameSlotKind.Double); + if (descriptor.getSlotKind(slotIndex) == FrameSlotKind.Illegal) { + descriptor.setSlotKind(slotIndex, FrameSlotKind.Double); return true; } return false; diff --git a/src/trufflesom/interpreter/supernodes/NonLocalVariableSquareNode.java b/src/trufflesom/interpreter/supernodes/NonLocalVariableSquareNode.java index bc3ba183d..35117f3ad 100644 --- a/src/trufflesom/interpreter/supernodes/NonLocalVariableSquareNode.java +++ b/src/trufflesom/interpreter/supernodes/NonLocalVariableSquareNode.java @@ -19,19 +19,21 @@ public NonLocalVariableSquareNode(final int contextLevel, final Local local) { super(contextLevel, local); } - @Specialization(guards = {"ctx.isLong(slot)"}, rewriteOn = {FrameSlotTypeException.class}) + @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(slot); + long current = ctx.getLong(slotIndex); return Math.multiplyExact(current, current); } - @Specialization(guards = {"ctx.isDouble(slot)"}, rewriteOn = {FrameSlotTypeException.class}) + @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(slot); + double current = ctx.getDouble(slotIndex); return current * current; } From d95dde2483b9189ce402cde97204b2390f9aa02c Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Mon, 25 Apr 2022 23:41:50 +0100 Subject: [PATCH 20/38] Merge PR #144: Update Truffle and MX, and rename bd package to bdt Signed-off-by: Stefan Marr --- src/trufflesom/compiler/ParserAst.java | 3 +++ src/trufflesom/interpreter/bc/RespecializeException.java | 6 +++--- .../interpreter/nodes/AbstractMessageSendNode.java | 1 + src/trufflesom/interpreter/nodes/MessageSendNode.java | 4 +++- .../interpreter/nodes/UninitializedMessageSendNode.java | 2 +- .../interpreter/supernodes/IncLocalVariableNode.java | 4 ++-- .../interpreter/supernodes/IncNonLocalVariableNode.java | 4 ++-- .../interpreter/supernodes/IntIncLocalVariableNode.java | 4 ++-- .../interpreter/supernodes/IntIncNonLocalVariableNode.java | 4 ++-- .../interpreter/supernodes/LocalFieldStringEqualsNode.java | 4 ++-- .../supernodes/LocalVariableReadSquareWriteNode.java | 4 ++-- .../interpreter/supernodes/LocalVariableSquareNode.java | 4 ++-- .../supernodes/NonLocalFieldStringEqualsNode.java | 4 ++-- .../supernodes/NonLocalVariableReadSquareWriteNode.java | 4 ++-- .../interpreter/supernodes/NonLocalVariableSquareNode.java | 4 ++-- tests/trufflesom/tests/AstInliningTests.java | 3 ++- 16 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/compiler/ParserAst.java index 5cc593476..61f48b2d8 100644 --- a/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/compiler/ParserAst.java @@ -27,6 +27,9 @@ import bdt.basic.ProgramDefinitionError; import bdt.inlining.InlinableNodes; import bdt.tools.structure.StructuralProbe; +import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.nodes.ArgumentReadNode.LocalArgumentReadNode; +import trufflesom.interpreter.nodes.ArgumentReadNode.NonLocalArgumentReadNode; import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.FieldNode; import trufflesom.interpreter.nodes.FieldNode.FieldReadNode; diff --git a/src/trufflesom/interpreter/bc/RespecializeException.java b/src/trufflesom/interpreter/bc/RespecializeException.java index 6da853394..1aa23f692 100644 --- a/src/trufflesom/interpreter/bc/RespecializeException.java +++ b/src/trufflesom/interpreter/bc/RespecializeException.java @@ -2,15 +2,15 @@ import com.oracle.truffle.api.nodes.ControlFlowException; -import trufflesom.interpreter.nodes.GenericMessageSendNode; +import trufflesom.interpreter.nodes.AbstractMessageSendNode; public class RespecializeException extends ControlFlowException { private static final long serialVersionUID = 8098665542946983677L; - public final transient GenericMessageSendNode send; + public final transient AbstractMessageSendNode send; - public RespecializeException(final GenericMessageSendNode send) { + public RespecializeException(final AbstractMessageSendNode send) { this.send = send; } } diff --git a/src/trufflesom/interpreter/nodes/AbstractMessageSendNode.java b/src/trufflesom/interpreter/nodes/AbstractMessageSendNode.java index 354eae716..7d06d378d 100644 --- a/src/trufflesom/interpreter/nodes/AbstractMessageSendNode.java +++ b/src/trufflesom/interpreter/nodes/AbstractMessageSendNode.java @@ -5,6 +5,7 @@ import bdt.primitives.nodes.PreevaluatedExpression; import bdt.tools.nodes.Invocation; +import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; import trufflesom.vmobjects.SSymbol; diff --git a/src/trufflesom/interpreter/nodes/MessageSendNode.java b/src/trufflesom/interpreter/nodes/MessageSendNode.java index 522d1e4af..215351d89 100644 --- a/src/trufflesom/interpreter/nodes/MessageSendNode.java +++ b/src/trufflesom/interpreter/nodes/MessageSendNode.java @@ -7,6 +7,8 @@ import bdt.primitives.Specializer; import bdt.primitives.nodes.PreevaluatedExpression; +import trufflesom.interpreter.nodes.ArgumentReadNode.LocalArgumentReadNode; +import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; import trufflesom.interpreter.nodes.dispatch.UninitializedDispatchNode; import trufflesom.interpreter.supernodes.BinaryArgSendNode; import trufflesom.interpreter.supernodes.QuatArgSendNode; @@ -108,7 +110,7 @@ public static AbstractMessageSendNode createSuperSend(final SClass superClass, "Currently #dnu with super sent is not yet implemented. "); } - PreevaluatedExpression node = method.copyTrivialNode(); + PreevaluatedExpression node = method.copyTrivialNode(); if (node != null) { return new SuperExprNode(selector, arguments, node).initialize(coord); } diff --git a/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java b/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java index 2ca25f67e..bd5e2eee2 100644 --- a/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java +++ b/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java @@ -5,7 +5,7 @@ import bdt.primitives.Specializer; import bdt.primitives.nodes.PreevaluatedExpression; -import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode; +import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; import trufflesom.interpreter.nodes.dispatch.UninitializedDispatchNode; import trufflesom.primitives.Primitives; import trufflesom.vmobjects.SSymbol; diff --git a/src/trufflesom/interpreter/supernodes/IncLocalVariableNode.java b/src/trufflesom/interpreter/supernodes/IncLocalVariableNode.java index 3a53660ee..01c388a03 100644 --- a/src/trufflesom/interpreter/supernodes/IncLocalVariableNode.java +++ b/src/trufflesom/interpreter/supernodes/IncLocalVariableNode.java @@ -7,8 +7,8 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; -import bd.inlining.ScopeAdaptationVisitor; -import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import bdt.inlining.ScopeAdaptationVisitor; +import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; import trufflesom.compiler.Variable.Local; import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.LocalVariableNode; diff --git a/src/trufflesom/interpreter/supernodes/IncNonLocalVariableNode.java b/src/trufflesom/interpreter/supernodes/IncNonLocalVariableNode.java index feb938f1f..eb4f41e2b 100644 --- a/src/trufflesom/interpreter/supernodes/IncNonLocalVariableNode.java +++ b/src/trufflesom/interpreter/supernodes/IncNonLocalVariableNode.java @@ -11,8 +11,8 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; -import bd.inlining.ScopeAdaptationVisitor; -import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import bdt.inlining.ScopeAdaptationVisitor; +import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; import trufflesom.compiler.Variable.Local; import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.NonLocalVariableNode; diff --git a/src/trufflesom/interpreter/supernodes/IntIncLocalVariableNode.java b/src/trufflesom/interpreter/supernodes/IntIncLocalVariableNode.java index 6e6083b25..aa05b5714 100644 --- a/src/trufflesom/interpreter/supernodes/IntIncLocalVariableNode.java +++ b/src/trufflesom/interpreter/supernodes/IntIncLocalVariableNode.java @@ -5,8 +5,8 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; -import bd.inlining.ScopeAdaptationVisitor; -import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import bdt.inlining.ScopeAdaptationVisitor; +import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; import trufflesom.compiler.Variable.Local; import trufflesom.interpreter.nodes.LocalVariableNode; diff --git a/src/trufflesom/interpreter/supernodes/IntIncNonLocalVariableNode.java b/src/trufflesom/interpreter/supernodes/IntIncNonLocalVariableNode.java index 278bc9621..30312d0ed 100644 --- a/src/trufflesom/interpreter/supernodes/IntIncNonLocalVariableNode.java +++ b/src/trufflesom/interpreter/supernodes/IntIncNonLocalVariableNode.java @@ -7,8 +7,8 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; -import bd.inlining.ScopeAdaptationVisitor; -import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import bdt.inlining.ScopeAdaptationVisitor; +import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; import trufflesom.compiler.Variable.Local; import trufflesom.interpreter.nodes.NonLocalVariableNode; diff --git a/src/trufflesom/interpreter/supernodes/LocalFieldStringEqualsNode.java b/src/trufflesom/interpreter/supernodes/LocalFieldStringEqualsNode.java index b54569147..1c2b57977 100644 --- a/src/trufflesom/interpreter/supernodes/LocalFieldStringEqualsNode.java +++ b/src/trufflesom/interpreter/supernodes/LocalFieldStringEqualsNode.java @@ -6,8 +6,8 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.UnexpectedResultException; -import bd.inlining.ScopeAdaptationVisitor; -import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import bdt.inlining.ScopeAdaptationVisitor; +import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; import trufflesom.compiler.Variable.Argument; import trufflesom.interpreter.bc.RespecializeException; import trufflesom.interpreter.nodes.AbstractMessageSendNode; diff --git a/src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java b/src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java index db4e864f8..0ba57f554 100644 --- a/src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java +++ b/src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java @@ -7,8 +7,8 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; -import bd.inlining.ScopeAdaptationVisitor; -import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import bdt.inlining.ScopeAdaptationVisitor; +import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; import trufflesom.compiler.Variable.Local; import trufflesom.interpreter.nodes.LocalVariableNode; diff --git a/src/trufflesom/interpreter/supernodes/LocalVariableSquareNode.java b/src/trufflesom/interpreter/supernodes/LocalVariableSquareNode.java index c3992bf1c..ba530ce7e 100644 --- a/src/trufflesom/interpreter/supernodes/LocalVariableSquareNode.java +++ b/src/trufflesom/interpreter/supernodes/LocalVariableSquareNode.java @@ -5,8 +5,8 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; -import bd.inlining.ScopeAdaptationVisitor; -import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import bdt.inlining.ScopeAdaptationVisitor; +import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; import trufflesom.compiler.Variable.Local; import trufflesom.interpreter.nodes.LocalVariableNode; diff --git a/src/trufflesom/interpreter/supernodes/NonLocalFieldStringEqualsNode.java b/src/trufflesom/interpreter/supernodes/NonLocalFieldStringEqualsNode.java index 71215b6ab..7b3f0f40f 100644 --- a/src/trufflesom/interpreter/supernodes/NonLocalFieldStringEqualsNode.java +++ b/src/trufflesom/interpreter/supernodes/NonLocalFieldStringEqualsNode.java @@ -6,8 +6,8 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.UnexpectedResultException; -import bd.inlining.ScopeAdaptationVisitor; -import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import bdt.inlining.ScopeAdaptationVisitor; +import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; import trufflesom.compiler.Variable.Argument; import trufflesom.interpreter.bc.RespecializeException; import trufflesom.interpreter.nodes.AbstractMessageSendNode; diff --git a/src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java b/src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java index a23988dc3..393ae66de 100644 --- a/src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java +++ b/src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java @@ -9,8 +9,8 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; -import bd.inlining.ScopeAdaptationVisitor; -import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import bdt.inlining.ScopeAdaptationVisitor; +import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; import trufflesom.compiler.Variable.Local; import trufflesom.interpreter.nodes.NonLocalVariableNode; diff --git a/src/trufflesom/interpreter/supernodes/NonLocalVariableSquareNode.java b/src/trufflesom/interpreter/supernodes/NonLocalVariableSquareNode.java index 35117f3ad..ed5fa7ade 100644 --- a/src/trufflesom/interpreter/supernodes/NonLocalVariableSquareNode.java +++ b/src/trufflesom/interpreter/supernodes/NonLocalVariableSquareNode.java @@ -7,8 +7,8 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; -import bd.inlining.ScopeAdaptationVisitor; -import bd.inlining.ScopeAdaptationVisitor.ScopeElement; +import bdt.inlining.ScopeAdaptationVisitor; +import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; import trufflesom.compiler.Variable.Local; import trufflesom.interpreter.nodes.NonLocalVariableNode; diff --git a/tests/trufflesom/tests/AstInliningTests.java b/tests/trufflesom/tests/AstInliningTests.java index 3ff857df5..395d3ab83 100644 --- a/tests/trufflesom/tests/AstInliningTests.java +++ b/tests/trufflesom/tests/AstInliningTests.java @@ -344,7 +344,8 @@ public void testBlockBlockInlinedSelf() { assertEquals("b", readB.getInvocationIdentifier().getString()); assertEquals(1, readB.argumentIndex); - IntUninitIncFieldNode incNode = read(blockBIfTrue, "bodyNode", IntUninitIncFieldNode.class); + IntUninitIncFieldNode incNode = + read(blockBIfTrue, "bodyNode", IntUninitIncFieldNode.class); NonLocalArgumentReadNode selfNode = (NonLocalArgumentReadNode) incNode.getSelf(); assertEquals(2, selfNode.getContextLevel()); assertEquals(0, (int) read(incNode, "fieldIndex", Integer.class)); From 9215df5261448ff1fabd9fd347b8615bcd6f6717 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 23 Feb 2022 16:50:09 +0000 Subject: [PATCH 21/38] Add super node for `local := local foo` Signed-off-by: Stefan Marr --- .../compiler/MethodGenerationContext.java | 29 ++++++++++ .../nodes/AbstractMessageSendNode.java | 4 ++ .../LocalVarReadUnaryMsgWriteNode.java | 48 ++++++++++++++++ .../NonLocalVarReadUnaryMsgWriteNode.java | 57 +++++++++++++++++++ 4 files changed, 138 insertions(+) create mode 100644 src/trufflesom/interpreter/supernodes/LocalVarReadUnaryMsgWriteNode.java create mode 100644 src/trufflesom/interpreter/supernodes/NonLocalVarReadUnaryMsgWriteNode.java diff --git a/src/trufflesom/compiler/MethodGenerationContext.java b/src/trufflesom/compiler/MethodGenerationContext.java index 367f86b84..2ff47ce53 100644 --- a/src/trufflesom/compiler/MethodGenerationContext.java +++ b/src/trufflesom/compiler/MethodGenerationContext.java @@ -52,11 +52,16 @@ import trufflesom.interpreter.nodes.FieldNode.FieldReadNode; import trufflesom.interpreter.nodes.FieldNode.UninitFieldIncNode; import trufflesom.interpreter.nodes.FieldNodeFactory.FieldWriteNodeGen; +import trufflesom.interpreter.nodes.LocalVariableNode.LocalVariableReadNode; +import trufflesom.interpreter.nodes.NonLocalVariableNode.NonLocalVariableReadNode; import trufflesom.interpreter.nodes.ReturnNonLocalNode; import trufflesom.interpreter.nodes.ReturnNonLocalNode.CatchNonLocalReturnNode; +import trufflesom.interpreter.nodes.UninitializedMessageSendNode; import trufflesom.interpreter.nodes.literals.BlockNode; import trufflesom.interpreter.supernodes.IntIncrementNode; +import trufflesom.interpreter.supernodes.LocalVarReadUnaryMsgWriteNode; import trufflesom.interpreter.supernodes.LocalVariableSquareNode; +import trufflesom.interpreter.supernodes.NonLocalVarReadUnaryMsgWriteNode; import trufflesom.interpreter.supernodes.NonLocalVariableSquareNode; import trufflesom.primitives.Primitives; import trufflesom.vm.NotYetImplementedException; @@ -421,6 +426,18 @@ public ExpressionNode getLocalWriteNode(final Variable variable, throw new NotYetImplementedException( "a missing read/square/write combination, used in a benchmark?"); } + + if (valExpr instanceof UninitializedMessageSendNode) { + UninitializedMessageSendNode val = (UninitializedMessageSendNode) valExpr; + ExpressionNode[] args = val.getArguments(); + if (args.length == 1 && args[0] instanceof LocalVariableReadNode) { + LocalVariableReadNode var = (LocalVariableReadNode) args[0]; + if (var.getLocal() == variable) { + return new LocalVarReadUnaryMsgWriteNode((Local) variable, + val.getInvocationIdentifier()); + } + } + } } else { if (valExpr instanceof NonLocalVariableSquareNode) { return variable.getReadSquareWriteNode(ctxLevel, coord, @@ -431,6 +448,18 @@ public ExpressionNode getLocalWriteNode(final Variable variable, return variable.getReadSquareWriteNode(ctxLevel, coord, ((LocalVariableSquareNode) valExpr).getLocal()); } + + if (valExpr instanceof UninitializedMessageSendNode) { + UninitializedMessageSendNode val = (UninitializedMessageSendNode) valExpr; + ExpressionNode[] args = val.getArguments(); + if (args.length == 1 && args[0] instanceof NonLocalVariableReadNode) { + NonLocalVariableReadNode var = (NonLocalVariableReadNode) args[0]; + if (var.getLocal() == variable) { + return new NonLocalVarReadUnaryMsgWriteNode(ctxLevel, (Local) variable, + val.getInvocationIdentifier()); + } + } + } } return variable.getWriteNode(ctxLevel, valExpr, coord); } diff --git a/src/trufflesom/interpreter/nodes/AbstractMessageSendNode.java b/src/trufflesom/interpreter/nodes/AbstractMessageSendNode.java index 7d06d378d..146e724ed 100644 --- a/src/trufflesom/interpreter/nodes/AbstractMessageSendNode.java +++ b/src/trufflesom/interpreter/nodes/AbstractMessageSendNode.java @@ -36,6 +36,10 @@ private Object[] evaluateArguments(final VirtualFrame frame) { return arguments; } + public ExpressionNode[] getArguments() { + return argumentNodes; + } + public final int getNumberOfArguments() { return numArguments; } diff --git a/src/trufflesom/interpreter/supernodes/LocalVarReadUnaryMsgWriteNode.java b/src/trufflesom/interpreter/supernodes/LocalVarReadUnaryMsgWriteNode.java new file mode 100644 index 000000000..e249e9e81 --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/LocalVarReadUnaryMsgWriteNode.java @@ -0,0 +1,48 @@ +package trufflesom.interpreter.supernodes; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; + +import bdt.inlining.ScopeAdaptationVisitor; +import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.nodes.LocalVariableNode; +import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode; +import trufflesom.interpreter.nodes.dispatch.UninitializedDispatchNode; +import trufflesom.vmobjects.SSymbol; + + +public final class LocalVarReadUnaryMsgWriteNode extends LocalVariableNode { + + @Child AbstractDispatchNode dispatch; + private final SSymbol selector; + + public LocalVarReadUnaryMsgWriteNode(final Local local, final SSymbol selector) { + super(local); + assert selector.getNumberOfSignatureArguments() == 1; + this.dispatch = new UninitializedDispatchNode(selector); + this.selector = selector; + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + Object rcvr = frame.getObject(slotIndex); + Object result = dispatch.executeDispatch(frame, new Object[] {rcvr}); + + frame.setObject(slotIndex, result); + return result; + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + ScopeElement se = inliner.getAdaptedVar(local); + + assert se.contextLevel == 0; + if (se.var != local) { + Node node = new LocalVarReadUnaryMsgWriteNode((Local) se.var, selector); + replace(node); + } else { + assert 0 == se.contextLevel; + } + } +} diff --git a/src/trufflesom/interpreter/supernodes/NonLocalVarReadUnaryMsgWriteNode.java b/src/trufflesom/interpreter/supernodes/NonLocalVarReadUnaryMsgWriteNode.java new file mode 100644 index 000000000..13d423a79 --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/NonLocalVarReadUnaryMsgWriteNode.java @@ -0,0 +1,57 @@ +package trufflesom.interpreter.supernodes; + +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; + +import bdt.inlining.ScopeAdaptationVisitor; +import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Local; +import trufflesom.interpreter.nodes.NonLocalVariableNode; +import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode; +import trufflesom.interpreter.nodes.dispatch.UninitializedDispatchNode; +import trufflesom.vmobjects.SSymbol; + + +public final class NonLocalVarReadUnaryMsgWriteNode extends NonLocalVariableNode { + + @Child AbstractDispatchNode dispatch; + private final SSymbol selector; + + public NonLocalVarReadUnaryMsgWriteNode(final int contextLevel, final Local local, + final SSymbol selector) { + super(contextLevel, local); + assert selector.getNumberOfSignatureArguments() == 1; + this.dispatch = new UninitializedDispatchNode(selector); + this.selector = selector; + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + MaterializedFrame ctx = determineContext(frame); + Object rcvr = ctx.getObject(slotIndex); + Object result = dispatch.executeDispatch(frame, new Object[] {rcvr}); + + 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) { + Node node; + if (se.contextLevel > 0) { + node = new NonLocalVarReadUnaryMsgWriteNode(se.contextLevel, (Local) se.var, selector); + } else { + assert se.contextLevel == 0; + node = new LocalVarReadUnaryMsgWriteNode((Local) se.var, selector); + } + + replace(node); + } else { + assert contextLevel == se.contextLevel; + } + } +} From 00f29ba19d33ee4c9508657dafbeb4d1ba713e45 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 23 Feb 2022 21:03:51 +0000 Subject: [PATCH 22/38] Add supernode for `isNil ifTrue:` sequence Signed-off-by: Stefan Marr --- src/trufflesom/compiler/ParserAst.java | 4 +++ .../specialized/IfInlinedLiteralNode.java | 9 ++++++ .../nodes/specialized/IsNilIfTrue.java | 31 +++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 src/trufflesom/interpreter/nodes/specialized/IsNilIfTrue.java diff --git a/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/compiler/ParserAst.java index 61f48b2d8..381bbfaff 100644 --- a/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/compiler/ParserAst.java @@ -43,6 +43,7 @@ import trufflesom.interpreter.nodes.literals.GenericLiteralNode; import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; import trufflesom.interpreter.nodes.literals.LiteralNode; +import trufflesom.interpreter.nodes.specialized.IfInlinedLiteralNode; import trufflesom.interpreter.supernodes.IntIncrementNodeGen; import trufflesom.interpreter.supernodes.LocalFieldStringEqualsNode; import trufflesom.interpreter.supernodes.LocalVariableSquareNodeGen; @@ -395,6 +396,9 @@ protected ExpressionNode keywordMessage(final MethodGenerationContext mgenc, ExpressionNode inlined = inlinableNodes.inline(msg, args, mgenc, coodWithL); if (inlined != null) { assert !isSuperSend; + if (args.length == 2 && inlined instanceof IfInlinedLiteralNode) { + return ((IfInlinedLiteralNode) inlined).asIsNilIfTrueIfPossible(); + } return inlined; } diff --git a/src/trufflesom/interpreter/nodes/specialized/IfInlinedLiteralNode.java b/src/trufflesom/interpreter/nodes/specialized/IfInlinedLiteralNode.java index 36c9e3458..d6bcd2f2a 100644 --- a/src/trufflesom/interpreter/nodes/specialized/IfInlinedLiteralNode.java +++ b/src/trufflesom/interpreter/nodes/specialized/IfInlinedLiteralNode.java @@ -12,6 +12,7 @@ import bdt.inlining.Inline.True; import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.NoPreEvalExprNode; +import trufflesom.primitives.reflection.ObjectPrims.IsNilNode; import trufflesom.vm.constants.Nil; @@ -56,4 +57,12 @@ public Object executeGeneric(final VirtualFrame frame) { return Nil.nilObject; } } + + public ExpressionNode asIsNilIfTrueIfPossible() { + if (conditionNode instanceof IsNilNode && expectedBool) { + return new IsNilIfTrue(((IsNilNode) conditionNode).getReceiver(), bodyNode).initialize( + sourceCoord); + } + return this; + } } diff --git a/src/trufflesom/interpreter/nodes/specialized/IsNilIfTrue.java b/src/trufflesom/interpreter/nodes/specialized/IsNilIfTrue.java new file mode 100644 index 000000000..b6bf7f978 --- /dev/null +++ b/src/trufflesom/interpreter/nodes/specialized/IsNilIfTrue.java @@ -0,0 +1,31 @@ +package trufflesom.interpreter.nodes.specialized; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.profiles.ConditionProfile; + +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.NoPreEvalExprNode; +import trufflesom.vm.constants.Nil; + + +public class IsNilIfTrue extends NoPreEvalExprNode { + private final ConditionProfile condProf = ConditionProfile.createCountingProfile(); + + @Child private ExpressionNode rcvr; + @Child private ExpressionNode arg1; + + public IsNilIfTrue(final ExpressionNode rcvr, final ExpressionNode inlinedArg1) { + this.rcvr = rcvr; + this.arg1 = inlinedArg1; + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + Object r = rcvr.executeGeneric(frame); + if (condProf.profile(r == Nil.nilObject)) { + return arg1.executeGeneric(frame); + } + return r; + } + +} From a55017ac7adfd8740a248b2fe1eed85268ee291e Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Tue, 25 Jan 2022 16:06:02 +0000 Subject: [PATCH 23/38] Add LocalArgGreaterThanInt Signed-off-by: Stefan Marr --- src/trufflesom/compiler/ParserAst.java | 5 + .../supernodes/LocalArgGreaterThanInt.java | 113 ++++++++++++++++++ .../supernodes/GreaterThanTests.java | 35 ++++++ 3 files changed, 153 insertions(+) create mode 100644 src/trufflesom/interpreter/supernodes/LocalArgGreaterThanInt.java create mode 100644 tests/trufflesom/supernodes/GreaterThanTests.java diff --git a/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/compiler/ParserAst.java index 381bbfaff..38620f24f 100644 --- a/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/compiler/ParserAst.java @@ -45,6 +45,7 @@ import trufflesom.interpreter.nodes.literals.LiteralNode; import trufflesom.interpreter.nodes.specialized.IfInlinedLiteralNode; import trufflesom.interpreter.supernodes.IntIncrementNodeGen; +import trufflesom.interpreter.supernodes.LocalArgGreaterThanInt; import trufflesom.interpreter.supernodes.LocalFieldStringEqualsNode; import trufflesom.interpreter.supernodes.LocalVariableSquareNodeGen; import trufflesom.interpreter.supernodes.NonLocalFieldStringEqualsNode; @@ -350,6 +351,10 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, return IntIncrementNodeGen.create(-lit.executeLong(null), true, receiver) .initialize(coordWithL); } + if (binSelector.equals(">") && receiver instanceof LocalArgumentReadNode) { + return new LocalArgGreaterThanInt(((LocalArgumentReadNode) receiver).getArg(), + lit.executeLong(null)).initialize(coordWithL); + } } ExpressionNode inlined = diff --git a/src/trufflesom/interpreter/supernodes/LocalArgGreaterThanInt.java b/src/trufflesom/interpreter/supernodes/LocalArgGreaterThanInt.java new file mode 100644 index 000000000..185e8d8c5 --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/LocalArgGreaterThanInt.java @@ -0,0 +1,113 @@ +package trufflesom.interpreter.supernodes; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.UnexpectedResultException; + +import bdt.inlining.ScopeAdaptationVisitor; +import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Argument; +import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.AbstractMessageSendNode; +import trufflesom.interpreter.nodes.ArgumentReadNode.LocalArgumentReadNode; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.MessageSendNode; +import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; +import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; +import trufflesom.vm.SymbolTable; +import trufflesom.vm.VmSettings; + + +public final class LocalArgGreaterThanInt extends ExpressionNode { + + private final Argument arg; + private final int argIdx; + private final long intValue; + + public LocalArgGreaterThanInt(final Argument arg, final long intValue) { + this.arg = arg; + this.argIdx = arg.index; + this.intValue = intValue; + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + Object arg = frame.getArguments()[argIdx]; + if (arg instanceof Long) { + long argVal = (Long) arg; + return argVal > intValue; + } + + CompilerDirectives.transferToInterpreterAndInvalidate(); + return fallbackGeneric(frame); + } + + @Override + public Object doPreEvaluated(final VirtualFrame frame, final Object[] args) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw new UnsupportedOperationException(); + } + + @Override + public boolean executeBoolean(final VirtualFrame frame) throws UnexpectedResultException { + Object arg = frame.getArguments()[argIdx]; + if (arg instanceof Long) { + long argVal = (Long) arg; + return argVal > intValue; + } + + CompilerDirectives.transferToInterpreterAndInvalidate(); + return fallbackBool(frame); + } + + private boolean fallbackBool(final VirtualFrame frame) throws UnexpectedResultException { + Object result = makeGenericSend().doPreEvaluated(frame, + new Object[] {arg, intValue}); + if (result instanceof Boolean) { + return (Boolean) result; + } + throw new UnexpectedResultException(result); + } + + private Object fallbackGeneric(final VirtualFrame frame) { + return makeGenericSend().doPreEvaluated(frame, + new Object[] {arg, intValue}); + } + + protected AbstractMessageSendNode makeGenericSend() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + AbstractMessageSendNode send = + MessageSendNode.createGenericBinary(SymbolTable.symbolFor(">"), + new LocalArgumentReadNode(arg), + new IntegerLiteralNode(intValue), 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); + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + ScopeElement se = inliner.getAdaptedVar(arg); + if (se.var != arg || se.contextLevel < 0) { + if (se.var instanceof Argument) { + replace( + new LocalArgGreaterThanInt((Argument) se.var, intValue).initialize(sourceCoord)); + } else { + replace(MessageSendNode.createGenericBinary( + SymbolTable.symbolFor(">"), + (ExpressionNode) se.var.getReadNode(se.contextLevel, sourceCoord), + new IntegerLiteralNode(intValue), + sourceCoord)); + } + } else { + assert 0 == se.contextLevel; + } + } +} diff --git a/tests/trufflesom/supernodes/GreaterThanTests.java b/tests/trufflesom/supernodes/GreaterThanTests.java new file mode 100644 index 000000000..c387ebf4d --- /dev/null +++ b/tests/trufflesom/supernodes/GreaterThanTests.java @@ -0,0 +1,35 @@ +package trufflesom.supernodes; + +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertThat; + +import org.junit.Test; + +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.SequenceNode; +import trufflesom.interpreter.supernodes.LocalArgGreaterThanInt; +import trufflesom.primitives.arithmetic.GreaterThanPrim; +import trufflesom.tests.AstTestSetup; + + +public class GreaterThanTests extends AstTestSetup { + @SuppressWarnings("unchecked") + private T assertThatMainNodeIs(final String test, final Class expectedNode) { + SequenceNode seq = (SequenceNode) parseMethod( + "test: arg = ( | l1 l2 l3 l4 | \n" + test + " )"); + + ExpressionNode testExpr = read(seq, "expressions", 0); + assertThat(testExpr, instanceOf(expectedNode)); + return (T) testExpr; + } + + @Test + public void testBasics() { + assertThatMainNodeIs("arg > 0", LocalArgGreaterThanInt.class); + + // unsupported at the moment + assertThatMainNodeIs("l1 > 0", GreaterThanPrim.class); + assertThatMainNodeIs("3 > 0", GreaterThanPrim.class); + assertThatMainNodeIs("3 > 0", GreaterThanPrim.class); + } +} From e53269153359a5d3c349cc6eeab506c922fa6222 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Tue, 25 Jan 2022 22:36:08 +0000 Subject: [PATCH 24/38] Add GreaterThanIntNode, LessThanIntNode, and LocalArgLessThanInt Signed-off-by: Stefan Marr --- src/trufflesom/compiler/ParserAst.java | 23 +++- .../supernodes/GreaterThanIntNode.java | 65 ++++++++++ .../supernodes/LessThanIntNode.java | 65 ++++++++++ .../supernodes/LocalArgLessThanInt.java | 113 ++++++++++++++++++ .../supernodes/GreaterThanTests.java | 35 ------ .../supernodes/LesserGreaterThanTests.java | 51 ++++++++ 6 files changed, 314 insertions(+), 38 deletions(-) create mode 100644 src/trufflesom/interpreter/supernodes/GreaterThanIntNode.java create mode 100644 src/trufflesom/interpreter/supernodes/LessThanIntNode.java create mode 100644 src/trufflesom/interpreter/supernodes/LocalArgLessThanInt.java delete mode 100644 tests/trufflesom/supernodes/GreaterThanTests.java create mode 100644 tests/trufflesom/supernodes/LesserGreaterThanTests.java diff --git a/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/compiler/ParserAst.java index 38620f24f..690d18f93 100644 --- a/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/compiler/ParserAst.java @@ -44,8 +44,11 @@ import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; import trufflesom.interpreter.nodes.literals.LiteralNode; import trufflesom.interpreter.nodes.specialized.IfInlinedLiteralNode; +import trufflesom.interpreter.supernodes.GreaterThanIntNodeGen; import trufflesom.interpreter.supernodes.IntIncrementNodeGen; +import trufflesom.interpreter.supernodes.LessThanIntNodeGen; import trufflesom.interpreter.supernodes.LocalArgGreaterThanInt; +import trufflesom.interpreter.supernodes.LocalArgLessThanInt; import trufflesom.interpreter.supernodes.LocalFieldStringEqualsNode; import trufflesom.interpreter.supernodes.LocalVariableSquareNodeGen; import trufflesom.interpreter.supernodes.NonLocalFieldStringEqualsNode; @@ -351,9 +354,23 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, return IntIncrementNodeGen.create(-lit.executeLong(null), true, receiver) .initialize(coordWithL); } - if (binSelector.equals(">") && receiver instanceof LocalArgumentReadNode) { - return new LocalArgGreaterThanInt(((LocalArgumentReadNode) receiver).getArg(), - lit.executeLong(null)).initialize(coordWithL); + if (binSelector.equals(">")) { + if (receiver instanceof LocalArgumentReadNode) { + return new LocalArgGreaterThanInt(((LocalArgumentReadNode) receiver).getArg(), + lit.executeLong(null)).initialize(coordWithL); + } + + return GreaterThanIntNodeGen.create(lit.executeLong(null), receiver) + .initialize(coordWithL); + } + if (binSelector.equals("<")) { + if (receiver instanceof LocalArgumentReadNode) { + return new LocalArgLessThanInt(((LocalArgumentReadNode) receiver).getArg(), + lit.executeLong(null)).initialize(coordWithL); + } + + return LessThanIntNodeGen.create(lit.executeLong(null), receiver) + .initialize(coordWithL); } } diff --git a/src/trufflesom/interpreter/supernodes/GreaterThanIntNode.java b/src/trufflesom/interpreter/supernodes/GreaterThanIntNode.java new file mode 100644 index 000000000..5bff22b84 --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/GreaterThanIntNode.java @@ -0,0 +1,65 @@ +package trufflesom.interpreter.supernodes; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; + +import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.AbstractMessageSendNode; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.MessageSendNode; +import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; +import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; +import trufflesom.interpreter.nodes.nary.UnaryExpressionNode; +import trufflesom.vm.SymbolTable; +import trufflesom.vm.VmSettings; +import trufflesom.vmobjects.SSymbol; + + +public abstract class GreaterThanIntNode extends UnaryExpressionNode { + + private final long intValue; + + public GreaterThanIntNode(final long intValue) { + this.intValue = intValue; + } + + @Override + public abstract ExpressionNode getReceiver(); + + @Specialization + public final boolean doLong(final long rcvr) { + return rcvr > intValue; + } + + @Specialization + public final boolean doDouble(final double rcvr) { + return rcvr > intValue; + } + + @Fallback + public final Object makeGenericSend(final VirtualFrame frame, + final Object receiver) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + return makeGenericSend(SymbolTable.symbolFor(">")).doPreEvaluated(frame, + new Object[] {receiver, intValue}); + } + + @Override + protected AbstractMessageSendNode makeGenericSend(final SSymbol selector) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + AbstractMessageSendNode send = + MessageSendNode.createGenericBinary(selector, getReceiver(), + new IntegerLiteralNode(intValue), 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); + } +} diff --git a/src/trufflesom/interpreter/supernodes/LessThanIntNode.java b/src/trufflesom/interpreter/supernodes/LessThanIntNode.java new file mode 100644 index 000000000..f8f2c1ccd --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/LessThanIntNode.java @@ -0,0 +1,65 @@ +package trufflesom.interpreter.supernodes; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; + +import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.AbstractMessageSendNode; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.MessageSendNode; +import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; +import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; +import trufflesom.interpreter.nodes.nary.UnaryExpressionNode; +import trufflesom.vm.SymbolTable; +import trufflesom.vm.VmSettings; +import trufflesom.vmobjects.SSymbol; + + +public abstract class LessThanIntNode extends UnaryExpressionNode { + + private final long intValue; + + public LessThanIntNode(final long intValue) { + this.intValue = intValue; + } + + @Override + public abstract ExpressionNode getReceiver(); + + @Specialization + public final boolean doLong(final long rcvr) { + return rcvr < intValue; + } + + @Specialization + public final boolean doDouble(final double rcvr) { + return rcvr < intValue; + } + + @Fallback + public final Object makeGenericSend(final VirtualFrame frame, + final Object receiver) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + return makeGenericSend(SymbolTable.symbolFor("<")).doPreEvaluated(frame, + new Object[] {receiver, intValue}); + } + + @Override + protected AbstractMessageSendNode makeGenericSend(final SSymbol selector) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + AbstractMessageSendNode send = + MessageSendNode.createGenericBinary(selector, getReceiver(), + new IntegerLiteralNode(intValue), 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); + } +} diff --git a/src/trufflesom/interpreter/supernodes/LocalArgLessThanInt.java b/src/trufflesom/interpreter/supernodes/LocalArgLessThanInt.java new file mode 100644 index 000000000..ce23472ee --- /dev/null +++ b/src/trufflesom/interpreter/supernodes/LocalArgLessThanInt.java @@ -0,0 +1,113 @@ +package trufflesom.interpreter.supernodes; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.UnexpectedResultException; + +import bdt.inlining.ScopeAdaptationVisitor; +import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; +import trufflesom.compiler.Variable.Argument; +import trufflesom.interpreter.bc.RespecializeException; +import trufflesom.interpreter.nodes.AbstractMessageSendNode; +import trufflesom.interpreter.nodes.ArgumentReadNode.LocalArgumentReadNode; +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.MessageSendNode; +import trufflesom.interpreter.nodes.bc.BytecodeLoopNode; +import trufflesom.interpreter.nodes.literals.IntegerLiteralNode; +import trufflesom.vm.SymbolTable; +import trufflesom.vm.VmSettings; + + +public final class LocalArgLessThanInt extends ExpressionNode { + + private final Argument arg; + private final int argIdx; + private final long intValue; + + public LocalArgLessThanInt(final Argument arg, final long intValue) { + this.arg = arg; + this.argIdx = arg.index; + this.intValue = intValue; + } + + @Override + public Object executeGeneric(final VirtualFrame frame) { + Object arg = frame.getArguments()[argIdx]; + if (arg instanceof Long) { + long argVal = (Long) arg; + return argVal < intValue; + } + + CompilerDirectives.transferToInterpreterAndInvalidate(); + return fallbackGeneric(frame); + } + + @Override + public Object doPreEvaluated(final VirtualFrame frame, final Object[] args) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw new UnsupportedOperationException(); + } + + @Override + public boolean executeBoolean(final VirtualFrame frame) throws UnexpectedResultException { + Object arg = frame.getArguments()[argIdx]; + if (arg instanceof Long) { + long argVal = (Long) arg; + return argVal < intValue; + } + + CompilerDirectives.transferToInterpreterAndInvalidate(); + return fallbackBool(frame); + } + + private boolean fallbackBool(final VirtualFrame frame) throws UnexpectedResultException { + Object result = makeGenericSend().doPreEvaluated(frame, + new Object[] {arg, intValue}); + if (result instanceof Boolean) { + return (Boolean) result; + } + throw new UnexpectedResultException(result); + } + + private Object fallbackGeneric(final VirtualFrame frame) { + return makeGenericSend().doPreEvaluated(frame, + new Object[] {arg, intValue}); + } + + protected AbstractMessageSendNode makeGenericSend() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + AbstractMessageSendNode send = + MessageSendNode.createGenericBinary(SymbolTable.symbolFor("<"), + new LocalArgumentReadNode(arg), + new IntegerLiteralNode(intValue), 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); + } + + @Override + public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { + ScopeElement se = inliner.getAdaptedVar(arg); + if (se.var != arg || se.contextLevel < 0) { + if (se.var instanceof Argument) { + replace( + new LocalArgLessThanInt((Argument) se.var, intValue).initialize(sourceCoord)); + } else { + replace(MessageSendNode.createGenericBinary( + SymbolTable.symbolFor("<"), + (ExpressionNode) se.var.getReadNode(se.contextLevel, sourceCoord), + new IntegerLiteralNode(intValue), + sourceCoord)); + } + } else { + assert 0 == se.contextLevel; + } + } +} diff --git a/tests/trufflesom/supernodes/GreaterThanTests.java b/tests/trufflesom/supernodes/GreaterThanTests.java deleted file mode 100644 index c387ebf4d..000000000 --- a/tests/trufflesom/supernodes/GreaterThanTests.java +++ /dev/null @@ -1,35 +0,0 @@ -package trufflesom.supernodes; - -import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.junit.Assert.assertThat; - -import org.junit.Test; - -import trufflesom.interpreter.nodes.ExpressionNode; -import trufflesom.interpreter.nodes.SequenceNode; -import trufflesom.interpreter.supernodes.LocalArgGreaterThanInt; -import trufflesom.primitives.arithmetic.GreaterThanPrim; -import trufflesom.tests.AstTestSetup; - - -public class GreaterThanTests extends AstTestSetup { - @SuppressWarnings("unchecked") - private T assertThatMainNodeIs(final String test, final Class expectedNode) { - SequenceNode seq = (SequenceNode) parseMethod( - "test: arg = ( | l1 l2 l3 l4 | \n" + test + " )"); - - ExpressionNode testExpr = read(seq, "expressions", 0); - assertThat(testExpr, instanceOf(expectedNode)); - return (T) testExpr; - } - - @Test - public void testBasics() { - assertThatMainNodeIs("arg > 0", LocalArgGreaterThanInt.class); - - // unsupported at the moment - assertThatMainNodeIs("l1 > 0", GreaterThanPrim.class); - assertThatMainNodeIs("3 > 0", GreaterThanPrim.class); - assertThatMainNodeIs("3 > 0", GreaterThanPrim.class); - } -} diff --git a/tests/trufflesom/supernodes/LesserGreaterThanTests.java b/tests/trufflesom/supernodes/LesserGreaterThanTests.java new file mode 100644 index 000000000..191eec499 --- /dev/null +++ b/tests/trufflesom/supernodes/LesserGreaterThanTests.java @@ -0,0 +1,51 @@ +package trufflesom.supernodes; + +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertThat; + +import org.junit.Test; + +import trufflesom.interpreter.nodes.ExpressionNode; +import trufflesom.interpreter.nodes.SequenceNode; +import trufflesom.interpreter.supernodes.GreaterThanIntNode; +import trufflesom.interpreter.supernodes.LessThanIntNode; +import trufflesom.interpreter.supernodes.LocalArgGreaterThanInt; +import trufflesom.interpreter.supernodes.LocalArgLessThanInt; +import trufflesom.tests.AstTestSetup; + + +public class LesserGreaterThanTests extends AstTestSetup { + @SuppressWarnings("unchecked") + private T assertThatMainNodeIs(final String test, final Class expectedNode) { + SequenceNode seq = (SequenceNode) parseMethod( + "test: arg = ( | l1 l2 l3 l4 | \n" + test + " )"); + + ExpressionNode testExpr = read(seq, "expressions", 0); + assertThat(testExpr, instanceOf(expectedNode)); + return (T) testExpr; + } + + @Test + public void testGreaterThan() { + assertThatMainNodeIs("arg > 0", LocalArgGreaterThanInt.class); + + assertThatMainNodeIs("(1 + 3) > 0", GreaterThanIntNode.class); + + // unsupported at the moment + assertThatMainNodeIs("l1 > 0", GreaterThanIntNode.class); + assertThatMainNodeIs("3 > 0", GreaterThanIntNode.class); + assertThatMainNodeIs("3 > 0", GreaterThanIntNode.class); + } + + @Test + public void testLesserThan() { + assertThatMainNodeIs("arg < 0", LocalArgLessThanInt.class); + + assertThatMainNodeIs("(1 + 3) < 0", LessThanIntNode.class); + + // unsupported at the moment + assertThatMainNodeIs("l1 < 0", LessThanIntNode.class); + assertThatMainNodeIs("3 < 0", LessThanIntNode.class); + assertThatMainNodeIs("3 < 0", LessThanIntNode.class); + } +} From 92f450f0fc1cdf0ee85b6ce03dbb272e98df7720 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sat, 22 Apr 2023 00:12:45 +0100 Subject: [PATCH 25/38] Remove unsafe getFieldOffset use and suppress deprecation warning for remaining use --- .../interpreter/objectstorage/StorageAnalyzer.java | 1 + .../interpreter/objectstorage/StorageLocation.java | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/trufflesom/interpreter/objectstorage/StorageAnalyzer.java b/src/trufflesom/interpreter/objectstorage/StorageAnalyzer.java index 0ee2e3f6e..6aeefa784 100644 --- a/src/trufflesom/interpreter/objectstorage/StorageAnalyzer.java +++ b/src/trufflesom/interpreter/objectstorage/StorageAnalyzer.java @@ -30,6 +30,7 @@ public class StorageAnalyzer { dimensions = 1) private static final DirectPrimitiveAccessor[] primAccessors = new DirectPrimitiveAccessor[SObject.NUM_PRIMITIVE_FIELDS]; + @SuppressWarnings("deprecation") private static long getFieldOffset(final String fieldName) { try { Field field = SObject.class.getDeclaredField(fieldName); diff --git a/src/trufflesom/interpreter/objectstorage/StorageLocation.java b/src/trufflesom/interpreter/objectstorage/StorageLocation.java index 871bb6f8b..acc5a3c0b 100644 --- a/src/trufflesom/interpreter/objectstorage/StorageLocation.java +++ b/src/trufflesom/interpreter/objectstorage/StorageLocation.java @@ -1,7 +1,5 @@ package trufflesom.interpreter.objectstorage; -import java.lang.reflect.Field; - import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.nodes.UnexpectedResultException; @@ -24,10 +22,6 @@ public abstract class StorageLocation { private static final Unsafe unsafe = UnsafeUtil.load(); - public static long getFieldOffset(final Field field) { - return unsafe.objectFieldOffset(field); - } - public interface LongStorageLocation { long readLong(SObject obj) throws UnexpectedResultException; From 72626a113f11877ab671884965c736c42caa67f9 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 23 Apr 2023 10:44:49 +0100 Subject: [PATCH 26/38] Adapt to changes in send nodes --- .../supernodes/BinaryArgSendNode.java | 16 +--------------- .../interpreter/supernodes/QuatArgSendNode.java | 16 +--------------- .../supernodes/TernaryArgSendNode.java | 16 +--------------- .../interpreter/supernodes/UnaryArgSendNode.java | 16 +--------------- 4 files changed, 4 insertions(+), 60 deletions(-) diff --git a/src/trufflesom/interpreter/supernodes/BinaryArgSendNode.java b/src/trufflesom/interpreter/supernodes/BinaryArgSendNode.java index 56d48cf0c..099a1bc28 100644 --- a/src/trufflesom/interpreter/supernodes/BinaryArgSendNode.java +++ b/src/trufflesom/interpreter/supernodes/BinaryArgSendNode.java @@ -1,12 +1,10 @@ package trufflesom.interpreter.supernodes; -import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.frame.VirtualFrame; import trufflesom.interpreter.nodes.AbstractMessageSendNode; import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode; -import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; import trufflesom.vmobjects.SSymbol; @@ -18,7 +16,7 @@ public class BinaryArgSendNode extends AbstractMessageSendNode { public BinaryArgSendNode(final int argIdx, final ExpressionNode arg1, final SSymbol selector, final AbstractDispatchNode dispatchNode) { - super(null); + super(2, null); this.argIdx = argIdx; this.selector = selector; this.dispatchNode = dispatchNode; @@ -44,18 +42,6 @@ public SSymbol getInvocationIdentifier() { return selector; } - @Override - public int getNumberOfArguments() { - return 2; - } - - @Override - public void replaceDispatchListHead( - final GenericDispatchNode replacement) { - CompilerAsserts.neverPartOfCompilation(); - dispatchNode.replace(replacement); - } - @Override public void notifyDispatchInserted() { dispatchNode.notifyAsInserted(); diff --git a/src/trufflesom/interpreter/supernodes/QuatArgSendNode.java b/src/trufflesom/interpreter/supernodes/QuatArgSendNode.java index 994b603f8..5903e9e5e 100644 --- a/src/trufflesom/interpreter/supernodes/QuatArgSendNode.java +++ b/src/trufflesom/interpreter/supernodes/QuatArgSendNode.java @@ -1,12 +1,10 @@ package trufflesom.interpreter.supernodes; -import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.frame.VirtualFrame; import trufflesom.interpreter.nodes.AbstractMessageSendNode; import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode; -import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; import trufflesom.vmobjects.SSymbol; @@ -22,7 +20,7 @@ public QuatArgSendNode(final int argIdx, final ExpressionNode arg1, final ExpressionNode arg2, final ExpressionNode arg3, final SSymbol selector, final AbstractDispatchNode dispatchNode) { - super(null); + super(4, null); this.argIdx = argIdx; this.selector = selector; this.dispatchNode = dispatchNode; @@ -52,18 +50,6 @@ public SSymbol getInvocationIdentifier() { return selector; } - @Override - public int getNumberOfArguments() { - return 4; - } - - @Override - public void replaceDispatchListHead( - final GenericDispatchNode replacement) { - CompilerAsserts.neverPartOfCompilation(); - dispatchNode.replace(replacement); - } - @Override public void notifyDispatchInserted() { dispatchNode.notifyAsInserted(); diff --git a/src/trufflesom/interpreter/supernodes/TernaryArgSendNode.java b/src/trufflesom/interpreter/supernodes/TernaryArgSendNode.java index 199d9a7f2..0831ae37a 100644 --- a/src/trufflesom/interpreter/supernodes/TernaryArgSendNode.java +++ b/src/trufflesom/interpreter/supernodes/TernaryArgSendNode.java @@ -1,12 +1,10 @@ package trufflesom.interpreter.supernodes; -import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.frame.VirtualFrame; import trufflesom.interpreter.nodes.AbstractMessageSendNode; import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode; -import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; import trufflesom.vmobjects.SSymbol; @@ -21,7 +19,7 @@ public TernaryArgSendNode(final int argIdx, final ExpressionNode arg1, final ExpressionNode arg2, final SSymbol selector, final AbstractDispatchNode dispatchNode) { - super(null); + super(3, null); this.argIdx = argIdx; this.selector = selector; this.dispatchNode = dispatchNode; @@ -49,18 +47,6 @@ public SSymbol getInvocationIdentifier() { return selector; } - @Override - public int getNumberOfArguments() { - return 3; - } - - @Override - public void replaceDispatchListHead( - final GenericDispatchNode replacement) { - CompilerAsserts.neverPartOfCompilation(); - dispatchNode.replace(replacement); - } - @Override public void notifyDispatchInserted() { dispatchNode.notifyAsInserted(); diff --git a/src/trufflesom/interpreter/supernodes/UnaryArgSendNode.java b/src/trufflesom/interpreter/supernodes/UnaryArgSendNode.java index 6a80c632e..7e5cd4538 100644 --- a/src/trufflesom/interpreter/supernodes/UnaryArgSendNode.java +++ b/src/trufflesom/interpreter/supernodes/UnaryArgSendNode.java @@ -1,11 +1,9 @@ package trufflesom.interpreter.supernodes; -import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.frame.VirtualFrame; import trufflesom.interpreter.nodes.AbstractMessageSendNode; import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode; -import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; import trufflesom.vmobjects.SSymbol; @@ -16,7 +14,7 @@ public final class UnaryArgSendNode extends AbstractMessageSendNode { public UnaryArgSendNode(final int argIdx, final SSymbol selector, final AbstractDispatchNode dispatchNode) { - super(null); + super(1, null); this.argIdx = argIdx; this.selector = selector; this.dispatchNode = dispatchNode; @@ -39,18 +37,6 @@ public SSymbol getInvocationIdentifier() { return selector; } - @Override - public int getNumberOfArguments() { - return 1; - } - - @Override - public void replaceDispatchListHead( - final GenericDispatchNode replacement) { - CompilerAsserts.neverPartOfCompilation(); - dispatchNode.replace(replacement); - } - @Override public void notifyDispatchInserted() { dispatchNode.notifyAsInserted(); From 3223c68520c06556f699fff27214f0eecae69a6a Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 23 Apr 2023 10:45:10 +0100 Subject: [PATCH 27/38] Fix merge issues in IntIncrementNode --- .../supernodes/IntIncrementNode.java | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/trufflesom/interpreter/supernodes/IntIncrementNode.java b/src/trufflesom/interpreter/supernodes/IntIncrementNode.java index 000c07e11..f2e97e608 100644 --- a/src/trufflesom/interpreter/supernodes/IntIncrementNode.java +++ b/src/trufflesom/interpreter/supernodes/IntIncrementNode.java @@ -44,22 +44,15 @@ public final Object doPreEvaluated(final VirtualFrame frame, final Object[] args public abstract ExpressionNode getRcvr(); @Specialization(rewriteOn = ArithmeticException.class) - public long doInc(final long rcvr) { + public final long doInc(final long rcvr) { return Math.addExact(rcvr, incValue); } @Specialization - public double doInc(final double rcvr) { + public final double doInc(final double rcvr) { return rcvr + incValue; } - public abstract Object executeEvaluated(Object rcvr); - - @Override - public final Object doPreEvaluated(final VirtualFrame frame, final Object[] args) { - return executeEvaluated(args[0]); - } - @Fallback public final Object makeGenericSend(final VirtualFrame frame, final Object rcvr) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -67,7 +60,7 @@ public final Object makeGenericSend(final VirtualFrame frame, final Object rcvr) new Object[] {rcvr, isMinusAndValueNegated ? -incValue : incValue}); } - public boolean doesAccessField(final int fieldIdx) { + public final boolean doesAccessField(final int fieldIdx) { ExpressionNode rcvr = getRcvr(); if (rcvr instanceof FieldReadNode) { FieldReadNode r = (FieldReadNode) rcvr; @@ -77,7 +70,7 @@ public boolean doesAccessField(final int fieldIdx) { return false; } - public boolean doesAccessVariable(final Variable var) { + public final boolean doesAccessVariable(final Variable var) { ExpressionNode rcvr = getRcvr(); Local local; if (rcvr instanceof LocalVariableNode) { @@ -90,7 +83,7 @@ public boolean doesAccessVariable(final Variable var) { return local.equals(var); } - protected AbstractMessageSendNode makeGenericSend() { + protected final AbstractMessageSendNode makeGenericSend() { CompilerDirectives.transferToInterpreterAndInvalidate(); SSymbol selector = @@ -110,12 +103,12 @@ protected AbstractMessageSendNode makeGenericSend() { throw new RespecializeException(send); } - public FieldNode createFieldIncNode(final ExpressionNode self, final int fieldIndex, + public final FieldNode createFieldIncNode(final ExpressionNode self, final int fieldIndex, final long coord) { return new IntUninitIncFieldNode(self, fieldIndex, coord, incValue); } - public ExpressionNode createIncNode(final Local local, final int ctxLevel) { + public final ExpressionNode createIncNode(final Local local, final int ctxLevel) { if (ctxLevel == 0) { return IntIncLocalVariableNodeGen.create(local, incValue).initialize(sourceCoord); } From a7d9b2fb494c8af161ed94d0e9c2dc577d55b8b8 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 23 Apr 2023 10:45:47 +0100 Subject: [PATCH 28/38] Fix based on changes in send nodes --- .../interpreter/nodes/AbstractMessageSendNode.java | 3 ++- .../interpreter/nodes/GenericMessageSendNode.java | 1 + .../interpreter/nodes/MessageSendNode.java | 12 ++++++++++-- .../nodes/UninitializedMessageSendNode.java | 6 +++++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/trufflesom/interpreter/nodes/AbstractMessageSendNode.java b/src/trufflesom/interpreter/nodes/AbstractMessageSendNode.java index 146e724ed..f934b7625 100644 --- a/src/trufflesom/interpreter/nodes/AbstractMessageSendNode.java +++ b/src/trufflesom/interpreter/nodes/AbstractMessageSendNode.java @@ -5,7 +5,6 @@ import bdt.primitives.nodes.PreevaluatedExpression; import bdt.tools.nodes.Invocation; -import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; import trufflesom.vmobjects.SSymbol; @@ -43,4 +42,6 @@ public ExpressionNode[] getArguments() { public final int getNumberOfArguments() { return numArguments; } + + public abstract void notifyDispatchInserted(); } diff --git a/src/trufflesom/interpreter/nodes/GenericMessageSendNode.java b/src/trufflesom/interpreter/nodes/GenericMessageSendNode.java index 14baed104..2d2e82e80 100644 --- a/src/trufflesom/interpreter/nodes/GenericMessageSendNode.java +++ b/src/trufflesom/interpreter/nodes/GenericMessageSendNode.java @@ -52,6 +52,7 @@ public SSymbol getInvocationIdentifier() { return selector; } + @Override public void notifyDispatchInserted() { if (VmSettings.UseInstrumentation) { notifyInserted(dispatchNode); diff --git a/src/trufflesom/interpreter/nodes/MessageSendNode.java b/src/trufflesom/interpreter/nodes/MessageSendNode.java index 215351d89..08e9a4695 100644 --- a/src/trufflesom/interpreter/nodes/MessageSendNode.java +++ b/src/trufflesom/interpreter/nodes/MessageSendNode.java @@ -1,6 +1,5 @@ package trufflesom.interpreter.nodes; -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; @@ -8,7 +7,6 @@ import bdt.primitives.Specializer; import bdt.primitives.nodes.PreevaluatedExpression; import trufflesom.interpreter.nodes.ArgumentReadNode.LocalArgumentReadNode; -import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; import trufflesom.interpreter.nodes.dispatch.UninitializedDispatchNode; import trufflesom.interpreter.supernodes.BinaryArgSendNode; import trufflesom.interpreter.supernodes.QuatArgSendNode; @@ -148,6 +146,11 @@ public SSymbol getInvocationIdentifier() { public String toString() { return "SuperSend(" + selector.getString() + ")"; } + + @Override + public void notifyDispatchInserted() { + throw new UnsupportedOperationException(); + } } private static final class SuperExprNode extends AbstractMessageSendNode { @@ -177,5 +180,10 @@ public SSymbol getInvocationIdentifier() { public String toString() { return "SendExpr(" + selector.getString() + ")"; } + + @Override + public void notifyDispatchInserted() { + throw new UnsupportedOperationException(); + } } } diff --git a/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java b/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java index bd5e2eee2..9f6efdfe2 100644 --- a/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java +++ b/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java @@ -5,7 +5,6 @@ import bdt.primitives.Specializer; import bdt.primitives.nodes.PreevaluatedExpression; -import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; import trufflesom.interpreter.nodes.dispatch.UninitializedDispatchNode; import trufflesom.primitives.Primitives; import trufflesom.vmobjects.SSymbol; @@ -82,4 +81,9 @@ private AbstractMessageSendNode makeGenericSend() { public SSymbol getInvocationIdentifier() { return selector; } + + @Override + public void notifyDispatchInserted() { + throw new UnsupportedOperationException(); + } } From 21860578c04793417316c1208ede64f2f0385f70 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 23 Apr 2023 10:46:14 +0100 Subject: [PATCH 29/38] Things changed around the increment nodes --- .../compiler/MethodGenerationContext.java | 23 +++++++++++++++---- src/trufflesom/compiler/ParserAst.java | 6 ++--- .../interpreter/nodes/FieldNode.java | 6 +++-- .../nodes/bc/BytecodeLoopNode.java | 2 +- .../objectstorage/FieldAccessorNode.java | 6 ++--- 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/trufflesom/compiler/MethodGenerationContext.java b/src/trufflesom/compiler/MethodGenerationContext.java index 2ff47ce53..9c91e7f83 100644 --- a/src/trufflesom/compiler/MethodGenerationContext.java +++ b/src/trufflesom/compiler/MethodGenerationContext.java @@ -50,7 +50,6 @@ 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.LocalVariableNode.LocalVariableReadNode; import trufflesom.interpreter.nodes.NonLocalVariableNode.NonLocalVariableReadNode; @@ -63,9 +62,10 @@ import trufflesom.interpreter.supernodes.LocalVariableSquareNode; import trufflesom.interpreter.supernodes.NonLocalVarReadUnaryMsgWriteNode; import trufflesom.interpreter.supernodes.NonLocalVariableSquareNode; +import trufflesom.interpreter.supernodes.UninitIncFieldNode; import trufflesom.primitives.Primitives; +import trufflesom.primitives.arithmetic.AdditionPrim; import trufflesom.vm.NotYetImplementedException; -import trufflesom.vm.constants.Nil; import trufflesom.vmobjects.SClass; import trufflesom.vmobjects.SInvokable; import trufflesom.vmobjects.SInvokable.SMethod; @@ -93,7 +93,7 @@ public class MethodGenerationContext protected final LinkedHashMap arguments; protected final LinkedHashMap locals; - private Internal frameOnStack; + private Internal frameOnStack; protected final LexicalScope currentScope; @@ -511,7 +511,22 @@ public FieldNode getObjectFieldWrite(final SSymbol fieldName, final ExpressionNo ExpressionNode self = getSelfRead(coord); if (exp instanceof IntIncrementNode && ((IntIncrementNode) exp).doesAccessField(fieldIndex)) { - return new UninitFieldIncNode(self, fieldIndex, coord); + return ((IntIncrementNode) exp).createFieldIncNode(self, fieldIndex, coord); + } + + if (exp instanceof AdditionPrim) { + AdditionPrim add = (AdditionPrim) exp; + ExpressionNode rcvr = add.getReceiver(); + ExpressionNode arg = add.getArgument(); + + if (rcvr instanceof FieldReadNode + && fieldIndex == ((FieldReadNode) rcvr).getFieldIndex()) { + return new UninitIncFieldNode(self, arg, true, fieldIndex, coord); + } + if (arg instanceof FieldReadNode + && fieldIndex == ((FieldReadNode) arg).getFieldIndex()) { + return new UninitIncFieldNode(self, rcvr, false, fieldIndex, coord); + } } return FieldWriteNodeGen.create(fieldIndex, self, exp).initialize(coord); diff --git a/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/compiler/ParserAst.java index 690d18f93..190588c5b 100644 --- a/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/compiler/ParserAst.java @@ -37,6 +37,7 @@ import trufflesom.interpreter.nodes.LocalVariableNode.LocalVariableReadNode; import trufflesom.interpreter.nodes.MessageSendNode; import trufflesom.interpreter.nodes.NonLocalVariableNode.NonLocalVariableReadNode; +import trufflesom.interpreter.nodes.SequenceNode; import trufflesom.interpreter.nodes.literals.BlockNode; import trufflesom.interpreter.nodes.literals.BlockNode.BlockNodeWithContext; import trufflesom.interpreter.nodes.literals.DoubleLiteralNode; @@ -383,9 +384,8 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, if (msg.getString().equals("+") && operand instanceof IntegerLiteralNode) { IntegerLiteralNode lit = (IntegerLiteralNode) operand; - if (lit.executeLong(null) == 1) { - return IntIncrementNodeGen.create(receiver); - } + long value = lit.executeLong(null); + return IntIncrementNodeGen.create(value, false, receiver); } return MessageSendNode.create(msg, args, coordWithL); } diff --git a/src/trufflesom/interpreter/nodes/FieldNode.java b/src/trufflesom/interpreter/nodes/FieldNode.java index 2a29570a1..c5c9a78db 100644 --- a/src/trufflesom/interpreter/nodes/FieldNode.java +++ b/src/trufflesom/interpreter/nodes/FieldNode.java @@ -295,7 +295,9 @@ public Object executeGeneric(final VirtualFrame frame) { throw new NotYetImplementedException(); } - IncrementLongFieldNode node = FieldAccessorNode.createIncrement(fieldIndex, obj, incValue); + assert incValue == 1; + IncrementLongFieldNode node = + FieldAccessorNode.createIncrement(fieldIndex, obj); IncFieldNode incNode = new IncFieldNode(self, node, sourceCoord); replace(incNode); node.notifyAsInserted(); @@ -334,7 +336,7 @@ public Object executeGeneric(final VirtualFrame frame) { @Override public long executeLong(final VirtualFrame frame) { SObject obj = (SObject) self.executeGeneric(frame); - return inc.increment(obj); + return inc.increment(obj, 1); } } diff --git a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java index 5b63a8e6c..19ed526f1 100644 --- a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java +++ b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java @@ -850,7 +850,7 @@ public Object executeGeneric(final VirtualFrame frame) { break; } - ((IncrementLongFieldNode) node).increment(obj); + ((IncrementLongFieldNode) node).increment(obj, 1); bytecodeIndex += Bytecodes.LEN_THREE_ARGS; break; } diff --git a/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java b/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java index cdb8ba59a..818f7f214 100644 --- a/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java +++ b/src/trufflesom/interpreter/objectstorage/FieldAccessorNode.java @@ -350,13 +350,13 @@ public long increment(final SObject obj, final long 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 From 450fcf7c8684ad6bb68262da0daa5e60194c5f07 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 23 Apr 2023 10:46:51 +0100 Subject: [PATCH 30/38] Bump Java version in Eclipse project to Java 19 --- .settings/org.eclipse.jdt.core.prefs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 2beb14a22..64a331b9e 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -11,9 +11,9 @@ org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled org.eclipse.jdt.core.classpath.outputOverlappingAnotherSource=error org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=19 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.compliance=19 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -24,7 +24,7 @@ org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.processAnnotations=enabled org.eclipse.jdt.core.compiler.release=disabled -org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.compiler.source=19 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=1 org.eclipse.jdt.core.formatter.align_type_members_on_columns=true org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 From d96d677363b558b6854350ffa584d7b9c3ef40f1 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 23 Apr 2023 22:06:47 +0100 Subject: [PATCH 31/38] Fix class not moved in merge, deleted now --- .../interpreter/nodes/FieldNode.java | 95 ------------------- 1 file changed, 95 deletions(-) diff --git a/src/trufflesom/interpreter/nodes/FieldNode.java b/src/trufflesom/interpreter/nodes/FieldNode.java index c5c9a78db..49ebeca86 100644 --- a/src/trufflesom/interpreter/nodes/FieldNode.java +++ b/src/trufflesom/interpreter/nodes/FieldNode.java @@ -21,7 +21,6 @@ */ package trufflesom.interpreter.nodes; -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; @@ -42,10 +41,8 @@ import trufflesom.interpreter.objectstorage.FieldAccessorNode; import trufflesom.interpreter.objectstorage.FieldAccessorNode.AbstractReadFieldNode; import trufflesom.interpreter.objectstorage.FieldAccessorNode.AbstractWriteFieldNode; -import trufflesom.interpreter.objectstorage.FieldAccessorNode.IncrementLongFieldNode; import trufflesom.interpreter.objectstorage.ObjectLayout; import trufflesom.interpreter.objectstorage.StorageLocation; -import trufflesom.vm.NotYetImplementedException; import trufflesom.vmobjects.SObject; @@ -248,98 +245,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; - private final long incValue; - - public UninitFieldIncNode(final ExpressionNode self, final int fieldIndex, - final long coord, final long value) { - this.self = self; - this.fieldIndex = fieldIndex; - this.sourceCoord = coord; - this.incValue = value; - } - - 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(); - } - - assert incValue == 1; - 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, 1); - } - } - public static final class WriteAndReturnSelf extends ExpressionNode implements PreevaluatedExpression { @Child ExpressionNode write; From 853f0c9cac9b2717a393528445cfc9c178fc6571 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Tue, 11 Apr 2023 22:25:21 +0100 Subject: [PATCH 32/38] =?UTF-8?q?The=20read+write=20square=20nodes=20may?= =?UTF-8?q?=20access=20locals=20in=20different=20lexical=20contexts?= =?UTF-8?q?=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure we track the context correctly for each variable. Add a specialization that fetches the context only once if possible. --- src/bdt/inlining/Variable.java | 3 +- .../compiler/MethodGenerationContext.java | 14 ++-- src/trufflesom/compiler/Variable.java | 19 ++--- .../interpreter/nodes/ContextualNode.java | 2 +- .../LocalVariableReadSquareWriteNode.java | 2 +- .../NonLocalVariableReadSquareWriteNode.java | 72 ++++++++++++++++--- 6 files changed, 84 insertions(+), 28 deletions(-) diff --git a/src/bdt/inlining/Variable.java b/src/bdt/inlining/Variable.java index bf519f9ea..7487cf38b 100644 --- a/src/bdt/inlining/Variable.java +++ b/src/bdt/inlining/Variable.java @@ -43,7 +43,8 @@ public interface Variable { N getSquareNode(int contextLevel, long coord); - N getReadSquareWriteNode(int contextLevel, long coord, Local readLocal); + N getReadSquareWriteNode(int writeContextLevel, long coord, Local readLocal, + int readContextLevel); /** * Create a node to write to this variable. diff --git a/src/trufflesom/compiler/MethodGenerationContext.java b/src/trufflesom/compiler/MethodGenerationContext.java index 9c91e7f83..d32b321c1 100644 --- a/src/trufflesom/compiler/MethodGenerationContext.java +++ b/src/trufflesom/compiler/MethodGenerationContext.java @@ -418,9 +418,8 @@ public ExpressionNode getLocalWriteNode(final Variable variable, } if (ctxLevel == 0) { - if (valExpr instanceof LocalVariableSquareNode) { - return variable.getReadSquareWriteNode(ctxLevel, coord, - ((LocalVariableSquareNode) valExpr).getLocal()); + if (valExpr instanceof LocalVariableSquareNode l) { + return variable.getReadSquareWriteNode(ctxLevel, coord, l.getLocal(), 0); } if (valExpr instanceof NonLocalVariableSquareNode) { throw new NotYetImplementedException( @@ -439,14 +438,13 @@ public ExpressionNode getLocalWriteNode(final Variable variable, } } } else { - if (valExpr instanceof NonLocalVariableSquareNode) { + if (valExpr instanceof NonLocalVariableSquareNode nl) { return variable.getReadSquareWriteNode(ctxLevel, coord, - ((NonLocalVariableSquareNode) valExpr).getLocal()); + nl.getLocal(), nl.getContextLevel()); } - if (valExpr instanceof LocalVariableSquareNode) { - return variable.getReadSquareWriteNode(ctxLevel, coord, - ((LocalVariableSquareNode) valExpr).getLocal()); + if (valExpr instanceof LocalVariableSquareNode l) { + return variable.getReadSquareWriteNode(ctxLevel, coord, l.getLocal(), 0); } if (valExpr instanceof UninitializedMessageSendNode) { diff --git a/src/trufflesom/compiler/Variable.java b/src/trufflesom/compiler/Variable.java index b8b21cfda..375f98c37 100644 --- a/src/trufflesom/compiler/Variable.java +++ b/src/trufflesom/compiler/Variable.java @@ -148,8 +148,8 @@ public ExpressionNode getSquareNode(final int contextLevel, final long coord) { } @Override - public ExpressionNode getReadSquareWriteNode(final int contextLevel, final long coord, - final Local readLocal) { + public ExpressionNode getReadSquareWriteNode(final int writeContextLevel, final long coord, + final Local readLocal, final int readContextLevel) { throw new NotYetImplementedException(); } @@ -227,12 +227,13 @@ public ExpressionNode getSquareNode(final int contextLevel, final long coord) { } @Override - public ExpressionNode getReadSquareWriteNode(final int contextLevel, final long coord, - final Local readLocal) { - if (contextLevel > 0) { - return NonLocalVariableReadSquareWriteNodeGen.create(contextLevel, this, readLocal) - .initialize(coord); + public ExpressionNode getReadSquareWriteNode(final int writeContextLevel, final long coord, + final Local readLocal, final int readContextLevel) { + if (writeContextLevel > 0) { + return NonLocalVariableReadSquareWriteNodeGen.create( + writeContextLevel, this, readLocal, readContextLevel).initialize(coord); } + assert readContextLevel == 0; return LocalVariableReadSquareWriteNodeGen.create(this, readLocal).initialize(coord); } @@ -349,8 +350,8 @@ public ExpressionNode getSquareNode(final int contextLevel, final long coord) { } @Override - public ExpressionNode getReadSquareWriteNode(final int contextLevel, final long coord, - final Local readLocal) { + public ExpressionNode getReadSquareWriteNode(final int readContextLevel, final long coord, + final Local readLocal, final int writeContextLevel) { throw new UnsupportedOperationException( "There shouldn't be any language-level square nodes for internal slots. "); } diff --git a/src/trufflesom/interpreter/nodes/ContextualNode.java b/src/trufflesom/interpreter/nodes/ContextualNode.java index 169e56947..4a3b2f0d8 100644 --- a/src/trufflesom/interpreter/nodes/ContextualNode.java +++ b/src/trufflesom/interpreter/nodes/ContextualNode.java @@ -31,7 +31,7 @@ public abstract class ContextualNode extends NoPreEvalExprNode { - private static final ValueProfile frameType = ValueProfile.createClassProfile(); + protected static final ValueProfile frameType = ValueProfile.createClassProfile(); protected final int contextLevel; diff --git a/src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java b/src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java index 0ba57f554..eaf38b508 100644 --- a/src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java +++ b/src/trufflesom/interpreter/supernodes/LocalVariableReadSquareWriteNode.java @@ -79,7 +79,7 @@ public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { assert seRead.var != readLocal || seRead.contextLevel < 0; replace( seWrite.var.getReadSquareWriteNode(seWrite.contextLevel, sourceCoord, - (Local) seRead.var)); + (Local) seRead.var, seRead.contextLevel)); } else { assert 0 == seWrite.contextLevel; } diff --git a/src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java b/src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java index 393ae66de..41534a623 100644 --- a/src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java +++ b/src/trufflesom/interpreter/supernodes/NonLocalVariableReadSquareWriteNode.java @@ -2,34 +2,61 @@ import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.FrameSlotKind; import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; import bdt.inlining.ScopeAdaptationVisitor; import bdt.inlining.ScopeAdaptationVisitor.ScopeElement; import trufflesom.compiler.Variable.Local; import trufflesom.interpreter.nodes.NonLocalVariableNode; +import trufflesom.vmobjects.SBlock; public abstract class NonLocalVariableReadSquareWriteNode extends NonLocalVariableNode { protected final Local readLocal; protected final int readIndex; + protected final int readContextLevel; - public NonLocalVariableReadSquareWriteNode(final int contextLevel, final Local writeLocal, - final Local readLocal) { - super(contextLevel, writeLocal); + public NonLocalVariableReadSquareWriteNode(final int writeContextLevel, + final Local writeLocal, + final Local readLocal, final int readContextLevel) { + super(writeContextLevel, writeLocal); this.readLocal = readLocal; this.readIndex = readLocal.getIndex(); + this.readContextLevel = readContextLevel; } - @Specialization(guards = {"isLongKind(ctx)", "ctx.isLong(readIndex)"}, + @ExplodeLoop + protected final Frame determineReadContext(final VirtualFrame frame) { + if (readContextLevel == 0) { + return frame; + } + + SBlock self = (SBlock) frame.getArguments()[0]; + int i = readContextLevel - 1; + + while (i > 0) { + self = (SBlock) self.getOuterSelf(); + i--; + } + + // Graal needs help here to see that this is always a MaterializedFrame + // so, we record explicitly a class profile + return frameType.profile(self.getContext()); + } + + @Specialization( + guards = {"isLongKind(ctx)", "ctx.isLong(readIndex)", + "contextLevel == readContextLevel"}, rewriteOn = {FrameSlotTypeException.class}) - public final long writeLong(final VirtualFrame frame, + public final long writeLongSameContext(final VirtualFrame frame, @Bind("determineContext(frame)") final MaterializedFrame ctx) throws FrameSlotTypeException { long current = ctx.getLong(readIndex); @@ -40,9 +67,25 @@ public final long writeLong(final VirtualFrame frame, return result; } - @Specialization(guards = {"isDoubleKind(ctx)", "ctx.isDouble(readIndex)"}, + @Specialization(guards = {"isLongKind(writeCtx)", "readCtx.isLong(readIndex)"}, rewriteOn = {FrameSlotTypeException.class}) - public final double writeDouble(final VirtualFrame frame, + public final long writeLong(final VirtualFrame frame, + @Bind("determineContext(frame)") final MaterializedFrame writeCtx, + @Bind("determineReadContext(frame)") final Frame readCtx) + throws FrameSlotTypeException { + long current = readCtx.getLong(readIndex); + long result = Math.multiplyExact(current, current); + + writeCtx.setLong(slotIndex, result); + + return result; + } + + @Specialization( + guards = {"isDoubleKind(ctx)", "ctx.isDouble(readIndex)", + "contextLevel == readContextLevel"}, + rewriteOn = {FrameSlotTypeException.class}) + public final double writeDoubleSameContext(final VirtualFrame frame, @Bind("determineContext(frame)") final MaterializedFrame ctx) throws FrameSlotTypeException { double current = ctx.getDouble(readIndex); @@ -52,6 +95,19 @@ public final double writeDouble(final VirtualFrame frame, return result; } + @Specialization(guards = {"isDoubleKind(writeCtx)", "readCtx.isDouble(readIndex)"}, + rewriteOn = {FrameSlotTypeException.class}) + public final double writeDouble(final VirtualFrame frame, + @Bind("determineContext(frame)") final MaterializedFrame writeCtx, + @Bind("determineReadContext(frame)") final Frame readCtx) + throws FrameSlotTypeException { + double current = readCtx.getDouble(readIndex); + double result = current * current; + + writeCtx.setDouble(slotIndex, result); + return result; + } + protected final boolean isLongKind(final VirtualFrame frame) { FrameDescriptor descriptor = local.getFrameDescriptor(); if (descriptor.getSlotKind(slotIndex) == FrameSlotKind.Long) { @@ -87,7 +143,7 @@ public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) { assert seRead.var != readLocal || seRead.contextLevel < contextLevel; replace( seWrite.var.getReadSquareWriteNode(seWrite.contextLevel, sourceCoord, - (Local) seRead.var)); + (Local) seRead.var, seRead.contextLevel)); } else { assert contextLevel == seWrite.contextLevel; } From c10025b2710a6ebaac245870853ae5a3eadb41e9 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Mon, 24 Apr 2023 21:31:08 +0100 Subject: [PATCH 33/38] Initialize separte test context for each test class This avoids issues in Eclipse with the SomTests interferring with the context of TruffleTestSetup --- tests/trufflesom/tests/SplittingTests.java | 2 +- tests/trufflesom/tests/TruffleTestSetup.java | 23 ++++++++++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/tests/trufflesom/tests/SplittingTests.java b/tests/trufflesom/tests/SplittingTests.java index 3fede4d9a..6acf7d236 100644 --- a/tests/trufflesom/tests/SplittingTests.java +++ b/tests/trufflesom/tests/SplittingTests.java @@ -18,6 +18,7 @@ public class SplittingTests extends AstTestSetup { @BeforeClass public static void init() { + initTruffle(); Universe.setupClassPath("Smalltalk"); enterContext(); @@ -31,7 +32,6 @@ public static void close() { @Test public void testCorrectFrameDescriptorUpdatesInBlocks() { - ExpressionNode body = parseMethod(""" methodToBeSplit = ( | local | diff --git a/tests/trufflesom/tests/TruffleTestSetup.java b/tests/trufflesom/tests/TruffleTestSetup.java index a8116c657..1fd8820d1 100644 --- a/tests/trufflesom/tests/TruffleTestSetup.java +++ b/tests/trufflesom/tests/TruffleTestSetup.java @@ -7,6 +7,8 @@ import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Context.Builder; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Ignore; import com.oracle.truffle.api.nodes.Node; @@ -31,7 +33,17 @@ @Ignore("provides just setup") public class TruffleTestSetup { - private static final Context truffleContext; + private static Context truffleContext; + + @BeforeClass + public static void init() { + initTruffle(); + } + + @AfterClass + public static void close() { + closeContext(); + } protected ClassGenerationContext cgenc; @@ -46,7 +58,7 @@ protected TruffleTestSetup() { argNames = new ArrayList<>(); } - private static Context initTruffle() { + protected static void initTruffle() { StorageAnalyzer.initAccessors(); if (VmSettings.UseAstInterp) { @@ -63,7 +75,7 @@ private static Context initTruffle() { Universe.selfSource = SomLanguage.getSyntheticSource("self", "self"); Universe.selfCoord = SourceCoordinate.createEmpty(); - return context; + truffleContext = context; } protected static void enterContext() { @@ -72,6 +84,7 @@ protected static void enterContext() { protected static void closeContext() { truffleContext.close(); + truffleContext = null; } protected void addField(final String name) { @@ -127,8 +140,4 @@ protected T read(final Object obj, final String fieldName, final Class c) throw new RuntimeException(e); } } - - static { - truffleContext = initTruffle(); - } } From 87ca852810b09fede9b616dad2545205283ab4ab Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Mon, 24 Apr 2023 21:51:21 +0100 Subject: [PATCH 34/38] Remove redundant transferToInterpreterAndInvalidate() Should be ensured in the caller. --- src/trufflesom/compiler/Variable.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/trufflesom/compiler/Variable.java b/src/trufflesom/compiler/Variable.java index 375f98c37..a9c4b919f 100644 --- a/src/trufflesom/compiler/Variable.java +++ b/src/trufflesom/compiler/Variable.java @@ -1,6 +1,5 @@ package trufflesom.compiler; -import static com.oracle.truffle.api.CompilerDirectives.transferToInterpreterAndInvalidate; import static trufflesom.compiler.bc.BytecodeGenerator.emitPOPARGUMENT; import static trufflesom.compiler.bc.BytecodeGenerator.emitPOPLOCAL; import static trufflesom.compiler.bc.BytecodeGenerator.emitPUSHARGUMENT; @@ -127,8 +126,6 @@ public Local splitToMergeIntoOuterScope(final int newSlotIndex) { @Override public ExpressionNode getReadNode(final int contextLevel, final long coord) { - transferToInterpreterAndInvalidate(); - if (contextLevel == 0) { return new LocalArgumentReadNode(this).initialize(coord); } else { @@ -156,8 +153,6 @@ public ExpressionNode getReadSquareWriteNode(final int writeContextLevel, final @Override public ExpressionNode getWriteNode(final int contextLevel, final ExpressionNode valueExpr, final long coord) { - transferToInterpreterAndInvalidate(); - if (contextLevel == 0) { return new LocalArgumentWriteNode(this, valueExpr).initialize(coord); } else { @@ -199,7 +194,6 @@ public void init(final FrameDescriptor descriptor) { @Override public ExpressionNode getReadNode(final int contextLevel, final long coord) { - transferToInterpreterAndInvalidate(); if (contextLevel > 0) { return NonLocalVariableReadNodeGen.create(contextLevel, this).initialize(coord); } @@ -209,7 +203,6 @@ public ExpressionNode getReadNode(final int contextLevel, final long coord) { @Override public ExpressionNode getIncNode(final int contextLevel, final long incValue, final long coord) { - transferToInterpreterAndInvalidate(); if (contextLevel > 0) { return IntIncNonLocalVariableNodeGen.create(contextLevel, this, incValue) .initialize(coord); @@ -219,7 +212,6 @@ public ExpressionNode getIncNode(final int contextLevel, final long incValue, @Override public ExpressionNode getSquareNode(final int contextLevel, final long coord) { - transferToInterpreterAndInvalidate(); if (contextLevel > 0) { return NonLocalVariableSquareNodeGen.create(contextLevel, this).initialize(coord); } @@ -254,8 +246,6 @@ public Local splitToMergeIntoOuterScope(final int newSlotIndex) { @Override public ExpressionNode getWriteNode(final int contextLevel, final ExpressionNode valueExpr, final long coord) { - transferToInterpreterAndInvalidate(); - if (contextLevel > 0) { if (valueExpr instanceof AdditionPrim) { AdditionPrim add = (AdditionPrim) valueExpr; From fecb6b19521ce988a008ed0276a5679a5f7e8c37 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Mon, 24 Apr 2023 21:57:26 +0100 Subject: [PATCH 35/38] Whitespace --- .../nodes/UninitializedMessageSendNode.java | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java b/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java index 9f6efdfe2..5eef71bc1 100644 --- a/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java +++ b/src/trufflesom/interpreter/nodes/UninitializedMessageSendNode.java @@ -57,20 +57,34 @@ private PreevaluatedExpression specialize(final Object[] arguments) { private AbstractMessageSendNode makeGenericSend() { int numArgs = argumentNodes.length; AbstractMessageSendNode send; - if (numArgs == 1) { - send = MessageSendNode.createGenericUnary(selector, argumentNodes[0], sourceCoord); - } else if (numArgs == 2) { - send = MessageSendNode.createGenericBinary(selector, argumentNodes[0], argumentNodes[1], - sourceCoord); - } else if (numArgs == 3) { - send = MessageSendNode.createGenericTernary(selector, argumentNodes[0], argumentNodes[1], - argumentNodes[2], sourceCoord); - } else if (numArgs == 4) { - send = MessageSendNode.createGenericQuat(selector, argumentNodes[0], argumentNodes[1], - argumentNodes[2], argumentNodes[3], sourceCoord); - } else { - send = new GenericMessageSendNode(selector, argumentNodes, - new UninitializedDispatchNode(selector)).initialize(sourceCoord); + + switch (numArgs) { + case 1: { + send = MessageSendNode.createGenericUnary( + selector, argumentNodes[0], sourceCoord); + break; + } + case 2: { + send = MessageSendNode.createGenericBinary( + selector, argumentNodes[0], argumentNodes[1], sourceCoord); + break; + } + case 3: { + send = MessageSendNode.createGenericTernary( + selector, argumentNodes[0], argumentNodes[1], argumentNodes[2], sourceCoord); + break; + } + case 4: { + send = MessageSendNode.createGenericQuat( + selector, argumentNodes[0], argumentNodes[1], argumentNodes[2], argumentNodes[3], + sourceCoord); + break; + } + default: { + send = new GenericMessageSendNode(selector, argumentNodes, + new UninitializedDispatchNode(selector)).initialize(sourceCoord); + break; + } } replace(send); send.notifyDispatchInserted(); From 5d3dbf6b2b262f98863b408bd5497d651265c1e5 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Mon, 24 Apr 2023 22:03:43 +0100 Subject: [PATCH 36/38] Keep child nodes only in AST interpreter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BC interpreter doesn’t need them. --- .../interpreter/nodes/nary/BinaryExpressionNode.java | 9 +++++---- .../interpreter/nodes/nary/QuaternaryExpressionNode.java | 8 ++++---- .../interpreter/nodes/nary/TernaryExpressionNode.java | 8 ++++---- .../interpreter/nodes/nary/UnaryExpressionNode.java | 8 +++++--- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/trufflesom/interpreter/nodes/nary/BinaryExpressionNode.java b/src/trufflesom/interpreter/nodes/nary/BinaryExpressionNode.java index 435a15172..d816da211 100644 --- a/src/trufflesom/interpreter/nodes/nary/BinaryExpressionNode.java +++ b/src/trufflesom/interpreter/nodes/nary/BinaryExpressionNode.java @@ -34,17 +34,18 @@ public final Object doPreEvaluated(final VirtualFrame frame, protected AbstractMessageSendNode makeGenericSend(final SSymbol selector) { CompilerDirectives.transferToInterpreterAndInvalidate(); - AbstractMessageSendNode send = - MessageSendNode.createGenericBinary(selector, getReceiver(), getArgument(), - sourceCoord); if (VmSettings.UseAstInterp) { + AbstractMessageSendNode send = + MessageSendNode.createGenericBinary(selector, getReceiver(), getArgument(), + sourceCoord); 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); + throw new RespecializeException( + MessageSendNode.createGenericBinary(selector, null, null, sourceCoord)); } } diff --git a/src/trufflesom/interpreter/nodes/nary/QuaternaryExpressionNode.java b/src/trufflesom/interpreter/nodes/nary/QuaternaryExpressionNode.java index 9e266b780..09b3689ad 100644 --- a/src/trufflesom/interpreter/nodes/nary/QuaternaryExpressionNode.java +++ b/src/trufflesom/interpreter/nodes/nary/QuaternaryExpressionNode.java @@ -40,17 +40,17 @@ public final Object doPreEvaluated(final VirtualFrame frame, protected AbstractMessageSendNode makeGenericSend(final SSymbol selector) { CompilerDirectives.transferToInterpreterAndInvalidate(); - AbstractMessageSendNode send = - MessageSendNode.createGenericQuat(selector, getReceiver(), getArg1(), getArg2(), - getArg3(), sourceCoord); if (VmSettings.UseAstInterp) { + AbstractMessageSendNode send = MessageSendNode.createGenericQuat( + selector, getReceiver(), getArg1(), getArg2(), getArg3(), sourceCoord); 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); + throw new RespecializeException(MessageSendNode.createGenericQuat( + selector, null, null, null, null, sourceCoord)); } } diff --git a/src/trufflesom/interpreter/nodes/nary/TernaryExpressionNode.java b/src/trufflesom/interpreter/nodes/nary/TernaryExpressionNode.java index f18a5237b..d344742be 100644 --- a/src/trufflesom/interpreter/nodes/nary/TernaryExpressionNode.java +++ b/src/trufflesom/interpreter/nodes/nary/TernaryExpressionNode.java @@ -35,17 +35,17 @@ public final Object doPreEvaluated(final VirtualFrame frame, protected AbstractMessageSendNode makeGenericSend(final SSymbol selector) { CompilerDirectives.transferToInterpreterAndInvalidate(); - AbstractMessageSendNode send = - MessageSendNode.createGenericTernary(selector, getReceiver(), getArg1(), getArg2(), - sourceCoord); if (VmSettings.UseAstInterp) { + AbstractMessageSendNode send = MessageSendNode.createGenericTernary( + selector, getReceiver(), getArg1(), getArg2(), sourceCoord); 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); + throw new RespecializeException(MessageSendNode.createGenericTernary( + selector, null, null, null, sourceCoord)); } } diff --git a/src/trufflesom/interpreter/nodes/nary/UnaryExpressionNode.java b/src/trufflesom/interpreter/nodes/nary/UnaryExpressionNode.java index 1ae4abd28..8de101eda 100644 --- a/src/trufflesom/interpreter/nodes/nary/UnaryExpressionNode.java +++ b/src/trufflesom/interpreter/nodes/nary/UnaryExpressionNode.java @@ -28,16 +28,18 @@ public final Object doPreEvaluated(final VirtualFrame frame, protected AbstractMessageSendNode makeGenericSend(final SSymbol selector) { CompilerDirectives.transferToInterpreterAndInvalidate(); - AbstractMessageSendNode send = - MessageSendNode.createGenericUnary(selector, getReceiver(), sourceCoord); if (VmSettings.UseAstInterp) { + AbstractMessageSendNode send = + MessageSendNode.createGenericUnary(selector, getReceiver(), sourceCoord); + 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); + throw new RespecializeException( + MessageSendNode.createGenericUnary(selector, null, sourceCoord)); } } From 4e2df5102f0097d4b3e3d542b9a49f88a55c6695 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Mon, 24 Apr 2023 23:28:24 +0100 Subject: [PATCH 37/38] Use instanceof pattern matching, and other code simplifications --- src/trufflesom/compiler/ParserAst.java | 75 +++++++------------ .../interpreter/nodes/LocalVariableNode.java | 4 + .../nodes/NonLocalVariableNode.java | 4 + 3 files changed, 36 insertions(+), 47 deletions(-) diff --git a/src/trufflesom/compiler/ParserAst.java b/src/trufflesom/compiler/ParserAst.java index 190588c5b..45ecce14f 100644 --- a/src/trufflesom/compiler/ParserAst.java +++ b/src/trufflesom/compiler/ParserAst.java @@ -27,7 +27,6 @@ import bdt.basic.ProgramDefinitionError; import bdt.inlining.InlinableNodes; import bdt.tools.structure.StructuralProbe; -import trufflesom.compiler.Variable.Local; import trufflesom.interpreter.nodes.ArgumentReadNode.LocalArgumentReadNode; import trufflesom.interpreter.nodes.ArgumentReadNode.NonLocalArgumentReadNode; import trufflesom.interpreter.nodes.ExpressionNode; @@ -275,78 +274,61 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, String binSelector = msg.getString(); if (binSelector.equals("*")) { - if (receiver instanceof LocalVariableReadNode - && operand instanceof LocalVariableReadNode) { - Local rcvrLocal = ((LocalVariableReadNode) receiver).getLocal(); - Local opLocal = ((LocalVariableReadNode) operand).getLocal(); - if (rcvrLocal.equals(opLocal)) { - return LocalVariableSquareNodeGen.create(rcvrLocal).initialize(coordWithL); + if (receiver instanceof LocalVariableReadNode rcvr + && operand instanceof LocalVariableReadNode op) { + if (rcvr.isSameLocal(op)) { + return LocalVariableSquareNodeGen.create(rcvr.getLocal()).initialize(coordWithL); } - } else if (receiver instanceof NonLocalVariableReadNode - && operand instanceof NonLocalVariableReadNode) { - Local rcvrLocal = ((NonLocalVariableReadNode) receiver).getLocal(); - Local opLocal = ((NonLocalVariableReadNode) operand).getLocal(); - - assert ((NonLocalVariableReadNode) receiver).getContextLevel() == ((NonLocalVariableReadNode) operand).getContextLevel(); - if (rcvrLocal.equals(opLocal)) { + } else if (receiver instanceof NonLocalVariableReadNode rcvr + && operand instanceof NonLocalVariableReadNode op) { + if (rcvr.isSameLocal(op)) { + assert rcvr.getContextLevel() == op.getContextLevel(); return NonLocalVariableSquareNodeGen.create( - ((NonLocalVariableReadNode) receiver).getContextLevel(), rcvrLocal) - .initialize(coordWithL); + rcvr.getContextLevel(), rcvr.getLocal()).initialize(coordWithL); } } } else if (binSelector.equals("=")) { if (operand instanceof GenericLiteralNode) { Object literal = operand.executeGeneric(null); - if (literal instanceof String) { - if (receiver instanceof FieldReadNode) { - FieldReadNode fieldRead = (FieldReadNode) receiver; + if (literal instanceof String l) { + if (receiver instanceof FieldReadNode fieldRead) { ExpressionNode self = fieldRead.getSelf(); - if (self instanceof LocalArgumentReadNode) { + if (self instanceof LocalArgumentReadNode selfLocal) { return new LocalFieldStringEqualsNode(fieldRead.getFieldIndex(), - ((LocalArgumentReadNode) self).getArg(), (String) literal).initialize( - coordWithL); - } else if (self instanceof NonLocalArgumentReadNode) { - NonLocalArgumentReadNode arg = (NonLocalArgumentReadNode) self; + selfLocal.getArg(), l).initialize(coordWithL); + } else if (self instanceof NonLocalArgumentReadNode arg) { return new NonLocalFieldStringEqualsNode(fieldRead.getFieldIndex(), - arg.getArg(), arg.getContextLevel(), (String) literal).initialize( - coordWithL); + arg.getArg(), arg.getContextLevel(), l).initialize(coordWithL); } else { throw new NotYetImplementedException(); } - } - return StringEqualsNodeGen.create((String) literal, receiver) - .initialize(coordWithL); + return StringEqualsNodeGen.create(l, receiver).initialize(coordWithL); } } if (receiver instanceof GenericLiteralNode) { Object literal = receiver.executeGeneric(null); - if (literal instanceof String) { - if (operand instanceof FieldReadNode) { - FieldReadNode fieldRead = (FieldReadNode) operand; + if (literal instanceof String l) { + if (operand instanceof FieldReadNode fieldRead) { ExpressionNode self = fieldRead.getSelf(); - if (self instanceof LocalArgumentReadNode) { + if (self instanceof LocalArgumentReadNode selfArg) { return new LocalFieldStringEqualsNode(fieldRead.getFieldIndex(), - ((LocalArgumentReadNode) self).getArg(), (String) literal).initialize( - coordWithL); + selfArg.getArg(), l).initialize(coordWithL); } else if (self instanceof NonLocalArgumentReadNode) { NonLocalArgumentReadNode arg = (NonLocalArgumentReadNode) self; return new NonLocalFieldStringEqualsNode(fieldRead.getFieldIndex(), - arg.getArg(), arg.getContextLevel(), (String) literal).initialize( - coordWithL); + arg.getArg(), arg.getContextLevel(), l).initialize(coordWithL); } else { throw new NotYetImplementedException(); } } - return StringEqualsNodeGen.create((String) literal, operand) - .initialize(coordWithL); + return StringEqualsNodeGen.create(l, operand).initialize(coordWithL); } } - } else if (operand instanceof IntegerLiteralNode) { - IntegerLiteralNode lit = (IntegerLiteralNode) operand; + } else if (operand instanceof IntegerLiteralNode lit) { if (binSelector.equals("+")) { return IntIncrementNodeGen.create(lit.executeLong(null), false, receiver) .initialize(coordWithL); @@ -356,8 +338,8 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, .initialize(coordWithL); } if (binSelector.equals(">")) { - if (receiver instanceof LocalArgumentReadNode) { - return new LocalArgGreaterThanInt(((LocalArgumentReadNode) receiver).getArg(), + if (receiver instanceof LocalArgumentReadNode rcvr) { + return new LocalArgGreaterThanInt(rcvr.getArg(), lit.executeLong(null)).initialize(coordWithL); } @@ -365,8 +347,8 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, .initialize(coordWithL); } if (binSelector.equals("<")) { - if (receiver instanceof LocalArgumentReadNode) { - return new LocalArgLessThanInt(((LocalArgumentReadNode) receiver).getArg(), + if (receiver instanceof LocalArgumentReadNode rcvr) { + return new LocalArgLessThanInt(rcvr.getArg(), lit.executeLong(null)).initialize(coordWithL); } @@ -382,8 +364,7 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc, return inlined; } - if (msg.getString().equals("+") && operand instanceof IntegerLiteralNode) { - IntegerLiteralNode lit = (IntegerLiteralNode) operand; + if (msg.getString().equals("+") && operand instanceof IntegerLiteralNode lit) { long value = lit.executeLong(null); return IntIncrementNodeGen.create(value, false, receiver); } diff --git a/src/trufflesom/interpreter/nodes/LocalVariableNode.java b/src/trufflesom/interpreter/nodes/LocalVariableNode.java index f42a64520..e0f44c4fb 100644 --- a/src/trufflesom/interpreter/nodes/LocalVariableNode.java +++ b/src/trufflesom/interpreter/nodes/LocalVariableNode.java @@ -31,6 +31,10 @@ public Local getLocal() { return local; } + public boolean isSameLocal(final LocalVariableNode node) { + return local.equals(node.local); + } + @Override public final SSymbol getInvocationIdentifier() { return local.name; diff --git a/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java b/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java index 245729e5e..1149322ea 100644 --- a/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java +++ b/src/trufflesom/interpreter/nodes/NonLocalVariableNode.java @@ -39,6 +39,10 @@ public Local getLocal() { return local; } + public boolean isSameLocal(final NonLocalVariableNode node) { + return local.equals(node.local); + } + public abstract static class NonLocalVariableReadNode extends NonLocalVariableNode { public NonLocalVariableReadNode(final int contextLevel, final Local local) { From 274c0e668160469d239bec9940ed3c357297b0d1 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Mon, 24 Apr 2023 23:43:44 +0100 Subject: [PATCH 38/38] Added more tests for the string literal equality supernode --- .../supernodes/StringEqualsTests.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/trufflesom/supernodes/StringEqualsTests.java b/tests/trufflesom/supernodes/StringEqualsTests.java index e35b4a070..d0f234b2e 100644 --- a/tests/trufflesom/supernodes/StringEqualsTests.java +++ b/tests/trufflesom/supernodes/StringEqualsTests.java @@ -7,7 +7,9 @@ import trufflesom.interpreter.nodes.ExpressionNode; import trufflesom.interpreter.nodes.SequenceNode; +import trufflesom.interpreter.nodes.literals.BlockNode; import trufflesom.interpreter.supernodes.LocalFieldStringEqualsNode; +import trufflesom.interpreter.supernodes.NonLocalFieldStringEqualsNode; import trufflesom.interpreter.supernodes.StringEqualsNode; import trufflesom.tests.AstTestSetup; @@ -25,6 +27,19 @@ private T assertThatMainNodeIs(final String test, final Class expectedNod return (T) testExpr; } + @SuppressWarnings("unchecked") + private T assertInBlock(final String test, final Class expectedNode) { + 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(expectedNode)); + return (T) testExpr; + } + @Test public void testStringEqual() { assertThatMainNodeIs("field = 'str'", LocalFieldStringEqualsNode.class); @@ -37,4 +52,23 @@ public void testStringEqual() { assertThatMainNodeIs("'str' = var", StringEqualsNode.class); assertThatMainNodeIs("'str' = ('s' + 'dd')", StringEqualsNode.class); } + + @Test + public void testStringEqualInBlock() { + assertInBlock("[ field = 'str' ] ", NonLocalFieldStringEqualsNode.class); + assertInBlock("[ arg = 'str' ]", StringEqualsNode.class); + assertInBlock("[ var = 'str' ]", StringEqualsNode.class); + + assertInBlock("[:a | a = 'str' ]", StringEqualsNode.class); + assertInBlock("[ | v | v = 'str' ]", StringEqualsNode.class); + + assertInBlock("[ ('s' + 'dd') = 'str' ]", StringEqualsNode.class); + + assertInBlock("[ 'str' = field ]", NonLocalFieldStringEqualsNode.class); + assertInBlock("[ 'str' = arg ]", StringEqualsNode.class); + assertInBlock("[ 'str' = var ]", StringEqualsNode.class); + assertInBlock("[:a | 'str' = a ]", StringEqualsNode.class); + assertInBlock("[ | v| 'str' = v ]", StringEqualsNode.class); + assertInBlock("[ 'str' = ('s' + 'dd') ]", StringEqualsNode.class); + } }