Skip to content

Commit

Permalink
Introduce DispatchPrimitiveNode
Browse files Browse the repository at this point in the history
to eliminate the generated code for the additional abstract `AbstractPrimitiveNode#execute(VirtualFrame)` method for each primitive.
  • Loading branch information
fniephaus committed Aug 2, 2024
1 parent 64c21b5 commit 659d0d4
Show file tree
Hide file tree
Showing 13 changed files with 109 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
import de.hpi.swa.trufflesqueak.nodes.bytecodes.AbstractSqueakBytecodeDecoder;
import de.hpi.swa.trufflesqueak.nodes.bytecodes.SqueakBytecodeSistaV1Decoder;
import de.hpi.swa.trufflesqueak.nodes.bytecodes.SqueakBytecodeV3PlusClosuresDecoder;
import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.DispatchPrimitiveNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.PrimitiveNodeFactory;
import de.hpi.swa.trufflesqueak.nodes.primitives.PrimitiveNodeFactory.ArgumentsLocation;
import de.hpi.swa.trufflesqueak.shared.SqueakLanguageConfig;
Expand Down Expand Up @@ -217,7 +217,7 @@ private void initializeCallTargetUnsafe() {
final SqueakLanguage language = SqueakImageContext.getSlow().getLanguage();
final RootNode rootNode;
if (hasPrimitive() && PrimitiveNodeFactory.isNonFailing(this)) {
final AbstractPrimitiveNode primitiveNode = PrimitiveNodeFactory.getOrCreateIndexedOrNamed(this, ArgumentsLocation.IN_FRAME_ARGUMENTS);
final DispatchPrimitiveNode primitiveNode = PrimitiveNodeFactory.getOrCreateIndexedOrNamed(this, ArgumentsLocation.IN_FRAME_ARGUMENTS);
assert primitiveNode != null;
rootNode = new ExecuteNonFailingPrimitiveRootNode(language, this, primitiveNode);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import de.hpi.swa.trufflesqueak.nodes.bytecodes.JumpBytecodes.ConditionalJumpNode;
import de.hpi.swa.trufflesqueak.nodes.bytecodes.ReturnBytecodes.AbstractReturnNode;
import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodes.AbstractSendNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.DispatchPrimitiveNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.PrimitiveNodeFactory;
import de.hpi.swa.trufflesqueak.nodes.primitives.PrimitiveNodeFactory.ArgumentsLocation;
import de.hpi.swa.trufflesqueak.util.ArrayUtils;
Expand All @@ -41,7 +41,7 @@ public final class ExecuteBytecodeNode extends AbstractExecuteContextNode implem
private final int initialPC;
private SourceSection section;

@Child private AbstractPrimitiveNode primitiveNode;
@Child private DispatchPrimitiveNode primitiveNode;
@Child private HandlePrimitiveFailedNode handlePrimitiveFailedNode;
@Children private AbstractBytecodeNode[] bytecodeNodes;
@Child private HandleNonLocalReturnNode handleNonLocalReturnNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@
import de.hpi.swa.trufflesqueak.SqueakLanguage;
import de.hpi.swa.trufflesqueak.exceptions.PrimitiveFailed;
import de.hpi.swa.trufflesqueak.model.CompiledCodeObject;
import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.DispatchPrimitiveNode;
import de.hpi.swa.trufflesqueak.shared.SqueakLanguageConfig;

@NodeInfo(language = SqueakLanguageConfig.ID, cost = NodeCost.NONE)
public final class ExecuteNonFailingPrimitiveRootNode extends AbstractRootNode {

@Child private AbstractPrimitiveNode primitiveNode;
@Child private DispatchPrimitiveNode primitiveNode;

public ExecuteNonFailingPrimitiveRootNode(final SqueakLanguage language, final CompiledCodeObject code, final AbstractPrimitiveNode primitiveNode) {
public ExecuteNonFailingPrimitiveRootNode(final SqueakLanguage language, final CompiledCodeObject code, final DispatchPrimitiveNode primitiveNode) {
super(language, code);
this.primitiveNode = primitiveNode;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import de.hpi.swa.trufflesqueak.nodes.dispatch.LookupClassNode;
import de.hpi.swa.trufflesqueak.nodes.dispatch.LookupSelectorNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.DispatchPrimitiveNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.PrimitiveNodeFactory;
import de.hpi.swa.trufflesqueak.nodes.primitives.PrimitiveNodeFactory.ArgumentsLocation;
import de.hpi.swa.trufflesqueak.nodes.primitives.impl.ControlPrimitives.PrimExitToDebuggerNode;
Expand Down Expand Up @@ -315,12 +316,14 @@ public static AbstractBytecodeNode create(final VirtualFrame frame, final Compil
return SendSpecialSelectorQuickPointYNodeGen.create(code, index, selectorIndex);
}
if (primitiveIndex > 0) {
final AbstractPrimitiveNode primitiveNode = PrimitiveNodeFactory.getOrCreateIndexed(primitiveIndex, 1 + numArguments, ArgumentsLocation.ON_STACK_REVERSED);
final int numReceiverAndArguments = 1 + numArguments;
final AbstractPrimitiveNode primitiveNode = PrimitiveNodeFactory.getOrCreateIndexed(primitiveIndex, numReceiverAndArguments);
assert primitiveNode != null;
final DispatchPrimitiveNode dispatchPrimitiveNode = DispatchPrimitiveNode.create(primitiveNode, ArgumentsLocation.ON_STACK_REVERSED, numReceiverAndArguments);
if (numArguments == 0) {
return new SendSpecialSelectorQuick0ArgumentsNode(code, index, selectorIndex, primitiveNode);
return new SendSpecialSelectorQuick0ArgumentsNode(code, index, selectorIndex, dispatchPrimitiveNode);
} else {
return new SendSpecialSelectorQuick1OrMoreArgumentsNode(code, index, selectorIndex, primitiveNode);
return new SendSpecialSelectorQuick1OrMoreArgumentsNode(code, index, selectorIndex, dispatchPrimitiveNode);
}
} else {
return new SelfSendNode(code, index, 1, specialSelector, numArguments);
Expand Down Expand Up @@ -370,9 +373,9 @@ public final String toString() {
}

private abstract static class SendSpecialSelectorQuickNode extends AbstractSendSpecialSelectorQuickNode {
@Child protected AbstractPrimitiveNode primitiveNode;
@Child protected DispatchPrimitiveNode primitiveNode;

private SendSpecialSelectorQuickNode(final CompiledCodeObject code, final int index, final int selectorIndex, final AbstractPrimitiveNode primitiveNode) {
private SendSpecialSelectorQuickNode(final CompiledCodeObject code, final int index, final int selectorIndex, final DispatchPrimitiveNode primitiveNode) {
super(code, index, selectorIndex);
this.primitiveNode = primitiveNode;
}
Expand All @@ -390,7 +393,7 @@ public void executeVoid(final VirtualFrame frame) {
}

private static final class SendSpecialSelectorQuick0ArgumentsNode extends SendSpecialSelectorQuickNode {
private SendSpecialSelectorQuick0ArgumentsNode(final CompiledCodeObject code, final int index, final int selectorIndex, final AbstractPrimitiveNode primitiveNode) {
private SendSpecialSelectorQuick0ArgumentsNode(final CompiledCodeObject code, final int index, final int selectorIndex, final DispatchPrimitiveNode primitiveNode) {
super(code, index, selectorIndex, primitiveNode);
}

Expand All @@ -408,7 +411,7 @@ protected void popArgumentAndPush(final VirtualFrame frame, final Object result)
private static final class SendSpecialSelectorQuick1OrMoreArgumentsNode extends SendSpecialSelectorQuickNode {
@CompilationFinal private int stackPointer;

private SendSpecialSelectorQuick1OrMoreArgumentsNode(final CompiledCodeObject code, final int index, final int selectorIndex, final AbstractPrimitiveNode primitiveNode) {
private SendSpecialSelectorQuick1OrMoreArgumentsNode(final CompiledCodeObject code, final int index, final int selectorIndex, final DispatchPrimitiveNode primitiveNode) {
super(code, index, selectorIndex, primitiveNode);
}

Expand All @@ -429,7 +432,7 @@ private abstract static class SendSpecialSelectorQuickWithClassCheckNode extends
@CompilationFinal private ClassObject cachedReceiverClass;
@CompilationFinal private Assumption cachedCallTargetStableAssumption;

@Child protected AbstractPrimitiveNode primitiveNode;
@Child protected DispatchPrimitiveNode primitiveNode;
@Child private FrameStackReadNode peekAtReceiverNode;
@Child private LookupClassNode lookupClassNode = LookupClassNode.create();

Expand Down Expand Up @@ -460,7 +463,7 @@ private boolean doesNotMatchClassOrMethodInvalidated(final ClassObject actualCla
final Object lookupResult = actualClass.lookupInMethodDictSlow(findSelector());
if (lookupResult instanceof final CompiledCodeObject primitiveMethod && primitiveMethod.hasPrimitive()) {
assert primitiveMethod.getNumArgs() == findNumArguments();
final AbstractPrimitiveNode node = PrimitiveNodeFactory.getOrCreateIndexedOrNamed(primitiveMethod, ArgumentsLocation.ON_STACK_REVERSED);
final DispatchPrimitiveNode node = PrimitiveNodeFactory.getOrCreateIndexedOrNamed(primitiveMethod, ArgumentsLocation.ON_STACK_REVERSED);
if (node == null) {
return true; // primitive not found / supported
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import de.hpi.swa.trufflesqueak.nodes.context.frame.GetOrCreateContextNode;
import de.hpi.swa.trufflesqueak.nodes.dispatch.CreateFrameArgumentNodes.CreateFrameArgumentsForDNUNode;
import de.hpi.swa.trufflesqueak.nodes.dispatch.CreateFrameArgumentNodes.CreateFrameArgumentsForOAMNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.DispatchPrimitiveNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.PrimitiveNodeFactory;
import de.hpi.swa.trufflesqueak.nodes.primitives.PrimitiveNodeFactory.ArgumentsLocation;
import de.hpi.swa.trufflesqueak.util.FrameAccess;
Expand All @@ -48,7 +48,7 @@ protected static final CachedDispatchNode create(final VirtualFrame frame, final
return createDNUNode(frame, selector, argumentCount, image, receiverClass);
} else if (lookupResult instanceof final CompiledCodeObject lookupMethod) {
if (lookupMethod.hasPrimitive()) {
final AbstractPrimitiveNode primitiveNode = PrimitiveNodeFactory.getOrCreateIndexedOrNamed(lookupMethod, ArgumentsLocation.ON_STACK);
final DispatchPrimitiveNode primitiveNode = PrimitiveNodeFactory.getOrCreateIndexedOrNamed(lookupMethod, ArgumentsLocation.ON_STACK);
if (primitiveNode != null) {
return new CachedDispatchPrimitiveNode(argumentCount, lookupMethod, primitiveNode);
}
Expand Down Expand Up @@ -94,9 +94,9 @@ protected static final class CachedDispatchPrimitiveNode extends CachedDispatchN
private final int argumentCount;
private final PrimitiveFailedCounter failureCounter;

@Child private AbstractPrimitiveNode primitiveNode;
@Child private DispatchPrimitiveNode primitiveNode;

private CachedDispatchPrimitiveNode(final int argumentCount, final CompiledCodeObject method, final AbstractPrimitiveNode primitiveNode) {
private CachedDispatchPrimitiveNode(final int argumentCount, final CompiledCodeObject method, final DispatchPrimitiveNode primitiveNode) {
super(method);
this.argumentCount = argumentCount;
this.primitiveNode = primitiveNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static DispatchEagerlyNode create() {
limit = "INLINE_CACHE_SIZE", assumptions = {"cachedMethod.getCallTargetStable()", "failureCounter.getAssumption()"}, rewriteOn = PrimitiveFailed.class)
protected static final Object doPrimitiveEagerly(final VirtualFrame frame, @SuppressWarnings("unused") final CompiledCodeObject method, final Object[] receiverAndArguments,
@Cached("method") final CompiledCodeObject cachedMethod,
@Cached("getOrCreateIndexedOrNamed(cachedMethod, PROVIDED_ON_EXECUTE)") final AbstractPrimitiveNode primitiveNode,
@Cached("getOrCreateIndexedOrNamed(cachedMethod)") final AbstractPrimitiveNode primitiveNode,
@Cached("create(primitiveNode)") final PrimitiveFailedCounter failureCounter) {
try {
return primitiveNode.executeWithArguments(frame, receiverAndArguments);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,10 @@ private static Object lookupModuleLibrary(final SqueakImageContext context, fina
return moduleLibrary;
}

@Override
public Object execute(final VirtualFrame frame) {
return doExternalCall(frame.materialize());
}

@Override
public Object executeWithArguments(final VirtualFrame frame, final Object... receiverAndArguments) {
// arguments are handled via manipulation of the stack pointer, see below
return execute(frame);
return doExternalCall(frame.materialize());
}

@TruffleBoundary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,13 @@
package de.hpi.swa.trufflesqueak.nodes.primitives;

import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.frame.VirtualFrame;

import de.hpi.swa.trufflesqueak.model.CompiledCodeObject;
import de.hpi.swa.trufflesqueak.nodes.AbstractNode;
import de.hpi.swa.trufflesqueak.nodes.context.ArgumentNodes.AbstractArgumentNode;

@NodeChild(value = "arguments", type = AbstractArgumentNode[].class)
public abstract class AbstractPrimitiveNode extends AbstractNode {

public abstract Object execute(VirtualFrame frame);

public abstract Object executeWithArguments(VirtualFrame frame, Object... receiverAndArguments);

public boolean acceptsMethod(@SuppressWarnings("unused") final CompiledCodeObject method) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,6 @@ public final Object executeWithArguments(final VirtualFrame frame, final Object.
return execute();
}

@Override
public final Object execute(final VirtualFrame frame) {
return execute();
}

protected abstract Object execute();

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2024 Software Architecture Group, Hasso Plattner Institute
* Copyright (c) 2024 Oracle and/or its affiliates
*
* Licensed under the MIT License.
*/
package de.hpi.swa.trufflesqueak.nodes.primitives;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.ExplodeLoop;

import de.hpi.swa.trufflesqueak.nodes.AbstractNode;
import de.hpi.swa.trufflesqueak.nodes.context.ArgumentNodes.AbstractArgumentNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.PrimitiveNodeFactory.ArgumentsLocation;

public final class DispatchPrimitiveNode extends AbstractNode {
@Child protected AbstractPrimitiveNode primitiveNode;
@Children protected AbstractArgumentNode[] argumentNodes;

private DispatchPrimitiveNode(final AbstractPrimitiveNode primitiveNode, final AbstractArgumentNode[] argumentNodes) {
this.primitiveNode = primitiveNode;
this.argumentNodes = argumentNodes;
}

public static DispatchPrimitiveNode create(final AbstractPrimitiveNode primitiveNode, final ArgumentsLocation location, final int numReceiverAndArguments) {
return new DispatchPrimitiveNode(primitiveNode, createArgumentNodes(location, numReceiverAndArguments));
}

private static AbstractArgumentNode[] createArgumentNodes(final ArgumentsLocation location, final int numReceiverAndArguments) {
final AbstractArgumentNode[] argumentNodes = new AbstractArgumentNode[numReceiverAndArguments];
final boolean useStack = location == ArgumentsLocation.ON_STACK || location == ArgumentsLocation.ON_STACK_REVERSED;
final int offset = location == ArgumentsLocation.ON_STACK_REVERSED ? numReceiverAndArguments : 0;
for (int i = 0; i < numReceiverAndArguments; i++) {
argumentNodes[i] = AbstractArgumentNode.create(i - offset, useStack);
}
return argumentNodes;
}

@ExplodeLoop
public Object execute(final VirtualFrame frame) {
final int numArguments = argumentNodes.length;
final Object[] arguments = new Object[numArguments];
for (int i = 0; i < numArguments; i++) {
arguments[i] = argumentNodes[i].execute(frame);
}
return primitiveNode.executeWithArguments(frame, arguments);
}
}
Loading

1 comment on commit 659d0d4

@TruffleSqueak-Bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performance Report (659d0d4)

Benchmarks ran on 22.0.2-graal.

Steady (after 100 iterations)

Benchmark Name Min Geomean Median Mean Max Total (ms) Total (min)
Bounce 530 537 532.34 531 532.33 106467 1.77
CD 490 511 495.62 492 495.59 99124 1.65
DeltaBlue 277 487 412.42 406.5 410.71 82483 1.37
Havlak 1127 1183 1158.61 1164 1158.54 231722 3.86
Json 374 383 376.46 375 376.45 75292 1.25
List 309 320 310.44 310 310.43 62087 1.03
Mandelbrot 127 138 127.71 128 127.7 25542 0.43
NBody 250 264 253.24 251 253.21 50647 0.84
Permute 154 172 157.06 155 156.99 31411 0.52
Queens 229 241 230.94 231 230.93 46188 0.77
Richards 1237 1264 1241.41 1242 1241.4 248281 4.14
Sieve 177 193 178.06 178 178.04 35611 0.59
Storage 140 148 141.88 141 141.86 28375 0.47
Towers 196 209 197.16 197 197.15 39432 0.66
5617 6050 5813.31 5801.5 5811.34 1162662 19.38

659d0d4-2-steady.svg

Warmup (first 100 iterations)

659d0d4-3-warmup.svg

Please sign in to comment.