From d07ded75fdac9631d627c5cbb5abbf6629bee3c2 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Tue, 7 Jan 2025 15:54:41 +0100 Subject: [PATCH] Introduce nodes for indirect dispatch --- .../model/AbstractSqueakObject.java | 2 +- .../AbstractSqueakObjectWithClassAndHash.java | 2 +- .../model/CompiledCodeObject.java | 26 ++- .../swa/trufflesqueak/model/NativeObject.java | 2 +- .../swa/trufflesqueak/nodes/CacheLimits.java | 1 + .../nodes/dispatch/DispatchSelector0Node.java | 141 ++++++++----- .../nodes/dispatch/DispatchSelector1Node.java | 138 ++++++++---- .../nodes/dispatch/DispatchSelector2Node.java | 140 +++++++++---- .../nodes/dispatch/DispatchSelector3Node.java | 142 +++++++++---- .../nodes/dispatch/DispatchSelector4Node.java | 143 +++++++++---- .../nodes/dispatch/DispatchSelector5Node.java | 151 +++++++++---- .../dispatch/DispatchSelectorNaryNode.java | 158 +++++++++----- .../primitives/impl/ControlPrimitives.java | 198 ++++-------------- 13 files changed, 771 insertions(+), 473 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/AbstractSqueakObject.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/AbstractSqueakObject.java index 474b38302..1bb773c5c 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/AbstractSqueakObject.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/AbstractSqueakObject.java @@ -139,7 +139,7 @@ protected static final Object doSendGeneric(final Node node, final AbstractSquea arguments[i] = wrapNode.executeWrap(node, rawArguments[i]); } if (method.hasPrimitive()) { - final AbstractPrimitiveNode primitiveNode = method.getPrimitiveNode(); + final AbstractPrimitiveNode primitiveNode = method.getPrimitiveNodeOrNull(); if (primitiveNode != null) { final VirtualFrame frame = null; // FIXME? try { diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/AbstractSqueakObjectWithClassAndHash.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/AbstractSqueakObjectWithClassAndHash.java index 6a3b048e7..eabdcf363 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/AbstractSqueakObjectWithClassAndHash.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/AbstractSqueakObjectWithClassAndHash.java @@ -158,7 +158,7 @@ public final Object send(final SqueakImageContext image, final String selector, image.interrupt.deactivate(); try { if (method.hasPrimitive()) { - final AbstractPrimitiveNode primitiveNode = method.getPrimitiveNode(); + final AbstractPrimitiveNode primitiveNode = method.getPrimitiveNodeOrNull(); if (primitiveNode != null) { try { return primitiveNode.executeWithArguments(image.externalSenderFrame, this, arguments); diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/CompiledCodeObject.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/CompiledCodeObject.java index 061b1874e..9ff87d630 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/CompiledCodeObject.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/CompiledCodeObject.java @@ -53,6 +53,9 @@ public final class CompiledCodeObject extends AbstractSqueakObjectWithClassAndHa private static final String SOURCE_UNAVAILABLE_NAME = ""; public static final String SOURCE_UNAVAILABLE_CONTENTS = "Source unavailable"; + private static final AbstractPrimitiveNode NULL_PRIMITIVE = new AbstractPrimitiveNode() { + }; + // header info and data @CompilationFinal private int header; /* @@ -93,7 +96,7 @@ static final class ExecutionData { @CompilationFinal private RootCallTarget resumptionCallTarget; } - private AbstractPrimitiveNode primitiveNode; + @CompilationFinal private AbstractPrimitiveNode primitiveNode; @TruffleBoundary public CompiledCodeObject(final long header, final ClassObject classObject) { @@ -198,13 +201,6 @@ public Source getSource() { return executionData.source; } - public AbstractPrimitiveNode getPrimitiveNode() { - if (primitiveNode == null) { - primitiveNode = PrimitiveNodeFactory.getOrCreateIndexedOrNamed(this); - } - return primitiveNode; - } - // used by CompiledMethod>>callTarget public RootCallTarget getCallTargetOrNull() { if (hasExecutionData()) { @@ -439,6 +435,20 @@ public int primitiveIndex() { return (Byte.toUnsignedInt(bytes[2]) << 8) + Byte.toUnsignedInt(bytes[1]); } + @Idempotent + public AbstractPrimitiveNode getPrimitiveNodeOrNull() { + if (primitiveNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + if (hasPrimitive()) { + primitiveNode = PrimitiveNodeFactory.getOrCreateIndexedOrNamed(this); + } + if (primitiveNode == null) { + primitiveNode = NULL_PRIMITIVE; + } + } + return primitiveNode == NULL_PRIMITIVE ? null : primitiveNode; + } + public boolean isUnwindMarked() { return hasPrimitive() && primitiveIndex() == PrimitiveNodeFactory.PRIMITIVE_ENSURE_MARKER_INDEX; } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/NativeObject.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/NativeObject.java index 87f3179dc..0e7c3adba 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/NativeObject.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/NativeObject.java @@ -360,7 +360,7 @@ public Object executeAsSymbolSlow(final SqueakImageContext image, final VirtualF final Object lookupResult = LookupMethodNode.executeUncached(SqueakObjectClassNode.executeUncached(receiver), this); if (lookupResult instanceof CompiledCodeObject method) { if (method.hasPrimitive()) { - final AbstractPrimitiveNode primitiveNode = method.getPrimitiveNode(); + final AbstractPrimitiveNode primitiveNode = method.getPrimitiveNodeOrNull(); if (primitiveNode != null) { try { return primitiveNode.executeWithArguments(image.externalSenderFrame, receiver, arguments); diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/CacheLimits.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/CacheLimits.java index 0e6eb6299..a42850ad8 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/CacheLimits.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/CacheLimits.java @@ -10,4 +10,5 @@ public final class CacheLimits { public static final int INLINE_METHOD_CACHE_LIMIT = 6; public static final int INLINE_BLOCK_CACHE_LIMIT = 3; public static final int PERFORM_SELECTOR_CACHE_LIMIT = 4; + public static final int INDIRECT_PRIMITIVE_CACHE_LIMIT = 2; } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector0Node.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector0Node.java index 8419134b1..7cd72932f 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector0Node.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector0Node.java @@ -115,35 +115,9 @@ protected static final Object doDirect(final VirtualFrame frame, final Object re @SuppressWarnings("truffle-static-method") protected final Object doIndirect(final VirtualFrame frame, final Object receiver, @Bind("this") final Node node, - @Cached final SqueakObjectClassNode classNode, - @Cached final ResolveMethodNode methodNode, - @Cached final InlinedBranchProfile hasPrimitiveProfile, - @Cached final CreateFrameArgumentsForIndirectCall0Node argumentsNode, + @Cached final DispatchIndirect0Node dispatchNode, @Cached final IndirectCallNode callNode) { - final ClassObject receiverClass = classNode.executeLookup(node, receiver); - final Object lookupResult = getContext(node).lookup(receiverClass, selector); - final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); - if (method.hasPrimitive()) { - final AbstractPrimitiveNode primitiveNode = method.getPrimitiveNode(); - if (primitiveNode != null) { - hasPrimitiveProfile.enter(node); - final Object result = tryPrimitive(primitiveNode, frame.materialize(), node, method, receiver); - if (result != null) { - return result; - } - } - } - return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, receiverClass, lookupResult, method, selector)); - } - - @TruffleBoundary - private static Object tryPrimitive(final AbstractPrimitiveNode primitiveNode, final MaterializedFrame frame, final Node node, final CompiledCodeObject method, final Object receiver) { - try { - return ((Primitive0) primitiveNode).execute(frame, receiver); - } catch (final PrimitiveFailed pf) { - DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); - return null; - } + return dispatchNode.execute(frame, node, callNode, selector, receiver); } } @@ -361,33 +335,102 @@ public Object execute(final VirtualFrame frame, final Object receiver) { @GenerateInline @GenerateCached(false) - public abstract static class CreateFrameArgumentsForIndirectCall0Node extends AbstractNode { - public abstract Object[] execute(VirtualFrame frame, Node node, Object receiver, ClassObject receiverClass, Object lookupResult, CompiledCodeObject method, NativeObject selector); + public abstract static class DispatchIndirect0Node extends AbstractNode { + public abstract Object execute(VirtualFrame frame, Node node, IndirectCallNode callNode, NativeObject selector, Object receiver); @Specialization - @SuppressWarnings("unused") - protected static final Object[] doMethod(final VirtualFrame frame, final Node node, final Object receiver, final ClassObject receiverClass, - final CompiledCodeObject lookupResult, final CompiledCodeObject method, final NativeObject selector, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - return FrameAccess.newWith(senderNode.execute(frame, node, method), null, receiver); + protected static final Object doIndirect(final VirtualFrame frame, final Node node, final IndirectCallNode callNode, final NativeObject selector, final Object receiver, + @Cached final SqueakObjectClassNode classNode, + @Cached final ResolveMethodNode methodNode, + @Cached final TryPrimitive0Node tryPrimitiveNode, + @Cached final CreateFrameArgumentsForIndirectCall0Node argumentsNode) { + final ClassObject receiverClass = classNode.executeLookup(node, receiver); + final Object lookupResult = getContext(node).lookup(receiverClass, selector); + final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); + final Object result = tryPrimitiveNode.execute(frame, node, method, receiver); + if (result != null) { + return result; + } else { + return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, receiverClass, lookupResult, method, selector)); + } } - @Specialization(guards = "lookupResult == null") - protected static final Object[] doDoesNotUnderstand(final VirtualFrame frame, final Node node, final Object receiver, final ClassObject receiverClass, - @SuppressWarnings("unused") final Object lookupResult, final CompiledCodeObject method, final NativeObject selector, - @Cached final AbstractPointersObjectWriteNode writeNode, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - final Object[] arguments = ArrayUtils.EMPTY_ARRAY; - final PointersObject message = getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); - return FrameAccess.newDNUWith(senderNode.execute(frame, node, method), receiver, message); + @GenerateInline + @GenerateCached(false) + protected abstract static class TryPrimitive0Node extends AbstractNode { + abstract Object execute(VirtualFrame frame, Node node, CompiledCodeObject method, Object receiver); + + @SuppressWarnings("unused") + @Specialization(guards = "method.getPrimitiveNodeOrNull() == null") + protected static final Object doNoPrimitive(final CompiledCodeObject method, final Object receiver) { + return null; + } + + @Specialization(guards = {"method == cachedMethod", "primitiveNode != null"}, limit = "INDIRECT_PRIMITIVE_CACHE_LIMIT") + protected static final Object doCached(final VirtualFrame frame, final Node node, @SuppressWarnings("unused") final CompiledCodeObject method, final Object receiver, + @SuppressWarnings("unused") @Cached("method") final CompiledCodeObject cachedMethod, + @Bind("cachedMethod.getPrimitiveNodeOrNull()") final AbstractPrimitiveNode primitiveNode, + @Cached final InlinedBranchProfile primitiveFailedProfile) { + try { + return ((Primitive0) primitiveNode).execute(frame, receiver); + } catch (final PrimitiveFailed pf) { + primitiveFailedProfile.enter(node); + DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); + return null; + } + } + + @Specialization(replaces = {"doNoPrimitive", "doCached"}) + protected static final Object doUncached(final VirtualFrame frame, final Node node, final CompiledCodeObject method, final Object receiver) { + final AbstractPrimitiveNode primitiveNode = method.getPrimitiveNodeOrNull(); + if (primitiveNode != null) { + return tryPrimitive(primitiveNode, frame.materialize(), node, method, receiver); + } else { + return null; + } + } + + @TruffleBoundary + private static Object tryPrimitive(final AbstractPrimitiveNode primitiveNode, final MaterializedFrame frame, final Node node, final CompiledCodeObject method, final Object receiver) { + try { + return ((Primitive0) primitiveNode).execute(frame, receiver); + } catch (final PrimitiveFailed pf) { + DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); + return null; + } + } } - @Specialization(guards = {"targetObject != null", "!isCompiledCodeObject(targetObject)"}) - protected static final Object[] doObjectAsMethod(final VirtualFrame frame, final Node node, final Object receiver, @SuppressWarnings("unused") final ClassObject receiverClass, - final Object targetObject, final CompiledCodeObject method, final NativeObject selector, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - final Object[] arguments = ArrayUtils.EMPTY_ARRAY; - return FrameAccess.newOAMWith(senderNode.execute(frame, node, method), targetObject, selector, getContext(node).asArrayOfObjects(arguments), receiver); + @GenerateInline + @GenerateCached(false) + protected abstract static class CreateFrameArgumentsForIndirectCall0Node extends AbstractNode { + abstract Object[] execute(VirtualFrame frame, Node node, Object receiver, ClassObject receiverClass, Object lookupResult, CompiledCodeObject method, NativeObject selector); + + @Specialization + @SuppressWarnings("unused") + protected static final Object[] doMethod(final VirtualFrame frame, final Node node, final Object receiver, final ClassObject receiverClass, + final CompiledCodeObject lookupResult, final CompiledCodeObject method, final NativeObject selector, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + return FrameAccess.newWith(senderNode.execute(frame, node, method), null, receiver); + } + + @Specialization(guards = "lookupResult == null") + protected static final Object[] doDoesNotUnderstand(final VirtualFrame frame, final Node node, final Object receiver, final ClassObject receiverClass, + @SuppressWarnings("unused") final Object lookupResult, final CompiledCodeObject method, final NativeObject selector, + @Cached final AbstractPointersObjectWriteNode writeNode, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + final Object[] arguments = ArrayUtils.EMPTY_ARRAY; + final PointersObject message = getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); + return FrameAccess.newDNUWith(senderNode.execute(frame, node, method), receiver, message); + } + + @Specialization(guards = {"targetObject != null", "!isCompiledCodeObject(targetObject)"}) + protected static final Object[] doObjectAsMethod(final VirtualFrame frame, final Node node, final Object receiver, @SuppressWarnings("unused") final ClassObject receiverClass, + final Object targetObject, final CompiledCodeObject method, final NativeObject selector, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + final Object[] arguments = ArrayUtils.EMPTY_ARRAY; + return FrameAccess.newOAMWith(senderNode.execute(frame, node, method), targetObject, selector, getContext(node).asArrayOfObjects(arguments), receiver); + } } } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector1Node.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector1Node.java index 62880fbc7..0c82aac40 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector1Node.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector1Node.java @@ -8,6 +8,7 @@ import com.oracle.truffle.api.Assumption; 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.Cached; import com.oracle.truffle.api.dsl.Cached.Shared; @@ -16,11 +17,12 @@ import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.ReportPolymorphism; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.IndirectCallNode; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.InlinedExactClassProfile; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; import de.hpi.swa.trufflesqueak.exceptions.PrimitiveFailed; import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; @@ -113,25 +115,9 @@ protected static final Object doDirect(final VirtualFrame frame, final Object re @SuppressWarnings("truffle-static-method") protected final Object doIndirect(final VirtualFrame frame, final Object receiver, final Object arg1, @Bind("this") final Node node, - @Cached final SqueakObjectClassNode classNode, - @Cached final ResolveMethodNode methodNode, - @Cached final InlinedExactClassProfile primitiveNodeProfile, - @Cached final CreateFrameArgumentsForIndirectCall1Node argumentsNode, + @Cached final DispatchIndirect1Node dispatchNode, @Cached final IndirectCallNode callNode) { - final ClassObject receiverClass = classNode.executeLookup(node, receiver); - final Object lookupResult = getContext(node).lookup(receiverClass, selector); - final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); - if (method.hasPrimitive()) { - final Primitive1 primitiveNode = (Primitive1) primitiveNodeProfile.profile(node, method.getPrimitiveNode()); - if (primitiveNode != null) { - try { - return primitiveNode.execute(frame, receiver, arg1); - } catch (final PrimitiveFailed pf) { - DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); - } - } - } - return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, arg1, receiverClass, lookupResult, method, selector)); + return dispatchNode.execute(frame, node, callNode, selector, receiver, arg1); } } @@ -349,34 +335,104 @@ public Object execute(final VirtualFrame frame, final Object receiver, final Obj @GenerateInline @GenerateCached(false) - public abstract static class CreateFrameArgumentsForIndirectCall1Node extends AbstractNode { - public abstract Object[] execute(VirtualFrame frame, Node node, Object receiver, Object arg1, ClassObject receiverClass, Object lookupResult, CompiledCodeObject method, NativeObject selector); + public abstract static class DispatchIndirect1Node extends AbstractNode { + public abstract Object execute(VirtualFrame frame, Node node, IndirectCallNode callNode, NativeObject selector, Object receiver, Object arg1); @Specialization - @SuppressWarnings("unused") - protected static final Object[] doMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final ClassObject receiverClass, - final CompiledCodeObject lookupResult, final CompiledCodeObject method, final NativeObject selector, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - return FrameAccess.newWith(senderNode.execute(frame, node, method), null, receiver, arg1); + protected static final Object doIndirect(final VirtualFrame frame, final Node node, final IndirectCallNode callNode, final NativeObject selector, final Object receiver, final Object arg1, + @Cached final SqueakObjectClassNode classNode, + @Cached final ResolveMethodNode methodNode, + @Cached final TryPrimitive1Node tryPrimitiveNode, + @Cached final CreateFrameArgumentsForIndirectCall1Node argumentsNode) { + final ClassObject receiverClass = classNode.executeLookup(node, receiver); + final Object lookupResult = getContext(node).lookup(receiverClass, selector); + final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); + final Object result = tryPrimitiveNode.execute(frame, node, method, receiver, arg1); + if (result != null) { + return result; + } else { + return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, arg1, receiverClass, lookupResult, method, selector)); + } } - @Specialization(guards = "lookupResult == null") - protected static final Object[] doDoesNotUnderstand(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final ClassObject receiverClass, - @SuppressWarnings("unused") final Object lookupResult, final CompiledCodeObject method, final NativeObject selector, - @Cached final AbstractPointersObjectWriteNode writeNode, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - final Object[] arguments = new Object[]{arg1}; - final PointersObject message = getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); - return FrameAccess.newDNUWith(senderNode.execute(frame, node, method), receiver, message); + @GenerateInline + @GenerateCached(false) + protected abstract static class TryPrimitive1Node extends AbstractNode { + abstract Object execute(VirtualFrame frame, Node node, CompiledCodeObject method, Object receiver, Object arg1); + + @SuppressWarnings("unused") + @Specialization(guards = "method.getPrimitiveNodeOrNull() == null") + protected static final Object doNoPrimitive(final CompiledCodeObject method, final Object receiver, final Object arg1) { + return null; + } + + @Specialization(guards = {"method == cachedMethod", "primitiveNode != null"}, limit = "INDIRECT_PRIMITIVE_CACHE_LIMIT") + protected static final Object doCached(final VirtualFrame frame, final Node node, @SuppressWarnings("unused") final CompiledCodeObject method, final Object receiver, final Object arg1, + @SuppressWarnings("unused") @Cached("method") final CompiledCodeObject cachedMethod, + @Bind("cachedMethod.getPrimitiveNodeOrNull()") final AbstractPrimitiveNode primitiveNode, + @Cached final InlinedBranchProfile primitiveFailedProfile) { + try { + return ((Primitive1) primitiveNode).execute(frame, receiver, arg1); + } catch (final PrimitiveFailed pf) { + primitiveFailedProfile.enter(node); + DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); + return null; + } + } + + @Specialization(replaces = {"doNoPrimitive", "doCached"}) + protected static final Object doUncached(final VirtualFrame frame, final Node node, final CompiledCodeObject method, final Object receiver, final Object arg1) { + final AbstractPrimitiveNode primitiveNode = method.getPrimitiveNodeOrNull(); + if (primitiveNode != null) { + return tryPrimitive(primitiveNode, frame.materialize(), node, method, receiver, arg1); + } else { + return null; + } + } + + @TruffleBoundary + private static Object tryPrimitive(final AbstractPrimitiveNode primitiveNode, final MaterializedFrame frame, final Node node, final CompiledCodeObject method, final Object receiver, + final Object arg1) { + try { + return ((Primitive1) primitiveNode).execute(frame, receiver, arg1); + } catch (final PrimitiveFailed pf) { + DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); + return null; + } + } } - @Specialization(guards = {"targetObject != null", "!isCompiledCodeObject(targetObject)"}) - protected static final Object[] doObjectAsMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, - @SuppressWarnings("unused") final ClassObject receiverClass, - final Object targetObject, final CompiledCodeObject method, final NativeObject selector, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - final Object[] arguments = new Object[]{arg1}; - return FrameAccess.newOAMWith(senderNode.execute(frame, node, method), targetObject, selector, getContext(node).asArrayOfObjects(arguments), receiver); + @GenerateInline + @GenerateCached(false) + protected abstract static class CreateFrameArgumentsForIndirectCall1Node extends AbstractNode { + abstract Object[] execute(VirtualFrame frame, Node node, Object receiver, Object arg1, ClassObject receiverClass, Object lookupResult, CompiledCodeObject method, NativeObject selector); + + @Specialization + @SuppressWarnings("unused") + protected static final Object[] doMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final ClassObject receiverClass, + final CompiledCodeObject lookupResult, final CompiledCodeObject method, final NativeObject selector, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + return FrameAccess.newWith(senderNode.execute(frame, node, method), null, receiver, arg1); + } + + @Specialization(guards = "lookupResult == null") + protected static final Object[] doDoesNotUnderstand(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final ClassObject receiverClass, + @SuppressWarnings("unused") final Object lookupResult, final CompiledCodeObject method, final NativeObject selector, + @Cached final AbstractPointersObjectWriteNode writeNode, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + final Object[] arguments = new Object[]{arg1}; + final PointersObject message = getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); + return FrameAccess.newDNUWith(senderNode.execute(frame, node, method), receiver, message); + } + + @Specialization(guards = {"targetObject != null", "!isCompiledCodeObject(targetObject)"}) + protected static final Object[] doObjectAsMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, + @SuppressWarnings("unused") final ClassObject receiverClass, + final Object targetObject, final CompiledCodeObject method, final NativeObject selector, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + final Object[] arguments = new Object[]{arg1}; + return FrameAccess.newOAMWith(senderNode.execute(frame, node, method), targetObject, selector, getContext(node).asArrayOfObjects(arguments), receiver); + } } } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector2Node.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector2Node.java index bd8ec54e3..fc793aded 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector2Node.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector2Node.java @@ -8,6 +8,7 @@ import com.oracle.truffle.api.Assumption; 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.Cached; import com.oracle.truffle.api.dsl.Cached.Shared; @@ -16,11 +17,12 @@ import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.ReportPolymorphism; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.IndirectCallNode; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.InlinedExactClassProfile; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; import de.hpi.swa.trufflesqueak.exceptions.PrimitiveFailed; import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; @@ -115,25 +117,9 @@ protected static final Object doDirect(final VirtualFrame frame, final Object re @SuppressWarnings("truffle-static-method") protected final Object doIndirect(final VirtualFrame frame, final Object receiver, final Object arg1, final Object arg2, @Bind("this") final Node node, - @Cached final SqueakObjectClassNode classNode, - @Cached final ResolveMethodNode methodNode, - @Cached final InlinedExactClassProfile primitiveNodeProfile, - @Cached final CreateFrameArgumentsForIndirectCall2Node argumentsNode, + @Cached final DispatchIndirect2Node dispatchNode, @Cached final IndirectCallNode callNode) { - final ClassObject receiverClass = classNode.executeLookup(node, receiver); - final Object lookupResult = getContext(node).lookup(receiverClass, selector); - final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); - if (method.hasPrimitive()) { - final Primitive2 primitiveNode = (Primitive2) primitiveNodeProfile.profile(node, method.getPrimitiveNode()); - if (primitiveNode != null) { - try { - return primitiveNode.execute(frame, receiver, arg1, arg2); - } catch (final PrimitiveFailed pf) { - DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); - } - } - } - return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, arg1, arg2, receiverClass, lookupResult, method, selector)); + return dispatchNode.execute(frame, node, callNode, selector, receiver, arg1, arg2); } } @@ -351,34 +337,106 @@ public Object execute(final VirtualFrame frame, final Object receiver, final Obj @GenerateInline @GenerateCached(false) - public abstract static class CreateFrameArgumentsForIndirectCall2Node extends AbstractNode { - public abstract Object[] execute(VirtualFrame frame, Node node, Object receiver, Object arg1, Object arg2, ClassObject receiverClass, Object lookupResult, CompiledCodeObject method, - NativeObject selector); + public abstract static class DispatchIndirect2Node extends AbstractNode { + public abstract Object execute(VirtualFrame frame, Node node, IndirectCallNode callNode, NativeObject selector, Object receiver, Object arg1, Object arg2); @Specialization - @SuppressWarnings("unused") - protected static final Object[] doMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final ClassObject receiverClass, - final CompiledCodeObject lookupResult, final CompiledCodeObject method, final NativeObject selector, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - return FrameAccess.newWith(senderNode.execute(frame, node, method), null, receiver, arg1, arg2); + protected static final Object doIndirect(final VirtualFrame frame, final Node node, final IndirectCallNode callNode, final NativeObject selector, final Object receiver, final Object arg1, + final Object arg2, + @Cached final SqueakObjectClassNode classNode, + @Cached final ResolveMethodNode methodNode, + @Cached final TryPrimitive2Node tryPrimitiveNode, + @Cached final CreateFrameArgumentsForIndirectCall2Node argumentsNode) { + final ClassObject receiverClass = classNode.executeLookup(node, receiver); + final Object lookupResult = getContext(node).lookup(receiverClass, selector); + final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); + final Object result = tryPrimitiveNode.execute(frame, node, method, receiver, arg1, arg2); + if (result != null) { + return result; + } else { + return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, arg1, arg2, receiverClass, lookupResult, method, selector)); + } } - @Specialization(guards = "lookupResult == null") - protected static final Object[] doDoesNotUnderstand(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final ClassObject receiverClass, - @SuppressWarnings("unused") final Object lookupResult, final CompiledCodeObject method, final NativeObject selector, - @Cached final AbstractPointersObjectWriteNode writeNode, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - final Object[] arguments = new Object[]{arg1, arg2}; - final PointersObject message = getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); - return FrameAccess.newDNUWith(senderNode.execute(frame, node, method), receiver, message); + @GenerateInline + @GenerateCached(false) + protected abstract static class TryPrimitive2Node extends AbstractNode { + abstract Object execute(VirtualFrame frame, Node node, CompiledCodeObject method, Object receiver, Object arg1, Object arg2); + + @SuppressWarnings("unused") + @Specialization(guards = "method.getPrimitiveNodeOrNull() == null") + protected static final Object doNoPrimitive(final CompiledCodeObject method, final Object receiver, final Object arg1, final Object arg2) { + return null; + } + + @Specialization(guards = {"method == cachedMethod", "primitiveNode != null"}, limit = "INDIRECT_PRIMITIVE_CACHE_LIMIT") + protected static final Object doCached(final VirtualFrame frame, final Node node, @SuppressWarnings("unused") final CompiledCodeObject method, final Object receiver, final Object arg1, + final Object arg2, + @SuppressWarnings("unused") @Cached("method") final CompiledCodeObject cachedMethod, + @Bind("cachedMethod.getPrimitiveNodeOrNull()") final AbstractPrimitiveNode primitiveNode, + @Cached final InlinedBranchProfile primitiveFailedProfile) { + try { + return ((Primitive2) primitiveNode).execute(frame, receiver, arg1, arg2); + } catch (final PrimitiveFailed pf) { + primitiveFailedProfile.enter(node); + DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); + return null; + } + } + + @Specialization(replaces = {"doNoPrimitive", "doCached"}) + protected static final Object doUncached(final VirtualFrame frame, final Node node, final CompiledCodeObject method, final Object receiver, final Object arg1, final Object arg2) { + final AbstractPrimitiveNode primitiveNode = method.getPrimitiveNodeOrNull(); + if (primitiveNode != null) { + return tryPrimitive(primitiveNode, frame.materialize(), node, method, receiver, arg1, arg2); + } else { + return null; + } + } + + @TruffleBoundary + private static Object tryPrimitive(final AbstractPrimitiveNode primitiveNode, final MaterializedFrame frame, final Node node, final CompiledCodeObject method, final Object receiver, + final Object arg1, final Object arg2) { + try { + return ((Primitive2) primitiveNode).execute(frame, receiver, arg1, arg2); + } catch (final PrimitiveFailed pf) { + DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); + return null; + } + } } - @Specialization(guards = {"targetObject != null", "!isCompiledCodeObject(targetObject)"}) - protected static final Object[] doObjectAsMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, - @SuppressWarnings("unused") final ClassObject receiverClass, final Object targetObject, final CompiledCodeObject method, final NativeObject selector, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - final Object[] arguments = new Object[]{arg1, arg2}; - return FrameAccess.newOAMWith(senderNode.execute(frame, node, method), targetObject, selector, getContext(node).asArrayOfObjects(arguments), receiver); + @GenerateInline + @GenerateCached(false) + protected abstract static class CreateFrameArgumentsForIndirectCall2Node extends AbstractNode { + abstract Object[] execute(VirtualFrame frame, Node node, Object receiver, Object arg1, Object arg2, ClassObject receiverClass, Object lookupResult, CompiledCodeObject method, + NativeObject selector); + + @Specialization + @SuppressWarnings("unused") + protected static final Object[] doMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final ClassObject receiverClass, + final CompiledCodeObject lookupResult, final CompiledCodeObject method, final NativeObject selector, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + return FrameAccess.newWith(senderNode.execute(frame, node, method), null, receiver, arg1, arg2); + } + + @Specialization(guards = "lookupResult == null") + protected static final Object[] doDoesNotUnderstand(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final ClassObject receiverClass, + @SuppressWarnings("unused") final Object lookupResult, final CompiledCodeObject method, final NativeObject selector, + @Cached final AbstractPointersObjectWriteNode writeNode, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + final Object[] arguments = new Object[]{arg1, arg2}; + final PointersObject message = getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); + return FrameAccess.newDNUWith(senderNode.execute(frame, node, method), receiver, message); + } + + @Specialization(guards = {"targetObject != null", "!isCompiledCodeObject(targetObject)"}) + protected static final Object[] doObjectAsMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, + @SuppressWarnings("unused") final ClassObject receiverClass, final Object targetObject, final CompiledCodeObject method, final NativeObject selector, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + final Object[] arguments = new Object[]{arg1, arg2}; + return FrameAccess.newOAMWith(senderNode.execute(frame, node, method), targetObject, selector, getContext(node).asArrayOfObjects(arguments), receiver); + } } } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector3Node.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector3Node.java index f5a5ae117..75cf65a53 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector3Node.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector3Node.java @@ -8,6 +8,7 @@ import com.oracle.truffle.api.Assumption; 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.Cached; import com.oracle.truffle.api.dsl.Cached.Shared; @@ -16,11 +17,12 @@ import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.ReportPolymorphism; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.IndirectCallNode; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.InlinedExactClassProfile; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; import de.hpi.swa.trufflesqueak.exceptions.PrimitiveFailed; import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; @@ -117,25 +119,9 @@ protected static final Object doDirect(final VirtualFrame frame, final Object re @SuppressWarnings("truffle-static-method") protected final Object doIndirect(final VirtualFrame frame, final Object receiver, final Object arg1, final Object arg2, final Object arg3, @Bind("this") final Node node, - @Cached final SqueakObjectClassNode classNode, - @Cached final ResolveMethodNode methodNode, - @Cached final InlinedExactClassProfile primitiveNodeProfile, - @Cached final CreateFrameArgumentsForIndirectCall3Node argumentsNode, + @Cached final DispatchIndirect3Node dispatchNode, @Cached final IndirectCallNode callNode) { - final ClassObject receiverClass = classNode.executeLookup(node, receiver); - final Object lookupResult = getContext(node).lookup(receiverClass, selector); - final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); - if (method.hasPrimitive()) { - final Primitive3 primitiveNode = (Primitive3) primitiveNodeProfile.profile(node, method.getPrimitiveNode()); - if (primitiveNode != null) { - try { - return primitiveNode.execute(frame, receiver, arg1, arg2, arg3); - } catch (final PrimitiveFailed pf) { - DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); - } - } - } - return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, arg1, arg2, arg3, receiverClass, lookupResult, method, selector)); + return dispatchNode.execute(frame, node, callNode, selector, receiver, arg1, arg2, arg3); } } @@ -354,34 +340,108 @@ public Object execute(final VirtualFrame frame, final Object receiver, final Obj @GenerateInline @GenerateCached(false) - public abstract static class CreateFrameArgumentsForIndirectCall3Node extends AbstractNode { - public abstract Object[] execute(VirtualFrame frame, Node node, Object receiver, Object arg1, Object arg2, Object arg3, ClassObject receiverClass, Object lookupResult, - CompiledCodeObject method, NativeObject selector); + public abstract static class DispatchIndirect3Node extends AbstractNode { + public abstract Object execute(VirtualFrame frame, Node node, IndirectCallNode callNode, NativeObject selector, Object receiver, Object arg1, Object arg2, Object arg3); @Specialization - @SuppressWarnings("unused") - protected static final Object[] doMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, - final ClassObject receiverClass, final CompiledCodeObject lookupResult, final CompiledCodeObject method, final NativeObject selector, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - return FrameAccess.newWith(senderNode.execute(frame, node, method), null, receiver, arg1, arg2, arg3); + protected static final Object doIndirect(final VirtualFrame frame, final Node node, final IndirectCallNode callNode, final NativeObject selector, final Object receiver, final Object arg1, + final Object arg2, final Object arg3, + @Cached final SqueakObjectClassNode classNode, + @Cached final ResolveMethodNode methodNode, + @Cached final TryPrimitive3Node tryPrimitiveNode, + @Cached final CreateFrameArgumentsForIndirectCall3Node argumentsNode) { + final ClassObject receiverClass = classNode.executeLookup(node, receiver); + final Object lookupResult = getContext(node).lookup(receiverClass, selector); + final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); + final Object result = tryPrimitiveNode.execute(frame, node, method, receiver, arg1, arg2, arg3); + if (result != null) { + return result; + } else { + return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, arg1, arg2, arg3, receiverClass, lookupResult, method, selector)); + } } - @Specialization(guards = "lookupResult == null") - protected static final Object[] doDoesNotUnderstand(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, - final ClassObject receiverClass, @SuppressWarnings("unused") final Object lookupResult, final CompiledCodeObject method, final NativeObject selector, - @Cached final AbstractPointersObjectWriteNode writeNode, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - final Object[] arguments = new Object[]{arg1, arg2, arg3}; - final PointersObject message = getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); - return FrameAccess.newDNUWith(senderNode.execute(frame, node, method), receiver, message); + @GenerateInline + @GenerateCached(false) + protected abstract static class TryPrimitive3Node extends AbstractNode { + abstract Object execute(VirtualFrame frame, Node node, CompiledCodeObject method, Object receiver, Object arg1, Object arg2, Object arg3); + + @SuppressWarnings("unused") + @Specialization(guards = "method.getPrimitiveNodeOrNull() == null") + protected static final Object doNoPrimitive(final CompiledCodeObject method, final Object receiver, final Object arg1, final Object arg2, final Object arg3) { + return null; + } + + @Specialization(guards = {"method == cachedMethod", "primitiveNode != null"}, limit = "INDIRECT_PRIMITIVE_CACHE_LIMIT") + protected static final Object doCached(final VirtualFrame frame, final Node node, @SuppressWarnings("unused") final CompiledCodeObject method, final Object receiver, final Object arg1, + final Object arg2, + final Object arg3, + @SuppressWarnings("unused") @Cached("method") final CompiledCodeObject cachedMethod, + @Bind("cachedMethod.getPrimitiveNodeOrNull()") final AbstractPrimitiveNode primitiveNode, + @Cached final InlinedBranchProfile primitiveFailedProfile) { + try { + return ((Primitive3) primitiveNode).execute(frame, receiver, arg1, arg2, arg3); + } catch (final PrimitiveFailed pf) { + primitiveFailedProfile.enter(node); + DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); + return null; + } + } + + @Specialization(replaces = {"doNoPrimitive", "doCached"}) + protected static final Object doUncached(final VirtualFrame frame, final Node node, final CompiledCodeObject method, final Object receiver, final Object arg1, final Object arg2, + final Object arg3) { + final AbstractPrimitiveNode primitiveNode = method.getPrimitiveNodeOrNull(); + if (primitiveNode != null) { + return tryPrimitive(primitiveNode, frame.materialize(), node, method, receiver, arg1, arg2, arg3); + } else { + return null; + } + } + + @TruffleBoundary + private static Object tryPrimitive(final AbstractPrimitiveNode primitiveNode, final MaterializedFrame frame, final Node node, final CompiledCodeObject method, final Object receiver, + final Object arg1, final Object arg2, final Object arg3) { + try { + return ((Primitive3) primitiveNode).execute(frame, receiver, arg1, arg2, arg3); + } catch (final PrimitiveFailed pf) { + DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); + return null; + } + } } - @Specialization(guards = {"targetObject != null", "!isCompiledCodeObject(targetObject)"}) - protected static final Object[] doObjectAsMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, - @SuppressWarnings("unused") final ClassObject receiverClass, final Object targetObject, final CompiledCodeObject method, final NativeObject selector, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - final Object[] arguments = new Object[]{arg1, arg2, arg3}; - return FrameAccess.newOAMWith(senderNode.execute(frame, node, method), targetObject, selector, getContext(node).asArrayOfObjects(arguments), receiver); + @GenerateInline + @GenerateCached(false) + protected abstract static class CreateFrameArgumentsForIndirectCall3Node extends AbstractNode { + abstract Object[] execute(VirtualFrame frame, Node node, Object receiver, Object arg1, Object arg2, Object arg3, ClassObject receiverClass, Object lookupResult, + CompiledCodeObject method, NativeObject selector); + + @Specialization + @SuppressWarnings("unused") + protected static final Object[] doMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, + final ClassObject receiverClass, final CompiledCodeObject lookupResult, final CompiledCodeObject method, final NativeObject selector, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + return FrameAccess.newWith(senderNode.execute(frame, node, method), null, receiver, arg1, arg2, arg3); + } + + @Specialization(guards = "lookupResult == null") + protected static final Object[] doDoesNotUnderstand(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, + final ClassObject receiverClass, @SuppressWarnings("unused") final Object lookupResult, final CompiledCodeObject method, final NativeObject selector, + @Cached final AbstractPointersObjectWriteNode writeNode, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + final Object[] arguments = new Object[]{arg1, arg2, arg3}; + final PointersObject message = getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); + return FrameAccess.newDNUWith(senderNode.execute(frame, node, method), receiver, message); + } + + @Specialization(guards = {"targetObject != null", "!isCompiledCodeObject(targetObject)"}) + protected static final Object[] doObjectAsMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, + @SuppressWarnings("unused") final ClassObject receiverClass, final Object targetObject, final CompiledCodeObject method, final NativeObject selector, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + final Object[] arguments = new Object[]{arg1, arg2, arg3}; + return FrameAccess.newOAMWith(senderNode.execute(frame, node, method), targetObject, selector, getContext(node).asArrayOfObjects(arguments), receiver); + } } } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector4Node.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector4Node.java index fc1e67fff..30f242207 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector4Node.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector4Node.java @@ -8,6 +8,7 @@ import com.oracle.truffle.api.Assumption; 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.Cached; import com.oracle.truffle.api.dsl.Cached.Shared; @@ -16,11 +17,12 @@ import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.ReportPolymorphism; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.IndirectCallNode; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.InlinedExactClassProfile; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; import de.hpi.swa.trufflesqueak.exceptions.PrimitiveFailed; import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; @@ -119,25 +121,9 @@ protected static final Object doDirect(final VirtualFrame frame, final Object re @SuppressWarnings("truffle-static-method") protected final Object doIndirect(final VirtualFrame frame, final Object receiver, final Object arg1, final Object arg2, final Object arg3, final Object arg4, @Bind("this") final Node node, - @Cached final SqueakObjectClassNode classNode, - @Cached final ResolveMethodNode methodNode, - @Cached final InlinedExactClassProfile primitiveNodeProfile, - @Cached final CreateFrameArgumentsForIndirectCall4Node argumentsNode, + @Cached final DispatchIndirect4Node dispatchNode, @Cached final IndirectCallNode callNode) { - final ClassObject receiverClass = classNode.executeLookup(node, receiver); - final Object lookupResult = getContext(node).lookup(receiverClass, selector); - final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); - if (method.hasPrimitive()) { - final Primitive4 primitiveNode = (Primitive4) primitiveNodeProfile.profile(node, method.getPrimitiveNode()); - if (primitiveNode != null) { - try { - return primitiveNode.execute(frame, receiver, arg1, arg2, arg3, arg4); - } catch (final PrimitiveFailed pf) { - DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); - } - } - } - return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, arg1, arg2, arg3, arg4, receiverClass, lookupResult, method, selector)); + return dispatchNode.execute(frame, node, callNode, selector, receiver, arg1, arg2, arg3, arg4); } } @@ -357,34 +343,109 @@ public Object execute(final VirtualFrame frame, final Object receiver, final Obj @GenerateInline @GenerateCached(false) - public abstract static class CreateFrameArgumentsForIndirectCall4Node extends AbstractNode { - public abstract Object[] execute(VirtualFrame frame, Node node, Object receiver, Object arg1, Object arg2, Object arg3, Object arg4, ClassObject receiverClass, Object lookupResult, - CompiledCodeObject method, NativeObject selector); + public abstract static class DispatchIndirect4Node extends AbstractNode { + public abstract Object execute(VirtualFrame frame, Node node, IndirectCallNode callNode, NativeObject selector, Object receiver, Object arg1, Object arg2, Object arg3, Object arg4); @Specialization - @SuppressWarnings("unused") - protected static final Object[] doMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, final Object arg4, - final ClassObject receiverClass, final CompiledCodeObject lookupResult, final CompiledCodeObject method, final NativeObject selector, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - return FrameAccess.newWith(senderNode.execute(frame, node, method), null, receiver, arg1, arg2, arg3, arg4); + protected static final Object doIndirect(final VirtualFrame frame, final Node node, final IndirectCallNode callNode, final NativeObject selector, final Object receiver, final Object arg1, + final Object arg2, final Object arg3, final Object arg4, + @Cached final SqueakObjectClassNode classNode, + @Cached final ResolveMethodNode methodNode, + @Cached final TryPrimitive4Node tryPrimitiveNode, + @Cached final CreateFrameArgumentsForIndirectCall4Node argumentsNode) { + final ClassObject receiverClass = classNode.executeLookup(node, receiver); + final Object lookupResult = getContext(node).lookup(receiverClass, selector); + final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); + final Object result = tryPrimitiveNode.execute(frame, node, method, receiver, arg1, arg2, arg3, arg4); + if (result != null) { + return result; + } else { + return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, arg1, arg2, arg3, arg4, receiverClass, lookupResult, method, selector)); + } } - @Specialization(guards = "lookupResult == null") - protected static final Object[] doDoesNotUnderstand(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, - final Object arg4, final ClassObject receiverClass, @SuppressWarnings("unused") final Object lookupResult, final CompiledCodeObject method, final NativeObject selector, - @Cached final AbstractPointersObjectWriteNode writeNode, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - final Object[] arguments = new Object[]{arg1, arg2, arg3, arg4}; - final PointersObject message = getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); - return FrameAccess.newDNUWith(senderNode.execute(frame, node, method), receiver, message); + @GenerateInline + @GenerateCached(false) + protected abstract static class TryPrimitive4Node extends AbstractNode { + abstract Object execute(VirtualFrame frame, Node node, CompiledCodeObject method, Object receiver, Object arg1, Object arg2, Object arg3, Object arg4); + + @SuppressWarnings("unused") + @Specialization(guards = "method.getPrimitiveNodeOrNull() == null") + protected static final Object doNoPrimitive(final CompiledCodeObject method, final Object receiver, final Object arg1, final Object arg2, final Object arg3, final Object arg4) { + return null; + } + + @Specialization(guards = {"method == cachedMethod", "primitiveNode != null"}, limit = "INDIRECT_PRIMITIVE_CACHE_LIMIT") + protected static final Object doCached(final VirtualFrame frame, final Node node, @SuppressWarnings("unused") final CompiledCodeObject method, final Object receiver, final Object arg1, + final Object arg2, + final Object arg3, final Object arg4, + @SuppressWarnings("unused") @Cached("method") final CompiledCodeObject cachedMethod, + @Bind("cachedMethod.getPrimitiveNodeOrNull()") final AbstractPrimitiveNode primitiveNode, + @Cached final InlinedBranchProfile primitiveFailedProfile) { + try { + return ((Primitive4) primitiveNode).execute(frame, receiver, arg1, arg2, arg3, arg4); + } catch (final PrimitiveFailed pf) { + primitiveFailedProfile.enter(node); + DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); + return null; + } + } + + @Specialization(replaces = {"doNoPrimitive", "doCached"}) + protected static final Object doUncached(final VirtualFrame frame, final Node node, final CompiledCodeObject method, final Object receiver, final Object arg1, final Object arg2, + final Object arg3, final Object arg4) { + final AbstractPrimitiveNode primitiveNode = method.getPrimitiveNodeOrNull(); + if (primitiveNode != null) { + return tryPrimitive(primitiveNode, frame.materialize(), node, method, receiver, arg1, arg2, arg3, arg4); + } else { + return null; + } + } + + @TruffleBoundary + private static Object tryPrimitive(final AbstractPrimitiveNode primitiveNode, final MaterializedFrame frame, final Node node, final CompiledCodeObject method, final Object receiver, + final Object arg1, final Object arg2, final Object arg3, final Object arg4) { + try { + return ((Primitive4) primitiveNode).execute(frame, receiver, arg1, arg2, arg3, arg4); + } catch (final PrimitiveFailed pf) { + DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); + return null; + } + } } - @Specialization(guards = {"targetObject != null", "!isCompiledCodeObject(targetObject)"}) - protected static final Object[] doObjectAsMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, final Object arg4, - @SuppressWarnings("unused") final ClassObject receiverClass, final Object targetObject, final CompiledCodeObject method, final NativeObject selector, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - final Object[] arguments = new Object[]{arg1, arg2, arg3, arg4}; - return FrameAccess.newOAMWith(senderNode.execute(frame, node, method), targetObject, selector, getContext(node).asArrayOfObjects(arguments), receiver); + @GenerateInline + @GenerateCached(false) + protected abstract static class CreateFrameArgumentsForIndirectCall4Node extends AbstractNode { + abstract Object[] execute(VirtualFrame frame, Node node, Object receiver, Object arg1, Object arg2, Object arg3, Object arg4, ClassObject receiverClass, Object lookupResult, + CompiledCodeObject method, NativeObject selector); + + @Specialization + @SuppressWarnings("unused") + protected static final Object[] doMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, final Object arg4, + final ClassObject receiverClass, final CompiledCodeObject lookupResult, final CompiledCodeObject method, final NativeObject selector, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + return FrameAccess.newWith(senderNode.execute(frame, node, method), null, receiver, arg1, arg2, arg3, arg4); + } + + @Specialization(guards = "lookupResult == null") + protected static final Object[] doDoesNotUnderstand(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, + final Object arg4, final ClassObject receiverClass, @SuppressWarnings("unused") final Object lookupResult, final CompiledCodeObject method, final NativeObject selector, + @Cached final AbstractPointersObjectWriteNode writeNode, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + final Object[] arguments = new Object[]{arg1, arg2, arg3, arg4}; + final PointersObject message = getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); + return FrameAccess.newDNUWith(senderNode.execute(frame, node, method), receiver, message); + } + + @Specialization(guards = {"targetObject != null", "!isCompiledCodeObject(targetObject)"}) + protected static final Object[] doObjectAsMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, + final Object arg4, + @SuppressWarnings("unused") final ClassObject receiverClass, final Object targetObject, final CompiledCodeObject method, final NativeObject selector, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + final Object[] arguments = new Object[]{arg1, arg2, arg3, arg4}; + return FrameAccess.newOAMWith(senderNode.execute(frame, node, method), targetObject, selector, getContext(node).asArrayOfObjects(arguments), receiver); + } } } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector5Node.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector5Node.java index f9c823bbb..3311ebcde 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector5Node.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelector5Node.java @@ -8,6 +8,7 @@ import com.oracle.truffle.api.Assumption; 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.Cached; import com.oracle.truffle.api.dsl.Cached.Shared; @@ -16,11 +17,12 @@ import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.ReportPolymorphism; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.IndirectCallNode; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.InlinedExactClassProfile; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; import de.hpi.swa.trufflesqueak.exceptions.PrimitiveFailed; import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; @@ -122,25 +124,9 @@ protected static final Object doDirect(final VirtualFrame frame, final Object re @SuppressWarnings("truffle-static-method") protected final Object doIndirect(final VirtualFrame frame, final Object receiver, final Object arg1, final Object arg2, final Object arg3, final Object arg4, final Object arg5, @Bind("this") final Node node, - @Cached final SqueakObjectClassNode classNode, - @Cached final ResolveMethodNode methodNode, - @Cached final InlinedExactClassProfile primitiveNodeProfile, - @Cached final CreateFrameArgumentsForIndirectCall5Node argumentsNode, + @Cached final DispatchIndirect5Node dispatchNode, @Cached final IndirectCallNode callNode) { - final ClassObject receiverClass = classNode.executeLookup(node, receiver); - final Object lookupResult = getContext(node).lookup(receiverClass, selector); - final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); - if (method.hasPrimitive()) { - final Primitive5 primitiveNode = (Primitive5) primitiveNodeProfile.profile(node, method.getPrimitiveNode()); - if (primitiveNode != null) { - try { - return primitiveNode.execute(frame, receiver, arg1, arg2, arg3, arg4, arg5); - } catch (final PrimitiveFailed pf) { - DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); - } - } - } - return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, arg1, arg2, arg3, arg4, arg5, receiverClass, lookupResult, method, selector)); + return dispatchNode.execute(frame, node, callNode, selector, receiver, arg1, arg2, arg3, arg4, arg5); } } @@ -360,37 +346,114 @@ public Object execute(final VirtualFrame frame, final Object receiver, final Obj @GenerateInline @GenerateCached(false) - public abstract static class CreateFrameArgumentsForIndirectCall5Node extends AbstractNode { - public abstract Object[] execute(VirtualFrame frame, Node node, Object receiver, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ClassObject receiverClass, - Object lookupResult, - CompiledCodeObject method, NativeObject selector); + public abstract static class DispatchIndirect5Node extends AbstractNode { + public abstract Object execute(VirtualFrame frame, Node node, IndirectCallNode callNode, NativeObject selector, Object receiver, Object arg1, Object arg2, Object arg3, Object arg4, + Object arg5); @Specialization - @SuppressWarnings("unused") - protected static final Object[] doMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, final Object arg4, - final Object arg5, - final ClassObject receiverClass, final CompiledCodeObject lookupResult, final CompiledCodeObject method, final NativeObject selector, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - return FrameAccess.newWith(senderNode.execute(frame, node, method), null, receiver, arg1, arg2, arg3, arg4, arg5); + protected static final Object doIndirect(final VirtualFrame frame, final Node node, final IndirectCallNode callNode, final NativeObject selector, final Object receiver, final Object arg1, + final Object arg2, final Object arg3, final Object arg4, final Object arg5, + @Cached final SqueakObjectClassNode classNode, + @Cached final ResolveMethodNode methodNode, + @Cached final TryPrimitive5Node tryPrimitiveNode, + @Cached final CreateFrameArgumentsForIndirectCall5Node argumentsNode) { + final ClassObject receiverClass = classNode.executeLookup(node, receiver); + final Object lookupResult = getContext(node).lookup(receiverClass, selector); + final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); + final Object result = tryPrimitiveNode.execute(frame, node, method, receiver, arg1, arg2, arg3, arg4, arg5); + if (result != null) { + return result; + } else { + return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, arg1, arg2, arg3, arg4, arg5, receiverClass, lookupResult, method, selector)); + } } - @Specialization(guards = "lookupResult == null") - protected static final Object[] doDoesNotUnderstand(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, - final Object arg4, final Object arg5, final ClassObject receiverClass, @SuppressWarnings("unused") final Object lookupResult, final CompiledCodeObject method, - final NativeObject selector, - @Cached final AbstractPointersObjectWriteNode writeNode, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - final Object[] arguments = new Object[]{arg1, arg2, arg3, arg4, arg5}; - final PointersObject message = getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); - return FrameAccess.newDNUWith(senderNode.execute(frame, node, method), receiver, message); + @GenerateInline + @GenerateCached(false) + protected abstract static class TryPrimitive5Node extends AbstractNode { + abstract Object execute(VirtualFrame frame, Node node, CompiledCodeObject method, Object receiver, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5); + + @SuppressWarnings("unused") + @Specialization(guards = "method.getPrimitiveNodeOrNull() == null") + protected static final Object doNoPrimitive(final CompiledCodeObject method, final Object receiver, final Object arg1, final Object arg2, final Object arg3, final Object arg4, + final Object arg5) { + return null; + } + + @Specialization(guards = {"method == cachedMethod", "primitiveNode != null"}, limit = "INDIRECT_PRIMITIVE_CACHE_LIMIT") + protected static final Object doCached(final VirtualFrame frame, final Node node, @SuppressWarnings("unused") final CompiledCodeObject method, final Object receiver, final Object arg1, + final Object arg2, + final Object arg3, final Object arg4, final Object arg5, + @SuppressWarnings("unused") @Cached("method") final CompiledCodeObject cachedMethod, + @Bind("cachedMethod.getPrimitiveNodeOrNull()") final AbstractPrimitiveNode primitiveNode, + @Cached final InlinedBranchProfile primitiveFailedProfile) { + try { + return ((Primitive5) primitiveNode).execute(frame, receiver, arg1, arg2, arg3, arg4, arg5); + } catch (final PrimitiveFailed pf) { + primitiveFailedProfile.enter(node); + DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); + return null; + } + } + + @Specialization(replaces = {"doNoPrimitive", "doCached"}) + protected static final Object doUncached(final VirtualFrame frame, final Node node, final CompiledCodeObject method, final Object receiver, final Object arg1, final Object arg2, + final Object arg3, final Object arg4, final Object arg5) { + final AbstractPrimitiveNode primitiveNode = method.getPrimitiveNodeOrNull(); + if (primitiveNode != null) { + return tryPrimitive(primitiveNode, frame.materialize(), node, method, receiver, arg1, arg2, arg3, arg4, arg5); + } else { + return null; + } + } + + @TruffleBoundary + private static Object tryPrimitive(final AbstractPrimitiveNode primitiveNode, final MaterializedFrame frame, final Node node, final CompiledCodeObject method, final Object receiver, + final Object arg1, final Object arg2, final Object arg3, final Object arg4, final Object arg5) { + try { + return ((Primitive5) primitiveNode).execute(frame, receiver, arg1, arg2, arg3, arg4, arg5); + } catch (final PrimitiveFailed pf) { + DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); + return null; + } + } } - @Specialization(guards = {"targetObject != null", "!isCompiledCodeObject(targetObject)"}) - protected static final Object[] doObjectAsMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, final Object arg4, - final Object arg5, @SuppressWarnings("unused") final ClassObject receiverClass, final Object targetObject, final CompiledCodeObject method, final NativeObject selector, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - final Object[] arguments = new Object[]{arg1, arg2, arg3, arg4, arg5}; - return FrameAccess.newOAMWith(senderNode.execute(frame, node, method), targetObject, selector, getContext(node).asArrayOfObjects(arguments), receiver); + @GenerateInline + @GenerateCached(false) + protected abstract static class CreateFrameArgumentsForIndirectCall5Node extends AbstractNode { + abstract Object[] execute(VirtualFrame frame, Node node, Object receiver, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ClassObject receiverClass, + Object lookupResult, + CompiledCodeObject method, NativeObject selector); + + @Specialization + @SuppressWarnings("unused") + protected static final Object[] doMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, final Object arg4, + final Object arg5, + final ClassObject receiverClass, final CompiledCodeObject lookupResult, final CompiledCodeObject method, final NativeObject selector, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + return FrameAccess.newWith(senderNode.execute(frame, node, method), null, receiver, arg1, arg2, arg3, arg4, arg5); + } + + @Specialization(guards = "lookupResult == null") + protected static final Object[] doDoesNotUnderstand(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, + final Object arg4, final Object arg5, final ClassObject receiverClass, @SuppressWarnings("unused") final Object lookupResult, final CompiledCodeObject method, + final NativeObject selector, + @Cached final AbstractPointersObjectWriteNode writeNode, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + final Object[] arguments = new Object[]{arg1, arg2, arg3, arg4, arg5}; + final PointersObject message = getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); + return FrameAccess.newDNUWith(senderNode.execute(frame, node, method), receiver, message); + } + + @Specialization(guards = {"targetObject != null", "!isCompiledCodeObject(targetObject)"}) + protected static final Object[] doObjectAsMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object arg1, final Object arg2, final Object arg3, + final Object arg4, + final Object arg5, @SuppressWarnings("unused") final ClassObject receiverClass, final Object targetObject, final CompiledCodeObject method, final NativeObject selector, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + final Object[] arguments = new Object[]{arg1, arg2, arg3, arg4, arg5}; + return FrameAccess.newOAMWith(senderNode.execute(frame, node, method), targetObject, selector, getContext(node).asArrayOfObjects(arguments), receiver); + } } } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelectorNaryNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelectorNaryNode.java index 14dae2cc4..97d04fbd9 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelectorNaryNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelectorNaryNode.java @@ -8,6 +8,7 @@ import com.oracle.truffle.api.Assumption; 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.Cached; import com.oracle.truffle.api.dsl.Cached.Shared; @@ -16,12 +17,13 @@ import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.ReportPolymorphism; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.IndirectCallNode; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.InlinedExactClassProfile; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; import de.hpi.swa.trufflesqueak.exceptions.PrimitiveFailed; import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; @@ -87,15 +89,15 @@ public NativeObject getSelector() { return dispatchNode.selector; } - protected static DispatchSelectorNaryNode create(final VirtualFrame frame, final int numArgs, final NativeObject selector) { + static DispatchSelectorNaryNode create(final VirtualFrame frame, final int numArgs, final NativeObject selector) { return new DispatchSelectorNaryNode(frame, numArgs, DispatchNaryNodeGen.create(selector)); } - protected static DispatchSelectorNaryNode createSuper(final VirtualFrame frame, final int numArgs, final ClassObject methodClass, final NativeObject selector) { + static DispatchSelectorNaryNode createSuper(final VirtualFrame frame, final int numArgs, final ClassObject methodClass, final NativeObject selector) { return new DispatchSelectorNaryNode(frame, numArgs, DispatchSuperNaryNodeGen.create(methodClass, selector)); } - protected static DispatchSelectorNaryNode createDirectedSuper(final VirtualFrame frame, final int numArgs, final NativeObject selector) { + static DispatchSelectorNaryNode createDirectedSuper(final VirtualFrame frame, final int numArgs, final NativeObject selector) { final int stackPointer = FrameAccess.getStackPointer(frame); // Trick: decrement stack pointer so that node uses the right receiver and args FrameAccess.setStackPointer(frame, stackPointer - 1); @@ -130,25 +132,9 @@ protected static final Object doDirect(final VirtualFrame frame, final Object re @SuppressWarnings("truffle-static-method") protected final Object doIndirect(final VirtualFrame frame, final Object receiver, final Object[] arguments, @Bind("this") final Node node, - @Cached final SqueakObjectClassNode classNode, - @Cached final ResolveMethodNode methodNode, - @Cached final InlinedExactClassProfile primitiveNodeProfile, - @Cached final CreateFrameArgumentsForIndirectCallNaryNode argumentsNode, + @Cached final DispatchIndirectNaryNode dispatchNode, @Cached final IndirectCallNode callNode) { - final ClassObject receiverClass = classNode.executeLookup(node, receiver); - final Object lookupResult = getContext(node).lookup(receiverClass, selector); - final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); - if (method.hasPrimitive()) { - final AbstractPrimitiveNode primitiveNode = primitiveNodeProfile.profile(node, method.getPrimitiveNode()); - if (primitiveNode != null) { - try { - return primitiveNode.executeWithArguments(frame, receiver, arguments); - } catch (final PrimitiveFailed pf) { - DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); - } - } - } - return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, arguments, receiverClass, lookupResult, method, selector)); + return dispatchNode.execute(frame, node, callNode, selector, receiver, arguments); } } @@ -251,7 +237,7 @@ private static DispatchDirectNaryNode create(final Assumption[] assumptions, fin if (primitiveNode != null) { return new DispatchDirectPrimitiveNaryNode(assumptions, method, primitiveNode); } - DispatchUtils.logMissingPrimitive(primitiveNode, method); + DispatchUtils.logMissingPrimitive(null, method); } return new DispatchDirectMethodNaryNode(assumptions, method); } @@ -546,35 +532,107 @@ public Object execute(final VirtualFrame frame, final Object receiver, final Obj @GenerateInline @GenerateCached(false) - public abstract static class CreateFrameArgumentsForIndirectCallNaryNode extends AbstractNode { - public abstract Object[] execute(VirtualFrame frame, Node node, Object receiver, Object[] arguments, ClassObject receiverClass, Object lookupResult, CompiledCodeObject method, - NativeObject selector); + public abstract static class DispatchIndirectNaryNode extends AbstractNode { + public abstract Object execute(VirtualFrame frame, Node node, IndirectCallNode callNode, NativeObject selector, Object receiver, Object[] arguments); @Specialization - @SuppressWarnings("unused") - protected static final Object[] doMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object[] arguments, final ClassObject receiverClass, - @SuppressWarnings("unused") final CompiledCodeObject lookupResult, - final CompiledCodeObject method, final NativeObject selector, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - return FrameAccess.newWith(senderNode.execute(frame, node, method), null, receiver, arguments); - } - - @Specialization(guards = "lookupResult == null") - protected static final Object[] doDoesNotUnderstand(final VirtualFrame frame, final Node node, final Object receiver, final Object[] arguments, final ClassObject receiverClass, - @SuppressWarnings("unused") final Object lookupResult, - final CompiledCodeObject method, final NativeObject selector, - @Cached final AbstractPointersObjectWriteNode writeNode, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - final PointersObject message = getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); - return FrameAccess.newDNUWith(senderNode.execute(frame, node, method), receiver, message); - } - - @Specialization(guards = {"targetObject != null", "!isCompiledCodeObject(targetObject)"}) - protected static final Object[] doObjectAsMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object[] arguments, - @SuppressWarnings("unused") final ClassObject receiverClass, - final Object targetObject, final CompiledCodeObject method, final NativeObject selector, - @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { - return FrameAccess.newOAMWith(senderNode.execute(frame, node, method), targetObject, selector, getContext(node).asArrayOfObjects(arguments), receiver); + protected static final Object doIndirect(final VirtualFrame frame, final Node node, final IndirectCallNode callNode, final NativeObject selector, final Object receiver, + final Object[] arguments, + @Cached final SqueakObjectClassNode classNode, + @Cached final ResolveMethodNode methodNode, + @Cached final TryPrimitiveNaryNode tryPrimitiveNode, + @Cached final CreateFrameArgumentsForIndirectCallNaryNode argumentsNode) { + final ClassObject receiverClass = classNode.executeLookup(node, receiver); + final Object lookupResult = getContext(node).lookup(receiverClass, selector); + final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); + final Object result = tryPrimitiveNode.execute(frame, node, method, receiver, arguments); + if (result != null) { + return result; + } else { + return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, arguments, receiverClass, lookupResult, method, selector)); + } + } + + @GenerateInline + @GenerateCached(false) + protected abstract static class TryPrimitiveNaryNode extends AbstractNode { + abstract Object execute(VirtualFrame frame, Node node, CompiledCodeObject method, Object receiver, Object[] arguments); + + @SuppressWarnings("unused") + @Specialization(guards = "method.getPrimitiveNodeOrNull() == null") + protected static final Object doNoPrimitive(final CompiledCodeObject method, final Object receiver, final Object[] arguments) { + return null; + } + + @Specialization(guards = {"method == cachedMethod", "primitiveNode != null"}, limit = "INDIRECT_PRIMITIVE_CACHE_LIMIT") + protected static final Object doCached(final VirtualFrame frame, final Node node, @SuppressWarnings("unused") final CompiledCodeObject method, final Object receiver, + final Object[] arguments, + @SuppressWarnings("unused") @Cached("method") final CompiledCodeObject cachedMethod, + @Bind("cachedMethod.getPrimitiveNodeOrNull()") final AbstractPrimitiveNode primitiveNode, + @Cached final InlinedBranchProfile primitiveFailedProfile) { + try { + return primitiveNode.executeWithArguments(frame, receiver, arguments); + } catch (final PrimitiveFailed pf) { + primitiveFailedProfile.enter(node); + DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); + return null; + } + } + + @Specialization(replaces = {"doNoPrimitive", "doCached"}) + protected static final Object doUncached(final VirtualFrame frame, final Node node, final CompiledCodeObject method, final Object receiver, final Object[] arguments) { + final AbstractPrimitiveNode primitiveNode = method.getPrimitiveNodeOrNull(); + if (primitiveNode != null) { + return tryPrimitive(primitiveNode, frame.materialize(), node, method, receiver, arguments); + } else { + return null; + } + } + + @TruffleBoundary + private static Object tryPrimitive(final AbstractPrimitiveNode primitiveNode, final MaterializedFrame frame, final Node node, final CompiledCodeObject method, final Object receiver, + final Object[] arguments) { + try { + return primitiveNode.executeWithArguments(frame, receiver, arguments); + } catch (final PrimitiveFailed pf) { + DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); + return null; + } + } + } + + @GenerateInline + @GenerateCached(false) + public abstract static class CreateFrameArgumentsForIndirectCallNaryNode extends AbstractNode { + public abstract Object[] execute(VirtualFrame frame, Node node, Object receiver, Object[] arguments, ClassObject receiverClass, Object lookupResult, CompiledCodeObject method, + NativeObject selector); + + @Specialization + @SuppressWarnings("unused") + protected static final Object[] doMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object[] arguments, final ClassObject receiverClass, + @SuppressWarnings("unused") final CompiledCodeObject lookupResult, + final CompiledCodeObject method, final NativeObject selector, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + return FrameAccess.newWith(senderNode.execute(frame, node, method), null, receiver, arguments); + } + + @Specialization(guards = "lookupResult == null") + protected static final Object[] doDoesNotUnderstand(final VirtualFrame frame, final Node node, final Object receiver, final Object[] arguments, final ClassObject receiverClass, + @SuppressWarnings("unused") final Object lookupResult, + final CompiledCodeObject method, final NativeObject selector, + @Cached final AbstractPointersObjectWriteNode writeNode, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + final PointersObject message = getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); + return FrameAccess.newDNUWith(senderNode.execute(frame, node, method), receiver, message); + } + + @Specialization(guards = {"targetObject != null", "!isCompiledCodeObject(targetObject)"}) + protected static final Object[] doObjectAsMethod(final VirtualFrame frame, final Node node, final Object receiver, final Object[] arguments, + @SuppressWarnings("unused") final ClassObject receiverClass, + final Object targetObject, final CompiledCodeObject method, final NativeObject selector, + @Shared("senderNode") @Cached final GetOrCreateContextOrMarkerNode senderNode) { + return FrameAccess.newOAMWith(senderNode.execute(frame, node, method), targetObject, selector, getContext(node).asArrayOfObjects(arguments), receiver); + } } } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java index 4c740caa4..dc94ad395 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java @@ -72,26 +72,27 @@ import de.hpi.swa.trufflesqueak.nodes.accessing.SqueakObjectClassNode; import de.hpi.swa.trufflesqueak.nodes.accessing.SqueakObjectIdentityNode; import de.hpi.swa.trufflesqueak.nodes.context.frame.FrameStackPushNode; -import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector0Node.CreateFrameArgumentsForIndirectCall0Node; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector0Node.Dispatch0Node; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector0Node.DispatchDirect0Node; -import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector1Node.CreateFrameArgumentsForIndirectCall1Node; +import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector0Node.DispatchIndirect0Node; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector1Node.Dispatch1Node; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector1Node.DispatchDirect1Node; -import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector2Node.CreateFrameArgumentsForIndirectCall2Node; +import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector1Node.DispatchIndirect1Node; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector2Node.Dispatch2Node; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector2Node.DispatchDirect2Node; -import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector3Node.CreateFrameArgumentsForIndirectCall3Node; +import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector2Node.DispatchIndirect2Node; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector3Node.Dispatch3Node; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector3Node.DispatchDirect3Node; -import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector4Node.CreateFrameArgumentsForIndirectCall4Node; +import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector3Node.DispatchIndirect3Node; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector4Node.Dispatch4Node; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector4Node.DispatchDirect4Node; -import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector5Node.CreateFrameArgumentsForIndirectCall5Node; +import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector4Node.DispatchIndirect4Node; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector5Node.Dispatch5Node; -import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelectorNaryNode.CreateFrameArgumentsForIndirectCallNaryNode; +import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector5Node.DispatchIndirect5Node; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelectorNaryNode.DispatchDirectNaryNode; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelectorNaryNode.DispatchDirectedSuperNaryNode.DirectedSuperDispatchNaryNode; +import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelectorNaryNode.DispatchIndirectNaryNode; +import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelectorNaryNode.DispatchIndirectNaryNode.CreateFrameArgumentsForIndirectCallNaryNode; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelectorNaryNode.DispatchNaryNode; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchUtils; import de.hpi.swa.trufflesqueak.nodes.dispatch.GetOrCreateContextOrMarkerNode; @@ -146,25 +147,9 @@ protected static final Object perform0Cached(final VirtualFrame frame, final Obj @Specialization(replaces = "perform0Cached") protected static final Object perform0(final VirtualFrame frame, final Object receiver, final NativeObject selector, @Bind("this") final Node node, - @Cached final SqueakObjectClassNode classNode, - @Cached final ResolveMethodNode methodNode, - @Cached final InlinedExactClassProfile primitiveNodeProfile, - @Cached final CreateFrameArgumentsForIndirectCall0Node argumentsNode, + @Cached final DispatchIndirect0Node dispatchNode, @Cached final IndirectCallNode callNode) { - final ClassObject receiverClass = classNode.executeLookup(node, receiver); - final Object lookupResult = getContext(node).lookup(receiverClass, selector); - final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); - if (method.hasPrimitive()) { - final Primitive0 primitiveNode = (Primitive0) primitiveNodeProfile.profile(node, method.getPrimitiveNode()); - if (primitiveNode != null) { - try { - return primitiveNode.execute(frame, receiver); - } catch (PrimitiveFailed pf) { - DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); - } - } - } - return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, receiverClass, lookupResult, method, selector)); + return dispatchNode.execute(frame, node, callNode, selector, receiver); } } @@ -173,37 +158,21 @@ protected static final Object perform0(final VirtualFrame frame, final Object re protected abstract static class PrimPerform1Node extends AbstractPrimitiveNode implements Primitive2WithFallback { @SuppressWarnings("unused") @Specialization(guards = {"selector == cachedSelector"}, limit = "PERFORM_SELECTOR_CACHE_LIMIT") - protected static final Object perform1Cached(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object object1, + protected static final Object perform1Cached(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object arg1, @Bind("this") final Node node, @Cached("selector") final NativeObject cachedSelector, @Cached("create(cachedSelector)") final Dispatch1Node dispatchNode) { - return dispatchNode.execute(frame, receiver, object1); + return dispatchNode.execute(frame, receiver, arg1); } @SuppressWarnings("unused") @ReportPolymorphism.Megamorphic @Specialization(replaces = "perform1Cached") - protected static final Object perform1(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object object1, + protected static final Object perform1(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object arg1, @Bind("this") final Node node, - @Cached final SqueakObjectClassNode classNode, - @Cached final ResolveMethodNode methodNode, - @Cached final InlinedExactClassProfile primitiveNodeProfile, - @Cached final CreateFrameArgumentsForIndirectCall1Node argumentsNode, + @Cached final DispatchIndirect1Node dispatchNode, @Cached final IndirectCallNode callNode) { - final ClassObject receiverClass = classNode.executeLookup(node, receiver); - final Object lookupResult = getContext(node).lookup(receiverClass, selector); - final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); - if (method.hasPrimitive()) { - final Primitive1 primitiveNode = (Primitive1) primitiveNodeProfile.profile(node, method.getPrimitiveNode()); - if (primitiveNode != null) { - try { - return primitiveNode.execute(frame, receiver, object1); - } catch (PrimitiveFailed pf) { - DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); - } - } - } - return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, object1, receiverClass, lookupResult, method, selector)); + return dispatchNode.execute(frame, node, callNode, selector, receiver, arg1); } } @@ -212,37 +181,21 @@ protected static final Object perform1(final VirtualFrame frame, final Object re protected abstract static class PrimPerform2Node extends AbstractPrimitiveNode implements Primitive3WithFallback { @SuppressWarnings("unused") @Specialization(guards = {"selector == cachedSelector"}, limit = "PERFORM_SELECTOR_CACHE_LIMIT") - protected static final Object perform2Cached(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object object1, final Object object2, + protected static final Object perform2Cached(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object arg1, final Object arg2, @Bind("this") final Node node, @Cached("selector") final NativeObject cachedSelector, @Cached("create(cachedSelector)") final Dispatch2Node dispatchNode) { - return dispatchNode.execute(frame, receiver, object1, object2); + return dispatchNode.execute(frame, receiver, arg1, arg2); } @SuppressWarnings("unused") @ReportPolymorphism.Megamorphic @Specialization(replaces = "perform2Cached") - protected static final Object perform2(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object object1, final Object object2, + protected static final Object perform2(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object arg1, final Object arg2, @Bind("this") final Node node, - @Cached final SqueakObjectClassNode classNode, - @Cached final ResolveMethodNode methodNode, - @Cached final InlinedExactClassProfile primitiveNodeProfile, - @Cached final CreateFrameArgumentsForIndirectCall2Node argumentsNode, + @Cached final DispatchIndirect2Node dispatchNode, @Cached final IndirectCallNode callNode) { - final ClassObject receiverClass = classNode.executeLookup(node, receiver); - final Object lookupResult = getContext(node).lookup(receiverClass, selector); - final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); - if (method.hasPrimitive()) { - final Primitive2 primitiveNode = (Primitive2) primitiveNodeProfile.profile(node, method.getPrimitiveNode()); - if (primitiveNode != null) { - try { - return primitiveNode.execute(frame, receiver, object1, object2); - } catch (PrimitiveFailed pf) { - DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); - } - } - } - return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, object1, object2, receiverClass, lookupResult, method, selector)); + return dispatchNode.execute(frame, node, callNode, selector, receiver, arg1, arg2); } } @@ -251,37 +204,21 @@ protected static final Object perform2(final VirtualFrame frame, final Object re protected abstract static class PrimPerform3Node extends AbstractPrimitiveNode implements Primitive4WithFallback { @SuppressWarnings("unused") @Specialization(guards = {"selector == cachedSelector"}, limit = "PERFORM_SELECTOR_CACHE_LIMIT") - protected static final Object perform3Cached(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object object1, final Object object2, final Object object3, + protected static final Object perform3Cached(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object arg1, final Object arg2, final Object arg3, @Bind("this") final Node node, @Cached("selector") final NativeObject cachedSelector, @Cached("create(cachedSelector)") final Dispatch3Node dispatchNode) { - return dispatchNode.execute(frame, receiver, object1, object2, object3); + return dispatchNode.execute(frame, receiver, arg1, arg2, arg3); } @SuppressWarnings("unused") @ReportPolymorphism.Megamorphic @Specialization(replaces = "perform3Cached") - protected static final Object perform3(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object object1, final Object object2, final Object object3, + protected static final Object perform3(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object arg1, final Object arg2, final Object arg3, @Bind("this") final Node node, - @Cached final SqueakObjectClassNode classNode, - @Cached final ResolveMethodNode methodNode, - @Cached final InlinedExactClassProfile primitiveNodeProfile, - @Cached final CreateFrameArgumentsForIndirectCall3Node argumentsNode, + @Cached final DispatchIndirect3Node dispatchNode, @Cached final IndirectCallNode callNode) { - final ClassObject receiverClass = classNode.executeLookup(node, receiver); - final Object lookupResult = getContext(node).lookup(receiverClass, selector); - final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); - if (method.hasPrimitive()) { - final Primitive3 primitiveNode = (Primitive3) primitiveNodeProfile.profile(node, method.getPrimitiveNode()); - if (primitiveNode != null) { - try { - return primitiveNode.execute(frame, receiver, object1, object2, object3); - } catch (PrimitiveFailed pf) { - DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); - } - } - } - return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, object1, object2, object3, receiverClass, lookupResult, method, selector)); + return dispatchNode.execute(frame, node, callNode, selector, receiver, arg1, arg2, arg3); } } @@ -290,39 +227,23 @@ protected static final Object perform3(final VirtualFrame frame, final Object re protected abstract static class PrimPerform4Node extends AbstractPrimitiveNode implements Primitive5WithFallback { @SuppressWarnings("unused") @Specialization(guards = {"selector == cachedSelector"}, limit = "PERFORM_SELECTOR_CACHE_LIMIT") - protected static final Object perform4Cached(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object object1, final Object object2, final Object object3, - final Object object4, + protected static final Object perform4Cached(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object arg1, final Object arg2, final Object arg3, + final Object arg4, @Bind("this") final Node node, @Cached("selector") final NativeObject cachedSelector, @Cached("create(cachedSelector)") final Dispatch4Node dispatchNode) { - return dispatchNode.execute(frame, receiver, object1, object2, object3, object4); + return dispatchNode.execute(frame, receiver, arg1, arg2, arg3, arg4); } @SuppressWarnings("unused") @ReportPolymorphism.Megamorphic @Specialization(replaces = "perform4Cached") - protected static final Object perform4(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object object1, final Object object2, final Object object3, - final Object object4, + protected static final Object perform4(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object arg1, final Object arg2, final Object arg3, + final Object arg4, @Bind("this") final Node node, - @Cached final SqueakObjectClassNode classNode, - @Cached final ResolveMethodNode methodNode, - @Cached final InlinedExactClassProfile primitiveNodeProfile, - @Cached final CreateFrameArgumentsForIndirectCall4Node argumentsNode, + @Cached final DispatchIndirect4Node dispatchNode, @Cached final IndirectCallNode callNode) { - final ClassObject receiverClass = classNode.executeLookup(node, receiver); - final Object lookupResult = getContext(node).lookup(receiverClass, selector); - final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); - if (method.hasPrimitive()) { - final Primitive4 primitiveNode = (Primitive4) primitiveNodeProfile.profile(node, method.getPrimitiveNode()); - if (primitiveNode != null) { - try { - return primitiveNode.execute(frame, receiver, object1, object2, object3, object4); - } catch (PrimitiveFailed pf) { - DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); - } - } - } - return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, object1, object2, object3, object4, receiverClass, lookupResult, method, selector)); + return dispatchNode.execute(frame, node, callNode, selector, receiver, arg1, arg2, arg3, arg4); } } @@ -331,39 +252,23 @@ protected static final Object perform4(final VirtualFrame frame, final Object re protected abstract static class PrimPerform5Node extends AbstractPrimitiveNode implements Primitive6WithFallback { @SuppressWarnings("unused") @Specialization(guards = {"selector == cachedSelector"}, limit = "PERFORM_SELECTOR_CACHE_LIMIT") - protected static final Object perform5Cached(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object object1, final Object object2, final Object object3, - final Object object4, final Object object5, + protected static final Object perform5Cached(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object arg1, final Object arg2, final Object arg3, + final Object arg4, final Object arg5, @Bind("this") final Node node, @Cached("selector") final NativeObject cachedSelector, @Cached("create(cachedSelector)") final Dispatch5Node dispatchNode) { - return dispatchNode.execute(frame, receiver, object1, object2, object3, object4, object5); + return dispatchNode.execute(frame, receiver, arg1, arg2, arg3, arg4, arg5); } @SuppressWarnings("unused") @ReportPolymorphism.Megamorphic @Specialization(replaces = "perform5Cached") - protected static final Object perform5(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object object1, final Object object2, final Object object3, - final Object object4, final Object object5, + protected static final Object perform5(final VirtualFrame frame, final Object receiver, final NativeObject selector, final Object arg1, final Object arg2, final Object arg3, + final Object arg4, final Object arg5, @Bind("this") final Node node, - @Cached final SqueakObjectClassNode classNode, - @Cached final ResolveMethodNode methodNode, - @Cached final InlinedExactClassProfile primitiveNodeProfile, - @Cached final CreateFrameArgumentsForIndirectCall5Node argumentsNode, + @Cached final DispatchIndirect5Node dispatchNode, @Cached final IndirectCallNode callNode) { - final ClassObject receiverClass = classNode.executeLookup(node, receiver); - final Object lookupResult = getContext(node).lookup(receiverClass, selector); - final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); - if (method.hasPrimitive()) { - final Primitive5 primitiveNode = (Primitive5) primitiveNodeProfile.profile(node, method.getPrimitiveNode()); - if (primitiveNode != null) { - try { - return primitiveNode.execute(frame, receiver, object1, object2, object3, object4, object5); - } catch (PrimitiveFailed pf) { - DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); - } - } - } - return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, object1, object2, object3, object4, object5, receiverClass, lookupResult, method, selector)); + return dispatchNode.execute(frame, node, callNode, selector, receiver, arg1, arg2, arg3, arg4, arg5); } } @@ -384,26 +289,10 @@ protected static final Object performCached(final VirtualFrame frame, final Obje protected static final Object perform(final VirtualFrame frame, final Object receiver, final NativeObject selector, final ArrayObject argumentsArray, @Bind("this") final Node node, @Exclusive @Cached final ArrayObjectToObjectArrayCopyNode getObjectArrayNode, - @Cached final SqueakObjectClassNode classNode, - @Cached final ResolveMethodNode methodNode, - @Cached final InlinedExactClassProfile primitiveNodeProfile, - @Cached final CreateFrameArgumentsForIndirectCallNaryNode argumentsNode, + @Cached final DispatchIndirectNaryNode dispatchNode, @Cached final IndirectCallNode callNode) { final Object[] arguments = getObjectArrayNode.execute(node, argumentsArray); - final ClassObject receiverClass = classNode.executeLookup(node, receiver); - final Object lookupResult = getContext(node).lookup(receiverClass, selector); - final CompiledCodeObject method = methodNode.execute(node, getContext(node), receiverClass, lookupResult); - if (method.hasPrimitive()) { - final AbstractPrimitiveNode primitiveNode = primitiveNodeProfile.profile(node, method.getPrimitiveNode()); - if (primitiveNode != null) { - try { - return primitiveNode.executeWithArguments(frame, receiver, arguments); - } catch (PrimitiveFailed pf) { - DispatchUtils.handlePrimitiveFailedIndirect(node, method, pf); - } - } - } - return callNode.call(method.getCallTarget(), argumentsNode.execute(frame, node, receiver, arguments, receiverClass, lookupResult, method, selector)); + return dispatchNode.execute(frame, node, callNode, selector, receiver, arguments); } } @@ -614,8 +503,7 @@ protected static final Object performGeneric(final VirtualFrame frame, final Obj @SqueakPrimitive(indices = 100) /* Object>>#perform:withArguments:inSuperclass: */ protected abstract static class PrimPerformWithArgumentsInSuperclass4Node extends AbstractPrimPerformWithArgumentsInSuperclassNode implements Primitive3WithFallback { - @Specialization(guards = "selector == cachedSelector", limit = "PERFORM_SELECTOR_CACHE_LIMIT" + - "") + @Specialization(guards = "selector == cachedSelector", limit = "PERFORM_SELECTOR_CACHE_LIMIT") protected static final Object performCached(final VirtualFrame frame, final Object receiver, @SuppressWarnings("unused") final NativeObject selector, final ArrayObject arguments, final ClassObject lookupClass, @Bind("this") final Node node, @@ -1167,7 +1055,7 @@ protected static final Object doExecute(final VirtualFrame frame, final Object r @Cached final IndirectCallNode callNode) { final Object[] arguments = arrayNode.execute(node, argArray); if (method.hasPrimitive()) { - final AbstractPrimitiveNode primitiveNode = primitiveNodeProfile.profile(node, method.getPrimitiveNode()); + final AbstractPrimitiveNode primitiveNode = primitiveNodeProfile.profile(node, method.getPrimitiveNodeOrNull()); if (primitiveNode != null) { try { return primitiveNode.executeWithArguments(frame, receiver, arguments);