@@ -3034,7 +3034,19 @@ public Operand buildRescue(RescueNode node) {
3034
3034
return buildEnsureInternal (node , null );
3035
3035
}
3036
3036
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
+
3037
3047
private Operand buildRescueInternal (RescueNode rescueNode , EnsureBlockInfo ensure ) {
3048
+ boolean needsBacktrace = !canBacktraceBeRemoved (rescueNode );
3049
+
3038
3050
// Labels marking start, else, end of the begin-rescue(-ensure)-end block
3039
3051
Label rBeginLabel = getNewLabel ();
3040
3052
Label rEndLabel = ensure .end ;
@@ -3045,6 +3057,7 @@ private Operand buildRescueInternal(RescueNode rescueNode, EnsureBlockInfo ensur
3045
3057
// Placeholder rescue instruction that tells rest of the compiler passes the boundaries of the rescue block.
3046
3058
addInstr (new ExceptionRegionStartMarkerInstr (rescueLabel ));
3047
3059
activeRescuers .push (rescueLabel );
3060
+ addInstr (manager .needsBacktrace (needsBacktrace ));
3048
3061
3049
3062
// Body
3050
3063
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
3102
3115
// Start of rescue logic
3103
3116
addInstr (new LabelInstr (rescueLabel ));
3104
3117
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
+
3105
3122
// Save off exception & exception comparison type
3106
3123
Variable exc = addResultInstr (new ReceiveRubyExceptionInstr (createTemporaryVariable ()));
3107
3124
3108
3125
// Build the actual rescue block(s)
3109
3126
buildRescueBodyInternal (rescueNode .getRescueNode (), rv , exc , rEndLabel );
3110
3127
3128
+ if (!needsBacktrace ) addInstr (manager .needsBacktrace (true ));
3129
+
3111
3130
activeRescueBlockStack .pop ();
3112
3131
return rv ;
3113
3132
}
0 commit comments