diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/SqueakGuards.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/SqueakGuards.java index ac7ce4de1..b7d8bf240 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/SqueakGuards.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/SqueakGuards.java @@ -193,6 +193,10 @@ public static boolean isZeroOrGreater(final double value) { return value >= 0; } + public static int subtract2(final int value) { + return value - 2; + } + public static long to0(final long value) { return value - 1; } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SendBytecodes.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SendBytecodes.java index 58aa3643b..c3d555beb 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SendBytecodes.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SendBytecodes.java @@ -6,26 +6,83 @@ */ package de.hpi.swa.trufflesqueak.nodes.bytecodes; +import static de.hpi.swa.trufflesqueak.nodes.primitives.impl.ArithmeticPrimitives.AbstractArithmeticPrimitiveNode.ensureFinite; + import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.debug.DebuggerTags; +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Cached.Shared; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.GenerateInline; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.StandardTags; import com.oracle.truffle.api.instrumentation.Tag; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.api.profiles.InlinedConditionProfile; +import de.hpi.swa.trufflesqueak.exceptions.RespecializeException; import de.hpi.swa.trufflesqueak.exceptions.Returns.NonLocalReturn; import de.hpi.swa.trufflesqueak.exceptions.Returns.NonVirtualReturn; import de.hpi.swa.trufflesqueak.image.SqueakImageContext; +import de.hpi.swa.trufflesqueak.model.AbstractPointersObject; +import de.hpi.swa.trufflesqueak.model.ArrayObject; +import de.hpi.swa.trufflesqueak.model.BooleanObject; +import de.hpi.swa.trufflesqueak.model.ClassObject; import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; +import de.hpi.swa.trufflesqueak.model.LargeIntegerObject; import de.hpi.swa.trufflesqueak.model.NativeObject; +import de.hpi.swa.trufflesqueak.model.PointersObject; +import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.POINT; +import de.hpi.swa.trufflesqueak.nodes.AbstractNode; +import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode; +import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectWriteNode; +import de.hpi.swa.trufflesqueak.nodes.accessing.ArrayObjectNodes.ArrayObjectSizeNode; +import de.hpi.swa.trufflesqueak.nodes.accessing.FloatObjectNodes.AsFloatObjectIfNessaryNode; +import de.hpi.swa.trufflesqueak.nodes.accessing.SqueakObjectClassNode; +import de.hpi.swa.trufflesqueak.nodes.accessing.SqueakObjectIdentityNode; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial0NodeFactory.BytecodePrimClassNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial0NodeFactory.BytecodePrimPointXNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial0NodeFactory.BytecodePrimPointYNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial0NodeFactory.BytecodePrimSizeNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimAddNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimBitAndNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimBitOrNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimBitShiftNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimDivNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimDivideNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimEqualNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimGreaterOrEqualNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimGreaterThanNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimIdenticalSistaV1NodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimLessOrEqualNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimLessThanNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimMakePointNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimModNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimMultiplyNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimNotEqualNodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimNotIdenticalSistaV1NodeGen; +import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodesFactory.SendSpecial1NodeFactory.BytecodePrimSubtractNodeGen; import de.hpi.swa.trufflesqueak.nodes.context.frame.FrameStackPushNode; +import de.hpi.swa.trufflesqueak.nodes.context.frame.FrameStackReadNode; +import de.hpi.swa.trufflesqueak.nodes.context.frame.FrameStackWriteNode; +import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector0Node.Dispatch0Node; +import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector1Node.Dispatch1Node; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelectorNode; import de.hpi.swa.trufflesqueak.nodes.primitives.impl.ControlPrimitives.PrimExitToDebuggerNode; import de.hpi.swa.trufflesqueak.util.FrameAccess; public final class SendBytecodes { public abstract static class AbstractSendNode extends AbstractInstrumentableBytecodeNode { + private AbstractSendNode(final CompiledCodeObject code, final int index, final int numBytecodes) { + super(code, index, numBytecodes); + } + } + + public abstract static class AbstractCommonSendNode extends AbstractSendNode { private final int stackPointer; private final ConditionProfile nlrProfile = ConditionProfile.create(); private final ConditionProfile nvrProfile = ConditionProfile.create(); @@ -33,7 +90,7 @@ public abstract static class AbstractSendNode extends AbstractInstrumentableByte @Child protected DispatchSelectorNode dispatchNode; @Child private FrameStackPushNode pushNode; - private AbstractSendNode(final VirtualFrame frame, final CompiledCodeObject code, final int index, final int numBytecodes, final int numArgs, final int numAdditional) { + private AbstractCommonSendNode(final VirtualFrame frame, final CompiledCodeObject code, final int index, final int numBytecodes, final int numArgs, final int numAdditional) { super(code, index, numBytecodes); stackPointer = FrameAccess.getStackPointer(frame) - 1 - numArgs - numAdditional; assert stackPointer >= 0 : "Bad stack pointer"; @@ -94,26 +151,19 @@ public final String toString() { protected abstract String getBytecodeName(); } - public static final class SelfSendNode extends AbstractSendNode { + public static final class SelfSendNode extends AbstractCommonSendNode { public SelfSendNode(final VirtualFrame frame, final CompiledCodeObject code, final int index, final int numBytecodes, final NativeObject selector, final int numArgs) { super(frame, code, index, numBytecodes, numArgs, 0); dispatchNode = DispatchSelectorNode.create(frame, selector, numArgs); } - public static AbstractBytecodeNode createSpecialSelectorSend(final VirtualFrame frame, final CompiledCodeObject code, final int index, final int selectorIndex) { - final SqueakImageContext image = code.getSqueakClass().getImage(); - final NativeObject specialSelector = image.getSpecialSelector(selectorIndex); - final int numArguments = image.getSpecialSelectorNumArgs(selectorIndex); - return new SelfSendNode(frame, code, index, 1, specialSelector, numArguments); - } - @Override protected String getBytecodeName() { return "send"; } } - public static final class SuperSendNode extends AbstractSendNode { + public static final class SuperSendNode extends AbstractCommonSendNode { public SuperSendNode(final VirtualFrame frame, final CompiledCodeObject code, final int index, final int numBytecodes, final int literalIndex, final int numArgs) { super(frame, code, index, numBytecodes, numArgs, 0); final NativeObject selector = (NativeObject) code.getLiteral(literalIndex); @@ -126,7 +176,7 @@ protected String getBytecodeName() { } } - public static final class DirectedSuperSendNode extends AbstractSendNode { + public static final class DirectedSuperSendNode extends AbstractCommonSendNode { public DirectedSuperSendNode(final VirtualFrame frame, final CompiledCodeObject code, final int index, final int numBytecodes, final int selectorLiteralIndex, final int numArgs) { super(frame, code, index, numBytecodes, numArgs, 1 /* directed class */); assert 0 <= selectorLiteralIndex && selectorLiteralIndex < 65535 : "selectorLiteralIndex out of range"; @@ -140,4 +190,675 @@ protected String getBytecodeName() { return "directedSuperSend"; } } + + public static AbstractBytecodeNode createSpecialSelectorSend(final VirtualFrame frame, final CompiledCodeObject code, final int index, final int selectorIndex) { + return switch (selectorIndex) { + case 0 /* #+ */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimAddNodeGen.create()); + case 1 /* #- */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimSubtractNodeGen.create()); + case 2 /* #< */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimLessThanNodeGen.create()); + case 3 /* #> */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimGreaterThanNodeGen.create()); + case 4 /* #<= */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimLessOrEqualNodeGen.create()); + case 5 /* #>= */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimGreaterOrEqualNodeGen.create()); + case 6 /* #= */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimEqualNodeGen.create()); + case 7 /* #~= */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimNotEqualNodeGen.create()); + case 8 /* #* */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimMultiplyNodeGen.create()); + case 9 /* #/ */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimDivideNodeGen.create()); + case 10 /* #\\ */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimModNodeGen.create()); + case 11 /* #@ */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimMakePointNodeGen.create()); + case 12 /* #bitShift: */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimBitShiftNodeGen.create()); + case 13 /* #// */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimDivNodeGen.create()); + case 14 /* #bitAnd: */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimBitAndNodeGen.create()); + case 15 /* #bitOr: */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimBitOrNodeGen.create()); + // case 16 /* #at: */ -> fallthrough; + // case 17 /* #at:put: */ -> fallthrough; + case 18 /* #size */ -> new SendSpecial0Node(frame, code, index, selectorIndex, BytecodePrimSizeNodeGen.create()); + // case 19 /* #next */ -> fallthrough; + // case 20 /* #nextPut: */ -> fallthrough; + // case 21 /* #atEnd */ -> fallthrough; + case 22 /* #== */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimIdenticalSistaV1NodeGen.create()); + case 23 /* #class */ -> new SendSpecial0Node(frame, code, index, selectorIndex, BytecodePrimClassNodeGen.create()); + case 24 /* #~~ */ -> new SendSpecial1Node(frame, code, index, selectorIndex, BytecodePrimNotIdenticalSistaV1NodeGen.create()); + // case 25 /* #value */ -> must go through SelfSendNode; + // case 26 /* #value: */ -> must go through SelfSendNode; + // case 27 /* #do: */ -> fallthrough; + // case 28 /* #new */ -> fallthrough; + // case 29 /* #new: */ -> fallthrough; + case 30 /* #x: */ -> new SendSpecial0Node(frame, code, index, selectorIndex, BytecodePrimPointXNodeGen.create()); + case 31 /* #y: */ -> new SendSpecial0Node(frame, code, index, selectorIndex, BytecodePrimPointYNodeGen.create()); + default -> { + final SqueakImageContext image = code.getSqueakClass().getImage(); + final NativeObject specialSelector = image.getSpecialSelector(selectorIndex); + final int numArguments = image.getSpecialSelectorNumArgs(selectorIndex); + yield new SelfSendNode(frame, code, index, 1, specialSelector, numArguments); + } + }; + } + + private abstract static class DispatchBytecodePrimNode extends AbstractNode { + protected final NativeObject getSpecialSelector() { + return getContext().getSpecialSelector(getSelectorIndex()); + } + + abstract int getSelectorIndex(); + } + + protected static final class SendSpecial0Node extends AbstractSendNode { + @Child private FrameStackReadNode receiverNode; + @Child private FrameStackWriteNode writeResultNode; + @Child private DispatchBytecodePrim0Node dispatchNode; + + SendSpecial0Node(final VirtualFrame frame, final CompiledCodeObject code, final int index, final int selectorIndex, final DispatchBytecodePrim0Node dispatchNode) { + super(code, index, 1); + final int stackPointer = FrameAccess.getStackPointer(frame); + receiverNode = FrameStackReadNode.create(frame, stackPointer - 1, false); // overwritten + writeResultNode = FrameStackWriteNode.create(frame, stackPointer - 1); + assert selectorIndex == dispatchNode.getSelectorIndex(); + this.dispatchNode = dispatchNode; + } + + @Override + public void executeVoid(final VirtualFrame frame) { + writeResultNode.executeWrite(frame, dispatchNode.execute(frame, receiverNode.executeRead(frame))); + } + + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return "send: " + dispatchNode.getSpecialSelector().asStringUnsafe(); + } + + abstract static class DispatchBytecodePrim0Node extends DispatchBytecodePrimNode { + abstract Object execute(VirtualFrame frame, Object receiver); + + protected static final Object dispatch(final VirtualFrame frame, final Object receiver, final int stackPointer, final Dispatch0Node dispatch0Node) { + FrameAccess.setStackPointer(frame, stackPointer - 1); + final Object result = dispatch0Node.execute(frame, receiver); + FrameAccess.setStackPointer(frame, stackPointer); + return result; + } + } + + @GenerateInline(false) + abstract static class BytecodePrimSizeNode extends DispatchBytecodePrim0Node { + @Override + protected final int getSelectorIndex() { + return 18; + } + + @Specialization(guards = "receiver.isByteType()") + protected static final long doNativeObjectByte(final NativeObject receiver) { + return receiver.getByteLength(); + } + + @Specialization + protected static final long doArray(final ArrayObject receiver, + @Bind("this") final Node node, + @Cached final ArrayObjectSizeNode sizeNode) { + return sizeNode.execute(node, receiver); + } + + @Specialization(replaces = {"doNativeObjectByte", "doArray"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, + @Cached("getStackPointer(frame)") final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch0Node dispatch0Node) { + return dispatch(frame, receiver, stackPointer, dispatch0Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimClassNode extends DispatchBytecodePrim0Node { + @Override + protected final int getSelectorIndex() { + return 23; + } + + @Specialization + protected static final ClassObject doGeneric(final Object receiver, + @Bind("this") final Node node, + @Cached final SqueakObjectClassNode classNode) { + return classNode.executeLookup(node, receiver); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimPointXNode extends DispatchBytecodePrim0Node { + @Override + protected final int getSelectorIndex() { + return 30; + } + + @Specialization(guards = "getContext(node).isPointClass(receiver.getSqueakClass())") + protected static final Object doX(final AbstractPointersObject receiver, + @Bind("this") final Node node, + @Cached final AbstractPointersObjectReadNode readNode) { + return readNode.execute(node, receiver, POINT.X); + } + + @Fallback + protected static final Object doSend(final VirtualFrame frame, final Object receiver, + @Cached("getStackPointer(frame)") final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch0Node dispatch0Node) { + return dispatch(frame, receiver, stackPointer, dispatch0Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimPointYNode extends DispatchBytecodePrim0Node { + @Override + protected final int getSelectorIndex() { + return 31; + } + + @Specialization(guards = "getContext(node).isPointClass(receiver.getSqueakClass())") + protected static final Object doY(final AbstractPointersObject receiver, + @Bind("this") final Node node, + @Cached final AbstractPointersObjectReadNode readNode) { + return readNode.execute(node, receiver, POINT.Y); + } + + @Fallback + protected static final Object doSend(final VirtualFrame frame, final Object receiver, + @Cached("getStackPointer(frame)") final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch0Node dispatch0Node) { + return dispatch(frame, receiver, stackPointer, dispatch0Node); + } + } + } + + protected static final class SendSpecial1Node extends AbstractSendNode { + private final int newStackPointer; + @Child private FrameStackReadNode receiverNode; + @Child private FrameStackReadNode arg1Node; + @Child private FrameStackWriteNode writeResultNode; + @Child private DispatchBytecodePrim1Node dispatchNode; + + SendSpecial1Node(final VirtualFrame frame, final CompiledCodeObject code, final int index, final int selectorIndex, final DispatchBytecodePrim1Node dispatchNode) { + super(code, index, 1); + final int stackPointer = FrameAccess.getStackPointer(frame); + newStackPointer = stackPointer - 1; + receiverNode = FrameStackReadNode.create(frame, stackPointer - 2, false); // overwritten + arg1Node = FrameStackReadNode.create(frame, stackPointer - 1, true); + writeResultNode = FrameStackWriteNode.create(frame, stackPointer - 2); + assert selectorIndex == dispatchNode.getSelectorIndex(); + this.dispatchNode = dispatchNode; + } + + @Override + public void executeVoid(final VirtualFrame frame) { + final Object result = dispatchNode.execute(frame, receiverNode.executeRead(frame), arg1Node.executeRead(frame)); + FrameAccess.setStackPointer(frame, newStackPointer); + writeResultNode.executeWrite(frame, result); + } + + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return "send: " + dispatchNode.getSpecialSelector().asStringUnsafe(); + } + + abstract static class DispatchBytecodePrim1Node extends DispatchBytecodePrimNode { + abstract Object execute(VirtualFrame frame, Object receiver, Object arg1); + + protected static final Object dispatch(final VirtualFrame frame, final Object receiver, final Object arg1, final int stackPointer, final Dispatch1Node dispatch1Node) { + FrameAccess.setStackPointer(frame, stackPointer); + return dispatch1Node.execute(frame, receiver, arg1); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimAddNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 0; + } + + @Specialization(rewriteOn = ArithmeticException.class) + protected static final long doLong(final long lhs, final long rhs) { + return Math.addExact(lhs, rhs); + } + + @Specialization(replaces = "doLong") + protected final Object doLongWithOverflow(final long lhs, final long rhs) { + return LargeIntegerObject.add(getContext(), lhs, rhs); + } + + @Specialization + protected static final double doDouble(final double lhs, final double rhs) { + return lhs + rhs; + } + + @Specialization(replaces = {"doLong", "doLongWithOverflow", "doDouble"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimSubtractNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 1; + } + + @Specialization(rewriteOn = ArithmeticException.class) + protected static final long doLong(final long lhs, final long rhs) { + return Math.subtractExact(lhs, rhs); + } + + @Specialization(replaces = "doLong") + protected final Object doLongWithOverflow(final long lhs, final long rhs) { + return LargeIntegerObject.subtract(getContext(), lhs, rhs); + } + + @Specialization + protected static final double doDouble(final double lhs, final double rhs) { + return lhs - rhs; + } + + @Specialization(replaces = {"doLong", "doLongWithOverflow", "doDouble"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimLessThanNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 2; + } + + @Specialization + protected static final boolean doLong(final long lhs, final long rhs) { + return BooleanObject.wrap(lhs < rhs); + } + + @Specialization + protected static final boolean doDouble(final double lhs, final double rhs) { + return BooleanObject.wrap(lhs < rhs); + } + + @Specialization(replaces = {"doLong", "doDouble"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimGreaterThanNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 3; + } + + @Specialization + protected static final boolean doLong(final long lhs, final long rhs) { + return BooleanObject.wrap(lhs > rhs); + } + + @Specialization + protected static final boolean doDouble(final double lhs, final double rhs) { + return BooleanObject.wrap(lhs > rhs); + } + + @Specialization(replaces = {"doLong", "doDouble"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimLessOrEqualNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 4; + } + + @Specialization + protected static final boolean doLong(final long lhs, final long rhs) { + return BooleanObject.wrap(lhs <= rhs); + } + + @Specialization + protected static final boolean doDouble(final double lhs, final double rhs) { + return BooleanObject.wrap(lhs <= rhs); + } + + @Specialization(replaces = {"doLong", "doDouble"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimGreaterOrEqualNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 5; + } + + @Specialization + protected static final boolean doLong(final long lhs, final long rhs) { + return BooleanObject.wrap(lhs >= rhs); + } + + @Specialization + protected static final boolean doDouble(final double lhs, final double rhs) { + return BooleanObject.wrap(lhs >= rhs); + } + + @Specialization(replaces = {"doLong", "doDouble"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimEqualNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 6; + } + + @Specialization + protected static final boolean doLong(final long lhs, final long rhs) { + return BooleanObject.wrap(lhs == rhs); + } + + @Specialization + protected static final boolean doDouble(final double lhs, final double rhs) { + return BooleanObject.wrap(lhs == rhs); + } + + @Specialization(replaces = {"doLong", "doDouble"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimNotEqualNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 7; + } + + @Specialization + protected static final boolean doLong(final long lhs, final long rhs) { + return BooleanObject.wrap(lhs != rhs); + } + + @Specialization + protected static final boolean doDouble(final double lhs, final double rhs) { + return BooleanObject.wrap(lhs != rhs); + } + + @Specialization(replaces = {"doLong", "doDouble"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimMultiplyNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 8; + } + + @Specialization(rewriteOn = ArithmeticException.class) + protected static final long doLong(final long lhs, final long rhs) { + return Math.multiplyExact(lhs, rhs); + } + + @Specialization(replaces = "doLong") + protected final Object doLongWithOverflow(final long lhs, final long rhs) { + return LargeIntegerObject.multiply(getContext(), lhs, rhs); + } + + @Specialization(rewriteOn = RespecializeException.class) + protected static final double doDoubleFinite(final double lhs, final double rhs) throws RespecializeException { + return ensureFinite(lhs * rhs); + } + + @Specialization(replaces = "doDoubleFinite") + protected static final Object doDouble(final double lhs, final double rhs, + @Bind("this") final Node node, + @Cached final AsFloatObjectIfNessaryNode boxNode) { + return boxNode.execute(node, lhs * rhs); + } + + @Specialization(replaces = {"doLong", "doLongWithOverflow", "doDoubleFinite", "doDouble"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimDivideNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 9; + } + + @Specialization(guards = {"rhs != 0", "!isOverflowDivision(lhs, rhs)", "isIntegralWhenDividedBy(lhs, rhs)"}) + protected static final long doLong(final long lhs, final long rhs) { + return lhs / rhs; + } + + @Specialization(guards = "!isZero(rhs)", rewriteOn = RespecializeException.class) + protected static final double doDoubleFinite(final double lhs, final double rhs) throws RespecializeException { + return ensureFinite(lhs / rhs); + } + + @Specialization(guards = "!isZero(rhs)", replaces = "doDoubleFinite") + protected static final Object doDouble(final double lhs, final double rhs, + @Bind("this") final Node node, + @Cached final AsFloatObjectIfNessaryNode boxNode) { + return boxNode.execute(node, lhs / rhs); + } + + @Specialization(replaces = {"doLong", "doDoubleFinite", "doDouble"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimModNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 10; + } + + /** Profiled version of {@link Math#floorMod(long, long)}. */ + @Specialization(guards = "rhs != 0") + protected static final long doLong(final long lhs, final long rhs, + @Bind("this") final Node node, + @Cached final InlinedConditionProfile profile) { + final long r = lhs % rhs; + // if the signs are different and modulo not zero, adjust result + if (profile.profile(node, (lhs ^ rhs) < 0 && r != 0)) { + return r + rhs; + } else { + return r; + } + } + + @Specialization(replaces = {"doLong"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimMakePointNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 11; + } + + @Specialization + protected static final PointersObject doLong(final long xPos, final long yPos, + @Bind("this") final Node node, + @Shared("writeNode") @Cached final AbstractPointersObjectWriteNode writeNode) { + return getContext(node).asPoint(writeNode, node, xPos, yPos); + } + + @Specialization + protected static final PointersObject doDouble(final double xPos, final double yPos, + @Bind("this") final Node node, + @Shared("writeNode") @Cached final AbstractPointersObjectWriteNode writeNode) { + return getContext(node).asPoint(writeNode, node, xPos, yPos); + } + + @Specialization(replaces = {"doLong", "doDouble"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimBitShiftNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 12; + } + + @Specialization(guards = {"arg >= 0", "!isLShiftLongOverflow(receiver, arg)"}) + protected static final long doLongPositive(final long receiver, final long arg) { + return receiver << arg; + } + + @Specialization(replaces = {"doLongPositive"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimDivNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 13; + } + + /** Profiled version of {@link Math#floorDiv(long, long)}. */ + @Specialization(guards = {"rhs != 0", "!isOverflowDivision(lhs, rhs)"}) + protected static final long doLong(final long lhs, final long rhs, + @Bind("this") final Node node, + @Cached final InlinedConditionProfile profile) { + final long q = lhs / rhs; + // if the signs are different and modulo not zero, round down + if (profile.profile(node, (lhs ^ rhs) < 0 && (q * rhs != lhs))) { + return q - 1; + } else { + return q; + } + } + + @Specialization(replaces = {"doLong"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimBitAndNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 14; + } + + @Specialization + protected static final long doLong(final long receiver, final long arg) { + return receiver & arg; + } + + @Specialization(replaces = {"doLong"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimBitOrNode extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 15; + } + + @Specialization + protected static final long doLong(final long receiver, final long arg) { + return receiver | arg; + } + + @Specialization(replaces = {"doLong"}) + protected static final Object doSend(final VirtualFrame frame, final Object receiver, final Object arg1, + @Cached(value = "subtract2(getStackPointer(frame))", neverDefault = false) final int stackPointer, + @Cached("create(getSpecialSelector())") final Dispatch1Node dispatch1Node) { + return dispatch(frame, receiver, arg1, stackPointer, dispatch1Node); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimIdenticalSistaV1Node extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 22; + } + + @Specialization + protected static final boolean doGeneric(final Object receiver, final Object arg1, + @Bind("this") final Node node, + @Cached final SqueakObjectIdentityNode identityNode) { + return identityNode.execute(node, receiver, arg1); + } + } + + @GenerateInline(false) + abstract static class BytecodePrimNotIdenticalSistaV1Node extends DispatchBytecodePrim1Node { + @Override + protected final int getSelectorIndex() { + return 24; + } + + @Specialization + protected static final boolean doGeneric(final Object receiver, final Object arg1, + @Bind("this") final Node node, + @Cached final SqueakObjectIdentityNode identityNode) { + return !identityNode.execute(node, receiver, arg1); + } + } + } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SqueakBytecodeSistaV1Decoder.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SqueakBytecodeSistaV1Decoder.java index 96442fbd3..11730bf97 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SqueakBytecodeSistaV1Decoder.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SqueakBytecodeSistaV1Decoder.java @@ -79,7 +79,7 @@ private static AbstractBytecodeNode decodeBytecode(final VirtualFrame frame, fin } case 0x5F -> new MiscellaneousBytecodes.NopBytecodeNode(code, index); case 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F // - -> SendBytecodes.SelfSendNode.createSpecialSelectorSend(frame, code, index, b - 96); + -> SendBytecodes.createSpecialSelectorSend(frame, code, index, b - 96); case 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F // -> new SendBytecodes.SelfSendNode(frame, code, index, 1, (NativeObject) code.getLiteral(b & 0xF), 0); case 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F // diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SqueakBytecodeV3PlusClosuresDecoder.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SqueakBytecodeV3PlusClosuresDecoder.java index 3aa22a567..d71e3c48b 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SqueakBytecodeV3PlusClosuresDecoder.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SqueakBytecodeV3PlusClosuresDecoder.java @@ -93,7 +93,7 @@ public AbstractBytecodeNode decodeBytecode(final VirtualFrame frame, final Compi case 0xA8, 0xA9, 0xAA, 0xAB -> JumpBytecodes.ConditionalJumpOnTrueNode.createLong(code, index, b, bytecode[index + 1]); case 0xAC, 0xAD, 0xAE, 0xAF -> JumpBytecodes.ConditionalJumpOnFalseNode.createLong(code, index, b, bytecode[index + 1]); case 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF // - -> SendBytecodes.SelfSendNode.createSpecialSelectorSend(frame, code, index, b - 176); + -> SendBytecodes.createSpecialSelectorSend(frame, code, index, b - 176); case 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF // -> new SendBytecodes.SelfSendNode(frame, code, index, 1, (NativeObject) code.getLiteral(b & 0xF), 0); case 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF //