Skip to content

Commit 90c3685

Browse files
committed
[GR-17173] [GR-17194] Fix ReadCallerFrameNode to still optimize for multiple callers
1 parent fbd2da4 commit 90c3685

File tree

1 file changed

+20
-14
lines changed

1 file changed

+20
-14
lines changed

src/main/java/org/truffleruby/language/arguments/ReadCallerFrameNode.java

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,43 +25,49 @@
2525
public class ReadCallerFrameNode extends RubyBaseNode {
2626

2727
private final ConditionProfile callerFrameProfile = ConditionProfile.createBinaryProfile();
28-
@CompilationFinal private volatile boolean firstCall = true;
28+
@CompilationFinal private volatile boolean deoptWhenNotPassedCallerFrame = true;
2929

3030
public static ReadCallerFrameNode create() {
3131
return new ReadCallerFrameNode();
3232
}
3333

3434
public MaterializedFrame execute(VirtualFrame frame) {
35-
// Avoid polluting the profile for the first call which has to use getCallerFrame()
36-
if (firstCall) {
37-
CompilerDirectives.transferToInterpreterAndInvalidate();
38-
firstCall = false;
39-
notifyCallerToSendFrame();
40-
return getCallerFrame();
41-
}
42-
4335
final MaterializedFrame callerFrame = RubyArguments.getCallerFrame(frame);
4436

4537
if (callerFrameProfile.profile(callerFrame != null)) {
4638
return callerFrame;
4739
} else {
40+
// Every time the caller of the method using ReadCallerFrameNode changes,
41+
// we need to notify the caller's CachedDispatchNode to pass us the frame next time.
42+
if (deoptWhenNotPassedCallerFrame) {
43+
// Invalidate because deoptWhenNotPassedCallerFrame might change and require recompilation
44+
CompilerDirectives.transferToInterpreterAndInvalidate();
45+
}
4846
return getCallerFrame();
4947
}
5048
}
5149

52-
private void notifyCallerToSendFrame() {
50+
@TruffleBoundary
51+
private MaterializedFrame getCallerFrame() {
52+
if (!notifyCallerToSendFrame()) {
53+
// If we fail to notify the call node (e.g., because it is a UncachedDispatchNode which is not handled yet),
54+
// we don't want to deoptimize this CallTarget on every call.
55+
deoptWhenNotPassedCallerFrame = false;
56+
}
57+
return getContext().getCallStack().getCallerFrameIgnoringSend().getFrame(FrameInstance.FrameAccess.MATERIALIZE).materialize();
58+
}
59+
60+
private boolean notifyCallerToSendFrame() {
5361
final Node callerNode = getContext().getCallStack().getCallerNode(0, false);
5462
if (callerNode instanceof DirectCallNode) {
5563
final Node parent = callerNode.getParent();
5664
if (parent instanceof CachedDispatchNode) {
5765
((CachedDispatchNode) parent).startSendingOwnFrame();
66+
return true;
5867
}
5968
}
60-
}
6169

62-
@TruffleBoundary
63-
private MaterializedFrame getCallerFrame() {
64-
return getContext().getCallStack().getCallerFrameIgnoringSend().getFrame(FrameInstance.FrameAccess.MATERIALIZE).materialize();
70+
return false;
6571
}
6672

6773
}

0 commit comments

Comments
 (0)