# HG changeset patch # User Christian Humer # Date 1394058805 -3600 # Node ID c5411233cdf8623c3beb3f5af83dbe739eecd69b # Parent 036e61d4cebd9a6fbaf7fc33b565d3abc80186c0 Truffle: Now keeps track of all not just inlined call-sites called by CallNode. Deprecated some old API in NodeUtil. diff -r 036e61d4cebd -r c5411233cdf8 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java Wed Mar 05 21:37:50 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java Wed Mar 05 23:33:25 2014 +0100 @@ -65,6 +65,11 @@ } @Override + public final OptimizedCallTarget getCurrentCallTarget() { + return (OptimizedCallTarget) super.getCurrentCallTarget(); + } + + @Override public OptimizedCallTarget getSplitCallTarget() { return null; } @@ -74,11 +79,7 @@ throw new IllegalStateException("CallNode must be adopted before it is split."); } - return replace(new InlinedOptimizedCallNode(getCallTarget(), getSplitCallTarget(), getExecutedCallTarget().getRootNode(), callCount)); - } - - public final OptimizedCallTarget getExecutedCallTarget() { - return getSplitCallTarget() != null ? getSplitCallTarget() : getCallTarget(); + return replace(new InlinedOptimizedCallNode(getCallTarget(), getSplitCallTarget(), getCurrentCallTarget().getRootNode(), callCount)); } public static OptimizedCallNode create(OptimizedCallTarget target) { @@ -126,7 +127,7 @@ int nodeCount = NodeUtil.countNodes(getCallTarget().getRootNode(), null, false); // max one child call and callCount > 2 and kind of small number of nodes - if (callCount > 2 && isCallMethod()) { + if (callCount > 2 && isMaxSingleCall()) { if (nodeCount <= 100) { return true; } @@ -138,9 +139,9 @@ return countPolymorphic() > 1 || countGeneric() > 0; } - private boolean isCallMethod() { + private boolean isMaxSingleCall() { final AtomicInteger count = new AtomicInteger(0); - getExecutedCallTarget().getRootNode().accept(new NodeVisitor() { + getCurrentCallTarget().getRootNode().accept(new NodeVisitor() { public boolean visit(Node node) { if (node instanceof CallNode) { @@ -179,8 +180,7 @@ } private OptimizedCallNode splitImpl(boolean heuristic) { - RootNode splittedRoot = getCallTarget().getRootNode().split(); - OptimizedCallTarget splitCallTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(splittedRoot); + OptimizedCallTarget splitCallTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(getCallTarget().getRootNode().split()); splitCallTarget.setSplitSource(getCallTarget()); if (heuristic) { OptimizedCallTarget.logSplit(this, getCallTarget(), splitCallTarget); @@ -210,7 +210,6 @@ this.inlinedRoot = inlinedRoot; this.splittedTarget = splittedTarget; this.callCount = callCount; - installParentInlinedCall(); } @Override @@ -236,11 +235,6 @@ } @Override - public RootNode getInlinedRoot() { - return inlinedRoot; - } - - @Override public OptimizedCallTarget getSplitCallTarget() { return splittedTarget; } diff -r 036e61d4cebd -r c5411233cdf8 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNodeProfile.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNodeProfile.java Wed Mar 05 21:37:50 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNodeProfile.java Wed Mar 05 23:33:25 2014 +0100 @@ -47,7 +47,7 @@ public OptimizedCallNodeProfile(OptimizedCallTarget target, OptimizedCallNode callNode) { this.callNode = callNode; - RootNode inlineRoot = callNode.getExecutedCallTarget().getRootNode(); + RootNode inlineRoot = callNode.getCurrentCallTarget().getRootNode(); this.callTarget = target; this.targetShallowNodeCount = NodeUtil.countNodes(inlineRoot, null, false); this.targetDeepNodeCount = NodeUtil.countNodes(inlineRoot, null, true); @@ -75,7 +75,7 @@ public boolean isInliningAllowed() { this.compilationRoots = findCompilationRoots(getCallNode()); - OptimizedCallTarget inlineTarget = callNode.getExecutedCallTarget(); + OptimizedCallTarget inlineTarget = callNode.getCurrentCallTarget(); for (OptimizedCallTarget compilationRoot : compilationRoots) { if (compilationRoot == inlineTarget) { // recursive call found @@ -109,11 +109,9 @@ private int calculateInlinedTotalNodeCount(OptimizedCallNode node) { int currentNodeCount = 0; for (OptimizedCallTarget compilationRoot : compilationRoots) { - if (compilationRoot.getRootNode().getParentInlinedCalls().isEmpty()) { - TotalNodeCountVisitor visitor = new TotalNodeCountVisitor(node, targetDeepNodeCount); - compilationRoot.getRootNode().accept(visitor); - currentNodeCount = Math.max(currentNodeCount, visitor.count); - } + TotalNodeCountVisitor visitor = new TotalNodeCountVisitor(node, targetDeepNodeCount); + compilationRoot.getRootNode().accept(visitor); + currentNodeCount = Math.max(currentNodeCount, visitor.count); } return currentNodeCount; } @@ -132,12 +130,12 @@ public boolean visit(Node node) { count++; - if (node instanceof CallNode) { - RootNode inlinedRoot = ((CallNode) node).getInlinedRoot(); - if (inlinedRoot != null) { - inlinedRoot.accept(this); - } else if (node == inlinedNode) { + if (node instanceof OptimizedCallNode) { + OptimizedCallNode callNode = ((OptimizedCallNode) node); + if (callNode == inlinedNode) { count += inlinedNodeCount; + } else if (callNode.isInlined()) { + callNode.getCurrentRootNode().accept(this); } } return true; @@ -149,18 +147,6 @@ return callNode.getCallCount() / (double) callTarget.getCompilationProfile().getCallCount(); } - double calculateAverageFrequency(List roots) { - int compilationRootCallCountSum = 0; - int compilationRootCount = 0; - for (OptimizedCallTarget compilationRoot : roots) { - if (compilationRoot.getRootNode().getParentInlinedCalls().isEmpty()) { - compilationRootCallCountSum += compilationRoot.getCompilationProfile().getCallCount(); - compilationRootCount++; - } - } - return (callNode.getCallCount() * compilationRootCount) / (double) compilationRootCallCountSum; - } - private static List findCompilationRoots(Node call) { RootNode root = call.getRootNode(); if (root == null) { @@ -168,8 +154,10 @@ } List roots = new ArrayList<>(); roots.add((OptimizedCallTarget) root.getCallTarget()); - for (CallNode callNode : root.getParentInlinedCalls()) { - roots.addAll(findCompilationRoots(callNode)); + for (CallNode callNode : root.getCachedCallNodes()) { + if (callNode.isInlined()) { + roots.addAll(findCompilationRoots(callNode)); + } } return roots; } @@ -183,7 +171,7 @@ public Map getDebugProperties() { Map properties = new LinkedHashMap<>(); - OptimizedCallTarget.addASTSizeProperty(getCallNode().getExecutedCallTarget().getRootNode(), properties); + OptimizedCallTarget.addASTSizeProperty(getCallNode().getCurrentRootNode().getRootNode(), properties); properties.put("shallowCount", targetShallowNodeCount); properties.put("currentCount", calculateInlinedTotalNodeCount(null)); properties.put("inlinedTotalCount", calculateInlinedTotalNodeCount(getCallNode())); diff -r 036e61d4cebd -r c5411233cdf8 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Wed Mar 05 21:37:50 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Wed Mar 05 23:33:25 2014 +0100 @@ -72,6 +72,10 @@ } } + public OptimizedCallTarget getSplitSource() { + return splitSource; + } + public void setSplitSource(OptimizedCallTarget splitSource) { this.splitSource = splitSource; } @@ -193,7 +197,7 @@ if (callSite.isInliningAllowed()) { OptimizedCallNode callNode = callSite.getCallNode(); logInlined(this, callSite); - RootNode inlinedRoot = callNode.inlineImpl().getInlinedRoot(); + RootNode inlinedRoot = callNode.inlineImpl().getCurrentRootNode(); assert inlinedRoot != null; queueCallSitesForInlining(this, inlinedRoot, visitedCallNodes, queue); } else { @@ -212,8 +216,10 @@ if (call.isInlinable() && !call.isInlined() && !visitedCallSites.contains(call)) { queue.add(call.createInliningProfile(target)); visitedCallSites.add(call); - } else if (call.getInlinedRoot() != null) { - call.getInlinedRoot().accept(this); + } + RootNode root = call.getCurrentRootNode(); + if (root != null && call.isInlined()) { + root.accept(this); } } return true; @@ -282,12 +288,29 @@ @Override public void reportLoopCount(int count) { compilationProfile.reportLoopCount(count); + + // delegate to inlined call sites + for (CallNode callNode : getRootNode().getCachedCallNodes()) { + if (callNode.isInlined()) { + callNode.getRootNode().reportLoopCount(count); + } + } } @Override public void nodeReplaced(Node oldNode, Node newNode, String reason) { compilationProfile.reportNodeReplaced(); invalidate(oldNode, newNode, reason); + + // delegate to inlined call sites + for (CallNode callNode : getRootNode().getCachedCallNodes()) { + if (callNode.isInlined()) { + CallTarget target = callNode.getRootNode().getCallTarget(); + if (target instanceof ReplaceObserver) { + ((ReplaceObserver) target).nodeReplaced(oldNode, newNode, reason); + } + } + } } public SpeculationLog getSpeculationLog() { @@ -304,25 +327,28 @@ private static void logInliningFailed(TruffleInliningProfile callSite) { if (TraceTruffleInliningDetails.getValue()) { - log(2, "inline failed", callSite.getCallNode().getExecutedCallTarget().toString(), callSite.getDebugProperties()); + log(2, "inline failed", callSite.getCallNode().getCurrentCallTarget().toString(), callSite.getDebugProperties()); } } - private static void logInlined(final OptimizedCallTarget target, TruffleInliningProfile callSite) { + private static void logInlined(@SuppressWarnings("unused") final OptimizedCallTarget target, TruffleInliningProfile callSite) { if (TraceTruffleInliningDetails.getValue() || TraceTruffleInlining.getValue()) { - log(2, "inline success", callSite.getCallNode().getExecutedCallTarget().toString(), callSite.getDebugProperties()); + log(2, "inline success", callSite.getCallNode().getCurrentCallTarget().toString(), callSite.getDebugProperties()); if (TraceTruffleInliningDetails.getValue()) { - RootNode root = callSite.getCallNode().getExecutedCallTarget().getRootNode(); + RootNode root = callSite.getCallNode().getCurrentCallTarget().getRootNode(); root.accept(new NodeVisitor() { int depth = 1; public boolean visit(Node node) { if (node instanceof OptimizedCallNode) { OptimizedCallNode callNode = ((OptimizedCallNode) node); - log(2 + (depth * 2), "inline success", callNode.getExecutedCallTarget().toString(), callNode.createInliningProfile(target).getDebugProperties()); - RootNode inlinedRoot = callNode.getInlinedRoot(); - if (inlinedRoot != null) { + RootNode inlinedRoot = callNode.getCurrentRootNode(); + + if (inlinedRoot != null && callNode.isInlined()) { + Map properties = new LinkedHashMap<>(); + addASTSizeProperty(callNode.getCurrentRootNode(), properties); + log(2 + (depth * 2), "inline success", callNode.getCurrentCallTarget().toString(), properties); depth++; inlinedRoot.accept(this); depth--; @@ -487,7 +513,10 @@ for (CallNode callNode : callers) { if (callNode.isInlined()) { count++; - count += countInlinedNodes(callNode.getInlinedRoot()); + RootNode root = callNode.getCurrentRootNode(); + if (root != null) { + count += countInlinedNodes(root); + } } } return count; diff -r 036e61d4cebd -r c5411233cdf8 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java Wed Mar 05 21:37:50 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java Wed Mar 05 23:33:25 2014 +0100 @@ -64,11 +64,6 @@ } @Override - public RootNode getInlinedRoot() { - return null; - } - - @Override public boolean isInlined() { return false; } diff -r 036e61d4cebd -r c5411233cdf8 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java Wed Mar 05 21:37:50 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java Wed Mar 05 23:33:25 2014 +0100 @@ -31,7 +31,7 @@ * This node represents a call to a static {@link CallTarget}. This node should be used whenever a * {@link CallTarget} is considered constant at a certain location in the tree. This enables the * Truffle runtime to perform inlining or other optimizations for this call-site. This class is - * intended to be implemented by truffle runtime implementors and not by guest languague + * intended to be implemented by truffle runtime implementors and not by guest language * implementors. * * @see #create(CallTarget) to create a CallNode instance. @@ -45,13 +45,6 @@ } /** - * @return the constant {@link CallTarget} that is associated with this {@link CallNode}. - */ - public CallTarget getCallTarget() { - return callTarget; - } - - /** * Calls this constant target passing a caller frame and arguments. * * @param caller the caller frame @@ -60,6 +53,17 @@ */ public abstract Object call(PackedFrame caller, Arguments arguments); + /** + * Returns the originally supplied {@link CallTarget} when this call node was created. Please + * note that the returned {@link CallTarget} is not necessarily the {@link CallTarget} that is + * called. For that use {@link #getCurrentCallTarget()} instead. + * + * @return the {@link CallTarget} provided. + */ + public CallTarget getCallTarget() { + return callTarget; + } + public abstract boolean isInlinable(); /** @@ -73,9 +77,78 @@ public abstract boolean split(); + public final boolean isSplit() { + return getSplitCallTarget() != null; + } + public abstract CallTarget getSplitCallTarget(); - public abstract RootNode getInlinedRoot(); + /** + * Returns the used call target when {@link #call(PackedFrame, Arguments)} is invoked. If the + * {@link CallNode} was split this method returns the {@link CallTarget} returned by + * {@link #getSplitCallTarget()}. If not split this method returns the original supplied + * {@link CallTarget}. + * + * @return the used {@link CallTarget} when node is called + */ + public CallTarget getCurrentCallTarget() { + CallTarget split = getSplitCallTarget(); + if (split != null) { + return split; + } else { + return getCallTarget(); + } + } + + @Override + protected void onReplace(Node newNode, String reason) { + super.onReplace(newNode, reason); + + /* + * Old call nodes are removed in the old target root node. + */ + CallNode oldCall = this; + RootNode oldRoot = getCurrentRootNode(); + if (oldRoot != null) { + oldRoot.removeCachedCallNode(oldCall); + } + + /* + * New call nodes are registered in the new target root node. + */ + CallNode newCall = (CallNode) newNode; + RootNode newRoot = newCall.getCurrentRootNode(); + if (newRoot != null) { + newRoot.addCachedCallNode(newCall); + } + } + + /** + * Returns the {@link RootNode} associated with {@link CallTarget} returned by + * {@link #getCurrentCallTarget()}. + * + * @see #getCurrentCallTarget() + * @return the root node of the used call target + */ + public final RootNode getCurrentRootNode() { + CallTarget target = getCurrentCallTarget(); + if (target instanceof RootCallTarget) { + return ((RootCallTarget) target).getRootNode(); + } + return null; + } + + /** + * @deprecated instead use {@link #getCurrentRootNode()} and check for {@link #isInlined()} for + * true. + */ + @Deprecated + public RootNode getInlinedRoot() { + if (!isInlined()) { + return null; + } + return getCurrentRootNode(); + } /** * Creates a new {@link CallNode} using a {@link CallTarget}. @@ -89,8 +162,4 @@ return Truffle.getRuntime().createCallNode(target); } - protected final void installParentInlinedCall() { - getInlinedRoot().addParentInlinedCall(this); - } - } diff -r 036e61d4cebd -r c5411233cdf8 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Wed Mar 05 21:37:50 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Wed Mar 05 23:33:25 2014 +0100 @@ -344,8 +344,9 @@ NodeClass nodeClass = NodeClass.get(node.getClass()); if (node instanceof CallNode) { - RootNode inlinedRoot = ((CallNode) node).getInlinedRoot(); - if (inlinedRoot != null) { + CallNode callNode = ((CallNode) node); + RootNode inlinedRoot = callNode.getCurrentRootNode(); + if (inlinedRoot != null && callNode.isInlined()) { nodes.put("inlinedRoot", inlinedRoot); } } diff -r 036e61d4cebd -r c5411233cdf8 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Wed Mar 05 21:37:50 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Wed Mar 05 23:33:25 2014 +0100 @@ -254,8 +254,9 @@ } private void reportReplace(Node oldNode, Node newNode, String reason) { - Collection targets = NodeUtil.findOutermostCallTargets(this); - for (CallTarget target : targets) { + RootNode rootNode = getRootNode(); + if (rootNode != null) { + CallTarget target = rootNode.getCallTarget(); if (target instanceof ReplaceObserver) { ((ReplaceObserver) target).nodeReplaced(oldNode, newNode, reason); } diff -r 036e61d4cebd -r c5411233cdf8 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Wed Mar 05 21:37:50 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Wed Mar 05 23:33:25 2014 +0100 @@ -452,6 +452,10 @@ return null; } + /** + * @deprecated will be removed, exposed Truffle runtime specific functionality. + */ + @Deprecated public static List findOutermostCallTargets(Node node) { RootNode root = node.getRootNode(); if (root == null) { @@ -459,19 +463,16 @@ } List roots = new ArrayList<>(); roots.add(root.getCallTarget()); - for (CallNode callNode : root.getParentInlinedCalls()) { - roots.addAll(findOutermostCallTargets(callNode)); + for (CallNode callNode : root.getCachedCallNodes()) { + if (callNode.isInlined()) { + roots.addAll(findOutermostCallTargets(callNode)); + } } return roots; } /** - * Returns the outermost not inlined {@link RootNode} which is a parent of this node. - * - * @see RootNode#getParentInlinedCalls() - * @param node to search - * @return the outermost {@link RootNode} - * @deprecated use {@link #findOutermostCallTargets(Node)} + * @deprecated will be removed, exposed Truffle runtime specific functionality. */ @Deprecated public static RootNode findOutermostRootNode(Node node) { @@ -617,7 +618,7 @@ } public static int countNodes(Node root, Class clazz, Kind nodeKind, boolean countInlinedCallNodes) { - NodeCountVisitor nodeCount = new NodeCountVisitor(root, clazz, nodeKind, countInlinedCallNodes); + NodeCountVisitor nodeCount = new NodeCountVisitor(clazz, nodeKind, countInlinedCallNodes); root.accept(nodeCount); return nodeCount.nodeCount; } @@ -628,14 +629,12 @@ private static final class NodeCountVisitor implements NodeVisitor { - private Node root; private final boolean inspectInlinedCalls; int nodeCount; private final Kind kind; private final Class clazz; - private NodeCountVisitor(Node root, Class clazz, Kind kind, boolean inspectInlinedCalls) { - this.root = root; + private NodeCountVisitor(Class clazz, Kind kind, boolean inspectInlinedCalls) { this.clazz = clazz; this.kind = kind; this.inspectInlinedCalls = inspectInlinedCalls; @@ -643,10 +642,6 @@ @Override public boolean visit(Node node) { - if (node instanceof RootNode && node != root) { - return false; - } - if ((clazz == null || clazz.isInstance(node)) && (kind == null || isKind(node))) { nodeCount++; } @@ -654,7 +649,10 @@ if (inspectInlinedCalls && node instanceof CallNode) { CallNode call = (CallNode) node; if (call.isInlined()) { - call.getInlinedRoot().getChildren().iterator().next().accept(this); + Node target = ((RootCallTarget) call.getCurrentCallTarget()).getRootNode(); + if (target != null) { + target.accept(this); + } } } @@ -673,8 +671,9 @@ public boolean visit(Node node) { if (node instanceof CallNode) { - RootNode inlinedRoot = ((CallNode) node).getInlinedRoot(); - if (inlinedRoot != null) { + CallNode callNode = ((CallNode) node); + RootNode inlinedRoot = callNode.getCurrentRootNode(); + if (inlinedRoot != null && callNode.isInlined()) { depth++; printRootNode(stream, depth * 2, inlinedRoot); inlinedRoot.accept(this); diff -r 036e61d4cebd -r c5411233cdf8 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Wed Mar 05 21:37:50 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Wed Mar 05 23:33:25 2014 +0100 @@ -27,7 +27,6 @@ import java.util.*; import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.*; import com.oracle.truffle.api.frame.*; /** @@ -41,10 +40,9 @@ private final FrameDescriptor frameDescriptor; /* - * Internal field to keep reference to the inlined call node. The inlined parent should not be - * the same as the Node parent to keep the same tree hierarchy if inlined vs not inlined. + * Internal set to keep back-references to the call-sites. */ - @CompilationFinal private List parentInlinedCalls = new ArrayList<>(); + private final Set cachedCallNodes = Collections.newSetFromMap(new WeakHashMap()); protected RootNode() { this(null, null); @@ -103,11 +101,8 @@ * heuristics can use the loop count to guide compilation and inlining. */ public void reportLoopCount(int count) { - List callTargets = NodeUtil.findOutermostCallTargets(this); - for (CallTarget target : callTargets) { - if (target instanceof LoopCountReceiver) { - ((LoopCountReceiver) target).reportLoopCount(count); - } + if (getCallTarget() instanceof LoopCountReceiver) { + ((LoopCountReceiver) getCallTarget()).reportLoopCount(count); } } @@ -127,24 +122,37 @@ return frameDescriptor; } - public void setCallTarget(CallTarget callTarget) { + public final void setCallTarget(CallTarget callTarget) { this.callTarget = callTarget; } /* Internal API. Do not use. */ - void addParentInlinedCall(CallNode inlinedParent) { - this.parentInlinedCalls.add(inlinedParent); + void addCachedCallNode(CallNode callSite) { + this.cachedCallNodes.add(callSite); } - public final List getParentInlinedCalls() { - return Collections.unmodifiableList(parentInlinedCalls); + /* Internal API. Do not use. */ + void removeCachedCallNode(CallNode callSite) { + this.cachedCallNodes.remove(callSite); } /** - * @deprecated use {@link #getParentInlinedCalls()} instead. + * Returns a {@link Set} of {@link CallNode} nodes which are created to invoke this RootNode. + * This method does not make any guarantees to contain all the {@link CallNode} nodes that are + * invoking this method. Due to its weak nature the elements returned by this method may change + * with each consecutive call. + * + * @return a set of {@link CallNode} nodes + */ + public final Set getCachedCallNodes() { + return Collections.unmodifiableSet(cachedCallNodes); + } + + /** + * @deprecated use {@link #getCachedCallNodes()} instead. */ @Deprecated public final CallNode getParentInlinedCall() { - return parentInlinedCalls.isEmpty() ? null : parentInlinedCalls.get(0); + return cachedCallNodes.isEmpty() ? null : cachedCallNodes.iterator().next(); } }