Example #1
0
  @Override
  public RubyNode visitArgsNode(org.jruby.ast.ArgsNode node) {
    argsNode = node;

    final SourceSection sourceSection = translate(node.getPosition());

    final List<RubyNode> sequence = new ArrayList<>();

    int localIndex = 0;

    if (node.getPre() != null) {
      state = State.PRE;
      for (org.jruby.ast.Node arg : node.getPre().childNodes()) {
        sequence.add(arg.accept(this));
        index = ++localIndex;
      }
    }

    if (node.getOptArgs() != null) {
      // (BlockNode 0, (OptArgNode:a 0, (LocalAsgnNode:a 0, (FixnumNode 0))), ...)
      state = State.OPT;
      for (org.jruby.ast.Node arg : node.getOptArgs().childNodes()) {
        sequence.add(arg.accept(this));
        index = ++localIndex;
      }
    }

    if (node.getPost() != null) {
      state = State.POST;
      for (org.jruby.ast.Node arg : node.getPost().childNodes()) {
        sequence.add(arg.accept(this));
        index = ++localIndex;
      }
    }

    if (node.getRestArgNode() != null) {
      methodBodyTranslator.getEnvironment().hasRestParameter = true;
      sequence.add(node.getRestArgNode().accept(this));
    }

    if (node.getBlock() != null) {
      sequence.add(node.getBlock().accept(this));
    }

    return SequenceNode.sequence(context, sourceSection, sequence);
  }
Example #2
0
  @JRubyMethod(name = "parameters", compat = CompatVersion.RUBY1_9)
  public IRubyObject parameters(ThreadContext context) {
    Ruby runtime = context.getRuntime();
    RubyArray parms = RubyArray.newEmptyArray(runtime);
    ArgsNode args;

    if (!(this.getBlock().getBody() instanceof Interpreted19Block)) {
      return parms;
    }

    // argument names are easily accessible from interpreter
    RubyArray elem = RubyArray.newEmptyArray(runtime);
    args = ((Interpreted19Block) this.getBlock().getBody()).getArgs();

    // required parameters
    List<Node> children = new ArrayList();
    if (args.getPreCount() > 0) children.addAll(args.getPre().childNodes());
    if (args.getPostCount() > 0) children.addAll(args.getPost().childNodes());

    Iterator iter = children.iterator();
    while (iter.hasNext()) {
      Node node = (Node) iter.next();
      elem = RubyArray.newEmptyArray(runtime);
      elem.add(RubySymbol.newSymbol(runtime, this.isLambda() ? "req" : "opt"));
      if (node instanceof ArgumentNode) {
        elem.add(RubySymbol.newSymbol(runtime, ((ArgumentNode) node).getName()));
      }
      parms.add(elem);
    }

    // optional parameters
    if (args.getOptArgs() != null) {
      children = args.getOptArgs().childNodes();
      if (!children.isEmpty()) {
        iter = children.iterator();
        while (iter.hasNext()) {
          Node node = (Node) iter.next();
          elem = RubyArray.newEmptyArray(runtime);
          elem.add(RubySymbol.newSymbol(runtime, "opt"));
          if (node instanceof OptArgNode) {
            elem.add(RubySymbol.newSymbol(runtime, ((OptArgNode) node).getName()));
          }
          parms.add(elem);
        }
      }
    }

    ArgumentNode rest = args.getRestArgNode();
    if (rest != null) {
      elem = RubyArray.newEmptyArray(runtime);
      elem.add(RubySymbol.newSymbol(runtime, "rest"));
      elem.add(RubySymbol.newSymbol(runtime, rest.getName()));
      parms.add(elem);
    }

    BlockArgNode blockArg = args.getBlock();
    if (blockArg != null) {
      elem = RubyArray.newEmptyArray(runtime);
      elem.add(RubySymbol.newSymbol(runtime, "block"));
      elem.add(RubySymbol.newSymbol(runtime, blockArg.getName()));
      parms.add(elem);
    }

    return parms;
  }
Example #3
0
  public void inspect(Node node) {
    if (RubyInstanceConfig.FULL_TRACE_ENABLED) {
      disable();
      // we still inspect since some nodes change state as a result (JRUBY-6836)
    }

    if (node == null) return;

    switch (node.getNodeType()) {
      case ALIASNODE:
        setFlag(node, METHOD);
        break;
      case ANDNODE:
        AndNode andNode = (AndNode) node;
        inspect(andNode.getFirstNode());
        inspect(andNode.getSecondNode());
        break;
      case ARGSCATNODE:
        ArgsCatNode argsCatNode = (ArgsCatNode) node;
        inspect(argsCatNode.getFirstNode());
        inspect(argsCatNode.getSecondNode());
        break;
      case ARGSPUSHNODE:
        ArgsPushNode argsPushNode = (ArgsPushNode) node;
        inspect(argsPushNode.getFirstNode());
        inspect(argsPushNode.getSecondNode());
        break;
      case ARGUMENTNODE:
        break;
      case ARRAYNODE:
      case BLOCKNODE:
      case DREGEXPNODE:
      case DSTRNODE:
      case DSYMBOLNODE:
      case DXSTRNODE:
      case LISTNODE:
        ListNode listNode = (ListNode) node;
        for (int i = 0; i < listNode.size(); i++) {
          inspect(listNode.get(i));
        }
        break;
      case ARGSNODE:
        ArgsNode argsNode = (ArgsNode) node;
        if (argsNode.getBlock() != null) setFlag(node, BLOCK_ARG);
        if (argsNode.getOptArgs() != null) {
          setFlag(node, OPT_ARGS);
          inspect(argsNode.getOptArgs());
        }
        if (argsNode.getRestArg() == -2 || argsNode.getRestArg() >= 0) setFlag(node, REST_ARG);
        break;
      case ATTRASSIGNNODE:
        AttrAssignNode attrAssignNode = (AttrAssignNode) node;
        inspect(attrAssignNode.getArgsNode());
        inspect(attrAssignNode.getReceiverNode());
        break;
      case BACKREFNODE:
        setFlag(node, BACKREF);
        break;
      case BEGINNODE:
        inspect(((BeginNode) node).getBodyNode());
        break;
      case BIGNUMNODE:
        break;
      case BINARYOPERATORNODE:
        BinaryOperatorNode binaryOperatorNode = (BinaryOperatorNode) node;
        inspect(binaryOperatorNode.getFirstNode());
        inspect(binaryOperatorNode.getSecondNode());
        break;
      case BLOCKARGNODE:
        break;
      case BLOCKPASSNODE:
        BlockPassNode blockPassNode = (BlockPassNode) node;
        inspect(blockPassNode.getArgsNode());
        inspect(blockPassNode.getBodyNode());
        break;
      case BREAKNODE:
        inspect(((BreakNode) node).getValueNode());
        break;
      case CALLNODE:
        CallNode callNode = (CallNode) node;
        inspect(callNode.getReceiverNode());
        // check for Proc.new, an especially magic method
        if (callNode.getName() == "new"
            && callNode.getReceiverNode() instanceof ConstNode
            && ((ConstNode) callNode.getReceiverNode()).getName() == "Proc") {
          // Proc.new needs the caller's block to instantiate a proc
          setFlag(node, FRAME_BLOCK);
        }
        if (callNode.getArgsNode() == null && callNode.getIterNode() == null) {
          switch (callNode.getReceiverNode().getNodeType()) {
              // no unary methods on literal numbers, symbols, or strings have frame/scope effects
            case FIXNUMNODE:
            case FLOATNODE:
            case BIGNUMNODE:
            case STRNODE:
            case SYMBOLNODE:
              return;
          }
        }
      case FCALLNODE:
        inspect(((IArgumentNode) node).getArgsNode());
        inspect(((BlockAcceptingNode) node).getIterNode());
      case VCALLNODE:
        INameNode nameNode = (INameNode) node;
        if (FRAME_AWARE_METHODS.contains(nameNode.getName())) {
          setFlag(node, FRAME_AWARE);
          if (nameNode.getName().indexOf("eval") != -1) {
            setFlag(node, EVAL);
          }
        }
        if (SCOPE_AWARE_METHODS.contains(nameNode.getName())) {
          setFlag(node, SCOPE_AWARE);
        }
        break;
      case CASENODE:
        CaseNode caseNode = (CaseNode) node;
        inspect(caseNode.getCaseNode());
        if (caseNode.getCases().size() > Options.COMPILE_OUTLINE_CASECOUNT.load()) {
          // if more than N cases, disable; we'll compile them as separate bodies
          // see BaseBodyCompiler#compiledSequencedConditional and ASTCompiler#compileCase
          disable();
          return;
        } else {
          for (Node when : caseNode.getCases().childNodes()) {
            inspect(when);
          }
          inspect(caseNode.getElseNode());
        }
        break;
      case CLASSNODE:
        setFlag(node, CLASS);
        ClassNode classNode = (ClassNode) node;
        inspect(classNode.getCPath());
        inspect(classNode.getSuperNode());
        break;
      case CLASSVARNODE:
        setFlag(node, CLASS_VAR);
        break;
      case CONSTDECLNODE:
        inspect(((AssignableNode) node).getValueNode());
        setFlag(node, CONSTANT);
        break;
      case CLASSVARASGNNODE:
        inspect(((AssignableNode) node).getValueNode());
        setFlag(node, CLASS_VAR);
        break;
      case CLASSVARDECLNODE:
        inspect(((AssignableNode) node).getValueNode());
        setFlag(node, CLASS_VAR);
        break;
      case COLON2NODE:
        inspect(((Colon2Node) node).getLeftNode());
        break;
      case COLON3NODE:
        break;
      case CONSTNODE:
        setFlag(node, CONSTANT);
        break;
      case DEFNNODE:
      case DEFSNODE:
        setFlag(node, METHOD);
        setFlag(node, FRAME_VISIBILITY);
        setFlag(node, SCOPE_AWARE);
        break;
      case DEFINEDNODE:
        switch (((DefinedNode) node).getExpressionNode().getNodeType()) {
          case CLASSVARASGNNODE:
          case CLASSVARDECLNODE:
          case CONSTDECLNODE:
          case DASGNNODE:
          case GLOBALASGNNODE:
          case LOCALASGNNODE:
          case MULTIPLEASGNNODE:
          case OPASGNNODE:
          case OPELEMENTASGNNODE:
          case DVARNODE:
          case FALSENODE:
          case TRUENODE:
          case LOCALVARNODE:
          case INSTVARNODE:
          case BACKREFNODE:
          case SELFNODE:
          case VCALLNODE:
          case YIELDNODE:
          case GLOBALVARNODE:
          case CONSTNODE:
          case FCALLNODE:
          case CLASSVARNODE:
            // ok, we have fast paths
            inspect(((DefinedNode) node).getExpressionNode());
            break;
          default:
            // long, slow way causes disabling
            // we still inspect because some nodes may change state (JRUBY-6836)
            inspect(((DefinedNode) node).getExpressionNode());
            disable();
        }
        break;
      case DOTNODE:
        DotNode dotNode = (DotNode) node;
        inspect(dotNode.getBeginNode());
        inspect(dotNode.getEndNode());
        break;
      case DASGNNODE:
        inspect(((AssignableNode) node).getValueNode());
        break;
      case DVARNODE:
        break;
      case ENSURENODE:
        inspect(((EnsureNode) node).getBodyNode());
        inspect(((EnsureNode) node).getEnsureNode());
        disable();
        break;
      case ENCODINGNODE:
        break;
      case EVSTRNODE:
        inspect(((EvStrNode) node).getBody());
        break;
      case FALSENODE:
        break;
      case FIXNUMNODE:
        break;
      case FLIPNODE:
        inspect(((FlipNode) node).getBeginNode());
        inspect(((FlipNode) node).getEndNode());
        break;
      case FLOATNODE:
        break;
      case FORNODE:
        setFlag(node, CLOSURE);
        setFlag(node, SCOPE_AWARE);
        inspect(((ForNode) node).getIterNode());
        inspect(((ForNode) node).getBodyNode());
        inspect(((ForNode) node).getVarNode());
        break;
      case GLOBALASGNNODE:
        GlobalAsgnNode globalAsgnNode = (GlobalAsgnNode) node;
        if (globalAsgnNode.getName().equals("$_")) {
          setFlag(node, LASTLINE);
        } else if (globalAsgnNode.getName().equals("$~")) {
          setFlag(node, BACKREF);
        }
        inspect(globalAsgnNode.getValueNode());
        break;
      case GLOBALVARNODE:
        {
          String name = ((GlobalVarNode) node).getName();
          if (name.equals("$_") || name.equals("$LAST_READ_LINE")) {
            setFlag(node, LASTLINE);
          } else if (name.equals("$~")
              || name.equals("$`")
              || name.equals("$'")
              || name.equals("$+")
              || name.equals("$LAST_MATCH_INFO")
              || name.equals("$PREMATCH")
              || name.equals("$POSTMATCH")
              || name.equals("$LAST_PAREN_MATCH")) {
            setFlag(node, BACKREF);
          }
          break;
        }
      case HASHNODE:
        HashNode hashNode = (HashNode) node;
        inspect(hashNode.getListNode());
        break;
      case IFNODE:
        IfNode ifNode = (IfNode) node;
        inspect(ifNode.getCondition());
        inspect(ifNode.getThenBody());
        inspect(ifNode.getElseBody());
        break;
      case INSTASGNNODE:
        inspect(((AssignableNode) node).getValueNode());
        break;
      case INSTVARNODE:
        break;
      case ISCOPINGNODE:
        IScopingNode iscopingNode = (IScopingNode) node;
        inspect(iscopingNode.getCPath());
        break;
      case ITERNODE:
        setFlag(node, CLOSURE);
        break;
      case LAMBDANODE:
        setFlag(node, CLOSURE);
        break;
      case LOCALASGNNODE:
        LocalAsgnNode localAsgnNode = (LocalAsgnNode) node;
        if (PRAGMAS.contains(localAsgnNode.getName())) {
          if (localAsgnNode.getName().equals("__NOFRAME__")) {
            noFrame = localAsgnNode.getValueNode() instanceof TrueNode;
          }
          break;
        }
        inspect(localAsgnNode.getValueNode());
        break;
      case LOCALVARNODE:
        break;
      case MATCHNODE:
        inspect(((MatchNode) node).getRegexpNode());
        setFlag(node, BACKREF);
        break;
      case MATCH2NODE:
        Match2Node match2Node = (Match2Node) node;
        inspect(match2Node.getReceiverNode());
        inspect(match2Node.getValueNode());
        setFlag(node, BACKREF);
        if (match2Node instanceof Match2CaptureNode) {
          // additionally need scope, to set local vars
          // FIXME: this can be done without heap scope
          setFlag(node, SCOPE_AWARE);
        }
        break;
      case MATCH3NODE:
        Match3Node match3Node = (Match3Node) node;
        inspect(match3Node.getReceiverNode());
        inspect(match3Node.getValueNode());
        setFlag(node, BACKREF);
        break;
      case MODULENODE:
        setFlag(node, CLASS);
        inspect(((ModuleNode) node).getCPath());
        break;
      case MULTIPLEASGN19NODE:
        MultipleAsgn19Node multipleAsgn19Node = (MultipleAsgn19Node) node;
        inspect(multipleAsgn19Node.getPre());
        inspect(multipleAsgn19Node.getPost());
        inspect(multipleAsgn19Node.getRest());
        inspect(multipleAsgn19Node.getValueNode());
        break;
      case MULTIPLEASGNNODE:
        MultipleAsgnNode multipleAsgnNode = (MultipleAsgnNode) node;
        inspect(multipleAsgnNode.getArgsNode());
        inspect(multipleAsgnNode.getHeadNode());
        inspect(multipleAsgnNode.getValueNode());
        break;
      case NEWLINENODE:
        inspect(((NewlineNode) node).getNextNode());
        break;
      case NEXTNODE:
        inspect(((NextNode) node).getValueNode());
        break;
      case NILNODE:
        break;
      case NOTNODE:
        inspect(((NotNode) node).getConditionNode());
        break;
      case NTHREFNODE:
        break;
      case OPASGNANDNODE:
        OpAsgnAndNode opAsgnAndNode = (OpAsgnAndNode) node;
        inspect(opAsgnAndNode.getFirstNode());
        inspect(opAsgnAndNode.getSecondNode());
        break;
      case OPASGNNODE:
        OpAsgnNode opAsgnNode = (OpAsgnNode) node;
        inspect(opAsgnNode.getReceiverNode());
        inspect(opAsgnNode.getValueNode());
        break;
      case OPASGNORNODE:
        switch (((OpAsgnOrNode) node).getFirstNode().getNodeType()) {
          case CLASSVARASGNNODE:
          case CLASSVARDECLNODE:
          case CONSTDECLNODE:
          case DASGNNODE:
          case GLOBALASGNNODE:
          case LOCALASGNNODE:
          case MULTIPLEASGNNODE:
          case OPASGNNODE:
          case OPELEMENTASGNNODE:
          case DVARNODE:
          case FALSENODE:
          case TRUENODE:
          case LOCALVARNODE:
          case INSTVARNODE:
          case BACKREFNODE:
          case SELFNODE:
          case VCALLNODE:
          case YIELDNODE:
          case GLOBALVARNODE:
          case CONSTNODE:
          case FCALLNODE:
          case CLASSVARNODE:
            // ok, we have fast paths
            inspect(((OpAsgnOrNode) node).getSecondNode());
            break;
          default:
            // long, slow way causes disabling for defined
            inspect(((OpAsgnOrNode) node).getFirstNode());
            inspect(((OpAsgnOrNode) node).getSecondNode());
            disable();
        }
        break;
      case OPELEMENTASGNNODE:
        OpElementAsgnNode opElementAsgnNode = (OpElementAsgnNode) node;
        inspect(opElementAsgnNode.getArgsNode());
        inspect(opElementAsgnNode.getReceiverNode());
        inspect(opElementAsgnNode.getValueNode());
        break;
      case OPTARGNODE:
        inspect(((OptArgNode) node).getValue());
        break;
      case ORNODE:
        OrNode orNode = (OrNode) node;
        inspect(orNode.getFirstNode());
        inspect(orNode.getSecondNode());
        break;
      case POSTEXENODE:
        PostExeNode postExeNode = (PostExeNode) node;
        setFlag(node, CLOSURE);
        setFlag(node, SCOPE_AWARE);
        inspect(postExeNode.getBodyNode());
        inspect(postExeNode.getVarNode());
        break;
      case PREEXENODE:
        PreExeNode preExeNode = (PreExeNode) node;
        setFlag(node, CLOSURE);
        setFlag(node, SCOPE_AWARE);
        inspect(preExeNode.getBodyNode());
        inspect(preExeNode.getVarNode());
        break;
      case REDONODE:
        break;
      case REGEXPNODE:
        break;
      case ROOTNODE:
        inspect(((RootNode) node).getBodyNode());
        if (((RootNode) node).getBodyNode() instanceof BlockNode) {
          BlockNode blockNode = (BlockNode) ((RootNode) node).getBodyNode();
          if (blockNode.size() > 500) {
            // method has more than 500 lines; we'll need to split it
            // and therefore need to use a heap-based scope
            setFlag(node, SCOPE_AWARE);
          }
        }
        break;
      case RESCUEBODYNODE:
        RescueBodyNode rescueBody = (RescueBodyNode) node;
        inspect(rescueBody.getExceptionNodes());
        inspect(rescueBody.getBodyNode());
        inspect(rescueBody.getOptRescueNode());
        break;
      case RESCUENODE:
        RescueNode rescueNode = (RescueNode) node;
        inspect(rescueNode.getBodyNode());
        inspect(rescueNode.getElseNode());
        inspect(rescueNode.getRescueNode());
        disable();
        break;
      case RETRYNODE:
        setFlag(node, RETRY);
        break;
      case RETURNNODE:
        inspect(((ReturnNode) node).getValueNode());
        break;
      case SCLASSNODE:
        setFlag(node, CLASS);
        setFlag(node, FRAME_AWARE);
        SClassNode sclassNode = (SClassNode) node;
        inspect(sclassNode.getReceiverNode());
        break;
      case SCOPENODE:
        break;
      case SELFNODE:
        break;
      case SPLATNODE:
        inspect(((SplatNode) node).getValue());
        break;
      case STARNODE:
        break;
      case STRNODE:
        break;
      case SUPERNODE:
        SuperNode superNode = (SuperNode) node;
        inspect(superNode.getArgsNode());
        inspect(superNode.getIterNode());
        setFlag(node, SUPER);
        break;
      case SVALUENODE:
        inspect(((SValueNode) node).getValue());
        break;
      case SYMBOLNODE:
        break;
      case TOARYNODE:
        inspect(((ToAryNode) node).getValue());
        break;
      case TRUENODE:
        break;
      case UNDEFNODE:
        setFlag(node, METHOD);
        break;
      case UNTILNODE:
        UntilNode untilNode = (UntilNode) node;
        ASTInspector untilInspector =
            subInspect(untilNode.getConditionNode(), untilNode.getBodyNode());
        // a while node could receive non-local flow control from any of these:
        // * a closure within the loop
        // * an eval within the loop
        // * a block-arg-based proc called within the loop
        if (untilInspector.getFlag(CLOSURE) || untilInspector.getFlag(EVAL)) {
          untilNode.containsNonlocalFlow = true;

          // we set scope-aware to true to force heap-based locals
          setFlag(node, SCOPE_AWARE);
        }
        integrate(untilInspector);
        break;
      case VALIASNODE:
        break;
      case WHENNODE:
        {
          inspect(((WhenNode) node).getBodyNode());
          inspect(((WhenNode) node).getExpressionNodes());
          inspect(((WhenNode) node).getNextCase());
          // if any elements are not literals or are regexp, set backref
          Node expr = ((WhenNode) node).getExpressionNodes();
          if (!(expr instanceof ILiteralNode) || expr.getNodeType() == NodeType.REGEXPNODE) {
            setFlag(node, BACKREF);
          }
          break;
        }
      case WHILENODE:
        WhileNode whileNode = (WhileNode) node;
        ASTInspector whileInspector =
            subInspect(whileNode.getConditionNode(), whileNode.getBodyNode());
        // a while node could receive non-local flow control from any of these:
        // * a closure within the loop
        // * an eval within the loop
        // * a block-arg-based proc called within the loop
        // * any case that disables optimization, like rescues and ensures
        if (whileInspector.getFlag(CLOSURE) || whileInspector.getFlag(EVAL) || getFlag(BLOCK_ARG)) {
          whileNode.containsNonlocalFlow = true;

          // we set scope-aware to true to force heap-based locals
          setFlag(node, SCOPE_AWARE);
        }
        integrate(whileInspector);
        break;
      case XSTRNODE:
        break;
      case YIELDNODE:
        inspect(((YieldNode) node).getArgsNode());
        break;
      case ZARRAYNODE:
        break;
      case ZEROARGNODE:
        break;
      case ZSUPERNODE:
        setFlag(node, SCOPE_AWARE);
        setFlag(node, ZSUPER);
        inspect(((ZSuperNode) node).getIterNode());
        break;
      default:
        // encountered a node we don't recognize, set everything to true to disable optz
        assert false : "All nodes should be accounted for in AST inspector: " + node;
        disable();
    }
  }