Beispiel #1
0
  @Override
  public IRubyObject interpret(
      Ruby runtime, ThreadContext context, IRubyObject self, Block aBlock) {
    // Serialization killed our dynamic scope.  We can just create an empty one
    // since serialization cannot serialize an eval (which is the only thing
    // which is capable of having a non-empty dynamic scope).
    if (scope == null) {
      scope = DynamicScope.newDynamicScope(staticScope);
    }

    StaticScope theStaticScope = scope.getStaticScope();

    // Each root node has a top-level scope that we need to push
    context.preScopedBody(scope);

    if (theStaticScope.getModule() == null) {
      theStaticScope.setModule(runtime.getObject());
    }

    try {
      return bodyNode.interpret(runtime, context, self, aBlock);
    } finally {
      context.postScopedBody();
    }
  }
Beispiel #2
0
  /**
   * Evaluate the given string.
   *
   * @param context the current thread's context
   * @param self the self to evaluate under
   * @param src The string containing the text to be evaluated
   * @param file The filename to use when reporting errors during the evaluation
   * @param lineNumber that the eval supposedly starts from
   * @return An IRubyObject result from the evaluation
   */
  public static IRubyObject evalSimple(
      ThreadContext context, IRubyObject self, RubyString src, String file, int lineNumber) {
    // this is ensured by the callers
    assert file != null;

    Ruby runtime = src.getRuntime();

    // no binding, just eval in "current" frame (caller's frame)
    RubyString source = src.convertToString();

    DynamicScope evalScope = context.getCurrentScope().getEvalScope(runtime);
    evalScope.getStaticScope().determineModule();

    try {
      Node node = runtime.parseEval(source.getByteList(), file, evalScope, lineNumber);

      if (runtime.getInstanceConfig().getCompileMode() == CompileMode.OFFIR) {
        // SSS FIXME: AST interpreter passed both a runtime (which comes from the source string)
        // and the thread-context rather than fetch one from the other.  Why is that?
        return Interpreter.interpretSimpleEval(runtime, file, lineNumber, "(eval)", node, self);
      } else {
        return INTERPRET_EVAL(
            runtime, context, file, lineNumber, node, "(eval)", self, Block.NULL_BLOCK);
      }
    } catch (JumpException.BreakJump bj) {
      throw runtime.newLocalJumpError(
          RubyLocalJumpError.Reason.BREAK, (IRubyObject) bj.getValue(), "unexpected break");
    } catch (StackOverflowError soe) {
      throw runtime.newSystemStackError("stack level too deep", soe);
    }
  }
Beispiel #3
0
  /**
   * Evaluate the given string under the specified binding object. If the binding is not a Proc or
   * Binding object (RubyProc or RubyBinding) throw an appropriate type error.
   *
   * @param context the thread context for the current thread
   * @param self the self against which eval was called; used as self in the eval in 1.9 mode
   * @param src The string containing the text to be evaluated
   * @param binding The binding object under which to perform the evaluation
   * @return An IRubyObject result from the evaluation
   */
  public static IRubyObject evalWithBinding(
      ThreadContext context, IRubyObject self, IRubyObject src, Binding binding) {
    Ruby runtime = src.getRuntime();
    DynamicScope evalScope;

    if (runtime.is1_9()) {
      // in 1.9, eval scopes are local to the binding
      evalScope = binding.getEvalScope(runtime);
    } else {
      // in 1.8, eval scopes are local to the parent scope
      evalScope = binding.getDynamicScope().getEvalScope(runtime);
    }

    // FIXME:  This determine module is in a strange location and should somehow be in block
    evalScope.getStaticScope().determineModule();

    Frame lastFrame = context.preEvalWithBinding(binding);
    try {
      // Binding provided for scope, use it
      RubyString source = src.convertToString();
      Node node =
          runtime.parseEval(source.getByteList(), binding.getFile(), evalScope, binding.getLine());
      Block block = binding.getFrame().getBlock();

      if (runtime.getInstanceConfig().getCompileMode() == CompileMode.OFFIR) {
        // SSS FIXME: AST interpreter passed both a runtime (which comes from the source string)
        // and the thread-context rather than fetch one from the other.  Why is that?
        return Interpreter.interpretBindingEval(
            runtime, binding.getFile(), binding.getLine(), binding.getMethod(), node, self, block);
      } else {
        return INTERPRET_EVAL(
            runtime,
            context,
            binding.getFile(),
            binding.getLine(),
            node,
            binding.getMethod(),
            self,
            block);
      }
    } catch (JumpException.BreakJump bj) {
      throw runtime.newLocalJumpError(
          RubyLocalJumpError.Reason.BREAK, (IRubyObject) bj.getValue(), "unexpected break");
    } catch (JumpException.RedoJump rj) {
      throw runtime.newLocalJumpError(
          RubyLocalJumpError.Reason.REDO, (IRubyObject) rj.getValue(), "unexpected redo");
    } catch (StackOverflowError soe) {
      throw runtime.newSystemStackError("stack level too deep", soe);
    } finally {
      context.postEvalWithBinding(binding, lastFrame);
    }
  }
Beispiel #4
0
 @Override
 public Object interpret(
     ThreadContext context,
     StaticScope currScope,
     DynamicScope currDynScope,
     IRubyObject self,
     Object[] temp) {
   int i = 0;
   while (!currDynScope.getStaticScope().isArgumentScope()) {
     currDynScope = currDynScope.getParentScope();
     i++;
   }
   return context.runtime.newFixnum(i);
 }
Beispiel #5
0
 private static void setResult(
     Object[] temp, DynamicScope currDynScope, Variable resultVar, Object result) {
   if (resultVar instanceof TemporaryVariable) {
     temp[((TemporaryVariable) resultVar).offset] = result;
   } else {
     LocalVariable lv = (LocalVariable) resultVar;
     currDynScope.setValue((IRubyObject) result, lv.getLocation(), lv.getScopeDepth());
   }
 }
Beispiel #6
0
  public RootNode(ISourcePosition position, DynamicScope scope, Node bodyNode) {
    super(position);

    assert bodyNode != null : "bodyNode is not null";

    this.scope = scope;
    this.staticScope = scope.getStaticScope();
    this.bodyNode = bodyNode;
  }
Beispiel #7
0
 protected void pre(
     InterpreterContext ic,
     ThreadContext context,
     IRubyObject self,
     String name,
     Block block,
     RubyModule implClass) {
   // update call stacks (push: frame, class, scope, etc.)
   context.preMethodFrameOnly(implClass, name, self, block);
   if (ic.pushNewDynScope()) {
     context.pushScope(DynamicScope.newDynamicScope(ic.getStaticScope()));
   }
 }
Beispiel #8
0
 private static Object retrieveOp(
     Operand r,
     ThreadContext context,
     IRubyObject self,
     DynamicScope currDynScope,
     Object[] temp) {
   Object res;
   if (r instanceof Self) {
     return self;
   } else if (r instanceof TemporaryVariable) {
     res = temp[((TemporaryVariable) r).offset];
     return res == null ? context.nil : res;
   } else if (r instanceof LocalVariable) {
     LocalVariable lv = (LocalVariable) r;
     res = currDynScope.getValue(lv.getLocation(), lv.getScopeDepth());
     return res == null ? context.nil : res;
   } else {
     return r.retrieve(context, self, currDynScope, temp);
   }
 }
Beispiel #9
0
 @Override
 public Object retrieve(
     ThreadContext context, IRubyObject self, DynamicScope currDynScope, Object[] temp) {
   return currDynScope.getStaticScope();
 }
Beispiel #10
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;
  }