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;
- }
-}