Skip to content

Commit fb4dcb4

Browse files
committed
The form 'expr rescue {simple}' where simple is immediate values or
values which do not cause any method execution (or side-effects) will omit generating backtraces since there is no way to get access to $!. This improves performance of these simple catch-all forms by ~48x. Note: a follow-on commit can fix 'begin; expr; rescue; {simple}; end' later. It is much less common and not as ripe a target. BEFORE: system ~/work/jruby master 814% jruby --dev ../snippets/bench2.rb Calculating ------------------------------------- begin moo rescue nil 89.000 i/100ms moo rescue nil (single) 91.000 i/100ms ------------------------------------------------- begin moo rescue nil 956.234 (± 4.4%) i/s - 9.612k moo rescue nil (single) 955.879 (± 4.8%) i/s - 9.555k system ~/work/jruby master 815% jruby -X-C ../snippets/bench2.rb Calculating ------------------------------------- begin moo rescue nil 100.000 i/100ms moo rescue nil (single) 106.000 i/100ms ------------------------------------------------- begin moo rescue nil 1.085k (± 5.2%) i/s - 10.900k moo rescue nil (single) 1.072k (± 5.5%) i/s - 10.706k system ~/work/jruby master 816% jruby ../snippets/bench2.rb Calculating ------------------------------------- begin moo rescue nil 104.000 i/100ms moo rescue nil (single) 105.000 i/100ms ------------------------------------------------- begin moo rescue nil 1.074k (± 5.7%) i/s - 10.712k moo rescue nil (single) 1.089k (± 5.0%) i/s - 10.920k system ~/work/jruby master 817% jruby -Xcompile.invokedynamic=true ../snippets/bench2.rb Calculating ------------------------------------- begin moo rescue nil 112.000 i/100ms moo rescue nil (single) 122.000 i/100ms ------------------------------------------------- begin moo rescue nil 1.275k (± 5.4%) i/s - 12.768k moo rescue nil (single) 1.253k (± 4.7%) i/s - 12.566k AFTER: system ~/work/jruby master * 820% jruby --dev ../snippets/bench2.rb Calculating ------------------------------------- begin moo rescue nil 89.000 i/100ms moo rescue nil (single) 1.199k i/100ms ------------------------------------------------- begin moo rescue nil 921.217 (± 5.1%) i/s - 9.256k moo rescue nil (single) 12.833k (± 4.9%) i/s - 128.293k system ~/work/jruby master * 821% jruby -X-C ../snippets/bench2.rb Calculating ------------------------------------- begin moo rescue nil 100.000 i/100ms moo rescue nil (single) 3.037k i/100ms ------------------------------------------------- begin moo rescue nil 1.031k (± 6.2%) i/s - 10.300k moo rescue nil (single) 35.393k (± 5.5%) i/s - 355.329k system ~/work/jruby master * 822% jruby ../snippets/bench2.rb Calculating ------------------------------------- begin moo rescue nil 100.000 i/100ms moo rescue nil (single) 4.725k i/100ms ------------------------------------------------- begin moo rescue nil 1.119k (± 4.6%) i/s - 11.200k moo rescue nil (single) 52.318k (± 5.8%) i/s - 524.475k system ~/work/jruby master * 823% jruby -Xcompile.invokedynamic=true ../snippets/bench2.rb Calculating ------------------------------------- begin moo rescue nil 106.000 i/100ms moo rescue nil (single) 5.076k i/100ms ------------------------------------------------- begin moo rescue nil 1.176k (± 5.5%) i/s - 11.766k moo rescue nil (single) 49.198k (± 5.5%) i/s - 492.372k MRI 2.2.2: system ~/work/jruby master * 824% mri22 ../snippets/bench2.rb Calculating ------------------------------------- begin moo rescue nil 2.771k i/100ms moo rescue nil (single) 2.707k i/100ms ------------------------------------------------- begin moo rescue nil 28.586k (± 5.2%) i/s - 285.413k moo rescue nil (single) 28.470k (± 4.2%) i/s - 284.235k
1 parent 55be66e commit fb4dcb4

29 files changed

+157
-29
lines changed

core/src/main/java/org/jruby/ast/BignumNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
/**
4242
* Represents a big integer literal.
4343
*/
44-
public class BignumNode extends NumericNode {
44+
public class BignumNode extends NumericNode implements SideEffectFree {
4545
private BigInteger value;
4646

4747
public BignumNode(ISourcePosition position, BigInteger value) {

core/src/main/java/org/jruby/ast/ClassVarNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
/**
4141
* Access to a class variable.
4242
*/
43-
public class ClassVarNode extends Node implements INameNode {
43+
public class ClassVarNode extends Node implements INameNode, SideEffectFree {
4444
private String name;
4545

4646
public ClassVarNode(ISourcePosition position, String name) {

core/src/main/java/org/jruby/ast/ComplexNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*
1515
* @author enebo
1616
*/
17-
public class ComplexNode extends NumericNode {
17+
public class ComplexNode extends NumericNode implements SideEffectFree {
1818
private NumericNode y;
1919

2020
public ComplexNode(ISourcePosition position, NumericNode y) {

core/src/main/java/org/jruby/ast/FalseNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
/**
4141
* Represents a false literal.
4242
*/
43-
public class FalseNode extends Node implements INameNode {
43+
public class FalseNode extends Node implements INameNode, SideEffectFree {
4444
public FalseNode(ISourcePosition position) {
4545
super(position, false);
4646
}

core/src/main/java/org/jruby/ast/FileNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
/**
3535
* Represents __FILE__ nodes
3636
*/
37-
public class FileNode extends StrNode {
37+
public class FileNode extends StrNode implements SideEffectFree {
3838
public FileNode(ISourcePosition position, ByteList value) {
3939
super(position, value);
4040
}

core/src/main/java/org/jruby/ast/FixnumNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
/**
4141
* Represents an integer literal.
4242
*/
43-
public class FixnumNode extends NumericNode implements ILiteralNode {
43+
public class FixnumNode extends NumericNode implements ILiteralNode, SideEffectFree {
4444
private long value;
4545

4646
public FixnumNode(ISourcePosition position, long value) {

core/src/main/java/org/jruby/ast/FloatNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
/**
4141
* Represents a float literal.
4242
*/
43-
public class FloatNode extends NumericNode implements ILiteralNode {
43+
public class FloatNode extends NumericNode implements ILiteralNode, SideEffectFree {
4444
private double value;
4545

4646
public FloatNode(ISourcePosition position, double value) {

core/src/main/java/org/jruby/ast/GlobalVarNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
/**
4141
* access to a global variable.
4242
*/
43-
public class GlobalVarNode extends Node implements INameNode {
43+
public class GlobalVarNode extends Node implements INameNode, SideEffectFree {
4444
private String name;
4545

4646
public GlobalVarNode(ISourcePosition position, String name) {

core/src/main/java/org/jruby/ast/InstVarNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
/**
4242
* Represents an instance variable accessor.
4343
*/
44-
public class InstVarNode extends Node implements INameNode {
44+
public class InstVarNode extends Node implements INameNode, SideEffectFree {
4545
private String name;
4646

4747
public InstVarNode(ISourcePosition position, String name) {

core/src/main/java/org/jruby/ast/LocalVarNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
/**
4141
* Access a local variable
4242
*/
43-
public class LocalVarNode extends Node implements INameNode, IScopedNode {
43+
public class LocalVarNode extends Node implements INameNode, IScopedNode, SideEffectFree {
4444
// The name of the variable
4545
private String name;
4646

core/src/main/java/org/jruby/ast/NilNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
/**
4141
* represents 'nil'
4242
*/
43-
public class NilNode extends Node implements INameNode {
43+
public class NilNode extends Node implements INameNode, SideEffectFree {
4444
public NilNode(ISourcePosition position) {
4545
super(position, false);
4646
}

core/src/main/java/org/jruby/ast/RationalNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*
1515
* @author enebo
1616
*/
17-
public class RationalNode extends NumericNode {
17+
public class RationalNode extends NumericNode implements SideEffectFree {
1818
private final long numerator;
1919
private final long denominator;
2020

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.jruby.ast;
2+
3+
import org.jruby.lexer.yacc.ISourcePosition;
4+
5+
/**
6+
* f rescue nil
7+
*/
8+
public class RescueModNode extends RescueNode {
9+
public RescueModNode(ISourcePosition position, Node bodyNode, RescueBodyNode rescueNode) {
10+
super(position, bodyNode, rescueNode, null /* else */);
11+
}
12+
}

core/src/main/java/org/jruby/ast/SelfNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
/**
4141
* Represents 'self' keyword
4242
*/
43-
public class SelfNode extends Node implements INameNode {
43+
public class SelfNode extends Node implements INameNode, SideEffectFree {
4444
public SelfNode(ISourcePosition position) {
4545
super(position, false);
4646
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.jruby.ast;
2+
3+
/**
4+
* Created by enebo on 9/26/15.
5+
*/
6+
public interface SideEffectFree {
7+
}

core/src/main/java/org/jruby/ast/StrNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
/**
4343
* Representing a simple String literal.
4444
*/
45-
public class StrNode extends Node implements ILiteralNode {
45+
public class StrNode extends Node implements ILiteralNode, SideEffectFree {
4646
private final ByteList value;
4747
private final int codeRange;
4848

core/src/main/java/org/jruby/ast/SymbolNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
/**
5555
* Represents a symbol (:symbol_name).
5656
*/
57-
public class SymbolNode extends Node implements ILiteralNode, INameNode {
57+
public class SymbolNode extends Node implements ILiteralNode, INameNode, SideEffectFree {
5858
private String name;
5959
private Encoding encoding;
6060

core/src/main/java/org/jruby/ast/TrueNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
/**
4040
* Represents 'true'.
4141
*/
42-
public class TrueNode extends Node implements INameNode {
42+
public class TrueNode extends Node implements INameNode, SideEffectFree {
4343
public TrueNode(ISourcePosition position) {
4444
super(position, false);
4545
}

core/src/main/java/org/jruby/exceptions/RaiseException.java

+14-11
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,9 @@ private void preRaise(ThreadContext context, StackTraceElement[] javaTrace) {
203203

204204
if (RubyInstanceConfig.LOG_EXCEPTIONS) TraceType.dumpException(exception);
205205

206-
exception.prepareIntegratedBacktrace(context, javaTrace);
206+
if (context.exceptionRequiresBacktrace) {
207+
exception.prepareIntegratedBacktrace(context, javaTrace);
208+
}
207209
}
208210

209211
private void preRaise(ThreadContext context, IRubyObject backtrace) {
@@ -213,17 +215,18 @@ private void preRaise(ThreadContext context, IRubyObject backtrace) {
213215

214216
if (RubyInstanceConfig.LOG_EXCEPTIONS) TraceType.dumpException(exception);
215217

216-
if (backtrace == null) {
217-
exception.prepareBacktrace(context, nativeException);
218-
} else {
219-
exception.forceBacktrace(backtrace);
220-
}
221-
222-
// call Throwable.setStackTrace so that when RaiseException appears nested inside another exception,
223-
// Ruby stack trace gets displayed
218+
// We can only omit backtraces of descendents of Standard error for 'foo rescue nil'
219+
if (!exception.kind_of_p(context, context.runtime.getStandardError()).isTrue() ||
220+
context.exceptionRequiresBacktrace) {
221+
if (backtrace == null) {
222+
exception.prepareBacktrace(context, nativeException);
223+
} else {
224+
exception.forceBacktrace(backtrace);
225+
}
224226

225-
// JRUBY-2673: if wrapping a NativeException, use the actual Java exception's trace as our Java trace
226-
if (context.exceptionRequiresBacktrace) {
227+
// call Throwable.setStackTrace so that when RaiseException appears nested inside another exception,
228+
// Ruby stack trace gets displayed
229+
// JRUBY-2673: if wrapping a NativeException, use the actual Java exception's trace as our Java trace
227230
if (exception instanceof NativeException) {
228231
setStackTrace(((NativeException) exception).getCause().getStackTrace());
229232
} else {

core/src/main/java/org/jruby/ir/IRBuilder.java

+19
Original file line numberDiff line numberDiff line change
@@ -3034,7 +3034,19 @@ public Operand buildRescue(RescueNode node) {
30343034
return buildEnsureInternal(node, null);
30353035
}
30363036

3037+
private boolean canBacktraceBeRemoved(RescueNode rescueNode) {
3038+
// For now we will only contemplate 'foo rescue nil' cases but simple non-mod rescue forms can be added later.
3039+
if (!(rescueNode instanceof RescueModNode)) return false;
3040+
3041+
// FIXME: This MIGHT be able to expand to more complicated expressions like Hash or Array if they
3042+
// contain only SideEffectFree nodes. Constructing a literal out of these should be safe from
3043+
// effecting or being able to access $!.
3044+
return rescueNode.getRescueNode().getBodyNode() instanceof SideEffectFree;
3045+
}
3046+
30373047
private Operand buildRescueInternal(RescueNode rescueNode, EnsureBlockInfo ensure) {
3048+
boolean needsBacktrace = !canBacktraceBeRemoved(rescueNode);
3049+
30383050
// Labels marking start, else, end of the begin-rescue(-ensure)-end block
30393051
Label rBeginLabel = getNewLabel();
30403052
Label rEndLabel = ensure.end;
@@ -3045,6 +3057,7 @@ private Operand buildRescueInternal(RescueNode rescueNode, EnsureBlockInfo ensur
30453057
// Placeholder rescue instruction that tells rest of the compiler passes the boundaries of the rescue block.
30463058
addInstr(new ExceptionRegionStartMarkerInstr(rescueLabel));
30473059
activeRescuers.push(rescueLabel);
3060+
addInstr(manager.needsBacktrace(needsBacktrace));
30483061

30493062
// Body
30503063
Operand tmp = manager.getNil(); // default return value if for some strange reason, we neither have the body node or the else node!
@@ -3102,12 +3115,18 @@ private Operand buildRescueInternal(RescueNode rescueNode, EnsureBlockInfo ensur
31023115
// Start of rescue logic
31033116
addInstr(new LabelInstr(rescueLabel));
31043117

3118+
// This is optimized no backtrace path so we need to reenable backtraces since we are
3119+
// exiting that region.
3120+
if (!needsBacktrace) addInstr(manager.needsBacktrace(true));
3121+
31053122
// Save off exception & exception comparison type
31063123
Variable exc = addResultInstr(new ReceiveRubyExceptionInstr(createTemporaryVariable()));
31073124

31083125
// Build the actual rescue block(s)
31093126
buildRescueBodyInternal(rescueNode.getRescueNode(), rv, exc, rEndLabel);
31103127

3128+
if (!needsBacktrace) addInstr(manager.needsBacktrace(true));
3129+
31113130
activeRescueBlockStack.pop();
31123131
return rv;
31133132
}

core/src/main/java/org/jruby/ir/IRManager.java

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.jruby.ir.instructions.Instr;
66
import org.jruby.ir.instructions.LineNumberInstr;
77
import org.jruby.ir.instructions.ReceiveSelfInstr;
8+
import org.jruby.ir.instructions.ToggleBacktraceInstr;
89
import org.jruby.ir.listeners.IRScopeListener;
910
import org.jruby.ir.listeners.InstructionsListener;
1011
import org.jruby.ir.operands.*;
@@ -41,6 +42,8 @@ public class IRManager {
4142
private final Nil nil = new Nil();
4243
private final Boolean tru = new Boolean(true);
4344
private final Boolean fals = new Boolean(false);
45+
public final ToggleBacktraceInstr needsBacktrace = new ToggleBacktraceInstr(true);
46+
public final ToggleBacktraceInstr needsNoBacktrace = new ToggleBacktraceInstr(false);
4447

4548
// Listeners for debugging and testing of IR
4649
private Set<CompilerPassListener> passListeners = new HashSet<CompilerPassListener>();
@@ -92,6 +95,10 @@ public IRModuleBody getObject() {
9295
return object;
9396
}
9497

98+
public ToggleBacktraceInstr needsBacktrace(boolean needsIt) {
99+
return needsIt ? needsBacktrace : needsNoBacktrace;
100+
}
101+
95102
public CompilerPassScheduler schedulePasses() {
96103
return schedulePasses(compilerPasses);
97104
}

core/src/main/java/org/jruby/ir/IRVisitor.java

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ private void error(Object object) {
116116
public void StoreLocalVarInstr(StoreLocalVarInstr storelocalvarinstr) { error(storelocalvarinstr); }
117117
public void ThreadPollInstr(ThreadPollInstr threadpollinstr) { error(threadpollinstr); }
118118
public void ThrowExceptionInstr(ThrowExceptionInstr throwexceptioninstr) { error(throwexceptioninstr); }
119+
public void ToggleBacktraceInstr(ToggleBacktraceInstr instr) { error(instr); }
119120
public void ToAryInstr(ToAryInstr toaryinstr) { error(toaryinstr); }
120121
public void UndefMethodInstr(UndefMethodInstr undefmethodinstr) { error(undefmethodinstr); }
121122
public void UnresolvedSuperInstr(UnresolvedSuperInstr unresolvedsuperinstr) { error(unresolvedsuperinstr); }

core/src/main/java/org/jruby/ir/Operation.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@ public enum Operation {
207207
PUSH_FRAME(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
208208
PUSH_BINDING(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
209209
POP_FRAME(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
210-
POP_BINDING(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect);
210+
POP_BINDING(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
211+
TOGGLE_BACKTRACE(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect);
211212

212213
public final OpClass opClass;
213214
private int flags;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package org.jruby.ir.instructions;
2+
3+
import org.jruby.ir.IRVisitor;
4+
import org.jruby.ir.Operation;
5+
import org.jruby.ir.persistence.IRReaderDecoder;
6+
import org.jruby.ir.persistence.IRWriterEncoder;
7+
import org.jruby.ir.transformations.inlining.CloneInfo;
8+
9+
/**
10+
* This instruction toggles a single per thread field which specifies whether an exception
11+
* being thrown needs to generate backtrace info. At any point after toggling this to be
12+
* false (no backtrace) you may encounter a nested exception which does require a backtrace.
13+
* This nested exception will toggle back to needing an exception.
14+
*
15+
* In theory, we could restore this field as we unwind frames but largely this optimization
16+
* only occurs in very simple scenarios.
17+
*
18+
* Also important to note this is only requesting for a backtrace or not. If you request
19+
* no backtrace but the error is not a StandardError exception it will still be required
20+
* to generate a backtrace.
21+
*/
22+
public class ToggleBacktraceInstr extends NoOperandInstr {
23+
private final boolean requiresBacktrace;
24+
25+
public ToggleBacktraceInstr(boolean requiresBacktrace) {
26+
super(Operation.TOGGLE_BACKTRACE);
27+
28+
this.requiresBacktrace = requiresBacktrace;
29+
}
30+
31+
public boolean requiresBacktrace() {
32+
return requiresBacktrace;
33+
}
34+
35+
public String[] toStringNonOperandArgs() {
36+
return new String[] { "" + requiresBacktrace };
37+
}
38+
39+
@Override
40+
public void encode(IRWriterEncoder e) {
41+
super.encode(e);
42+
e.encode(requiresBacktrace);
43+
}
44+
45+
public static ToggleBacktraceInstr decode(IRReaderDecoder d) {
46+
return new ToggleBacktraceInstr(d.decodeBoolean());
47+
}
48+
49+
50+
@Override
51+
public void visit(IRVisitor visitor) {
52+
visitor.ToggleBacktraceInstr(this);
53+
}
54+
55+
@Override
56+
public Instr clone(CloneInfo info) {
57+
return this;
58+
}
59+
}

core/src/main/java/org/jruby/ir/interpreter/InterpreterEngine.java

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.jruby.ir.instructions.ReturnBase;
2525
import org.jruby.ir.instructions.RuntimeHelperCall;
2626
import org.jruby.ir.instructions.SearchConstInstr;
27+
import org.jruby.ir.instructions.ToggleBacktraceInstr;
2728
import org.jruby.ir.instructions.TraceInstr;
2829
import org.jruby.ir.instructions.boxing.AluInstr;
2930
import org.jruby.ir.instructions.boxing.BoxBooleanInstr;
@@ -359,6 +360,9 @@ protected static void processBookKeepingOp(ThreadContext context, Instr instr, O
359360
case LINE_NUM:
360361
context.setLine(((LineNumberInstr)instr).lineNumber);
361362
break;
363+
case TOGGLE_BACKTRACE:
364+
context.setExceptionRequiresBacktrace(((ToggleBacktraceInstr) instr).requiresBacktrace());
365+
break;
362366
case TRACE: {
363367
if (context.runtime.hasEventHooks()) {
364368
TraceInstr trace = (TraceInstr) instr;

core/src/main/java/org/jruby/ir/persistence/IRReaderStream.java

+1
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ public Instr decodeInstr() {
281281
case THREAD_POLL: return ThreadPollInstr.decode(this);
282282
case THROW: return ThrowExceptionInstr.decode(this);
283283
case TO_ARY: return ToAryInstr.decode(this);
284+
case TOGGLE_BACKTRACE: return ToggleBacktraceInstr.decode(this);
284285
case UNDEF_METHOD: return UndefMethodInstr.decode(this);
285286
case UNRESOLVED_SUPER: return UnresolvedSuperInstr.decode(this);
286287
case YIELD: return YieldInstr.decode(this);

core/src/main/java/org/jruby/ir/targets/JVMVisitor.java

+7
Original file line numberDiff line numberDiff line change
@@ -1708,6 +1708,13 @@ public void RuntimeHelperCall(RuntimeHelperCall runtimehelpercall) {
17081708
}
17091709
}
17101710

1711+
@Override
1712+
public void ToggleBacktraceInstr(ToggleBacktraceInstr instr) {
1713+
jvmMethod().loadContext();
1714+
jvmAdapter().pushBoolean(instr.requiresBacktrace());
1715+
jvmAdapter().invokevirtual(p(ThreadContext.class), "setExceptionRequiresBacktrace", sig(void.class, boolean.class));
1716+
}
1717+
17111718
@Override
17121719
public void NonlocalReturnInstr(NonlocalReturnInstr returninstr) {
17131720
jvmMethod().loadContext();

0 commit comments

Comments
 (0)