Skip to content

Commit 21c3647

Browse files
committed
Make the top-level exception handler more compatible with MRI
* Fixes #2047
1 parent cc37760 commit 21c3647

File tree

3 files changed

+27
-14
lines changed

3 files changed

+27
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Compatibility:
6565
* Implemented `ONIGENC_MBC_CASE_FOLD`.
6666
* Fixed `Thread#raise` to call the exception class' constructor with no arguments when given no message (#2045).
6767
* Fixed `refine + super` compatibility (#2039, @ssnickolay)
68+
* Make the top-level exception handler more compatible with MRI (#2047).
6869

6970
Performance:
7071

src/main/java/org/truffleruby/core/kernel/AtExitManager.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.truffleruby.Layouts;
1818
import org.truffleruby.RubyContext;
1919
import org.truffleruby.core.proc.ProcOperations;
20+
import org.truffleruby.language.control.ExitException;
2021
import org.truffleruby.language.control.RaiseException;
2122

2223
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
@@ -42,15 +43,15 @@ public void add(DynamicObject block, boolean always) {
4243
}
4344

4445
public DynamicObject runAtExitHooks() {
45-
return runExitHooks(atExitHooks);
46+
return runExitHooks(atExitHooks, "at_exit");
4647
}
4748

4849
public void runSystemExitHooks() {
49-
runExitHooks(systemExitHooks);
50+
runExitHooks(systemExitHooks, "system at_exit");
5051
}
5152

5253
@TruffleBoundary
53-
private DynamicObject runExitHooks(Deque<DynamicObject> stack) {
54+
private DynamicObject runExitHooks(Deque<DynamicObject> stack, String name) {
5455
DynamicObject lastException = null;
5556

5657
while (true) {
@@ -62,8 +63,12 @@ private DynamicObject runExitHooks(Deque<DynamicObject> stack) {
6263
try {
6364
ProcOperations.rootCall(block);
6465
} catch (RaiseException e) {
65-
lastException = handleAtExitException(context, e);
66+
handleAtExitException(context, e.getException());
67+
lastException = e.getException();
68+
} catch (ExitException e) {
69+
throw e;
6670
} catch (Exception e) {
71+
System.err.println("Unexpected internal exception in " + name + ":");
6772
e.printStackTrace();
6873
}
6974
}
@@ -77,16 +82,14 @@ public List<DynamicObject> getHandlers() {
7782
}
7883

7984
@TruffleBoundary
80-
public static DynamicObject handleAtExitException(RubyContext context, RaiseException raiseException) {
81-
final DynamicObject rubyException = raiseException.getException();
85+
public static void handleAtExitException(RubyContext context, DynamicObject rubyException) {
8286
DynamicObject logicalClass = Layouts.BASIC_OBJECT.getLogicalClass(rubyException);
8387
if (logicalClass == context.getCoreLibrary().systemExitClass ||
8488
logicalClass == context.getCoreLibrary().signalExceptionClass) {
8589
// Do not show the backtrace for these
8690
} else {
8791
context.getDefaultBacktraceFormatter().printRubyExceptionOnEnvStderr("", rubyException);
8892
}
89-
return rubyException;
9093
}
9194

9295
}

src/main/java/org/truffleruby/language/exceptions/TopLevelRaiseHandler.java

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,25 +38,34 @@ public Object execute(VirtualFrame frame) {
3838
int exitCode = 0;
3939
DynamicObject caughtException = null;
4040

41+
// Execute the main script
4142
try {
4243
body.execute(frame);
4344
} catch (RaiseException e) {
44-
DynamicObject rubyException = AtExitManager.handleAtExitException(getContext(), e);
45-
caughtException = rubyException;
46-
setLastException(rubyException);
47-
exitCode = statusFromException(rubyException);
45+
caughtException = e.getException();
46+
exitCode = statusFromException(caughtException);
47+
setLastException(caughtException); // Set $! for at_exit
48+
// printing the main script exception is delayed after at_exit hooks
4849
} catch (ExitException e) {
49-
exitCode = e.getCode();
50-
} finally {
51-
final DynamicObject atExitException = getContext().getAtExitManager().runAtExitHooks();
50+
// hard #exit!, return immediately, skip at_exit hooks
51+
return e.getCode();
52+
}
5253

54+
// Execute at_exit hooks (except if hard #exit!)
55+
try {
56+
DynamicObject atExitException = getContext().getAtExitManager().runAtExitHooks();
5357
if (atExitException != null) {
5458
exitCode = statusFromException(atExitException);
5559
}
5660

5761
if (caughtException != null) {
62+
// print the main script exception now
63+
AtExitManager.handleAtExitException(getContext(), caughtException);
5864
handleSignalException(caughtException);
5965
}
66+
} catch (ExitException e) {
67+
// hard #exit! during at_exit: ignore the main script exception
68+
exitCode = e.getCode();
6069
}
6170

6271
return exitCode;

0 commit comments

Comments
 (0)