Skip to content

Commit f17a736

Browse files
committed
Modify yield logic to be aware of the on-stack block.
Previously, because we only had one yield instruction and one way to prepare any incoming block, the lowest-common-denominator was to always turn passed blocks into a Proc object before sending it on to a yield. This is less overhead than in 1.7, and resulted in our yield performance being worse than it should be. See #2442. In order to fix this I have made the following changes. * ReceiveClosure, the instruction which reifies an implicit block into a Proc, has been renamed to ReifyClosure. It is now used only for block args, as in def foo(&b). * LoadImplicitClosure and LoadFrameClosure are added to retrieve a block from either the JVM stack or from our frame stack. Method bodies and singleton class bodies use the stack, and all other scopes use frame. This allows us to load the block used for yielding in an efficient way regardless of which scope we are in. * IRScope temporarily aggregates two variables: one for the "yield" closure, the one used for yielding (which may come from either JVM stack or our frame); and one for the "implicit" closure, which is the one passed directly to this scope on the JVM stack. This additional closure is needed to represent two-block scopes like a block that receives a block. * ProcessModuleBody now has an operand to load a block passed to the module/class body. For normal module and class bodies this is always NullBlock (new operand for Block.NULL_BLOCK), but singleton class bodies (class << obj) inherit the surrounding scope's yield closure (not the implicit closure, since that would capture nearest block's block rather than outer method's block). This results in a substantial reduction of allocation, and a decent performance improvement: BEFORE yield 6.901M (±19.0%) i/s - 32.351M block.call 6.509M (±10.6%) i/s - 31.999M method dispatch 18.988M (±16.8%) i/s - 90.797M AFTER yield 8.002M (±22.4%) i/s - 36.745M block.call 6.399M (±12.8%) i/s - 31.314M method dispatch 18.939M (±10.5%) i/s - 92.585M
1 parent e1ffae8 commit f17a736

19 files changed

+370
-95
lines changed

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

Lines changed: 79 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -312,24 +312,6 @@ public void addInstrAtBeginning(IRScope s, Instr i) {
312312
}
313313
}
314314

315-
// FIXME: This all seems wrong to me. IRClosures can receive explicit closures why are we searching only methods
316-
// and by-passing closures
317-
private Operand getImplicitBlockArg(IRScope s) {
318-
int n = 0;
319-
while (s instanceof IRClosure || s instanceof IRMetaClassBody) {
320-
n++;
321-
s = s.getLexicalParent();
322-
}
323-
324-
if (s != null) {
325-
LocalVariable v = s instanceof IRMethod ? s.getLocalVariable(Variable.BLOCK, 0) : null;
326-
327-
if (v != null) return n == 0 ? v : v.cloneForDepth(n);
328-
}
329-
330-
return manager.getNil();
331-
}
332-
333315
// Emit cloned ensure bodies by walking up the ensure block stack.
334316
// If we have been passed a loop value, only emit bodies that are nested within that loop.
335317
private void emitEnsureBlocks(IRScope s, IRLoop loop) {
@@ -509,8 +491,8 @@ public Operand buildLambda(LambdaNode node, IRScope s) {
509491
// like the ensure block stack
510492
IRBuilder closureBuilder = newIRBuilder(manager);
511493

512-
// Receive self
513-
closureBuilder.addInstr(closure, new ReceiveSelfInstr(closure.getSelf()));
494+
// Prepare all implicit state (self, frame block, etc)
495+
closureBuilder.prepareImplicitState(closure);
514496

515497
// Set %current_scope = <current-scope>
516498
// Set %current_module = <current-module>
@@ -1124,7 +1106,7 @@ public Operand buildClass(ClassNode classNode, IRScope s) {
11241106
IRClassBody body = new IRClassBody(manager, s, className, classNode.getPosition().getLine(), classNode.getScope());
11251107
Variable classVar = addResultInstr(s, new DefineClassInstr(s.createTemporaryVariable(), body, container, superClass));
11261108

1127-
return buildModuleOrClassBody(s, classVar, body, classNode.getBodyNode(), classNode.getPosition().getLine());
1109+
return buildModuleOrClassBody(s, classVar, body, classNode.getBodyNode(), classNode.getPosition().getLine(), NullBlock.INSTANCE);
11281110
}
11291111

11301112
// class Foo; class << self; end; end
@@ -1135,7 +1117,8 @@ public Operand buildSClass(SClassNode sclassNode, IRScope s) {
11351117
IRModuleBody body = new IRMetaClassBody(manager, s, manager.getMetaClassName(), sclassNode.getPosition().getLine(), sclassNode.getScope());
11361118
Variable sClassVar = addResultInstr(s, new DefineMetaClassInstr(s.createTemporaryVariable(), receiver, body));
11371119

1138-
return buildModuleOrClassBody(s, sClassVar, body, sclassNode.getBodyNode(), sclassNode.getPosition().getLine());
1120+
// sclass bodies inherit the block of their containing method
1121+
return buildModuleOrClassBody(s, sClassVar, body, sclassNode.getBodyNode(), sclassNode.getPosition().getLine(), s.getYieldClosureVariable());
11391122
}
11401123

11411124
// @@c
@@ -1445,7 +1428,7 @@ public Operand run() {
14451428
return addResultInstr(scope, new RuntimeHelperCall(scope.createTemporaryVariable(), IS_DEFINED_METHOD,
14461429
new Operand[] { scope.getSelf(), new StringLiteral(((VCallNode) node).getName()), Boolean.FALSE}));
14471430
case YIELDNODE:
1448-
return buildDefinitionCheck(scope, new BlockGivenInstr(scope.createTemporaryVariable(), getImplicitBlockArg(scope)), "yield");
1431+
return buildDefinitionCheck(scope, new BlockGivenInstr(scope.createTemporaryVariable(), scope.getYieldClosureVariable()), "yield");
14491432
case ZSUPERNODE:
14501433
return addResultInstr(scope, new RuntimeHelperCall(scope.createTemporaryVariable(), IS_DEFINED_SUPER,
14511434
new Operand[] { scope.getSelf() } ));
@@ -1678,6 +1661,8 @@ protected IRMethod defineMethodInner(MethodDefNode defNode, IRMethod method, IRS
16781661

16791662
addInstr(method, new ReceiveSelfInstr(method.getSelf()));
16801663

1664+
// Prepare all implicit state (self, frame block, etc)
1665+
prepareImplicitState(method);
16811666

16821667
// These instructions need to be toward the top of the method because they may both be needed for
16831668
// processing optional arguments as in def foo(a = Object).
@@ -1766,23 +1751,6 @@ public void receiveRequiredArg(Node node, IRScope s, int argIndex, boolean post,
17661751
}
17671752
}
17681753

1769-
private void receiveClosureArg(BlockArgNode blockVarNode, IRScope s) {
1770-
Variable blockVar = null;
1771-
if (blockVarNode != null) {
1772-
String blockArgName = blockVarNode.getName();
1773-
blockVar = s.getNewLocalVariable(blockArgName, 0);
1774-
if (s instanceof IRMethod) ((IRMethod)s).addArgDesc(IRMethodArgs.ArgType.block, blockArgName);
1775-
addInstr(s, new ReceiveClosureInstr(blockVar));
1776-
}
1777-
1778-
// In addition, store the block argument in an implicit block variable
1779-
if (s instanceof IRMethod) {
1780-
Variable implicitBlockArg = (Variable)getImplicitBlockArg(s);
1781-
if (blockVar == null) addInstr(s, new ReceiveClosureInstr(implicitBlockArg));
1782-
else addInstr(s, new CopyInstr(implicitBlockArg, blockVar));
1783-
}
1784-
}
1785-
17861754
protected void receiveNonBlockArgs(final ArgsNode argsNode, IRScope s) {
17871755
final int numPreReqd = argsNode.getPreCount();
17881756
final int numPostReqd = argsNode.getPostCount();
@@ -1863,13 +1831,54 @@ protected void receiveNonBlockArgs(final ArgsNode argsNode, IRScope s) {
18631831
}
18641832
}
18651833

1834+
/**
1835+
* Reify the implicit incoming block into a full Proc, for use as "block arg", but only if
1836+
* a block arg is specified in this scope's arguments.
1837+
*
1838+
* @param argsNode the arguments containing the block arg, if any
1839+
* @param s the scope to which we are adding instructions
1840+
*/
18661841
protected void receiveBlockArg(final ArgsNode argsNode, IRScope s) {
1867-
// For methods, we always receive it (implicitly, if the block arg is not explicit)
1868-
// For closures, only if it is explicitly present
1842+
// reify to Proc if we have a block arg
18691843
BlockArgNode blockArg = argsNode.getBlock();
1870-
if (s instanceof IRMethod || blockArg != null) receiveClosureArg(blockArg, s);
1844+
if (blockArg != null) {
1845+
String blockArgName = blockArg.getName();
1846+
Variable blockVar = s.getNewLocalVariable(blockArgName, 0);
1847+
if (s instanceof IRMethod) ((IRMethod) s).addArgDesc(IRMethodArgs.ArgType.block, blockArgName);
1848+
addInstr(s, new ReifyClosureInstr(s.getImplicitClosureVariable(), blockVar));
1849+
}
18711850
}
18721851

1852+
/**
1853+
* Prepare implicit runtime state needed for typical methods to execute. This includes such things
1854+
* as the implicit self variable and any yieldable block available to this scope.
1855+
*
1856+
* @param s the scope to which we are adding instructions
1857+
*/
1858+
private void prepareImplicitState(IRScope s) {
1859+
// Receive self
1860+
addInstr(s, new ReceiveSelfInstr(s.getSelf()));
1861+
1862+
// used for constructing block arg; if none, this will go away
1863+
addInstr(s, new LoadImplicitClosureInstr(s.getImplicitClosureVariable()));
1864+
1865+
// used for yields; metaclass body (sclass) inherits yield var from surrounding, and accesses it as implicit
1866+
if (s instanceof IRMethod || s instanceof IRMetaClassBody) {
1867+
addInstr(s, new LoadImplicitClosureInstr(s.getYieldClosureVariable()));
1868+
} else {
1869+
addInstr(s, new LoadFrameClosureInstr(s.getYieldClosureVariable()));
1870+
}
1871+
}
1872+
1873+
/**
1874+
* Process all arguments specified for this scope. This includes pre args (required args
1875+
* at the beginning of the argument list), opt args (arguments with a default value),
1876+
* a rest arg (catch-all for argument list overflow), post args (required arguments after
1877+
* a rest arg) and a block arg (to reify an incoming block into a Proc object.
1878+
*
1879+
* @param argsNode the args node containing the specification for the arguments
1880+
* @param s the scope to which we are adding instructions
1881+
*/
18731882
public void receiveArgs(final ArgsNode argsNode, IRScope s) {
18741883
// 1.9 pre, opt, rest, post args
18751884
receiveNonBlockArgs(argsNode, s);
@@ -2023,7 +2032,7 @@ private void handleBreakAndReturnsInLambdas(IRClosure s) {
20232032
addInstr(s, new LabelInstr(rEndLabel));
20242033
}
20252034

2026-
public void receiveMethodArgs(final ArgsNode argsNode, IRScope s) {
2035+
public void receiveMethodArgs(final ArgsNode argsNode, IRMethod s) {
20272036
receiveArgs(argsNode, s);
20282037
}
20292038

@@ -2348,8 +2357,8 @@ public Operand buildForIter(final ForNode forNode, IRScope s) {
23482357
// like the ensure block stack
23492358
IRBuilder forBuilder = newIRBuilder(manager);
23502359

2351-
// Receive self
2352-
forBuilder.addInstr(closure, new ReceiveSelfInstr(closure.getSelf()));
2360+
// Prepare all implicit state (self, frame block, etc)
2361+
forBuilder.prepareImplicitState(closure);
23532362

23542363
// Build args
23552364
Node varNode = forNode.getVarNode();
@@ -2499,8 +2508,15 @@ public Operand buildIter(final IterNode iterNode, IRScope s) {
24992508
// like the ensure block stack
25002509
IRBuilder closureBuilder = newIRBuilder(manager);
25012510

2502-
// Receive self
2503-
closureBuilder.addInstr(closure, new ReceiveSelfInstr(closure.getSelf()));
2511+
// Prepare all implicit state (self, frame block, etc)
2512+
closureBuilder.prepareImplicitState(closure);
2513+
2514+
// load block into temporary variable
2515+
if (s instanceof IRMethod) {
2516+
addInstr(s, new LoadImplicitClosureInstr(s.getYieldClosureVariable()));
2517+
} else {
2518+
addInstr(s, new LoadFrameClosureInstr(s.getYieldClosureVariable()));
2519+
}
25042520

25052521
// Build args
25062522
if (iterNode.getVarNode().getNodeType() != null) closureBuilder.receiveBlockArgs(iterNode, closure);
@@ -2635,7 +2651,7 @@ public Operand buildModule(ModuleNode moduleNode, IRScope s) {
26352651
IRModuleBody body = new IRModuleBody(manager, s, moduleName, moduleNode.getPosition().getLine(), moduleNode.getScope());
26362652
Variable moduleVar = addResultInstr(s, new DefineModuleInstr(s.createTemporaryVariable(), body, container));
26372653

2638-
return buildModuleOrClassBody(s, moduleVar, body, moduleNode.getBodyNode(), moduleNode.getPosition().getLine());
2654+
return buildModuleOrClassBody(s, moduleVar, body, moduleNode.getBodyNode(), moduleNode.getPosition().getLine(), NullBlock.INSTANCE);
26392655
}
26402656

26412657
public Operand buildMultipleAsgn(MultipleAsgnNode multipleAsgnNode, IRScope s) {
@@ -3232,6 +3248,8 @@ public IREvalScript buildEvalRoot(StaticScope staticScope, IRScope containingSco
32323248
// Debug info: record line number
32333249
addInstr(script, new LineNumberInstr(lineNumber));
32343250

3251+
prepareImplicitState(script);
3252+
32353253
// Set %current_scope = <current-scope>
32363254
// Set %current_module = <current-module>
32373255
addInstr(script, new CopyInstr(script.getCurrentScopeVariable(), CURRENT_SCOPE[0]));
@@ -3249,7 +3267,10 @@ public IRScriptBody buildRoot(RootNode rootNode) {
32493267

32503268
// Top-level script!
32513269
IRScriptBody script = new IRScriptBody(manager, file, staticScope);
3252-
addInstr(script, new ReceiveSelfInstr(script.getSelf()));
3270+
3271+
// Prepare all implicit state (self, frame block, etc)
3272+
prepareImplicitState(script);
3273+
32533274
// Set %current_scope = <current-scope>
32543275
// Set %current_module = <current-module>
32553276
addInstr(script, new CopyInstr(script.getCurrentScopeVariable(), CURRENT_SCOPE[0]));
@@ -3301,7 +3322,7 @@ public Operand buildSuper(SuperNode superNode, IRScope s) {
33013322

33023323
Operand[] args = setupCallArgs(superNode.getArgsNode(), s);
33033324
Operand block = setupCallClosure(superNode.getIterNode(), s);
3304-
if (block == null) block = getImplicitBlockArg(s);
3325+
if (block == null) block = s.getYieldClosureVariable();
33053326
return buildSuperInstr(s, block, args);
33063327
}
33073328

@@ -3418,7 +3439,7 @@ public Operand buildYield(YieldNode node, IRScope s) {
34183439
}
34193440

34203441
Variable ret = s.createTemporaryVariable();
3421-
addInstr(s, new YieldInstr(ret, getImplicitBlockArg(s), build(argNode, s), unwrap));
3442+
addInstr(s, new YieldInstr(ret, s.getYieldClosureVariable(), build(argNode, s), unwrap));
34223443
return ret;
34233444
}
34243445

@@ -3490,7 +3511,7 @@ public Operand buildZSuper(ZSuperNode zsuperNode, IRScope s) {
34903511
if (s.isModuleBody()) return buildSuperInScriptBody(s);
34913512

34923513
Operand block = setupCallClosure(zsuperNode.getIterNode(), s);
3493-
if (block == null) block = getImplicitBlockArg(s);
3514+
if (block == null) block = s.getYieldClosureVariable();
34943515

34953516
// Enebo:ZSuper in for (or nested for) can be statically resolved like method but it needs to fixup depth.
34963517
if (s instanceof IRMethod) {
@@ -3519,15 +3540,17 @@ private Operand[] adjustVariableDepth(Operand[] args, int depthFromSuper) {
35193540
return newArgs;
35203541
}
35213542

3522-
private Operand buildModuleOrClassBody(IRScope parent, Variable moduleVar, IRModuleBody body, Node bodyNode, int linenumber) {
3523-
Variable processBodyResult = addResultInstr(parent, new ProcessModuleBodyInstr(parent.createTemporaryVariable(), moduleVar));
3543+
private Operand buildModuleOrClassBody(IRScope parent, Variable moduleVar, IRModuleBody body, Node bodyNode, int linenumber, Operand block) {
3544+
Variable processBodyResult = addResultInstr(parent, new ProcessModuleBodyInstr(parent.createTemporaryVariable(), moduleVar, block));
35243545
IRBuilder bodyBuilder = newIRBuilder(manager);
35253546

35263547
if (RubyInstanceConfig.FULL_TRACE_ENABLED) {
35273548
bodyBuilder.addInstr(body, new TraceInstr(RubyEvent.CLASS, null, body.getFileName(), linenumber));
35283549
}
35293550

3530-
bodyBuilder.addInstr(body, new ReceiveSelfInstr(body.getSelf())); // %self
3551+
// Prepare all implicit state (self, frame block, etc)
3552+
bodyBuilder.prepareImplicitState(body);
3553+
35313554
bodyBuilder.addInstr(body, new CopyInstr(body.getCurrentScopeVariable(), CURRENT_SCOPE[0])); // %scope
35323555
bodyBuilder.addInstr(body, new CopyInstr(body.getCurrentModuleVariable(), SCOPE_MODULE[0])); // %module
35333556
// Create a new nested builder to ensure this gets its own IR builder state

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ public enum IRFlags {
4444
HAS_EXPLICIT_CALL_PROTOCOL, // contains call protocol instrs => we don't need to manage bindings frame implicitly
4545
HAS_LOOPS, // has a loop
4646
HAS_NONLOCAL_RETURNS, // has a non-local return
47-
HAS_UNUSED_IMPLICIT_BLOCK_ARG,// Is %block implicit block arg unused?
4847
RECEIVES_CLOSURE_ARG, // This scope (or parent receives a closure
4948
RECEIVES_KEYWORD_ARGS, // receives keyword args
5049
REQUIRES_DYNSCOPE, // does this scope require a dynamic scope?

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

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ public abstract class IRScope implements ParseResult {
133133

134134
private IRManager manager;
135135

136+
private TemporaryVariable yieldClosureVariable;
137+
138+
private TemporaryVariable implicitClosureVariable;
139+
136140
// Used by cloning code
137141
protected IRScope(IRScope s, IRScope lexicalParent) {
138142
this.lexicalParent = lexicalParent;
@@ -190,7 +194,6 @@ public IRScope(IRManager manager, IRScope lexicalParent, String name,
190194
flags.remove(HAS_EXPLICIT_CALL_PROTOCOL);
191195
flags.remove(HAS_LOOPS);
192196
flags.remove(HAS_NONLOCAL_RETURNS);
193-
flags.remove(HAS_UNUSED_IMPLICIT_BLOCK_ARG);
194197
flags.remove(RECEIVES_KEYWORD_ARGS);
195198

196199
// These flags are true by default!
@@ -896,6 +899,29 @@ public void setTemporaryVariableCount(int count) {
896899
temporaryVariableIndex = count + 1;
897900
}
898901

902+
/**
903+
* Get the variable for accessing the "yieldable" closure in this scope.
904+
*/
905+
public TemporaryVariable getYieldClosureVariable() {
906+
if (yieldClosureVariable == null) {
907+
return yieldClosureVariable = createTemporaryVariable();
908+
}
909+
910+
return yieldClosureVariable;
911+
}
912+
913+
/**
914+
* Get the variable for accessing the implicit closure in this scope (the block
915+
* passed along the JVM stack).
916+
*/
917+
public TemporaryVariable getImplicitClosureVariable() {
918+
if (implicitClosureVariable == null) {
919+
return implicitClosureVariable = createTemporaryVariable();
920+
}
921+
922+
return implicitClosureVariable;
923+
}
924+
899925
public TemporaryLocalVariable getNewUnboxedVariable(Class type) {
900926
TemporaryVariableType varType;
901927
if (type == Float.class) {

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ private void error(Object object) {
7373
public void LexicalSearchConstInstr(LexicalSearchConstInstr lexicalsearchconstinstr) { error(lexicalsearchconstinstr); }
7474
public void LineNumberInstr(LineNumberInstr linenumberinstr) { error(linenumberinstr); }
7575
public void LoadLocalVarInstr(LoadLocalVarInstr loadlocalvarinstr) { error(loadlocalvarinstr); }
76+
public void LoadImplicitClosure(LoadImplicitClosureInstr loadimplicitclosureinstr) { error(loadimplicitclosureinstr); }
77+
public void LoadFrameClosure(LoadFrameClosureInstr loadframeclosureinstr) { error(loadframeclosureinstr); }
7678
public void Match2Instr(Match2Instr match2instr) { error(match2instr); }
7779
public void Match3Instr(Match3Instr match3instr) { error(match3instr); }
7880
public void MatchInstr(MatchInstr matchinstr) { error(matchinstr); }
@@ -95,7 +97,7 @@ private void error(Object object) {
9597
public void PushFrameInstr(PushFrameInstr pushframeinstr) { error(pushframeinstr); }
9698
public void RaiseArgumentErrorInstr(RaiseArgumentErrorInstr raiseargumenterrorinstr) { error(raiseargumenterrorinstr); }
9799
public void RaiseRequiredKeywordArgumentErrorInstr(RaiseRequiredKeywordArgumentError instr) { error(instr); }
98-
public void ReceiveClosureInstr(ReceiveClosureInstr receiveclosureinstr) { error(receiveclosureinstr); }
100+
public void ReifyClosureInstr(ReifyClosureInstr reifyclosureinstr) { error(reifyclosureinstr); }
99101
public void ReceiveRubyExceptionInstr(ReceiveRubyExceptionInstr receiveexceptioninstr) { error(receiveexceptioninstr); }
100102
public void ReceiveJRubyExceptionInstr(ReceiveJRubyExceptionInstr receiveexceptioninstr) { error(receiveexceptioninstr); }
101103
public void ReceiveKeywordArgInstr(ReceiveKeywordArgInstr receiveKeywordArgInstr) { error(receiveKeywordArgInstr); }
@@ -163,6 +165,7 @@ private void error(Object object) {
163165
public void LocalVariable(LocalVariable localvariable) { error(localvariable); }
164166
public void Nil(Nil nil) { error(nil); }
165167
public void NthRef(NthRef nthref) { error(nthref); }
168+
public void NullBlock(NullBlock nullblock) { error(nullblock); }
166169
public void ObjectClass(ObjectClass objectclass) { error(objectclass); }
167170
public void Rational(Rational rational) { error(rational); }
168171
public void Regexp(Regexp regexp) { error(regexp); }

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,13 @@ public enum Operation {
4949
RECV_KW_REST_ARG(OpFlags.f_is_arg_receive),
5050
RECV_REST_ARG(OpFlags.f_is_arg_receive),
5151
RECV_OPT_ARG(OpFlags.f_is_arg_receive),
52-
RECV_CLOSURE(OpFlags.f_is_arg_receive),
5352
RECV_RUBY_EXC(OpFlags.f_is_arg_receive),
5453
RECV_JRUBY_EXC(OpFlags.f_is_arg_receive),
54+
LOAD_IMPLICT_CLOSURE(OpFlags.f_is_arg_receive),
55+
LOAD_FRAME_CLOSURE(OpFlags.f_is_arg_receive),
56+
57+
/** Instruction to reify an passed-in block to a Proc for def foo(&b) */
58+
REIFY_CLOSURE(0),
5559

5660
/* By default, call instructions cannot be deleted even if their results
5761
* aren't used by anyone unless we know more about what the call is,

core/src/main/java/org/jruby/ir/dataflow/analyses/LiveVariableNode.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,6 @@ void markDeadInstructions() {
298298
// System.out.println("YES!");
299299
i.markDead();
300300
it.remove();
301-
problem.getScope().getFlags().add(IRFlags.HAS_UNUSED_IMPLICIT_BLOCK_ARG);
302301
} else {
303302
// System.out.println("NO! has side effects! Op is: " + i.getOperation());
304303
}

0 commit comments

Comments
 (0)