Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   package org.jruby.ir;
   
   import java.util.ArrayList;
   import java.util.HashMap;
   import java.util.List;
   import java.util.Map;
   import java.util.Set;
   import java.util.SortedSet;
   import java.util.TreeSet;
  
Right now, this class abstracts the following execution scopes: Method, Closure, Module, Class, MetaClass Top-level Script, and Eval Script In the compiler-land, IR versions of these scopes encapsulate only as much information as is required to convert Ruby code into equivalent Java code. But, in the non-compiler land, there will be a corresponding java object for some of these scopes which encapsulates the runtime semantics and data needed for implementing them. In the case of Module, Class, MetaClass, and Method, they also happen to be instances of the corresponding Ruby classes -- so, in addition to providing code that help with this specific ruby implementation, they also have code that let them behave as ruby instances of their corresponding classes. Examples: - the runtime class object might have refs. to the runtime method objects. - the runtime method object might have a slot for a heap frame (for when it has closures that need access to the method's local variables), it might have version information, it might have references to other methods that were optimized with the current version number, etc. - the runtime closure object will have a slot for a heap frame (for when it has closures within) and might get reified as a method in the java land (but inaccessible in ruby land). So, passing closures in Java land might be equivalent to passing around the method handles. and so on ...
  
  public abstract class IRScope {
      private static final Logger LOG = LoggerFactory.getLogger("IRScope");
  
      private static Integer globalScopeCount = 0;

    
Unique global scope id
  
      private int scopeId;

    
Name
  
      private String name;

    
File within which this scope has been defined
  
      private final String fileName;

    
Starting line for this scope's definition
  
      private final int lineNumber;

    
Lexical parent scope
  
      private IRScope lexicalParent;

    
Parser static-scope that this IR scope corresponds to
  
      private StaticScope staticScope;
    
    
Live version of module within whose context this method executes
  
      private RubyModule containerModule
    
    
List of IR instructions for this method
  
      private List<InstrinstrList

    
Control flow graph representation of this method's instructions
 
     private CFG cfg;

    
List of (nested) closures in this scope
 
     private List<IRClosurenestedClosures;

    
Local variables defined in this scope
 
     private Set<VariabledefinedLocalVars;

    
Local variables used in this scope
 
     private Set<VariableusedLocalVars;

    
Is %block implicit block arg unused?
 
     private boolean hasUnusedImplicitBlockArg;

    
%current_module and %current_scope variables
 
     private TemporaryVariable currentScopeVar;

    
Map of name -> dataflow problem
 
     private Map<StringDataFlowProblemdfProbs;
     
     private Instr[] linearizedInstrArray;
     private List<BasicBlocklinearizedBBList;
     protected int temporaryVariableIndex;

    
Keeps track of types of prefix indexes for variables and labels
 
     private Map<StringIntegernextVarIndex;
 
     // Index values to guarantee we don't assign same internal index twice
     private int nextClosureIndex;
     
     // List of all scopes this scope contains lexically.  This is not used
     // for execution, but is used during dry-runs for debugging.
 
     protected static class LocalVariableAllocator {
         public int nextSlot;
         public Map<StringLocalVariablevarMap;
 
         public LocalVariableAllocator() {
              = new HashMap<StringLocalVariable>();
              = 0;
         }
 
         public final LocalVariable getVariable(String name) {
             return .get(name);
         }
 
         public final void putVariable(String nameLocalVariable var) {
             .put(namevar);
             ++;
         }
     }
 
 
     /* *****************************************************************************************************
      * Does this execution scope (applicable only to methods) receive a block and use it in such a way that
      * all of the caller's local variables need to be materialized into a heap binding?
      * Ex: 
      *    def foo(&b)
      *      eval 'puts a', b
      *    end
      *  
      *    def bar
      *      a = 1
      *      foo {} # prints out '1'
      *    end
      *
      * Here, 'foo' can access all of bar's variables because it captures the caller's closure.
      *
      * There are 2 scenarios when this can happen (even this is conservative -- but, good enough for now)
      * 1. This method receives an explicit block argument (in this case, the block can be stored, passed around,
      *    eval'ed against, called, etc.).  
      *    CAVEAT: This is conservative ... it may not actually be stored & passed around, evaled, called, ...
      * 2. This method has a 'super' call (ZSuper AST node -- ZSuperInstr IR instruction)
      *    In this case, the parent (in the inheritance hierarchy) can access the block and store it, etc.  So, in reality,
      *    rather than assume that the parent will always do this, we can query the parent, if we can precisely identify
      *    the parent method (which in the face of Ruby's dynamic hierarchy, we cannot).  So, be pessimistic.
      *
      * This logic was extracted from an email thread on the JRuby mailing list -- Yehuda Katz & Charles Nutter
      * contributed this analysis above.
      * ********************************************************************************************************/
     private boolean canCaptureCallersBinding;
 
     /* ****************************************************************************
      * Does this scope define code, i.e. does it (or anybody in the downward call chain)
      * do class_eval, module_eval? In the absence of any other information, we default
      * to yes -- which basically leads to pessimistic but safe optimizations.  But, for
      * library and internal methods, this might be false.
      * **************************************************************************** */
     private boolean canModifyCode;
 
     /* ****************************************************************************
      * Does this scope require a binding to be materialized?
      * Yes if any of the following holds true:
      * - calls 'Proc.new'
      * - calls 'eval'
      * - calls 'call' (could be a call on a stored block which could be local!)
      * - calls 'send' and we cannot resolve the message (method name) that is being sent!
      * - calls methods that can access the caller's binding
      * - calls a method which we cannot resolve now!
      * - has a call whose closure requires a binding
      * **************************************************************************** */
     private boolean bindingHasEscaped;

    
Does this scope call any eval
 
     private boolean usesEval;

    
Since backref ($~) and lastline ($_) vars are allocated space on the dynamic scope, this is an useful flag to compute.
 
     private boolean usesBackrefOrLastline;

    
Does this scope call any zsuper
 
     private boolean usesZSuper;

    
Does this scope have loops?
 
     private boolean hasLoops;

    
# of thread poll instrs added to this scope
 
     private int threadPollInstrsCount;

    
Does this scope have explicit call protocol instructions? If yes, there are IR instructions for managing bindings/frames, etc. If not, this has to be managed implicitly as in the current runtime For now, only dyn-scopes are managed explicitly. Others will come in time
 
     private boolean hasExplicitCallProtocol;

    
Should we re-run compiler passes -- yes after we've inlined, for example
 
     private boolean relinearizeCFG;
     
     private IRManager manager;
 
     // Used by cloning code
     protected IRScope(IRScope sIRScope lexicalParent) {
         this. = lexicalParent;
         this. = s.manager;
         this. = s.fileName;
         this. = s.lineNumber;
         this. = s.staticScope;
         this. = s.threadPollInstrsCount;
         this. = s.nextClosureIndex;
         this. = s.temporaryVariableIndex;
         this. = s.hasLoops;
         this. = s.hasUnusedImplicitBlockArg;
         this. = null;
         this. = new ArrayList<IRClosure>();
         this. = new HashMap<StringDataFlowProblem>();
         this. = new HashMap<StringInteger>(); // SSS FIXME: clone!
         this. = null;
         this. = null;
         this. = null;
         this. = s.canModifyCode;
         this. = s.canCaptureCallersBinding;
         this. = s.bindingHasEscaped;
         this. = s.usesEval;
         this. = s.usesBackrefOrLastline;
         this. = s.usesZSuper;
         this. = s.hasExplicitCallProtocol;
 
         this. = new LocalVariableAllocator(); // SSS FIXME: clone!
         this.. = s.localVars.nextSlot;
         this. = false;
         
         setupLexicalContainment();
     }
     
     public IRScope(IRManager managerIRScope lexicalParentString name
             String fileNameint lineNumberStaticScope staticScope) {
         this. = manager;
         this. = lexicalParent;        
         this. = name;
         this. = fileName;
         this. = lineNumber;
         this. = staticScope;
         this. = 0;
         this. = 0;
         this. = -1;
         this. = new ArrayList<Instr>();
         this. = new ArrayList<IRClosure>();
         this. = new HashMap<StringDataFlowProblem>();
         this. = new HashMap<StringInteger>();
         this. = null;
         this. = null;
         this. = null;
         this. = false;
         this. = false;
 
         // These flags are true by default!
         this. = true;
         this. = true;
         this. = true;
         this. = true;
         this. = true;
         this. = true;
 
         this. = false;
 
         this. = new LocalVariableAllocator();
         synchronized() { this. = ++; }
         this. = false;
         
         setupLexicalContainment();
     }
     
     private final void setupLexicalContainment() {
         if (.isDryRun()) {
              = new ArrayList<IRScope>();
             if ( != null.addChildScope(this);
         }        
     }
 
     @Override
     public int hashCode() {
         return ;
     }
     
     protected void addChildScope(IRScope scope) {
         .add(scope);
     }
     
     public List<IRScopegetLexicalScopes() {
         return ;
     }
 
     public void addClosure(IRClosure c) {
         .add(c);
     }
     
     public Instr getLastInstr() {
         return .get(.size() - 1);
     }
     
     public void addInstr(Instr i) {
         if (i instanceof ThreadPollInstr++;
         .add(i);
     }
 
         return getLocalVariable("%flip_" + allocateNextPrefixedName("%flip"), 0);
     }
 
     public void initFlipStateVariable(Variable vOperand initState) {
         // Add it to the beginning
         .add(0, new CopyInstr(vinitState));
     }
 
     public boolean isForLoopBody() {
         return false;
     }
     
     public Label getNewLabel(String prefix) {
         return new Label(prefix + "_" + allocateNextPrefixedName(prefix));
     }
 
     public Label getNewLabel() {
         return getNewLabel("LBL");
     }    
 
     public List<IRClosuregetClosures() {
         return ;
     }
     
     public IRManager getManager() {
         return ;
     }
    
    
Returns the lexical scope that contains this scope definition
 
     public IRScope getLexicalParent() {
         return ;
     }
     
     public StaticScope getStaticScope() {
         return ;
     }    
     
     public IRMethod getNearestMethod() {
         IRScope current = this;
 
         while (current != null && !(current instanceof IRMethod)) {
             current = current.getLexicalParent();
         }
 
         return (IRMethodcurrent;
     }
 
     public IRScope getNearestFlipVariableScope() {
         IRScope current = this;
 
         while (current != null && !current.isFlipScope()) {
             current = current.getLexicalParent();
         }
         
         return current;
     }
 
         IRScope current = this;
 
         while (current != null && !current.isTopLocalVariableScope()) {
             current = current.getLexicalParent();
         }
         
         return current;
     }
    
    
Returns the nearest scope which we can extract a live module from. If this returns null (like for evals), then it means it cannot be statically determined.
 
         IRScope current = this;
 
         while (!(current instanceof IRModuleBody)) {
             // When eval'ing, we dont have a lexical view of what module we are nested in
             // because binding_eval, class_eval, module_eval, instance_eval can switch
             // around the lexical scope for evaluation to be something else.            
             if (current == null || current instanceof IREvalScriptreturn null;
             
             current = current.getLexicalParent();
         }
 
         return current;
     }
     
     public String getName() {
         return ;
     }
 
     public void setName(String name) { // This is for IRClosure ;(
         this. = name;
     }
 
     public String getFileName() {
         return ;
     }
 
     public int getLineNumber() {
         return ;
     }

    
Returns the top level scope
 
     public IRScope getTopLevelScope() {
         IRScope current = this;
         
         for (; current != null && !current.isScriptScope(); current = current.getLexicalParent()) {}
         
         return current;
     }
 
     public boolean isNestedInClosure(IRClosure closure) {
         for (IRScope s = thiss != null && !s.isTopLocalVariableScope(); s = s.getLexicalParent()) {
             if (s == closurereturn true;
         }
         
         return false;
     }
 
     public void setHasLoopsFlag(boolean f) {
          = true;
     }
 
     public boolean hasLoops() {
         return ;
     }
 
     public boolean hasExplicitCallProtocol() {
         return ;
     }
 
     public void setExplicitCallProtocolFlag(boolean flag) {
         this. = flag;
     }
 
     public void setCodeModificationFlag(boolean f) { 
          = f;
     }
 
     public boolean modifiesCode() { 
         return ;
     }
 
     public boolean bindingHasEscaped() {
         return ;
     }
 
     public boolean usesBackrefOrLastline() {
         return ;
     }
 
     public boolean usesEval() {
         return ;
     }
 
     public boolean usesZSuper() {
         return ;
     }
 
     public boolean canCaptureCallersBinding() {
         return ;
     }
 
     public CFG buildCFG() {
          = new CFG(this);
         .build();
         // Clear out instruction list after CFG has been built.
         this. = null;  
         return ;
     }
 
     protected void setCFG(CFG cfg) {
        this. = cfg;
     }
     
     public CFG getCFG() {
         return ;
     }
 
     private void setupLabelPCs(HashMap<LabelIntegerlabelIPCMap) {
         for (BasicBlock b) {
             Label l = b.getLabel();
             l.setTargetPC(labelIPCMap.get(l));
         }
     }
     
         checkRelinearization();
 
         if ( != nullreturn // Already prepared
 
         try {
             buildLinearization(); // FIXME: compiler passes should have done this
             depends(linearization());
         } catch (RuntimeException e) {
             .error("Error linearizing cfg: "e);
             CFG c = cfg();
             .error("\nGraph:\n" + c.toStringGraph());
             .error("\nInstructions:\n" + c.toStringInstrs());
             throw e;
         }
 
         // Set up IPCs
         HashMap<LabelIntegerlabelIPCMap = new HashMap<LabelInteger>();
         List<InstrnewInstrs = new ArrayList<Instr>();
         int ipc = 0;
         for (BasicBlock b) {
             labelIPCMap.put(b.getLabel(), ipc);
             List<InstrbbInstrs = b.getInstrs();
             int bbInstrsLength = bbInstrs.size();
             for (int i = 0; i < bbInstrsLengthi++) {
                 Instr instr = bbInstrs.get(i);
                 
                 if (instr instanceof Specializeable) {
                     instr = ((Specializeableinstr).specializeForInterpretation();
                     bbInstrs.set(iinstr);
                 }
                 
                 if (!(instr instanceof ReceiveSelfInstr)) {
                     newInstrs.add(instr);
                     ipc++;
                 }
             }
         }
 
         // Set up label PCs
         setupLabelPCs(labelIPCMap);
 
         // Exit BB ipc
         cfg().getExitBB().getLabel().setTargetPC(ipc + 1);
 
          = newInstrs.toArray(new Instr[newInstrs.size()]);
         return ;
     }
 
     private void runCompilerPasses() {
         // SSS FIXME: Why is this again?  Document this weirdness!
         // Forcibly clear out the shared eval-scope variable allocator each time this method executes
         initEvalScopeVariableAllocator(true); 
         
         // SSS FIXME: We should configure different optimization levels
         // and run different kinds of analysis depending on time budget.  Accordingly, we need to set
         // IR levels/states (basic, optimized, etc.) and the
         // ENEBO: If we use a MT optimization mechanism we cannot mutate CFG
         // while another thread is using it.  This may need to happen on a clone()
         // and we may need to update the method to return the new method.  Also,
         // if this scope is held in multiple locations how do we update all references?
         for (CompilerPass passgetManager().getCompilerPasses(this)) {
             pass.run(this);
         }
     }

    
Run any necessary passes to get the IR ready for interpretation
 
     public synchronized Instr[] prepareForInterpretation() {
         checkRelinearization();
 
         if ( != nullreturn ;
 
         // Build CFG and run compiler passes, if necessary
         if (getCFG() == nullrunCompilerPasses();
 
         // Linearize CFG, etc.
         return prepareInstructionsForInterpretation();
     }
 
     /* SSS FIXME: Do we need to synchronize on this?  Cache this info in a scope field? */
    
Run any necessary passes to get the IR ready for compilation
 
     public Tuple<Instr[], Map<Integer,Label[]>> prepareForCompilation() {
         // Build CFG and run compiler passes, if necessary
         if (getCFG() == nullrunCompilerPasses();
 
         try {
             buildLinearization(); // FIXME: compiler passes should have done this
             depends(linearization());
         } catch (RuntimeException e) {
             .error("Error linearizing cfg: "e);
             CFG c = cfg();
             .error("\nGraph:\n" + c.toStringGraph());
             .error("\nInstructions:\n" + c.toStringInstrs());
             throw e;
         }
 
         // Set up IPCs
         // FIXME: Would be nice to collapse duplicate labels; for now, using Label[]
         HashMap<IntegerLabel[]> ipcLabelMap = new HashMap<IntegerLabel[]>();
         HashMap<LabelInteger>   labelIPCMap = new HashMap<LabelInteger>();
         List<InstrnewInstrs = new ArrayList<Instr>();
         int ipc = 0;
         for (BasicBlock b : ) {
             Label l = b.getLabel();
             labelIPCMap.put(lipc);
             ipcLabelMap.put(ipccatLabels(ipcLabelMap.get(ipc), l));
             for (Instr i : b.getInstrs()) {
                 if (!(i instanceof ReceiveSelfInstr)) {
                     newInstrs.add(i);
                     ipc++;
                 }
             }
         }
 
         // Set up label PCs
         setupLabelPCs(labelIPCMap);
 
         return new Tuple<Instr[], Map<Integer,Label[]>>(newInstrs.toArray(new Instr[newInstrs.size()]), ipcLabelMap);
     }
 
     private List<Object[]> buildJVMExceptionTable() {
         List<Object[]> etEntries = new ArrayList<Object[]>();
         for (BasicBlock b) {
             // We need handlers for:
             // - RaiseException (Ruby exceptions -- handled by rescues),
             // - Unrescuable    (JRuby exceptions -- handled by ensures),
             // - Throwable      (JRuby/Java exceptions -- handled by rescues)
             // in that order since Throwable < Unrescuable and Throwable < RaiseException
             BasicBlock rBB = cfg().getRescuerBBFor(b);
             BasicBlock eBB = cfg().getEnsurerBBFor(b);
             if ((eBB != null) && (rBB == eBB || rBB == null)) {
                 // 1. same rescue and ensure handler ==> just spit out one entry with a Throwable class
                 // 2. only ensure handler            ==> just spit out one entry with a Throwable class
                 //
                 // The rescue handler knows whether to unwrap or not.  But for now, the rescue handler
                 // has to process its recv_exception instruction as
                 //    e = (e instanceof RaiseException) ? unwrap(e) : e;
 
                 int start = b.getLabel().getTargetPC();
                 int end   = start + b.instrCount();
                 etEntries.add(new Object[] {startendeBB.getLabel().getTargetPC(), Throwable.class});
             } else if (rBB != null) {
                 int start = b.getLabel().getTargetPC();
                 int end   = start + b.instrCount();
                 // Unrescuable comes before Throwable
                 if (eBB != nulletEntries.add(new Object[] {startendeBB.getLabel().getTargetPC(), Unrescuable.class});
                 etEntries.add(new Object[] {startendrBB.getLabel().getTargetPC(), Throwable.class});
             }
         }
 
         // SSS FIXME: This could be optimized by compressing entries for adjacent BBs that have identical handlers
         // This could be optimized either during generation or as another pass over the table.  But, if the JVM
         // does that already, do we need to bother with it?
         return etEntries;
     }
     
     private static Label[] catLabels(Label[] labelsLabel cat) {
         if (labels == nullreturn new Label[] {cat};
         Label[] newLabels = new Label[labels.length + 1];
         System.arraycopy(labels, 0, newLabels, 0, labels.length);
         newLabels[labels.length] = cat;
         return newLabels;
     }
 
     private boolean computeScopeFlags(boolean receivesClosureArgList<Instrinstrs) {
         for (Instr iinstrs) {
             Operation op = i.getOperation();
             if (op == .) {
                 receivesClosureArg = true;
             } else if (op == .) {
                  = true;
                  = true;
             } else if (i instanceof CallBase) {
                 CallBase call = (CallBasei;
 
                 if (call.targetRequiresCallersBinding())  = true;
 
                 Operand o = ((CallBasei).getClosureArg(null);
                 if (o != null) {
                     if (o instanceof WrappedIRClosure) {
                         IRClosure cl = ((WrappedIRClosure)o).getClosure();
                         cl.computeScopeFlags();
                         if (cl.usesZSuper())  = true;
                     }
                     // If the closure comes from a variable, then the zsuper invocation in the
                     // block corresponds to the scope in which it is defined. 
                 }
 
                 if (call.canBeEval()) {
                      = true;
 
                     // If this method receives a closure arg, and this call is an eval that has more than 1 argument,
                     // it could be using the closure as a binding -- which means it could be using pretty much any
                     // variable from the caller's binding!
                     if (receivesClosureArg && (call.getCallArgs().length > 1)) {
                          = true;
                     }
                 }
             } else if (op == .) {
                 GlobalVariable gv = (GlobalVariable)((GetGlobalVariableInstr)i).getSource();
                 String gvName = gv.getName();
                 if (gvName.equals("$_") || 
                     gvName.equals("$~") ||
                     gvName.equals("$`") ||
                     gvName.equals("$'") ||
                     gvName.equals("$+") ||
                     gvName.equals("$LAST_READ_LINE") ||
                     gvName.equals("$LAST_MATCH_INFO") ||
                     gvName.equals("$PREMATCH") ||
                     gvName.equals("$POSTMATCH") ||
                     gvName.equals("$LAST_PAREN_MATCH")) {
                      = true;
                 }
             } else if (op == .) {
                 GlobalVariable gv = (GlobalVariable)((PutGlobalVarInstr)i).getTarget();
                 String gvName = gv.getName();
                 if (gvName.equals("$_") || gvName.equals("$~"))  = true;
             } else if (op == . || op == . || op == .) {
                  = true;
             }
         }
 
         return receivesClosureArg;
     }
 
     // SSS FIXME: This method does nothing a whole lot useful right now.
     // hasEscapedBinding is the crucial flag and it continues to be unconditionally true.
     //
     // This can help use eliminate writes to %block that are not used since this is
     // a special local-variable, not programmer-defined local-variable
     public void computeScopeFlags() {
         // init
          = true;
          = false;
          = false;
          = false;
          = false;
          = (this instanceof IREvalScript); // for eval scopes, bindings are considered escaped ...
 
         // recompute flags -- we could be calling this method different times
         // definitely once after ir generation and local optimizations propagates constants locally
         // but potentially at a later time after doing ssa generation and constant propagation
         if ( == null) {
             computeScopeFlags(falsegetInstrs());
         } else {
             boolean receivesClosureArg = false;
             for (BasicBlock b.getBasicBlocks()) {
                 receivesClosureArg = computeScopeFlags(receivesClosureArgb.getInstrs());
             }
         }
     }
 
     public abstract String getScopeName();
 
     @Override
     public String toString() {
         return getScopeName() + " " + getName() + "[" + getFileName() + ":" + getLineNumber() + "]";
     }    
 
     public String toStringInstrs() {
         StringBuilder b = new StringBuilder();
 
         int i = 0;
         for (Instr instr : ) {
             if (i > 0) b.append("\n");
             
             b.append("  ").append(i).append('\t').append(instr);
             
             i++;
         }
 
         if (!.isEmpty()) {
             b.append("\n\n------ Closures encountered in this scope ------\n");
             for (IRClosure c)
                 b.append(c.toStringBody());
             b.append("------------------------------------------------\n");
         }
 
         return b.toString();
     }
     
     public String toPersistableString() {
         StringBuilder b = new StringBuilder();
 
         b.append("Scope:<");
         b.append();
         b.append(">");
         for (Instr instr : ) {
             b.append("\n");
             b.append(instr);
         }
         
         return b.toString();
     }
 
     public String toStringVariables() {
         Map<VariableIntegerends = new HashMap<VariableInteger>();
         Map<VariableIntegerstarts = new HashMap<VariableInteger>();
         SortedSet<Variablevariables = new TreeSet<Variable>();
         
         for (int i = .size() - 1; i >= 0; i--) {
             Instr instr = .get(i);
 
             if (instr instanceof ResultInstr) {
                 Variable var = ((ResultInstrinstr).getResult();
                 variables.add(var);
                 starts.put(vari);
             }
 
             for (Operand operand : instr.getOperands()) {
                 if (operand != null && operand instanceof Variable && ends.get((Variable)operand) == null) {
                     ends.put((Variable)operandi);
                     variables.add((Variable)operand);
                 }
             }
         }
 
         StringBuilder sb = new StringBuilder();
         int i = 0;
         for (Variable var : variables) {
             Integer end = ends.get(var);
             if (end != null) { // Variable is actually used somewhere and not dead
                 if (i > 0) sb.append("\n");
                 i++;
                 sb.append("    ").append(var).append(": ").append(starts.get(var)).append("-").append(end);
             }
         }
 
         return sb.toString();
     }

    
--------------------------------------- SSS FIXME: What is this method for?

Interp:
public void calculateParameterCounts() { for (int i = instrList.size() - 1; i >= 0; i--) { Instr instr = instrList.get(i); } } ------------------------------------------
 
 
     public LocalVariable getSelf() {
         return .;
     }
 
     public Variable getCurrentModuleVariable() {
         // SSS: Used in only 3 cases in generated IR:
         // -> searching a constant in the inheritance hierarchy
         // -> searching a super-method in the inheritance hierarchy
         // -> looking up 'StandardError' (which can be eliminated by creating a special operand type for this)
         return ;
     }
 
     public Variable getCurrentScopeVariable() {
         // SSS: Used in only 1 case in generated IR:
         // -> searching a constant in the lexical scope hierarchy
         return ;
     }
 
     public abstract LocalVariable getImplicitBlockArg();
 
     public void markUnusedImplicitBlockArg() {
          = true;
     }
 
     public LocalVariable findExistingLocalVariable(String nameint depth) {
         return .getVariable(name);
     }

    
Find or create a local variable. By default, scopes are assumed to only check current depth. Blocks/Closures override this because they have special nesting rules.
 
     public LocalVariable getLocalVariable(String nameint scopeDepth) {
         LocalVariable lvar = findExistingLocalVariable(namescopeDepth);
         if (lvar == null) {
             lvar = new LocalVariable(namescopeDepth.);
             .putVariable(namelvar);
         }
 
         return lvar;
     }
 
     public LocalVariable getNewLocalVariable(String nameint depth) {
         throw new RuntimeException("getNewLocalVariable should be called for: " + this.getClass().getName());
     }
 
     protected void initEvalScopeVariableAllocator(boolean reset) {
         if (reset ||  == null = new LocalVariableAllocator();
     }
     
         ++;
         return new TemporaryVariable();
     }    
 
         ++;
         return new TemporaryVariable(name);
     }    
 
     public void resetTemporaryVariables() {
          = -1;
     }
     
     public int getTemporaryVariableSize() {
         return  + 1;
     }
     
     // Generate a new variable for inlined code
     public Variable getNewInlineVariable(String inlinePrefixVariable v) {
         if (v instanceof LocalVariable) {
             LocalVariable lv = (LocalVariable)v;
             return getLocalVariable(inlinePrefix + lv.getName(), lv.getScopeDepth());
         } else {
             return getNewTemporaryVariable();
         }
     }
 
     public int getThreadPollInstrsCount() {
         return ;
     }
     
     public int getLocalVariablesCount() {
         return .;
     }
 
     public int getUsedVariablesCount() {
         // System.out.println("For " + this + ", # lvs: " + nextLocalVariableSlot);
         // # local vars, # flip vars
         //
         // SSS FIXME: When we are opting local var access, 
         // no need to allocate local var space except when we have been asked to!
         return getLocalVariablesCount() + getPrefixCountSize("%flip");
     }
 
     public void setUpUseDefLocalVarMaps() {
          = new java.util.HashSet<Variable>();
          = new java.util.HashSet<Variable>();
         for (BasicBlock bb : cfg().getBasicBlocks()) {
             for (Instr i : bb.getInstrs()) {
                 for (Variable v : i.getUsedVariables()) {
                     if (v instanceof LocalVariable.add(v);
                 }
                 
                 if (i instanceof ResultInstr) {
                     Variable v = ((ResultInstri).getResult();
                     
                     if (v instanceof LocalVariable.add(v);
                 }
             }
         }
 
         for (IRClosure cl : getClosures()) {
             cl.setUpUseDefLocalVarMaps();
         }
     }
 
     public boolean usesLocalVariable(Variable v) {
         if ( == nullsetUpUseDefLocalVarMaps();
         if (.contains(v)) return true;
 
         for (IRClosure cl : getClosures()) {
             if (cl.usesLocalVariable(v)) return true;
        }
        return false;
    }
    public boolean definesLocalVariable(Variable v) {
        if ( == nullsetUpUseDefLocalVarMaps();
        if (.contains(v)) return true;
        for (IRClosure cl : getClosures()) {
            if (cl.definesLocalVariable(v)) return true;
        }
        return false;
    }    
    
    public void setDataFlowSolution(String nameDataFlowProblem p) {
        .put(namep);
    }
        return .get(name);
    }
    
    // This should only be used to do pre-cfg opts and to build the CFG.
    // Everyone else should use the CFG.
    public List<InstrgetInstrs() {
        if ( != nullthrow new RuntimeException("Please use the CFG to access this scope's instructions.");
        return ;
    }
    public Instr[] getInstrsForInterpretation() {
        return ;
    }
    
    public void resetLinearizationData() {
         = null;
         = false;        
    }
    
    public void checkRelinearization() {
        if (resetLinearizationData();
    }
    
    public List<BasicBlockbuildLinearization() {
        checkRelinearization();
        if ( != nullreturn // Already linearized
        
         = CFGLinearizer.linearize();
        
        return ;
    }
    
    // SSS FIXME: Extremely inefficient
    public int getRescuerPC(Instr excInstr) {
        depends(cfg());
        
        for (BasicBlock b : ) {
            for (Instr i : b.getInstrs()) {
                if (i == excInstr) {
                    BasicBlock rescuerBB = cfg().getRescuerBBFor(b);
                    return (rescuerBB == null) ? -1 : rescuerBB.getLabel().getTargetPC();
                }
            }
        }
        // SSS FIXME: Cannot happen! Throw runtime exception
        .error("Fell through looking for rescuer ipc for " + excInstr);
        return -1;
    }
    // SSS FIXME: Extremely inefficient
    public int getEnsurerPC(Instr excInstr) {
        depends(cfg());
        
        for (BasicBlock b : ) {
            for (Instr i : b.getInstrs()) {
                if (i == excInstr) {
                    BasicBlock ensurerBB = .getEnsurerBBFor(b);
                    return (ensurerBB == null) ? -1 : ensurerBB.getLabel().getTargetPC();
                }
            }
        }
        // SSS FIXME: Cannot happen! Throw runtime exception
        .error("Fell through looking for ensurer ipc for " + excInstr);
        return -1;
    }
    
    public List<BasicBlocklinearization() {
        depends(cfg());
        
        assert  != null"You have not run linearization";
        
        return ;
    }
    
    protected void depends(Object obj) {
        assert obj != null"Unsatisfied dependency and this depends() was set " +
                "up wrong.  Use depends(build()) not depends(build).";
    }
    
    public CFG cfg() {
        assert  != null"Trying to access build before build started";
        return ;
    }     
    public void splitCalls() {
        // FIXME: (Enebo) We are going to make a SplitCallInstr so this logic can be separate
        // from unsplit calls.  Comment out until new SplitCall is created.
//        for (BasicBlock b: getNodes()) {
//            List<Instr> bInstrs = b.getInstrs();
//            for (ListIterator<Instr> it = ((ArrayList<Instr>)b.getInstrs()).listIterator(); it.hasNext(); ) {
//                Instr i = it.next();
//                // Only user calls, not Ruby & JRuby internal calls
//                if (i.operation == Operation.CALL) {
//                    CallInstr call = (CallInstr)i;
//                    Operand   r    = call.getReceiver();
//                    Operand   m    = call.getMethodAddr();
//                    Variable  mh   = _scope.getNewTemporaryVariable();
//                    MethodLookupInstr mli = new MethodLookupInstr(mh, m, r);
//                    // insert method lookup at the right place
//                    it.previous();
//                    it.add(mli);
//                    it.next();
//                    // update call address
//                    call.setMethodAddr(mh);
//                }
//            }
//        }
//        List<IRClosure> nestedClosures = _scope.getClosures();
//        if (!nestedClosures.isEmpty()) {
//            for (IRClosure c : nestedClosures) {
//                c.getCFG().splitCalls();
//            }
//