示例#1
0
  public static IRubyObject INTERPRET_METHOD(
      ThreadContext context,
      InterpretedIRMethod irMethod,
      IRubyObject self,
      String name,
      IRubyObject[] args,
      Block block,
      Block.Type blockType,
      boolean isTraceable) {
    Ruby runtime = context.runtime;
    IRScope scope = irMethod.getIRMethod();
    RubyModule implClass = irMethod.getImplementationClass();
    Visibility viz = irMethod.getVisibility();
    boolean syntheticMethod = name == null || name.equals("");

    try {
      if (!syntheticMethod)
        ThreadContext.pushBacktrace(context, name, scope.getFileName(), context.getLine());
      if (isTraceable) methodPreTrace(runtime, context, name, implClass);
      return interpret(context, self, scope, viz, implClass, args, block, blockType);
    } finally {
      if (isTraceable) {
        try {
          methodPostTrace(runtime, context, name, implClass);
        } finally {
          if (!syntheticMethod) ThreadContext.popBacktrace(context);
        }
      } else {
        if (!syntheticMethod) ThreadContext.popBacktrace(context);
      }
    }
  }
示例#2
0
  @Override
  public boolean computeScopeFlags(IRScope scope) {
    boolean modifiedScope = false;

    if (targetRequiresCallersBinding()) {
      modifiedScope = true;
      scope.getFlags().add(BINDING_HAS_ESCAPED);
    }

    if (targetRequiresCallersFrame()) {
      modifiedScope = true;
      scope.getFlags().add(REQUIRES_FRAME);
    }

    if (canBeEval()) {
      modifiedScope = true;
      scope.getFlags().add(USES_EVAL);

      // 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 (scope.getFlags().contains(RECEIVES_CLOSURE_ARG) && (getCallArgs().length > 1)) {
        scope.getFlags().add(CAN_CAPTURE_CALLERS_BINDING);
      }
    }

    return modifiedScope;
  }
示例#3
0
  public boolean isNestedInClosure(IRClosure closure) {
    for (IRScope s = this; s != null && !s.isTopLocalVariableScope(); s = s.getLexicalParent()) {
      if (s == closure) return true;
    }

    return false;
  }
示例#4
0
  /** Returns the top level scope */
  public IRScope getTopLevelScope() {
    IRScope current = this;

    for (; current != null && !current.isScriptScope(); current = current.getLexicalParent()) {}

    return current;
  }
示例#5
0
  public IRScope getNearestTopLocalVariableScope() {
    IRScope current = this;

    while (current != null && !current.isTopLocalVariableScope()) {
      current = current.getLexicalParent();
    }

    return current;
  }
示例#6
0
  public IRMethod getNearestMethod() {
    IRScope current = this;

    while (current != null && !(current instanceof IRMethod)) {
      current = current.getLexicalParent();
    }

    return (IRMethod) current;
  }
 public void applyPreMeetHandler() {
   IRScope s = problem.getScope();
   if (s instanceof IRClosure && basicBlock == s.getCFG().getEntryBB()) {
     // If it is not null, it has already been initialized
     if (inState == null) {
       inState = new UnboxState();
     }
   } else {
     inState = new UnboxState();
   }
 }
示例#8
0
 protected void doDebug() {
   // FIXME: This is printing out IRScope CFG but JIT may be active and it might not reflect
   // currently executing.  Move into JIT and into interp since they will be getting CFG from
   // different sources
   // FIXME: This is only printing out CFG once.  If we keep applying more passes then we
   // will want to print out after those new passes.
   ensureInstrsReady();
   LOG.info("Executing '" + method.getName() + "'");
   if (!displayedCFG) {
     LOG.info(method.debugOutput());
     displayedCFG = true;
   }
 }
示例#9
0
  /**
   * 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.
   */
  public IRScope getNearestModuleReferencingScope() {
    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 IREvalScript) return null;

      current = current.getLexicalParent();
    }

    return current;
  }
  private boolean doesItRequireFrame(IRScope scope, boolean bindingHasEscaped) {
    boolean requireFrame = bindingHasEscaped || scope.usesEval();

    for (IRFlags flag : scope.getFlags()) {
      switch (flag) {
        case BINDING_HAS_ESCAPED:
        case CAN_CAPTURE_CALLERS_BINDING:
        case REQUIRES_FRAME:
        case REQUIRES_VISIBILITY:
        case USES_BACKREF_OR_LASTLINE:
        case USES_EVAL:
        case USES_ZSUPER:
          requireFrame = true;
      }
    }

    return requireFrame;
  }
 private TemporaryLocalVariable getLocalVarReplacement(
     LocalVariable v, IRScope scope, Map<Operand, Operand> varRenameMap) {
   TemporaryLocalVariable value = (TemporaryLocalVariable) varRenameMap.get(v);
   if (value == null) {
     value = scope.getNewTemporaryVariableFor(v);
     varRenameMap.put(v, value);
   }
   return value;
 }
示例#12
0
  public IREvalScript(
      IRManager manager,
      IRScope lexicalParent,
      String fileName,
      int lineNumber,
      StaticScope staticScope) {
    super(manager, lexicalParent, fileName, lineNumber, staticScope, "EVAL_");

    int n = 0;
    IRScope s = lexicalParent;
    while (s instanceof IREvalScript) {
      n++;
      s = s.getLexicalParent();
    }

    this.nearestNonEvalScope = s;
    this.nearestNonEvalScopeDepth = n;
    this.nearestNonEvalScope.initEvalScopeVariableAllocator(false);
  }
示例#13
0
 @Override
 public LocalVariable findExistingLocalVariable(String name, int scopeDepth) {
   // Look in the nearest non-eval scope's shared eval scope vars first.
   // If you dont find anything there, look in the nearest non-eval scope's regular vars.
   LocalVariable lvar = lookupExistingLVar(name);
   if (lvar != null || scopeDepth == 0) return lvar;
   else
     return nearestNonEvalScope.findExistingLocalVariable(
         name, scopeDepth - nearestNonEvalScopeDepth - 1);
 }
示例#14
0
  public MixedModeIRMethod(IRScope method, Visibility visibility, RubyModule implementationClass) {
    super(implementationClass, visibility, CallConfiguration.FrameNoneScopeNone, method.getName());
    this.method = method;
    getStaticScope().determineModule();
    this.signature = getStaticScope().getSignature();

    // disable JIT if JIT is disabled
    if (!implementationClass.getRuntime().getInstanceConfig().getCompileMode().shouldJIT()) {
      this.box.callCount = -1;
    }
  }
  public void addDFVar(Variable v) {
    Integer dfv = addDataFlowVar();
    dfVarMap.put(v, dfv);
    varDfVarMap.put(dfv, v);

    if (v instanceof LocalVariable && !v.isSelf()) {
      // System.out.println("Adding df var for " + v + ":" + dfv.id);
      IRScope s = getScope();
      for (int n = ((LocalVariable) v).getScopeDepth(); s != null && n >= 0; n--) {
        if (s instanceof IREvalScript) {
          // If a variable is at the topmost scope of the eval OR crosses an eval boundary,
          // it is going to be marked always live since it could be used by other evals (n = 0)
          // or by enclosing scopes (n > 0)
          alwaysLiveVars.add((LocalVariable) v);
          break;
        }

        s = s.getLexicalParent();
      }
      localVars.add((LocalVariable) v);
    }
  }
示例#16
0
 public static IRubyObject INTERPRET_BLOCK(
     ThreadContext context,
     IRubyObject self,
     IRScope scope,
     IRubyObject[] args,
     String name,
     Block block,
     Block.Type blockType) {
   try {
     ThreadContext.pushBacktrace(context, name, scope.getFileName(), context.getLine());
     return interpret(context, self, scope, null, null, args, block, blockType);
   } finally {
     ThreadContext.popBacktrace(context);
   }
 }
  @Override
  public Object execute(IRScope s, Object... data) {
    StoreLocalVarPlacementProblem slvp = new StoreLocalVarPlacementProblem();

    // Only run if we are pushing a scope or we are reusing the parents scope.
    if (!s.getFlags().contains(IRFlags.DYNSCOPE_ELIMINATED)
        || s.getFlags().contains(IRFlags.REUSE_PARENT_DYNSCOPE)) {
      // Make sure flags are computed
      s.computeScopeFlags();

      Map<Operand, Operand> varRenameMap = new HashMap<Operand, Operand>();
      // 1. Figure out required stores
      // 2. Add stores
      // 3. Figure out required loads
      // 4. Add loads
      //
      // Order is important since loads in 3. depend on stores in 2.
      slvp.setup(s);
      slvp.compute_MOP_Solution();

      // Add stores, assigning an equivalent tmp-var for each local var
      slvp.addStores(varRenameMap);

      // Once stores have been added, figure out required loads
      LoadLocalVarPlacementProblem llvp = new LoadLocalVarPlacementProblem();
      llvp.setup(s);
      llvp.compute_MOP_Solution();

      // Add loads
      llvp.addLoads(varRenameMap);

      // Rename all local var uses with their tmp-var stand-ins
      for (BasicBlock b : s.getCFG().getBasicBlocks()) {
        for (Instr i : b.getInstrs()) i.renameVars(varRenameMap);
      }

      // Run on all nested closures.
      //
      // In the current implementation, nested scopes are processed independently (unlike Live
      // Variable Analysis)
      for (IRClosure c : s.getClosures()) run(c, false, true);

      // LVA information is no longer valid after this pass
      // FIXME: Grrr ... this seems broken to have to create a new object to invalidate
      (new LiveVariableAnalysis()).invalidate(s);
    }

    s.setDataFlowSolution(StoreLocalVarPlacementProblem.NAME, slvp);

    return slvp;
  }
  @Override
  public void applyTransferFunction(Instr i) {
    IRScope scope = problem.getScope();
    boolean scopeBindingHasEscaped = scope.bindingHasEscaped();

    // Right away, clear the variable defined by this instruction -- it doesn't have to be loaded!
    if (i instanceof ResultInstr) {
      reqdLoads.remove(((ResultInstr) i).getResult());
    }

    // Process closure accepting instrs specially -- these are the sites of binding loads!
    if (i instanceof ClosureAcceptingInstr) {
      Operand o = ((ClosureAcceptingInstr) i).getClosureArg();
      if (o != null && o instanceof WrappedIRClosure) {
        IRClosure cl = ((WrappedIRClosure) o).getClosure();

        // Variables defined in the closure do not need to be loaded anymore at
        // program points before the call, because they will be loaded after the
        // call completes to fetch the latest value.
        //
        // Allocate a new hash-set and modify it to get around ConcurrentModificationException on
        // reqdLoads
        Set<LocalVariable> newReqdLoads = new HashSet<LocalVariable>(reqdLoads);
        for (LocalVariable v : reqdLoads) {
          if (cl.definesLocalVariable(v)) newReqdLoads.remove(v);
        }
        reqdLoads = newReqdLoads;
      }

      // In this case, we are going to blindly load everything -- so, at the call site, pending
      // loads dont carry over!
      if (scopeBindingHasEscaped) {
        reqdLoads.clear();
      } else {
        // All variables not defined in the current scope have to be always loaded
        // because of multi-threading scenarios where some other scope
        // could update this variable concurrently.
        //
        // Allocate a new hash-set and modify it to get around ConcurrentModificationException on
        // reqdLoads
        Set<LocalVariable> newReqdLoads = new HashSet<LocalVariable>(reqdLoads);
        for (LocalVariable v : reqdLoads) {
          if (!scope.definesLocalVariable(v)) newReqdLoads.remove(v);
        }
        reqdLoads = newReqdLoads;
      }
    } else if (scopeBindingHasEscaped && (i.getOperation() == Operation.PUT_GLOBAL_VAR)) {
      // global-var tracing can execute closures set up in previous trace-var calls
      // in which case we would have the 'scopeBindingHasEscaped' flag set to true
      reqdLoads.clear();
    }

    if (i.getOperation() == Operation.BINDING_STORE) {
      LocalVariable lv = ((StoreLocalVarInstr) i).getLocalVar();
      if (!lv.isSelf()) reqdLoads.add(lv);
    } else {
      // The variables used as arguments will need to be loaded
      // %self is local to every scope and never crosses scope boundaries and need not be
      // spilled/refilled
      for (Variable x : i.getUsedVariables()) {
        if (x instanceof LocalVariable && !x.isSelf()) {
          reqdLoads.add((LocalVariable) x);
        }
      }
    }
  }
  public void addLoads(Map<Operand, Operand> varRenameMap) {
    IRScope scope = problem.getScope();
    boolean isEvalScript = scope instanceof IREvalScript;
    boolean scopeBindingHasEscaped = scope.bindingHasEscaped();

    List<Instr> instrs = basicBlock.getInstrs();
    ListIterator<Instr> it = instrs.listIterator(instrs.size());

    initSolution();
    while (it.hasPrevious()) {
      Instr i = it.previous();

      // Right away, clear the variable defined by this instruction -- it doesn't have to be loaded!
      if (i instanceof ResultInstr) reqdLoads.remove(((ResultInstr) i).getResult());

      // Process closure accepting instrs specially -- these are the sites of binding loads!
      if (i instanceof ClosureAcceptingInstr) {
        Operand o = ((ClosureAcceptingInstr) i).getClosureArg();
        if (o != null && o instanceof WrappedIRClosure) {
          IRClosure cl = ((WrappedIRClosure) o).getClosure();

          // Only those variables that are defined in the closure, and are in the required loads set
          // will need to be loaded from the binding after the call!  Rest can wait ..
          //
          // Allocate a new hash-set and modify it to get around ConcurrentModificationException on
          // reqdLoads
          Set<LocalVariable> newReqdLoads = new HashSet<LocalVariable>(reqdLoads);
          it.next();
          for (LocalVariable v : reqdLoads) {
            if (cl.definesLocalVariable(v)) {
              it.add(
                  new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
              it.previous();
              newReqdLoads.remove(v);
            }
          }
          it.previous();
          reqdLoads = newReqdLoads;
        }

        // In this case, we are going to blindly load everything
        if (scopeBindingHasEscaped) {
          it.next();
          for (LocalVariable v : reqdLoads) {
            it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
            it.previous();
          }
          it.previous();
          reqdLoads.clear();
        } else {
          // All variables not defined in the current scope have to be always loaded
          // because of multi-threading scenarios where some other scope
          // could update this variable concurrently.
          //
          // Allocate a new hash-set and modify it to get around ConcurrentModificationException on
          // reqdLoads
          Set<LocalVariable> newReqdLoads = new HashSet<LocalVariable>(reqdLoads);
          it.next();
          for (LocalVariable v : reqdLoads) {
            if (!scope.definesLocalVariable(v)) {
              it.add(
                  new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
              it.previous();
              newReqdLoads.remove(v);
            }
          }
          it.previous();
          reqdLoads = newReqdLoads;
        }
      } else if (scopeBindingHasEscaped && (i.getOperation() == Operation.PUT_GLOBAL_VAR)) {
        // global-var tracing can execute closures set up in previous trace-var calls
        // in which case we would have the 'scopeBindingHasEscaped' flag set to true
        it.next();
        for (LocalVariable v : reqdLoads) {
          it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
          it.previous();
        }
        it.previous();
        reqdLoads.clear();
      }

      if (i.getOperation() == Operation.BINDING_STORE) {
        LocalVariable lv = ((StoreLocalVarInstr) i).getLocalVar();
        if (!lv.isSelf()) {
          reqdLoads.add(lv);
          // SSS FIXME: Why is this reqd again?  Document with example
          // Make sure there is a replacement var for all local vars
          getLocalVarReplacement(lv, scope, varRenameMap);
        }
      } else {
        // The variables used as arguments will need to be loaded
        // %self is local to every scope and never crosses scope boundaries and need not be
        // spilled/refilled
        for (Variable v : i.getUsedVariables()) {
          if (!(v instanceof LocalVariable)) continue;

          LocalVariable lv = (LocalVariable) v;
          if (!lv.isSelf()) {
            reqdLoads.add(lv);
            // SSS FIXME: Why is this reqd again?  Document with example
            // Make sure there is a replacement var for all local vars
            getLocalVarReplacement(lv, scope, varRenameMap);
          }
        }
      }
    }

    // Add loads on entry of a rescue block.
    if (basicBlock.isRescueEntry()) {
      for (LocalVariable v : reqdLoads) {
        it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
      }
    }

    // Load first use of variables in closures
    if (scope instanceof IRClosure && basicBlock.isEntryBB()) {
      // System.out.println("\n[In Entry BB] For CFG " + getCFG() + ":");
      // System.out.println("\t--> Reqd loads   : " +
      // java.util.Arrays.toString(reqdLoads.toArray()));
      for (LocalVariable v : reqdLoads) {
        if (scope.usesLocalVariable(v) || scope.definesLocalVariable(v)) {
          if (isEvalScript
              || !(v instanceof ClosureLocalVariable)
              || (scope != ((ClosureLocalVariable) v).definingScope)) {
            it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
          }
        }
      }
    }
  }
示例#20
0
  private static IRubyObject interpret(
      ThreadContext context,
      IRubyObject self,
      IRScope scope,
      Visibility visibility,
      RubyModule implClass,
      IRubyObject[] args,
      Block block,
      Block.Type blockType) {
    Instr[] instrs = scope.getInstrsForInterpretation();

    // The base IR may not have been processed yet
    if (instrs == null) instrs = scope.prepareForInterpretation(blockType == Block.Type.LAMBDA);

    int numTempVars = scope.getTemporaryVariableSize();
    Object[] temp = numTempVars > 0 ? new Object[numTempVars] : null;
    int n = instrs.length;
    int ipc = 0;
    Instr instr = null;
    Object exception = null;
    int kwArgHashCount =
        (scope.receivesKeywordArgs() && args[args.length - 1] instanceof RubyHash) ? 1 : 0;
    DynamicScope currDynScope = context.getCurrentScope();

    // Counter tpCount = null;

    // Init profiling this scope
    boolean debug = IRRuntimeHelpers.isDebug();
    boolean profile = IRRuntimeHelpers.inProfileMode();
    Integer scopeVersion = profile ? initProfiling(scope) : 0;

    // Enter the looooop!
    while (ipc < n) {
      instr = instrs[ipc];
      ipc++;
      Operation operation = instr.getOperation();
      if (debug) {
        LOG.info("I: {}", instr);
        interpInstrsCount++;
      } else if (profile) {
        if (operation.modifiesCode()) codeModificationsCount++;
        interpInstrsCount++;
        /*
        Counter cnt = opStats.get(operation);
        if (cnt == null) {
            cnt = new Counter();
            opStats.put(operation, cnt);
        }
        cnt.count++;
        */
      }

      try {
        switch (operation.opClass) {
          case ARG_OP:
            {
              receiveArg(
                  context,
                  instr,
                  operation,
                  args,
                  kwArgHashCount,
                  currDynScope,
                  temp,
                  exception,
                  block);
              break;
            }
          case BRANCH_OP:
            {
              if (operation == Operation.JUMP) {
                ipc = ((JumpInstr) instr).getJumpTarget().getTargetPC();
              } else {
                ipc = instr.interpretAndGetNewIPC(context, currDynScope, self, temp, ipc);
              }
              break;
            }
          case CALL_OP:
            {
              if (profile) updateCallSite(instr, scope, scopeVersion);
              processCall(
                  context, instr, operation, scope, currDynScope, temp, self, block, blockType);
              break;
            }
          case BOOK_KEEPING_OP:
            {
              switch (operation) {
                case PUSH_FRAME:
                  {
                    context.preMethodFrameAndClass(
                        implClass, scope.getName(), self, block, scope.getStaticScope());
                    context.setCurrentVisibility(visibility);
                    break;
                  }
                case PUSH_BINDING:
                  {
                    // SSS NOTE: Method scopes only!
                    //
                    // Blocks are a headache -- so, these instrs. are only added to IRMethods.
                    // Blocks have more complicated logic for pushing a dynamic scope (see
                    // InterpretedIRBlockBody)
                    // Changed by DPR
                    currDynScope =
                        DynamicScope.newDynamicScope(
                            scope.getStaticScope(), context.getCurrentScope().getDepth());
                    context.pushScope(currDynScope);
                    break;
                  }
                case CHECK_ARITY:
                  ((CheckArityInstr) instr).checkArity(context.runtime, args.length);
                  break;
                case POP_FRAME:
                  context.popFrame();
                  context.popRubyClass();
                  break;
                case POP_BINDING:
                  context.popScope();
                  break;
                case THREAD_POLL:
                  if (profile) {
                    // SSS: Not being used currently
                    // tpCount.count++;
                    globalThreadPollCount++;

                    // 20K is arbitrary
                    // Every 20K profile counts, spit out profile stats
                    if (globalThreadPollCount % 20000 == 0) {
                      analyzeProfile();
                      // outputProfileStats();
                    }
                  }
                  context.callThreadPoll();
                  break;
                case LINE_NUM:
                  context.setLine(((LineNumberInstr) instr).lineNumber);
                  break;
                case RECORD_END_BLOCK:
                  ((RecordEndBlockInstr) instr).interpret();
                  break;
              }
              break;
            }
          case OTHER_OP:
            {
              Object result = null;
              switch (operation) {
                  // --------- Return flavored instructions --------
                case BREAK:
                  {
                    BreakInstr bi = (BreakInstr) instr;
                    IRubyObject rv =
                        (IRubyObject)
                            bi.getReturnValue().retrieve(context, self, currDynScope, temp);
                    // This also handles breaks in lambdas -- by converting them to a return
                    return IRRuntimeHelpers.initiateBreak(
                        context, scope, bi.getScopeToReturnTo().getScopeId(), rv, blockType);
                  }
                case RETURN:
                  {
                    return (IRubyObject)
                        retrieveOp(
                            ((ReturnBase) instr).getReturnValue(),
                            context,
                            self,
                            currDynScope,
                            temp);
                  }
                case NONLOCAL_RETURN:
                  {
                    NonlocalReturnInstr ri = (NonlocalReturnInstr) instr;
                    IRubyObject rv =
                        (IRubyObject)
                            retrieveOp(ri.getReturnValue(), context, self, currDynScope, temp);
                    ipc = n;
                    // If not in a lambda, check if this was a non-local return
                    if (!IRRuntimeHelpers.inLambda(blockType)) {
                      IRRuntimeHelpers.initiateNonLocalReturn(
                          context, scope, ri.methodToReturnFrom, rv);
                    }
                    return rv;
                  }

                  // ---------- Common instruction ---------
                case COPY:
                  {
                    CopyInstr c = (CopyInstr) instr;
                    result = retrieveOp(c.getSource(), context, self, currDynScope, temp);
                    setResult(temp, currDynScope, c.getResult(), result);
                    break;
                  }

                case GET_FIELD:
                  {
                    GetFieldInstr gfi = (GetFieldInstr) instr;
                    IRubyObject object =
                        (IRubyObject) gfi.getSource().retrieve(context, self, currDynScope, temp);
                    VariableAccessor a = gfi.getAccessor(object);
                    result = a == null ? null : (IRubyObject) a.get(object);
                    if (result == null) {
                      result = context.nil;
                    }
                    setResult(temp, currDynScope, gfi.getResult(), result);
                    break;
                  }

                case SEARCH_CONST:
                  {
                    SearchConstInstr sci = (SearchConstInstr) instr;
                    result = sci.getCachedConst();
                    if (!sci.isCached(context, result))
                      result = sci.cache(context, currDynScope, self, temp);
                    setResult(temp, currDynScope, sci.getResult(), result);
                    break;
                  }

                  // ---------- All the rest ---------
                default:
                  result = instr.interpret(context, currDynScope, self, temp, block);
                  setResult(temp, currDynScope, instr, result);
                  break;
              }

              break;
            }
        }
      } catch (Throwable t) {
        // Unrescuable:
        //    IRReturnJump, ThreadKill, RubyContinuation, MainExitException, etc.
        //    These cannot be rescued -- only run ensure blocks
        //
        // Others:
        //    IRBreakJump, Ruby exceptions, errors, and other java exceptions.
        //    These can be rescued -- run rescue blocks

        if (debug)
          LOG.info(
              "in scope: "
                  + scope
                  + ", caught Java throwable: "
                  + t
                  + "; excepting instr: "
                  + instr);
        ipc = (t instanceof Unrescuable) ? scope.getEnsurerPC(instr) : scope.getRescuerPC(instr);
        if (debug) LOG.info("ipc for rescuer/ensurer: " + ipc);

        if (ipc == -1) {
          Helpers.throwException((Throwable) t);
        } else {
          exception = t;
        }
      }
    }

    // Control should never get here!
    // SSS FIXME: But looks like BEGIN/END blocks get here -- needs fixing
    return null;
  }
示例#21
0
 public StaticScope getStaticScope() {
   return method.getStaticScope();
 }
示例#22
0
 public int getLine() {
   return method.getLineNumber();
 }
示例#23
0
 public String getFile() {
   return method.getFileName();
 }
示例#24
0
  public Object execute(IRScope scope, Object... data) {
    scope.buildLinearization();

    return null;
  }
示例#25
0
 // FIXME: for subclasses we should override this method since it can be simple get
 // FIXME: to avoid cost of synch call in lazilyacquire we can save the ic here
 public InterpreterContext ensureInstrsReady() {
   if (method instanceof IRMethod) {
     return ((IRMethod) method).lazilyAcquireInterpreterContext();
   }
   return method.getInterpreterContext();
 }
 @Override
 public boolean invalidate(IRScope scope) {
   super.invalidate(scope);
   scope.setDataFlowSolution(StoreLocalVarPlacementProblem.NAME, null);
   return true;
 }
 @Override
 public Object previouslyRun(IRScope scope) {
   return scope.getDataFlowSolution(StoreLocalVarPlacementProblem.NAME);
 }
  public BeginEndInterpreterContext(IRScope scope, Instr[] instructions, boolean rebuild) {
    super(scope, instructions, rebuild);

    beginBlocks = scope.getBeginBlocks();
  }
示例#29
0
 @Override
 public boolean computeScopeFlags(IRScope scope) {
   scope.getFlags().add(IRFlags.RECEIVES_CLOSURE_ARG);
   return true;
 }
  @Override
  public Object execute(IRScope scope, Object... data) {
    // IRScriptBody do not get explicit call protocol instructions right now.
    // They dont push/pop a frame and do other special things like run begin/end blocks.
    // So, for now, they go through the runtime stub in IRScriptBody.
    //
    // 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 (explicitCallProtocolSupported(scope)) {
      StoreLocalVarPlacementProblem slvpp =
          (StoreLocalVarPlacementProblem)
              scope.getDataFlowSolution(StoreLocalVarPlacementProblem.NAME);
      boolean scopeHasLocalVarStores = false;
      boolean bindingHasEscaped = scope.bindingHasEscaped();

      CFG cfg = scope.cfg();

      if (slvpp != null && bindingHasEscaped) {
        scopeHasLocalVarStores = slvpp.scopeHasLocalVarStores();
      } 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 = bindingHasEscaped;
      }

      boolean requireFrame = doesItRequireFrame(scope, bindingHasEscaped);
      boolean requireBinding = !scope.getFlags().contains(IRFlags.DYNSCOPE_ELIMINATED);

      if (requireBinding || requireFrame) {
        BasicBlock entryBB = cfg.getEntryBB();
        // Push
        if (requireFrame) entryBB.addInstr(new PushFrameInstr(scope.getName()));
        if (requireBinding) entryBB.addInstr(new PushBindingInstr());

        // SSS FIXME: We are doing this conservatively.
        // Only scopes that have unrescued exceptions need a GEB.
        //
        // Allocate GEB if necessary for popping
        BasicBlock geb = cfg.getGlobalEnsureBB();
        if (geb == null) {
          Variable exc = scope.createTemporaryVariable();
          geb = new BasicBlock(cfg, Label.getGlobalEnsureBlockLabel());
          geb.addInstr(
              new ReceiveJRubyExceptionInstr(exc)); // JRuby Implementation exception handling
          geb.addInstr(new ThrowExceptionInstr(exc));
          cfg.addGlobalEnsureBB(geb);
        }

        // Pop on all scope-exit paths
        for (BasicBlock bb : cfg.getBasicBlocks()) {
          Instr i = null;
          ListIterator<Instr> instrs = bb.getInstrs().listIterator();
          while (instrs.hasNext()) {
            i = instrs.next();
            // Right now, we only support explicit call protocol on methods.
            // So, non-local returns and breaks don't get here.
            // Non-local-returns and breaks are tricky since they almost always
            // throw an exception and we don't multiple pops (once before the
            // return/break, and once when the exception is caught).
            if (!bb.isExitBB() && i instanceof ReturnBase) {
              // Add before the break/return
              instrs.previous();
              if (requireBinding) instrs.add(new PopBindingInstr());
              if (requireFrame) instrs.add(new PopFrameInstr());
              break;
            }
          }

          if (bb.isExitBB() && !bb.isEmpty()) {
            // Last instr could be a return -- so, move iterator one position back
            if (i != null && i instanceof ReturnBase) instrs.previous();
            if (requireBinding) instrs.add(new PopBindingInstr());
            if (requireFrame) instrs.add(new PopFrameInstr());
          }

          if (bb == geb) {
            // Add before throw-exception-instr which would be the last instr
            if (i != null) {
              // Assumption: Last instr should always be a control-transfer instruction
              assert i.getOperation().transfersControl()
                  : "Last instruction of GEB in scope: "
                      + scope
                      + " is "
                      + i
                      + ", not a control-xfer instruction";
              instrs.previous();
            }
            if (requireBinding) instrs.add(new PopBindingInstr());
            if (requireFrame) instrs.add(new PopFrameInstr());
          }
        }
      }

      // This scope has an explicit call protocol flag now
      scope.setExplicitCallProtocolFlag();
    }

    // FIXME: Useless for now
    // Run on all nested closures.
    for (IRClosure c : scope.getClosures()) run(c, false, true);

    // LVA information is no longer valid after the pass
    // FIXME: Grrr ... this seems broken to have to create a new object to invalidate
    (new LiveVariableAnalysis()).invalidate(scope);

    return null;
  }