@@ -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
0 commit comments