Skip to content

Commit bf84216

Browse files
committed
Fix: Nodes tagged with RootTag throw ReturnException
1 parent 6d1b078 commit bf84216

File tree

3 files changed

+82
-20
lines changed

3 files changed

+82
-20
lines changed

com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionBodyNode.java

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,18 +23,22 @@
2323
package com.oracle.truffle.r.nodes.function;
2424

2525
import com.oracle.truffle.api.CompilerDirectives;
26+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
2627
import com.oracle.truffle.api.frame.FrameDescriptor;
2728
import com.oracle.truffle.api.frame.FrameSlot;
2829
import com.oracle.truffle.api.frame.FrameSlotKind;
2930
import com.oracle.truffle.api.frame.VirtualFrame;
3031
import com.oracle.truffle.api.nodes.Node;
3132
import com.oracle.truffle.api.profiles.BranchProfile;
33+
import com.oracle.truffle.api.profiles.ConditionProfile;
3234
import com.oracle.truffle.api.source.SourceSection;
3335
import com.oracle.truffle.r.runtime.RArguments;
3436
import com.oracle.truffle.r.runtime.RArguments.DispatchArgs;
3537
import com.oracle.truffle.r.runtime.RArguments.S3Args;
3638
import com.oracle.truffle.r.runtime.RArguments.S4Args;
39+
import com.oracle.truffle.r.runtime.RInternalError;
3740
import com.oracle.truffle.r.runtime.RRuntime;
41+
import com.oracle.truffle.r.runtime.ReturnException;
3842
import com.oracle.truffle.r.runtime.RootBodyNode;
3943
import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
4044
import com.oracle.truffle.r.runtime.nodes.RNode;
@@ -46,16 +50,34 @@ public final class FunctionBodyNode extends Node implements RootBodyNode {
4650
@Child private SetupS3ArgsNode setupS3Args;
4751
@Child private SetupS4ArgsNode setupS4Args;
4852

53+
// Profiling for catching ReturnException
54+
private final BranchProfile returnExceptionProfile = BranchProfile.create();
55+
@CompilationFinal private ConditionProfile returnTopLevelProfile;
56+
4957
public FunctionBodyNode(SaveArgumentsNode saveArguments, RNode body) {
5058
this.body = body;
5159
this.saveArguments = saveArguments;
5260
}
5361

5462
@Override
5563
public Object visibleExecute(VirtualFrame frame) {
56-
setupDispatchSlots(frame);
57-
saveArguments.execute(frame);
58-
return body.visibleExecute(frame);
64+
try {
65+
setupDispatchSlots(frame);
66+
saveArguments.execute(frame);
67+
return body.visibleExecute(frame);
68+
} catch (ReturnException ex) {
69+
returnExceptionProfile.enter();
70+
if (profileReturnToTopLevel(ex.getTarget() == RArguments.getCall(frame))) {
71+
Object result = ex.getResult();
72+
if (CompilerDirectives.inInterpreter() && result == null) {
73+
throw RInternalError.shouldNotReachHere("invalid null from ReturnException.getResult() of " + this);
74+
}
75+
return result;
76+
} else {
77+
// re-thrown until it reaches its target
78+
throw ex;
79+
}
80+
}
5981
}
6082

6183
@Override
@@ -68,6 +90,14 @@ public SourceSection getSourceSection() {
6890
return body.getSourceSection();
6991
}
7092

93+
public boolean profileReturnToTopLevel(boolean condition) {
94+
if (returnTopLevelProfile == null) {
95+
CompilerDirectives.transferToInterpreterAndInvalidate();
96+
returnTopLevelProfile = ConditionProfile.createBinaryProfile();
97+
}
98+
return returnTopLevelProfile.profile(condition);
99+
}
100+
71101
private void setupDispatchSlots(VirtualFrame frame) {
72102
DispatchArgs dispatchArgs = RArguments.getDispatchArgs(frame);
73103
if (dispatchArgs == null) {

com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -132,10 +132,8 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
132132
@CompilationFinal private FrameSlot handlerStackSlot;
133133
@CompilationFinal private FrameSlot restartStackSlot;
134134

135-
/**
136-
* Profiling for catching {@link ReturnException}s.
137-
*/
138-
private final ConditionProfile returnTopLevelProfile = ConditionProfile.createBinaryProfile();
135+
// Profiling for catching ReturnException thrown from an exit handler
136+
@CompilationFinal private ConditionProfile returnTopLevelProfile;
139137

140138
public static FunctionDefinitionNode create(TruffleRLanguage language, SourceSection src, FrameDescriptor frameDesc, SourceSection[] argSourceSections, SaveArgumentsNode saveArguments,
141139
RSyntaxNode body,
@@ -288,15 +286,9 @@ public Object execute(VirtualFrame frame) {
288286
}
289287
return result;
290288
} catch (ReturnException ex) {
291-
if (returnTopLevelProfile.profile(ex.getTarget() == RArguments.getCall(frame))) {
292-
Object result = ex.getResult();
293-
if (CompilerDirectives.inInterpreter() && result == null) {
294-
throw RInternalError.shouldNotReachHere("invalid null from ReturnException.getResult() of " + this);
295-
}
296-
return result;
297-
} else {
298-
throw ex;
299-
}
289+
// here we just re-throw, the check whether this function is the target of the return is
290+
// done in the function body node
291+
throw ex;
300292
} catch (BreakException e) {
301293
breakProfile.enter();
302294
throw e;
@@ -391,7 +383,7 @@ public Object execute(VirtualFrame frame) {
391383
}
392384
}
393385
} catch (ReturnException ex) {
394-
if (returnTopLevelProfile.profile(ex.getTarget() == RArguments.getCall(frame))) {
386+
if (profileReturnToTopLevel(ex.getTarget() == RArguments.getCall(frame))) {
395387
return ex.getResult();
396388
} else {
397389
throw ex;
@@ -405,6 +397,14 @@ public Object execute(VirtualFrame frame) {
405397
}
406398
}
407399

400+
public boolean profileReturnToTopLevel(boolean condition) {
401+
if (returnTopLevelProfile == null) {
402+
CompilerDirectives.transferToInterpreterAndInvalidate();
403+
returnTopLevelProfile = ConditionProfile.createBinaryProfile();
404+
}
405+
return returnTopLevelProfile.profile(condition);
406+
}
407+
408408
private static RPairList getCurrentOnExitList(VirtualFrame frame, FrameSlot slot) {
409409
try {
410410
return (RPairList) FrameSlotChangeMonitor.getObject(slot, frame);

com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -594,6 +594,38 @@ public void testActiveBinding() throws Throwable {
594594
assertExecutedOK();
595595
}
596596

597+
@Test
598+
public void testStepOut() throws Throwable {
599+
final Source source = sourceFromText("fnc <- function() {\n" +
600+
" x <- 10L\n" +
601+
" return(x + 10)\n" +
602+
"}\n" +
603+
"fnc() + fnc()\n",
604+
"test.r");
605+
context.eval(source);
606+
run.addLast(() -> {
607+
assertNull(suspendedEvent);
608+
assertNotNull(debuggerSession);
609+
debuggerSession.setSteppingFilter(SuspensionFilter.newBuilder().ignoreLanguageContextInitialization(true).build());
610+
debuggerSession.suspendNextExecution();
611+
});
612+
assertLocation(1, "fnc <- function() {");
613+
stepOver(1);
614+
assertLocation(5, "fnc() + fnc()");
615+
stepInto(1);
616+
assertLocation(2, "x <- 10L");
617+
stepOver(1);
618+
assertLocation(3, "return(x + 10)");
619+
stepOut();
620+
assertLocation(5, "fnc()");
621+
stepInto(1);
622+
assertLocation(2, "x <- 10L");
623+
continueExecution();
624+
performWork();
625+
context.eval(source);
626+
assertExecutedOK();
627+
}
628+
597629
private void performWork() {
598630
try {
599631
if (ex == null && !run.isEmpty()) {

0 commit comments

Comments
 (0)