diff --git a/build.xml b/build.xml index 94ab26eef..e4aac539f 100644 --- a/build.xml +++ b/build.xml @@ -58,8 +58,6 @@ - - diff --git a/src/trufflesom/compiler/MethodGenerationContext.java b/src/trufflesom/compiler/MethodGenerationContext.java index 0b1226267..7ec0efd10 100644 --- a/src/trufflesom/compiler/MethodGenerationContext.java +++ b/src/trufflesom/compiler/MethodGenerationContext.java @@ -90,7 +90,7 @@ public class MethodGenerationContext private Internal frameOnStack; protected final LexicalScope currentScope; - private final List embeddedBlockMethods; + protected final List embeddedBlockMethods; public final StructuralProbe structuralProbe; diff --git a/src/trufflesom/compiler/bc/BytecodeMethodGenContext.java b/src/trufflesom/compiler/bc/BytecodeMethodGenContext.java index bc69b3b6a..72ebf2c1d 100644 --- a/src/trufflesom/compiler/bc/BytecodeMethodGenContext.java +++ b/src/trufflesom/compiler/bc/BytecodeMethodGenContext.java @@ -182,6 +182,12 @@ public void addBytecodeArgument(final byte code) { bytecode.add(code); } + public void replaceWith(final SMethod oldBlock, final SMethod newBlock) { + boolean wasInList = embeddedBlockMethods.remove(oldBlock); + assert wasInList : "The block to be removed is expected to be in the list of embedded methods"; + embeddedBlockMethods.add(newBlock); + } + public void patchJumpOffsetToPointToNextInstruction(final int idxOfOffset, final ParserBc parser) throws ParseError { int instructionStart = idxOfOffset - 1; diff --git a/src/trufflesom/interpreter/Invokable.java b/src/trufflesom/interpreter/Invokable.java index c2bbac272..6dd7c88f3 100644 --- a/src/trufflesom/interpreter/Invokable.java +++ b/src/trufflesom/interpreter/Invokable.java @@ -1,5 +1,6 @@ package trufflesom.interpreter; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.RootNode; @@ -20,7 +21,7 @@ public abstract class Invokable extends RootNode { protected final ExpressionNode uninitializedBody; - protected SClass holder; + @CompilationFinal protected SClass holder; protected Invokable(final String name, final SourceSection sourceSection, final FrameDescriptor frameDescriptor, diff --git a/src/trufflesom/interpreter/Method.java b/src/trufflesom/interpreter/Method.java index c60df3d95..7a9ee76c4 100644 --- a/src/trufflesom/interpreter/Method.java +++ b/src/trufflesom/interpreter/Method.java @@ -99,6 +99,7 @@ public Method cloneAndAdaptAfterScopeChange(final BytecodeMethodGenContext mgenc Method clone = new Method(name, sourceSection, adaptedBody, adaptedScope, uninit, getLanguage(SomLanguage.class)); adaptedScope.setMethod(clone); + clone.setHolder(holder); return clone; } diff --git a/src/trufflesom/interpreter/Primitive.java b/src/trufflesom/interpreter/Primitive.java index c9eb14be2..365901b5c 100644 --- a/src/trufflesom/interpreter/Primitive.java +++ b/src/trufflesom/interpreter/Primitive.java @@ -26,8 +26,10 @@ public Primitive(final String name, final SourceSection sourceSection, @Override public Node deepCopy() { assert getFrameDescriptor().getSize() == 0 : "Make sure there are no slots to be taken care off"; - return new Primitive(name, sourceSection, NodeUtil.cloneNode(uninitializedBody), + Primitive p = new Primitive(name, sourceSection, NodeUtil.cloneNode(uninitializedBody), getFrameDescriptor(), uninitializedBody, getLanguage(SomLanguage.class)); + p.setHolder(holder); + return p; } @Override diff --git a/src/trufflesom/interpreter/nodes/MessageSendNode.java b/src/trufflesom/interpreter/nodes/MessageSendNode.java index 84b676c00..6fc752e12 100644 --- a/src/trufflesom/interpreter/nodes/MessageSendNode.java +++ b/src/trufflesom/interpreter/nodes/MessageSendNode.java @@ -1,26 +1,33 @@ package trufflesom.interpreter.nodes; -import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.Truffle; 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.InvalidAssumptionException; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.source.SourceSection; import bd.primitives.Specializer; import bd.primitives.nodes.PreevaluatedExpression; import bd.tools.nodes.Invocation; -import trufflesom.interpreter.TruffleCompiler; +import trufflesom.interpreter.Types; import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode; -import trufflesom.interpreter.nodes.dispatch.DispatchChain.Cost; +import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode.CachedDispatchNode; +import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode.CachedExprNode; +import trufflesom.interpreter.nodes.dispatch.CachedDnuNode; +import trufflesom.interpreter.nodes.dispatch.DispatchGuard; import trufflesom.interpreter.nodes.dispatch.GenericDispatchNode; -import trufflesom.interpreter.nodes.dispatch.UninitializedDispatchNode; import trufflesom.primitives.Primitives; import trufflesom.vm.NotYetImplementedException; import trufflesom.vm.Universe; import trufflesom.vmobjects.SClass; import trufflesom.vmobjects.SInvokable; +import trufflesom.vmobjects.SObject; import trufflesom.vmobjects.SSymbol; @@ -32,8 +39,7 @@ public static ExpressionNode create(final SSymbol selector, Specializer specializer = prims.getParserSpecializer(selector, arguments); if (specializer == null) { - return new UninitializedMessageSendNode( - selector, arguments, universe).initialize(source); + return new GenericMessageSendNode(selector, arguments, universe).initialize(source); } ExpressionNode newNode = specializer.create(null, arguments, source, universe); @@ -44,14 +50,14 @@ public static ExpressionNode create(final SSymbol selector, public static AbstractMessageSendNode createForPerformNodes(final SSymbol selector, final SourceSection source, final Universe universe) { - return new UninitializedMessageSendNode(selector, NO_ARGS, universe).initialize(source); + return new GenericMessageSendNode(selector, NO_ARGS, universe).initialize(source); } public static GenericMessageSendNode createGeneric(final SSymbol selector, final ExpressionNode[] argumentNodes, final SourceSection source, final Universe universe) { - return new GenericMessageSendNode(selector, argumentNodes, - new UninitializedDispatchNode(selector, universe)).initialize(source); + return new GenericMessageSendNode( + selector, argumentNodes, universe, 0).initialize(source); } public static AbstractMessageSendNode createSuperSend(final SClass superClass, @@ -102,109 +108,177 @@ private Object[] evaluateArguments(final VirtualFrame frame) { public abstract int getNumberOfArguments(); } - public static final class UninitializedMessageSendNode extends AbstractMessageSendNode { + public static final class GenericMessageSendNode + extends AbstractMessageSendNode { + + private final SSymbol selector; + private final Universe universe; + + private final int numberOfSignatureArguments; + + @CompilationFinal private int numCacheNodes; - protected final SSymbol selector; - protected final Universe universe; + @Child private AbstractDispatchNode dispatchCache; - protected UninitializedMessageSendNode(final SSymbol selector, - final ExpressionNode[] arguments, final Universe universe) { + private GenericMessageSendNode(final SSymbol selector, final ExpressionNode[] arguments, + final Universe universe, final int numCacheNodes) { super(arguments); this.selector = selector; this.universe = universe; + this.numCacheNodes = numCacheNodes; + this.numberOfSignatureArguments = selector.getNumberOfSignatureArguments(); } - @Override - public String toString() { - return getClass().getSimpleName() + "(" + selector.getString() + ")"; + private GenericMessageSendNode(final SSymbol selector, final ExpressionNode[] arguments, + final Universe universe) { + this(selector, arguments, universe, -1); } @Override + @ExplodeLoop public Object doPreEvaluated(final VirtualFrame frame, final Object[] arguments) { + AbstractDispatchNode cache = dispatchCache; + + if (cache != null) { + Object rcvr = arguments[0]; + + do { + try { + if (cache.entryMatches(rcvr)) { + return cache.doPreEvaluated(frame, arguments); + } + } catch (InvalidAssumptionException e) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + cache = removeInvalidEntryAndReturnNext(cache); + continue; + } + cache = cache.next; + } while (cache != null); + } + + CompilerDirectives.transferToInterpreterAndInvalidate(); return specialize(arguments).doPreEvaluated(frame, arguments); } - private PreevaluatedExpression specialize(final Object[] arguments) { - TruffleCompiler.transferToInterpreterAndInvalidate("Specialize Message Node"); - - // We treat super sends separately for simplicity, might not be the - // optimal solution, especially in cases were the knowledge of the - // receiver class also allows us to do more specific things, but for the - // moment we will leave it at this. - // TODO: revisit, and also do more specific optimizations for super sends. - - Primitives prims = universe.getPrimitives(); - - Specializer specializer = - prims.getEagerSpecializer(selector, arguments, argumentNodes); - - if (specializer != null) { - PreevaluatedExpression newNode = - (PreevaluatedExpression) specializer.create(arguments, argumentNodes, - sourceSection, universe); - - return (PreevaluatedExpression) replace((ExpressionNode) newNode); + private AbstractDispatchNode removeInvalidEntryAndReturnNext( + final AbstractDispatchNode cache) { + Node prev = cache.getParent(); + if (prev == this) { + return dispatchCache = insert(cache.next); } - return makeGenericSend(); - } - - private GenericMessageSendNode makeGenericSend() { - GenericMessageSendNode send = new GenericMessageSendNode(selector, argumentNodes, - new UninitializedDispatchNode(selector, universe)).initialize(sourceSection); - return replace(send); + AbstractDispatchNode parent = (AbstractDispatchNode) prev; + return parent.next = parent.insertHere(cache.next); } @Override - public SSymbol getInvocationIdentifier() { - return selector; + public String toString() { + return "GMsgSend(" + selector.getString() + ")"; } @Override - public int getNumberOfArguments() { - return selector.getNumberOfSignatureArguments(); + public NodeCost getCost() { + if (numCacheNodes < 0) { + return NodeCost.UNINITIALIZED; + } + + int cacheSize = numCacheNodes; + + if (cacheSize == 0) { + return NodeCost.UNINITIALIZED; + } + + if (cacheSize == 1) { + return NodeCost.MONOMORPHIC; + } + + if (cacheSize < AbstractDispatchNode.INLINE_CACHE_SIZE) { + return NodeCost.POLYMORPHIC; + } + return NodeCost.MEGAMORPHIC; } - } - // TODO: currently, we do not only specialize the given stuff above, but also what has been - // classified as 'value' sends in the OMOP branch. Is that a problem? + private PreevaluatedExpression specialize(final Object[] arguments) { + int cacheSize = numCacheNodes; + if (cacheSize < 0) { + PreevaluatedExpression eager = attemptEagerSpecialization(arguments); + if (eager != null) { + return eager; + } + + cacheSize = numCacheNodes = 0; + } - public static final class GenericMessageSendNode - extends AbstractMessageSendNode { + Object rcvr = arguments[0]; + assert rcvr != null; - private final SSymbol selector; - private final int numberOfSignatureArguments; + if (rcvr instanceof SObject) { + SObject r = (SObject) rcvr; + if (r.updateLayoutToMatchClass() && cacheSize > 0) { + // if the dispatchCache is null, we end up here, so continue directly below instead + // otherwise, let's retry the cache! + return this; + } + } - @Child private AbstractDispatchNode dispatchNode; + if (cacheSize < AbstractDispatchNode.INLINE_CACHE_SIZE) { + SClass rcvrClass = Types.getClassOf(rcvr, universe); + SInvokable method = rcvrClass.lookupInvokable(selector); + CallTarget callTarget = null; + PreevaluatedExpression expr = null; + if (method != null) { + if (method.isTrivial()) { + expr = method.copyTrivialNode(); + assert expr != null; + } else { + callTarget = method.getCallTarget(); + } + } + + DispatchGuard guard = DispatchGuard.create(rcvr); + + AbstractDispatchNode node; + if (expr != null) { + node = new CachedExprNode(guard, expr); + } else if (method != null) { + node = new CachedDispatchNode(guard, callTarget); + } else { + node = new CachedDnuNode(rcvrClass, guard, selector); + } + + if (cacheSize > 0) { + reportPolymorphicSpecialize(); + final AbstractDispatchNode first = dispatchCache; + node.next = node.insertHere(first); + } + dispatchCache = insert(node); + numCacheNodes = cacheSize + 1; + return node; + } - private GenericMessageSendNode(final SSymbol selector, final ExpressionNode[] arguments, - final AbstractDispatchNode dispatchNode) { - super(arguments); - this.selector = selector; - this.dispatchNode = dispatchNode; - this.numberOfSignatureArguments = selector.getNumberOfSignatureArguments(); + // the chain is longer than the maximum defined by INLINE_CACHE_SIZE and + // thus, this callsite is considered to be megaprophic, and we generalize it. + GenericDispatchNode generic = new GenericDispatchNode(selector, universe); + dispatchCache = insert(generic); + reportPolymorphicSpecialize(); + numCacheNodes = cacheSize + 1; + return generic; } - @Override - public Object doPreEvaluated(final VirtualFrame frame, - final Object[] arguments) { - return dispatchNode.executeDispatch(frame, arguments); - } + private PreevaluatedExpression attemptEagerSpecialization(final Object[] arguments) { + Primitives prims = universe.getPrimitives(); - public void replaceDispatchListHead( - final GenericDispatchNode replacement) { - CompilerAsserts.neverPartOfCompilation(); - dispatchNode.replace(replacement); - } + Specializer specializer = + prims.getEagerSpecializer(selector, arguments, argumentNodes); - @Override - public String toString() { - return "GMsgSend(" + selector.getString() + ")"; - } + if (specializer != null) { + PreevaluatedExpression newNode = + (PreevaluatedExpression) specializer.create(arguments, argumentNodes, + sourceSection, universe); - @Override - public NodeCost getCost() { - return Cost.getCost(dispatchNode); + return (PreevaluatedExpression) replace((ExpressionNode) newNode); + } + return null; } @Override diff --git a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java index cad76f445..9cb347d49 100644 --- a/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java +++ b/src/trufflesom/interpreter/nodes/bc/BytecodeLoopNode.java @@ -1334,6 +1334,7 @@ private void inlineInto(final BytecodeMethodGenContext mgenc, final int targetCo SMethod newMethod = new SMethod(blockMethod.getSignature(), adapted, blockMethod.getEmbeddedBlocks(), blockIvk.getSourceSection()); newMethod.setHolder(blockMethod.getHolder()); + mgenc.replaceWith(blockMethod, newMethod); mgenc.addLiteralIfAbsent(newMethod, null); emitPUSHBLOCK(mgenc, newMethod, bytecodes[i] == PUSH_BLOCK); break; diff --git a/src/trufflesom/interpreter/nodes/dispatch/AbstractDispatchNode.java b/src/trufflesom/interpreter/nodes/dispatch/AbstractDispatchNode.java index f04711087..0b2b21c44 100644 --- a/src/trufflesom/interpreter/nodes/dispatch/AbstractDispatchNode.java +++ b/src/trufflesom/interpreter/nodes/dispatch/AbstractDispatchNode.java @@ -4,32 +4,61 @@ import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; +import com.oracle.truffle.api.nodes.InvalidAssumptionException; import com.oracle.truffle.api.nodes.Node; +import bd.primitives.nodes.PreevaluatedExpression; -public abstract class AbstractDispatchNode extends Node implements DispatchChain { + +public abstract class AbstractDispatchNode extends Node implements PreevaluatedExpression { public static final int INLINE_CACHE_SIZE = 6; - public abstract Object executeDispatch(VirtualFrame frame, Object[] arguments); + private final DispatchGuard guard; + + @Child public AbstractDispatchNode next; + + protected AbstractDispatchNode(final DispatchGuard guard) { + this.guard = guard; + } + + @Override + public abstract Object doPreEvaluated(VirtualFrame frame, Object[] args); + + public boolean entryMatches(final Object rcvr) throws InvalidAssumptionException { + return guard.entryMatches(rcvr); + } + + public final T insertHere(final T newChild) { + return super.insert(newChild); + } + + public static final class CachedDispatchNode extends AbstractDispatchNode { + + @Child protected DirectCallNode cachedMethod; + + public CachedDispatchNode(final DispatchGuard guard, final CallTarget callTarget) { + super(guard); + cachedMethod = insert(Truffle.getRuntime().createDirectCallNode(callTarget)); + } - public abstract static class AbstractCachedDispatchNode - extends AbstractDispatchNode { + @Override + public Object doPreEvaluated(final VirtualFrame frame, final Object[] arguments) { + return cachedMethod.call(arguments); + } + } - @Child protected DirectCallNode cachedMethod; - @Child protected AbstractDispatchNode nextInCache; + public static final class CachedExprNode extends AbstractDispatchNode { - public AbstractCachedDispatchNode(final CallTarget methodCallTarget, - final AbstractDispatchNode nextInCache) { - DirectCallNode cachedMethod = - Truffle.getRuntime().createDirectCallNode(methodCallTarget); + @Child protected PreevaluatedExpression expr; - this.cachedMethod = cachedMethod; - this.nextInCache = nextInCache; + public CachedExprNode(final DispatchGuard guard, final PreevaluatedExpression expr) { + super(guard); + this.expr = expr; } @Override - public final int lengthOfDispatchChain() { - return 1 + nextInCache.lengthOfDispatchChain(); + public Object doPreEvaluated(final VirtualFrame frame, final Object[] arguments) { + return expr.doPreEvaluated(frame, arguments); } } } diff --git a/src/trufflesom/interpreter/nodes/dispatch/CachedDispatchNode.java b/src/trufflesom/interpreter/nodes/dispatch/CachedDispatchNode.java deleted file mode 100644 index 6b6c36a2f..000000000 --- a/src/trufflesom/interpreter/nodes/dispatch/CachedDispatchNode.java +++ /dev/null @@ -1,36 +0,0 @@ -package trufflesom.interpreter.nodes.dispatch; - -import com.oracle.truffle.api.CallTarget; -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.InvalidAssumptionException; - -import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode.AbstractCachedDispatchNode; - - -public final class CachedDispatchNode extends AbstractCachedDispatchNode { - - private final DispatchGuard guard; - - public CachedDispatchNode(final DispatchGuard guard, - final CallTarget callTarget, final AbstractDispatchNode nextInCache) { - super(callTarget, nextInCache); - this.guard = guard; - } - - @Override - public Object executeDispatch( - final VirtualFrame frame, final Object[] arguments) { - Object rcvr = arguments[0]; - try { - if (guard.entryMatches(rcvr)) { - return cachedMethod.call(arguments); - } else { - return nextInCache.executeDispatch(frame, arguments); - } - } catch (InvalidAssumptionException e) { - CompilerDirectives.transferToInterpreter(); - return replace(nextInCache).executeDispatch(frame, arguments); - } - } -} diff --git a/src/trufflesom/interpreter/nodes/dispatch/CachedDnuNode.java b/src/trufflesom/interpreter/nodes/dispatch/CachedDnuNode.java index 293e117aa..84813d597 100644 --- a/src/trufflesom/interpreter/nodes/dispatch/CachedDnuNode.java +++ b/src/trufflesom/interpreter/nodes/dispatch/CachedDnuNode.java @@ -4,13 +4,13 @@ import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.InvalidAssumptionException; +import com.oracle.truffle.api.nodes.DirectCallNode; import trufflesom.interpreter.SArguments; import trufflesom.interpreter.SomLanguage; import trufflesom.interpreter.Types; -import trufflesom.interpreter.nodes.dispatch.AbstractDispatchNode.AbstractCachedDispatchNode; import trufflesom.primitives.basics.SystemPrims.PrintStackTracePrim; import trufflesom.vm.Universe; import trufflesom.vm.VmSettings; @@ -18,48 +18,38 @@ import trufflesom.vmobjects.SSymbol; -public final class CachedDnuNode extends AbstractCachedDispatchNode { - private final SSymbol selector; - private final DispatchGuard guard; +public final class CachedDnuNode extends AbstractDispatchNode { + private final SSymbol selector; + + @Child protected DirectCallNode cachedMethod; public CachedDnuNode(final SClass rcvrClass, final DispatchGuard guard, - final SSymbol selector, final AbstractDispatchNode nextInCache, - final Universe universe) { - super(getDnuCallTarget(rcvrClass, universe), nextInCache); + final SSymbol selector) { + super(guard); this.selector = selector; - this.guard = guard; + + cachedMethod = insert(Truffle.getRuntime().createDirectCallNode( + getDnuCallTarget(rcvrClass))); } @Override - public Object executeDispatch(final VirtualFrame frame, final Object[] arguments) { + public Object doPreEvaluated(final VirtualFrame frame, final Object[] arguments) { Object rcvr = arguments[0]; - try { - if (guard.entryMatches(rcvr)) { - return performDnu(arguments, rcvr); - } else { - return nextInCache.executeDispatch(frame, arguments); - } - } catch (InvalidAssumptionException e) { - CompilerDirectives.transferToInterpreter(); - return replace(nextInCache).executeDispatch(frame, arguments); - } - } - - public static CallTarget getDnuCallTarget(final SClass rcvrClass, final Universe universe) { - return rcvrClass.lookupInvokable( - symbolFor("doesNotUnderstand:arguments:")).getCallTarget(); - } - - protected Object performDnu(final Object[] arguments, final Object rcvr) { if (VmSettings.PrintStackTraceOnDNU) { CompilerDirectives.transferToInterpreter(); PrintStackTracePrim.printStackTrace(0, getSourceSection()); Universe.errorPrintln("Lookup of " + selector + " failed in " - + Types.getClassOf(rcvr, SomLanguage.getCurrentContext()).getName().getString()); + + Types.getClassOf(rcvr, SomLanguage.getCurrentContext()).getName() + .getString()); } Object[] argsArr = new Object[] { rcvr, selector, SArguments.getArgumentsWithoutReceiver(arguments)}; return cachedMethod.call(argsArr); } + + public static CallTarget getDnuCallTarget(final SClass rcvrClass) { + return rcvrClass.lookupInvokable( + symbolFor("doesNotUnderstand:arguments:")).getCallTarget(); + } } diff --git a/src/trufflesom/interpreter/nodes/dispatch/CachedExprNode.java b/src/trufflesom/interpreter/nodes/dispatch/CachedExprNode.java deleted file mode 100644 index 013138c9a..000000000 --- a/src/trufflesom/interpreter/nodes/dispatch/CachedExprNode.java +++ /dev/null @@ -1,45 +0,0 @@ -package trufflesom.interpreter.nodes.dispatch; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.InvalidAssumptionException; - -import bd.primitives.nodes.PreevaluatedExpression; - - -public class CachedExprNode extends AbstractDispatchNode { - - private final DispatchGuard guard; - - @Child protected AbstractDispatchNode nextInCache; - - @Child protected PreevaluatedExpression expr; - - public CachedExprNode(final DispatchGuard guard, final PreevaluatedExpression expr, - final AbstractDispatchNode nextInCache) { - this.guard = guard; - this.expr = expr; - this.nextInCache = nextInCache; - } - - @Override - public Object executeDispatch( - final VirtualFrame frame, final Object[] arguments) { - Object rcvr = arguments[0]; - try { - if (guard.entryMatches(rcvr)) { - return expr.doPreEvaluated(frame, arguments); - } else { - return nextInCache.executeDispatch(frame, arguments); - } - } catch (InvalidAssumptionException e) { - CompilerDirectives.transferToInterpreter(); - return replace(nextInCache).executeDispatch(frame, arguments); - } - } - - @Override - public final int lengthOfDispatchChain() { - return 1 + nextInCache.lengthOfDispatchChain(); - } -} diff --git a/src/trufflesom/interpreter/nodes/dispatch/GenericDispatchNode.java b/src/trufflesom/interpreter/nodes/dispatch/GenericDispatchNode.java index 66b26955c..24ea769d6 100644 --- a/src/trufflesom/interpreter/nodes/dispatch/GenericDispatchNode.java +++ b/src/trufflesom/interpreter/nodes/dispatch/GenericDispatchNode.java @@ -1,11 +1,11 @@ package trufflesom.interpreter.nodes.dispatch; import com.oracle.truffle.api.CallTarget; -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.IndirectCallNode; +import com.oracle.truffle.api.nodes.InvalidAssumptionException; import trufflesom.interpreter.SArguments; import trufflesom.primitives.reflection.ObjectPrims.ClassPrim; @@ -22,47 +22,38 @@ public final class GenericDispatchNode extends AbstractDispatchNode { @Child private ClassPrim classNode; protected final SSymbol selector; - private final Universe universe; public GenericDispatchNode(final SSymbol selector, final Universe universe) { + super(null); this.selector = selector; - this.universe = universe; - call = Truffle.getRuntime().createIndirectCallNode(); - classNode = ClassPrimFactory.create(null); + call = insert(Truffle.getRuntime().createIndirectCallNode()); + classNode = insert(ClassPrimFactory.create(null)); classNode.initialize(universe); } @TruffleBoundary - private Object dispatch(final Object[] arguments) { - Object rcvr = arguments[0]; - SClass rcvrClass = classNode.executeEvaluated(rcvr); - SInvokable method = rcvrClass.lookupInvokable(selector); + private Object sendDnu(final SClass rcvrClass, final Object[] arguments) { + // Won't use DNU caching here, because it is already a megamorphic node + SArray argumentsArray = SArguments.getArgumentsWithoutReceiver(arguments); + Object[] args = new Object[] {arguments[0], selector, argumentsArray}; + CallTarget target = CachedDnuNode.getDnuCallTarget(rcvrClass); - CallTarget target; - Object[] args; - - if (method != null) { - target = method.getCallTarget(); - args = arguments; - } else { - // TODO: actually do use node - CompilerDirectives.transferToInterpreter(); - // Won't use DNU caching here, because it is already a megamorphic node - SArray argumentsArray = SArguments.getArgumentsWithoutReceiver(arguments); - args = new Object[] {arguments[0], selector, argumentsArray}; - target = CachedDnuNode.getDnuCallTarget(rcvrClass, universe); - } return call.call(target, args); } @Override - public Object executeDispatch( - final VirtualFrame frame, final Object[] arguments) { - return dispatch(arguments); + public Object doPreEvaluated(final VirtualFrame frame, final Object[] arguments) { + Object rcvr = arguments[0]; + SClass rcvrClass = classNode.executeEvaluated(rcvr); + SInvokable method = rcvrClass.lookupInvokable(selector); + if (method != null) { + return call.call(method.getCallTarget(), arguments); + } + return sendDnu(rcvrClass, arguments); } @Override - public int lengthOfDispatchChain() { - return 1000; + public boolean entryMatches(final Object rcvr) throws InvalidAssumptionException { + return true; } } diff --git a/src/trufflesom/interpreter/nodes/dispatch/UninitializedDispatchNode.java b/src/trufflesom/interpreter/nodes/dispatch/UninitializedDispatchNode.java deleted file mode 100644 index a5bd909f0..000000000 --- a/src/trufflesom/interpreter/nodes/dispatch/UninitializedDispatchNode.java +++ /dev/null @@ -1,96 +0,0 @@ -package trufflesom.interpreter.nodes.dispatch; - -import static trufflesom.interpreter.TruffleCompiler.transferToInterpreterAndInvalidate; - -import com.oracle.truffle.api.CallTarget; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.Node; - -import bd.primitives.nodes.PreevaluatedExpression; -import trufflesom.interpreter.Types; -import trufflesom.interpreter.nodes.MessageSendNode.GenericMessageSendNode; -import trufflesom.vm.Universe; -import trufflesom.vmobjects.SClass; -import trufflesom.vmobjects.SInvokable; -import trufflesom.vmobjects.SObject; -import trufflesom.vmobjects.SSymbol; - - -public final class UninitializedDispatchNode extends AbstractDispatchNode { - private final SSymbol selector; - private final Universe universe; - - public UninitializedDispatchNode(final SSymbol selector, final Universe universe) { - this.selector = selector; - this.universe = universe; - } - - private AbstractDispatchNode specialize(final Object[] arguments) { - // Determine position in dispatch node chain, i.e., size of inline cache - Node i = this; - int chainDepth = 0; - while (i.getParent() instanceof AbstractDispatchNode) { - i = i.getParent(); - chainDepth++; - } - AbstractDispatchNode first = (AbstractDispatchNode) i; - - Object rcvr = arguments[0]; - assert rcvr != null; - - if (rcvr instanceof SObject) { - SObject r = (SObject) rcvr; - if (r.updateLayoutToMatchClass() && first != this) { // if first is this, short cut and - // directly continue... - return first; - } - } - - if (chainDepth < INLINE_CACHE_SIZE) { - SClass rcvrClass = Types.getClassOf(rcvr, universe); - SInvokable method = rcvrClass.lookupInvokable(selector); - CallTarget callTarget = null; - PreevaluatedExpression expr = null; - if (method != null) { - if (method.isTrivial()) { - expr = method.copyTrivialNode(); - assert expr != null; - } else { - callTarget = method.getCallTarget(); - } - } - - UninitializedDispatchNode newChainEnd = - new UninitializedDispatchNode(selector, universe); - DispatchGuard guard = DispatchGuard.create(rcvr); - AbstractDispatchNode node; - if (expr != null) { - node = new CachedExprNode(guard, expr, newChainEnd); - } else if (method != null) { - node = new CachedDispatchNode(guard, callTarget, newChainEnd); - } else { - node = new CachedDnuNode(rcvrClass, guard, selector, newChainEnd, universe); - } - return replace(node); - } - - // the chain is longer than the maximum defined by INLINE_CACHE_SIZE and - // thus, this callsite is considered to be megaprophic, and we generalize - // it. - GenericDispatchNode genericReplacement = new GenericDispatchNode(selector, universe); - GenericMessageSendNode sendNode = (GenericMessageSendNode) first.getParent(); - sendNode.replaceDispatchListHead(genericReplacement); - return genericReplacement; - } - - @Override - public Object executeDispatch(final VirtualFrame frame, final Object[] arguments) { - transferToInterpreterAndInvalidate("Initialize a dispatch node."); - return specialize(arguments).executeDispatch(frame, arguments); - } - - @Override - public int lengthOfDispatchChain() { - return 0; - } -}