Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package org.jruby.ir.passes;
  
  import java.util.Arrays;
  import java.util.List;
  
 
 public class AddCallProtocolInstructions extends CompilerPass {
     boolean addedInstrs = false;
 
     @Override
     public String getLabel() {
         return "Add Call Protocol Instructions (push/pop of dyn-scope, frame, impl-class values)";
     }
 
     public static List<Class<? extends CompilerPass>> DEPENDENCIES = Arrays.<Class<? extends CompilerPass>>asList(CFGBuilder.class);
 
     @Override
     public List<Class<? extends CompilerPass>> getDependencies() {
         return ;
     }
 
     @Override
     public Object execute(IRScope scopeObject... data) {
 
         boolean scopeHasLocalVarStores      = false;
         boolean scopeHasUnrescuedExceptions = false;
 
         CFG        cfg = scope.cfg();
         BasicBlock geb = cfg.getGlobalEnsureBB();
 
         if (slvpp != null) {
             scopeHasLocalVarStores      = slvpp.scopeHasLocalVarStores();
             scopeHasUnrescuedExceptions = slvpp.scopeHasUnrescuedExceptions();
         } else {
             // We dont require local-var load/stores to have been run.
             // If it is not run, we go conservative and add push/pop binding instrs. everywhere
             scopeHasLocalVarStores      = true;
             scopeHasUnrescuedExceptions = false;
             for (BasicBlock bbcfg.getBasicBlocks()) {
                 // SSS FIXME: This is highly conservative.  If the bb has an exception raising instr.
                 // and if we dont have a rescuer, only then do we have unrescued exceptions.
                 if (cfg.getRescuerBBFor(bb) == null) {
                     scopeHasUnrescuedExceptions = true;
                     break;
                 }
             }
         }
 
         BasicBlock entryBB = cfg.getEntryBB();
 
         // SSS FIXME: Right now, we always add push/pop frame instrs -- in the future, we may skip them
         // for certain scopes.
         //
         // Add explicit frame and binding push/pop instrs ONLY for methods -- we cannot handle this in closures and evals yet
         // If the scope uses $_ or $~ family of vars, has local load/stores, or if its binding has escaped, we have
         // to allocate a dynamic scope for it and add binding push/pop instructions.
         if ((scope instanceof IRMethod) || (scope instanceof IRScriptBody) || (scope instanceof IRModuleBody)) {
             if (scope.bindingHasEscaped() || scope.usesBackrefOrLastline() || scopeHasLocalVarStores || scopeHasUnrescuedExceptions) {
                 // Push
                 entryBB.addInstr(new PushFrameInstr());
                 entryBB.addInstr(new PushBindingInstr(scope));
 
                 // Allocate GEB if necessary for popping binding
                 if (geb == null && (scopeHasLocalVarStores || scopeHasUnrescuedExceptions)) {
                     Variable exc = scope.getNewTemporaryVariable();
                     geb = new BasicBlock(cfgnew Label("_GLOBAL_ENSURE_BLOCK"));
                     geb.addInstr(new ReceiveExceptionInstr(excfalse)); // No need to check type since it is not used before rethrowing
                     geb.addInstr(new ThrowExceptionInstr(exc));
                     cfg.addGlobalEnsureBB(geb);
                 }
 
                 // Pop on all scope-exit paths
                 BasicBlock exitBB = cfg.getExitBB();
                 for (BasicBlock bbcfg.getBasicBlocks()) {
                     ListIterator<Instrinstrs = bb.getInstrs().listIterator();
                     while (instrs.hasNext()) {
                         Instr i = instrs.next();
                         if ((bb != exitBB) && (i instanceof ReturnBase) || (i instanceof BreakInstr)) {
                            // Add before the break/return
                            instrs.previous();
                            instrs.add(new PopBindingInstr());
                            instrs.add(new PopFrameInstr());
                            break;
                        }
                    }
                    if ((bb == exitBB) && !bb.isEmpty()) {
                        // Last instr could be a return -- so, move iterator one position back
                        if (instrs.hasPrevious()) instrs.previous();
                        instrs.add(new PopBindingInstr());
                        instrs.add(new PopFrameInstr());
                    }
                    if (bb == geb) {
                        // Add before throw-exception-instr which would be the last instr
                        instrs.previous();
                        instrs.add(new PopBindingInstr());
                        instrs.add(new PopFrameInstr());
                    }
                }
            }
            // This scope has an explicit call protocol flag now
            scope.setExplicitCallProtocolFlag(true);
        }
        // Run on all nested closures.
        for (IRClosure cscope.getClosures()) execute(c);
        // Mark as done
         = true;
        return null;
    }
    @Override
    public Object previouslyRun(IRScope scope) {
        return  ? new Object() : null;
    }
    @Override
    public void invalidate(IRScope scope) {
        // Cannot add call protocol instructions after we've added them once.
    }
New to GrepCode? Check out our FAQ X