Index: src/org/jruby/evaluator/ASTInterpreter.java =================================================================== --- src/org/jruby/evaluator/ASTInterpreter.java (revision 4558) +++ src/org/jruby/evaluator/ASTInterpreter.java (working copy) @@ -1426,6 +1426,10 @@ // falsely set $! to nil and this sets it back to something valid. This should // get fixed at the same time we address bug #1296484. runtime.getGlobalVariables().set("$!", raisedException); + + if (runtime.getClass("SystemExit") == raisedException.getMetaClass()) { + throw raiseJump; + } RescueBodyNode rescueNode = iVisited.getRescueNode(); Index: src/org/jruby/RubyThread.java =================================================================== --- src/org/jruby/RubyThread.java (revision 4558) +++ src/org/jruby/RubyThread.java (working copy) @@ -233,7 +233,7 @@ } } - private RubyThread(Ruby runtime, RubyClass type) { + protected RubyThread(Ruby runtime, RubyClass type) { super(runtime, type); this.threadService = runtime.getThreadService(); // set to default thread group @@ -676,14 +676,16 @@ public void exceptionRaised(RaiseException exception) { assert isCurrent(); - Ruby runtime = exception.getException().getRuntime(); - if (abortOnException(runtime)) { + RubyException rubyException = exception.getException(); + Ruby runtime = rubyException.getRuntime(); + if (rubyException.getMetaClass() == runtime.getClass("SystemExit")) { + threadService.getMainThread().raise(rubyException, Block.NULL_BLOCK); + } else if (abortOnException(runtime)) { // FIXME: printError explodes on some nullpointer //getRuntime().getRuntime().printError(exception.getException()); - // TODO: Doesn't SystemExit have its own method to make this less wordy.. - RubyException re = RubyException.newException(getRuntime(), getRuntime().getClass("SystemExit"), exception.getMessage()); - re.setInstanceVariable("status", getRuntime().newFixnum(1)); - threadService.getMainThread().raise(re, Block.NULL_BLOCK); + RubyException systemExit = RubySystemExit.newInstance(runtime, 1); + systemExit.message = rubyException.message; + threadService.getMainThread().raise(systemExit, Block.NULL_BLOCK); } else { exitingException = exception; } Index: src/org/jruby/Ruby.java =================================================================== --- src/org/jruby/Ruby.java (revision 4558) +++ src/org/jruby/Ruby.java (working copy) @@ -2111,9 +2111,7 @@ } public RaiseException newSystemExit(int status) { - RubyClass exc = getClass("SystemExit"); - IRubyObject[]exArgs = new IRubyObject[]{newFixnum(status), newString("exit")}; - return new RaiseException((RubyException)exc.newInstance(exArgs, Block.NULL_BLOCK)); + return new RaiseException(RubySystemExit.newInstance(this, status)); } public RaiseException newIOError(String message) { Index: src/org/jruby/RubySystemExit.java =================================================================== --- src/org/jruby/RubySystemExit.java (revision 4558) +++ src/org/jruby/RubySystemExit.java (working copy) @@ -49,6 +49,14 @@ systemExitClass.defineAnnotatedMethods(RubySystemExit.class, callbackFactory); return systemExitClass; + } + + public static RubySystemExit newInstance(Ruby runtime, int status) { + RubyClass exc = runtime.getClass("SystemExit"); + IRubyObject[] exArgs = new IRubyObject[] { + runtime.newFixnum(status), + runtime.newString("exit") }; + return (RubySystemExit) exc.newInstance(exArgs, Block.NULL_BLOCK); } protected RubySystemExit(Ruby runtime, RubyClass exceptionClass) { Index: src/org/jruby/compiler/impl/StandardASMCompiler.java =================================================================== --- src/org/jruby/compiler/impl/StandardASMCompiler.java (revision 4558) +++ src/org/jruby/compiler/impl/StandardASMCompiler.java (working copy) @@ -2322,6 +2322,18 @@ cg.params(ThreadContext.class, IRubyObject.class, Object.class, String.class, String.class, String[].class, int.class, int.class, int.class, int.class, CallConfiguration.class))); } } + + public void rethrowIfSystemExit() { + method.invokevirtual(cg.p(RubyException.class), "getMetaClass", cg.sig(RubyClass.class)); + loadRuntime(); + method.ldc("SystemExit"); + method.invokevirtual(cg.p(Ruby.class), "getClass", cg.sig(RubyClass.class, String.class)); + Label ifEnd = new Label(); + method.if_acmpne(ifEnd); + loadException(); + method.athrow(); + method.label(ifEnd); + } } public class ASMClosureCompiler extends AbstractMethodCompiler { Index: src/org/jruby/compiler/ASTCompiler.java =================================================================== --- src/org/jruby/compiler/ASTCompiler.java (revision 4558) +++ src/org/jruby/compiler/ASTCompiler.java (working copy) @@ -2617,8 +2617,10 @@ public void branch(MethodCompiler context) { context.loadException(); context.unwrapRaiseException(); + context.duplicateCurrentValue(); context.assignGlobalVariable("$!"); context.consumeCurrentValue(); + context.rethrowIfSystemExit(); compileRescueBody(rescueNode.getRescueNode(), context); } }; Index: src/org/jruby/compiler/MethodCompiler.java =================================================================== --- src/org/jruby/compiler/MethodCompiler.java (revision 4558) +++ src/org/jruby/compiler/MethodCompiler.java (working copy) @@ -454,6 +454,7 @@ public void checkWhenWithSplat(); public void createNewEndBlock(ClosureCallback body); public void runBeginBlock(StaticScope scope, ClosureCallback body); + public void rethrowIfSystemExit(); public MethodCompiler chainToMethod(String name, ASTInspector inspector); }