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 Jul 30, 2024
1 parent 2d4a231 commit e711ba7
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

2 comments on commit e711ba7

@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 (e711ba7)

Benchmarks ran on 22.0.2-graal.

Steady (after 100 iterations)

Benchmark Name Min Geomean Median Mean Max Total (ms) Total (min)
Bounce 552 560 554.33 553 554.33 110866 1.85
CD 492 504 495.7 493 495.68 99139 1.65
DeltaBlue 290 488 420.74 417 419.51 84147 1.4
Havlak 1171 1232 1200.15 1204 1200.08 240029 4
Json 368 377 370.93 369 370.91 74185 1.24
List 379 389 379.75 379 379.74 75949 1.27
Mandelbrot 223 234 227.12 226.5 227.09 45423 0.76
NBody 256 270 259.26 258 259.24 51851 0.86
Permute 154 168 155.7 155 155.68 31139 0.52
Queens 231 246 232.89 232 232.88 46578 0.78
Richards 1242 1291 1246.99 1245.5 1246.98 249398 4.16
Sieve 270 286 271.62 271 271.61 54324 0.91
Storage 140 149 141.84 141 141.82 28368 0.47
Towers 201 219 205.05 205 205.03 41009 0.68
5969 6413 6162.03 6149 6160.59 1232405 20.54

e711ba7-2-steady.svg

Warmup (first 100 iterations)

e711ba7-3-warmup.svg

@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 (e711ba7)

Benchmarks ran on 22.0.2-graal.

Steady (after 100 iterations)

Benchmark Name Min Geomean Median Mean Max Total (ms) Total (min)
Bounce 552 561 554.64 553 554.63 110928 1.85
CD 489 499 492.54 491 492.53 98508 1.64
DeltaBlue 286 503 422.18 417 420.64 84435 1.41
Havlak 1142 1269 1174.47 1177 1174.39 234894 3.91
Json 385 394 387.72 386 387.71 77544 1.29
List 378 388 378.76 378 378.75 75751 1.26
Mandelbrot 225 235 229.34 231 229.32 45867 0.76
NBody 256 271 259.57 258 259.55 51914 0.87
Permute 154 167 156.01 155 156 31203 0.52
Queens 231 244 233.62 234 233.61 46724 0.78
Richards 1264 1307 1268.54 1269 1268.53 253708 4.23
Sieve 270 282 271.58 271 271.57 54315 0.91
Storage 142 154 143.99 143 143.96 28797 0.48
Towers 196 212 198.11 198 198.1 39622 0.66
5970 6486 6171.05 6161 6169.3 1234210 20.57

e711ba7-2-steady.svg

Warmup (first 100 iterations)

e711ba7-3-warmup.svg

Please sign in to comment.