@Override public IRubyObject call( ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0) { Ruby runtime = context.getRuntime(); int callNumber = context.callNumber; try { pre(context, name, self, Block.NULL_BLOCK, runtime); argsNode.checkArgCount(runtime, name, 1); argsNode.prepare(context, runtime, self, arg0, Block.NULL_BLOCK); return ASTInterpreter.INTERPRET_METHOD( runtime, context, file, line, getImplementationClass(), body, name, self, Block.NULL_BLOCK, isTraceable()); } catch (JumpException.ReturnJump rj) { return handleReturn(context, rj, callNumber); } catch (JumpException.RedoJump rj) { return handleRedo(runtime); } catch (JumpException.BreakJump bj) { return handleBreak(context, runtime, bj, callNumber); } finally { post(runtime, context, name); } }
@Override public RubyNode visitArgumentNode(org.jruby.ast.ArgumentNode node) { final SourceSection sourceSection = translate(node.getPosition()); final RubyNode readNode; if (useArray()) { readNode = readArgument(sourceSection, index); } else { if (state == State.PRE) { readNode = readArgument(sourceSection, index); } else if (state == State.POST) { readNode = readArgument( sourceSection, (argsNode.getPreCount() + argsNode.getOptionalArgsCount() + argsNode.getPostCount()) - index - 1); } else { throw new IllegalStateException(); } } final FrameSlot slot = methodBodyTranslator.getEnvironment().getFrameDescriptor().findFrameSlot(node.getName()); return WriteLocalVariableNodeFactory.create(context, sourceSection, slot, readNode); }
public Arity( int required, int optional, boolean allowsMore, boolean hasKeywords, boolean hasKeyRest, int definedKeywords, ArgsNode argsNode) { this.required = required; this.optional = optional; this.allowsMore = allowsMore; this.definedKeywords = definedKeywords; this.hasKeywords = hasKeywords; this.hasKeyRest = hasKeyRest; if (argsNode.hasKwargs()) { keywordArguments = new ArrayList<>(); if (argsNode.getKeywords() != null) { for (Node node : argsNode.getKeywords().children()) { final KeywordArgNode kwarg = (KeywordArgNode) node; final AssignableNode assignableNode = kwarg.getAssignable(); if (assignableNode instanceof LocalAsgnNode) { keywordArguments.add(((LocalAsgnNode) assignableNode).getName()); } else if (assignableNode instanceof DAsgnNode) { keywordArguments.add(((DAsgnNode) assignableNode).getName()); } else { throw new UnsupportedOperationException("unsupported keyword arg " + node); } } } } else { keywordArguments = null; } }
public static Arity getArity(org.jruby.ast.ArgsNode argsNode) { final String[] keywordArguments; if (argsNode.hasKwargs() && argsNode.getKeywords() != null) { final org.jruby.ast.Node[] keywordNodes = argsNode.getKeywords().children(); final int keywordsCount = keywordNodes.length; keywordArguments = new String[keywordsCount]; for (int i = 0; i < keywordsCount; i++) { final KeywordArgNode kwarg = (KeywordArgNode) keywordNodes[i]; final AssignableNode assignableNode = kwarg.getAssignable(); if (assignableNode instanceof LocalAsgnNode) { keywordArguments[i] = ((LocalAsgnNode) assignableNode).getName(); } else if (assignableNode instanceof DAsgnNode) { keywordArguments[i] = ((DAsgnNode) assignableNode).getName(); } else { throw new UnsupportedOperationException("unsupported keyword arg " + kwarg); } } } else { keywordArguments = Arity.NO_KEYWORDS; } return new Arity( argsNode.getPreCount(), argsNode.getOptionalArgsCount(), argsNode.hasRestArg(), argsNode.getPostCount(), keywordArguments, argsNode.hasKeyRest()); }
private RubyNode translateLocalAssignment( ISourcePosition sourcePosition, String name, org.jruby.ast.Node valueNode) { final SourceSection sourceSection = translate(sourcePosition); final RubyNode readNode; if (valueNode instanceof org.jruby.ast.NilImplicitNode) { // Multiple assignment if (useArray()) { readNode = ArrayIndexNodeFactory.create(context, sourceSection, index, loadArray(sourceSection)); } else { readNode = readArgument(sourceSection, index); } } else { // Optional argument final RubyNode defaultValue = valueNode.accept(this); readNode = new ReadOptionalArgumentNode( context, sourceSection, index, index + argsNode.getPostCount() + 1, defaultValue); } final FrameSlot slot = methodBodyTranslator.getEnvironment().getFrameDescriptor().findFrameSlot(name); return WriteLocalVariableNodeFactory.create(context, sourceSection, slot, readNode); }
@Override public RubyNode visitRestArgNode(org.jruby.ast.RestArgNode node) { final SourceSection sourceSection = translate(node.getPosition()); final RubyNode readNode; if (useArray()) { readNode = ArrayGetTailNodeFactory.create( context, sourceSection, argsNode.getPreCount(), loadArray(sourceSection)); } else { readNode = new ReadRestArgumentNode(context, sourceSection, argsNode.getPreCount()); } final FrameSlot slot = methodBodyTranslator.getEnvironment().getFrameDescriptor().findFrameSlot(node.getName()); return WriteLocalVariableNodeFactory.create(context, sourceSection, slot, readNode); }
private void declareArguments( SourceSection sourceSection, String methodName, SharedMethodInfo sharedMethodInfo) { final ParameterCollector parameterCollector = new ParameterCollector(); argsNode.accept(parameterCollector); for (String parameter : parameterCollector.getParameters()) { environment.declareVar(parameter); } }
private RubyNode readArgument(SourceSection sourceSection, int index) { if (useArray()) { return ArrayIndexNodeFactory.create(context, sourceSection, index, loadArray(sourceSection)); } else { if (state == State.PRE) { return new ReadPreArgumentNode( context, sourceSection, index, isBlock ? MissingArgumentBehaviour.NIL : MissingArgumentBehaviour.RUNTIME_ERROR); } else if (state == State.POST) { return new ReadPostArgumentNode( context, sourceSection, (argsNode.getPreCount() + argsNode.getOptionalArgsCount() + argsNode.getPostCount()) - index - 1); } else { throw new IllegalStateException(); } } }
public RubyNode doCompileMethodBody( SourceSection sourceSection, String methodName, org.jruby.ast.Node bodyNode, SharedMethodInfo sharedMethodInfo) { declareArguments(sourceSection, methodName, sharedMethodInfo); final Arity arity = getArity(argsNode); final LoadArgumentsTranslator loadArgumentsTranslator = new LoadArgumentsTranslator(currentNode, context, source, false, this); final RubyNode loadArguments = argsNode.accept(loadArgumentsTranslator); RubyNode body; parentSourceSection.push(sourceSection); try { body = translateNodeOrNil(sourceSection, bodyNode); } finally { parentSourceSection.pop(); } final RubyNode prelude; if (usesRubiniusPrimitive) { // Use Rubinius.primitive seems to turn off arity checking. See Time.from_array for example. prelude = loadArguments; } else { prelude = SequenceNode.sequence( context, sourceSection, CheckArityNode.create(context, sourceSection, arity), loadArguments); } body = SequenceNode.sequence(context, body.getSourceSection(), prelude, body); if (environment.getFlipFlopStates().size() > 0) { body = SequenceNode.sequence( context, body.getSourceSection(), initFlipFlopStates(sourceSection), body); } body = new CatchForMethodNode(context, body.getSourceSection(), body, environment.getReturnID()); // TODO(CS, 10-Jan-15) why do we only translate exceptions in methods and not blocks? body = new ExceptionTranslatingNode(context, body.getSourceSection(), body); return body; }
@Override public void prepare( ThreadContext context, Ruby runtime, IRubyObject self, IRubyObject[] args, Block block) { super.prepare(context, runtime, self, args, block); }
@Override public Arity getArity() { return argsNode.getArity(); }
@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; }
@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); }
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(); } }
private static String calculateFilename(ArgsNode argsNode, Node bodyNode) { if (bodyNode != null) return bodyNode.getPosition().getFile(); if (argsNode != null) return argsNode.getPosition().getFile(); return "__eval__"; }
public BlockDefinitionNode compileBlockNode( SourceSection sourceSection, String methodName, org.jruby.ast.Node bodyNode, SharedMethodInfo sharedMethodInfo, Type type) { declareArguments(sourceSection, methodName, sharedMethodInfo); final Arity arity = getArity(argsNode); final Arity arityForCheck; /* * If you have a block with parameters |a,| Ruby checks the arity as if was minimum 1, maximum 1. That's * counter-intuitive - as you'd expect the anonymous rest argument to cause it to have no maximum. Indeed, * that's how JRuby reports it, and by the look of their failing spec they consider this to be correct. We'll * follow the specs for now until we see a reason to do something else. */ if (argsNode.getRestArgNode() instanceof org.jruby.ast.UnnamedRestArgNode && !((UnnamedRestArgNode) argsNode.getRestArgNode()).isStar()) { arityForCheck = arity.withRest(false); } else { arityForCheck = arity; } final boolean isProc = type == Type.PROC; final LoadArgumentsTranslator loadArgumentsTranslator = new LoadArgumentsTranslator(currentNode, context, source, isProc, this); final RubyNode loadArguments = argsNode.accept(loadArgumentsTranslator); final RubyNode preludeProc; if (shouldConsiderDestructuringArrayArg(arity)) { final RubyNode readArrayNode = new ReadPreArgumentNode( context, sourceSection, 0, MissingArgumentBehaviour.RUNTIME_ERROR); final RubyNode castArrayNode = ArrayCastNodeGen.create(context, sourceSection, readArrayNode); final FrameSlot arraySlot = environment.declareVar(environment.allocateLocalTemp("destructure")); final RubyNode writeArrayNode = new WriteLocalVariableNode(context, sourceSection, castArrayNode, arraySlot); final LoadArgumentsTranslator destructureArgumentsTranslator = new LoadArgumentsTranslator(currentNode, context, source, isProc, this); destructureArgumentsTranslator.pushArraySlot(arraySlot); final RubyNode newDestructureArguments = argsNode.accept(destructureArgumentsTranslator); final RubyNode shouldDestructure = new ShouldDestructureNode( context, sourceSection, new RespondToNode(context, sourceSection, readArrayNode, "to_ary")); final RubyNode arrayWasNotNil = SequenceNode.sequence( context, sourceSection, writeArrayNode, new NotNode( context, sourceSection, new IsNilNode( context, sourceSection, new ReadLocalVariableNode(context, sourceSection, arraySlot)))); final RubyNode shouldDestructureAndArrayWasNotNil = new AndNode(context, sourceSection, shouldDestructure, arrayWasNotNil); preludeProc = new IfNode( context, sourceSection, shouldDestructureAndArrayWasNotNil, newDestructureArguments, loadArguments); } else { preludeProc = loadArguments; } final RubyNode preludeLambda = SequenceNode.sequence( context, sourceSection, CheckArityNode.create(context, sourceSection, arityForCheck), NodeUtil.cloneNode(loadArguments)); RubyNode body; parentSourceSection.push(sourceSection); try { if (argsNode.getBlockLocalVariables() != null && !argsNode.getBlockLocalVariables().isEmpty()) { for (org.jruby.ast.Node var : argsNode.getBlockLocalVariables().children()) { environment.declareVar(((INameNode) var).getName()); } } body = translateNodeOrNil(sourceSection, bodyNode); } finally { parentSourceSection.pop(); } // Procs final RubyNode bodyProc = new CatchForProcNode( context, SequenceNode.enclosing(sourceSection, body.getEncapsulatingSourceSection()), composeBody(preludeProc, NodeUtil.cloneNode(body))); final RubyRootNode newRootNodeForProcs = new RubyRootNode( context, considerExtendingMethodToCoverEnd(bodyProc.getEncapsulatingSourceSection()), environment.getFrameDescriptor(), environment.getSharedMethodInfo(), bodyProc, environment.needsDeclarationFrame()); // Lambdas final RubyNode composed = composeBody(preludeLambda, body /* no copy, last usage */); final RubyNode bodyLambda = new CatchForLambdaNode( context, composed.getEncapsulatingSourceSection(), composed, environment.getReturnID()); final RubyRootNode newRootNodeForLambdas = new RubyRootNode( context, considerExtendingMethodToCoverEnd(bodyLambda.getEncapsulatingSourceSection()), environment.getFrameDescriptor(), environment.getSharedMethodInfo(), bodyLambda, environment.needsDeclarationFrame()); // TODO CS 23-Nov-15 only the second one will get instrumented properly! final CallTarget callTargetAsLambda = Truffle.getRuntime().createCallTarget(newRootNodeForLambdas); final CallTarget callTargetAsProc = Truffle.getRuntime().createCallTarget(newRootNodeForProcs); FrameSlot frameOnStackMarkerSlot; if (frameOnStackMarkerSlotStack.isEmpty()) { frameOnStackMarkerSlot = null; } else { frameOnStackMarkerSlot = frameOnStackMarkerSlotStack.peek(); if (frameOnStackMarkerSlot == BAD_FRAME_SLOT) { frameOnStackMarkerSlot = null; } } return new BlockDefinitionNode( context, newRootNodeForProcs.getEncapsulatingSourceSection(), type, environment.getSharedMethodInfo(), callTargetAsProc, callTargetAsLambda, environment.getBreakID(), frameOnStackMarkerSlot); }