private static Block getIterNodeBlock(Node blockNode, ThreadContext context, IRubyObject self) { IterNode iterNode = (IterNode) blockNode; StaticScope scope = iterNode.getScope(); scope.determineModule(); // Create block for this iter node // FIXME: We shouldn't use the current scope if it's not actually from the same hierarchy of // static scopes return InterpretedBlock.newInterpretedClosure(context, iterNode.getBlockBody(), self); }
public InterpretedBlock(IterNode iterNode, Arity arity, int argumentType) { super(iterNode.getScope(), arity, argumentType); this.bodyNode = iterNode.getBodyNode() == null ? NilImplicitNode.NIL : iterNode.getBodyNode(); this.scope = iterNode.getScope(); this.position = iterNode.getPosition(); // precache these this.file = position.getFile(); this.line = position.getLine(); assignerFor(iterNode); }
public BlockBody newCompiledBlockBody( ThreadContext context, IterNode iterNode, Arity arity, int argumentType) { NodeType argsNodeId = getArgumentTypeWackyHack(iterNode); boolean hasMultipleArgsHead = false; if (iterNode.getVarNode() instanceof MultipleAsgnNode) { hasMultipleArgsHead = ((MultipleAsgnNode) iterNode.getVarNode()).getHeadNode() != null; } return new CompiledBlock( Arity.procArityOf(iterNode.getVarNode()), iterNode.getScope(), compileBlock( context, new StandardASMCompiler("blahfooblah" + System.currentTimeMillis(), "blahfooblah"), iterNode), hasMultipleArgsHead, BlockBody.asArgumentType(argsNodeId)); }
public static Block newInterpretedClosure( ThreadContext context, IterNode iterNode, IRubyObject self) { Binding binding = context.currentBinding(self); NodeType argsNodeId = getArgumentTypeWackyHack(iterNode); BlockBody body = new InterpretedBlock( iterNode, Arity.procArityOf(iterNode.getVarNode()), asArgumentType(argsNodeId)); return new Block(body, binding); }
// ENEBO: Some of this logic should be put back into the Nodes themselves, but the more // esoteric features of 1.9 make this difficult to know how to do this yet. public BlockBody newCompiledBlockBody19(ThreadContext context, IterNode iterNode) { final ArgsNode argsNode = (ArgsNode) iterNode.getVarNode(); boolean hasMultipleArgsHead = false; if (iterNode.getVarNode() instanceof MultipleAsgnNode) { hasMultipleArgsHead = ((MultipleAsgnNode) iterNode.getVarNode()).getHeadNode() != null; } NodeType argsNodeId = BlockBody.getArgumentTypeWackyHack(iterNode); return new CompiledBlock19( ((ArgsNode) iterNode.getVarNode()).getArity(), iterNode.getScope(), compileBlock19( context, new StandardASMCompiler("blahfooblah" + System.currentTimeMillis(), "blahfooblah"), iterNode), hasMultipleArgsHead, BlockBody.asArgumentType(argsNodeId), Helpers.encodeParameterList(argsNode).split(";")); }
public Block newCompiledClosure(ThreadContext context, IterNode iterNode, IRubyObject self) { Binding binding = context.currentBinding(self); NodeType argsNodeId = getArgumentTypeWackyHack(iterNode); boolean hasMultipleArgsHead = false; if (iterNode.getVarNode() instanceof MultipleAsgnNode) { hasMultipleArgsHead = ((MultipleAsgnNode) iterNode.getVarNode()).getHeadNode() != null; } BlockBody body = new CompiledBlock( Arity.procArityOf(iterNode.getVarNode()), iterNode.getScope(), compileBlock( context, new StandardASMCompiler("blahfooblah" + System.currentTimeMillis(), "blahfooblah"), iterNode), hasMultipleArgsHead, BlockBody.asArgumentType(argsNodeId)); return new Block(body, binding); }
public CompiledBlockCallback19 compileBlock19( ThreadContext context, StandardASMCompiler asmCompiler, final IterNode iterNode) { final ASTCompiler19 astCompiler = new ASTCompiler19(); final StaticScope scope = iterNode.getScope(); asmCompiler.startScript(scope); final ArgsNode argsNode = (ArgsNode) iterNode.getVarNode(); // create the closure class and instantiate it final CompilerCallback closureBody = new CompilerCallback() { public void call(BodyCompiler context) { if (iterNode.getBodyNode() != null) { astCompiler.compile(iterNode.getBodyNode(), context, true); } else { context.loadNil(); } } }; // create the closure class and instantiate it final CompilerCallback closureArgs = new CompilerCallback() { public void call(BodyCompiler context) { // FIXME: This is temporary since the variable compilers assume we want // args already on stack for assignment. We just pop and continue with // 1.9 args logic. context.consumeCurrentValue(); // args value context.consumeCurrentValue(); // passed block if (iterNode.getVarNode() != null) { if (iterNode instanceof LambdaNode) { final int required = argsNode.getRequiredArgsCount(); final int opt = argsNode.getOptionalArgsCount(); final int rest = argsNode.getRestArg(); context.getVariableCompiler().checkMethodArity(required, opt, rest); astCompiler.compileMethodArgs(argsNode, context, true); } else { astCompiler.compileMethodArgs(argsNode, context, true); } } } }; ASTInspector inspector = new ASTInspector(); inspector.inspect(iterNode.getBodyNode()); inspector.inspect(iterNode.getVarNode()); NodeType argsNodeId = BlockBody.getArgumentTypeWackyHack(iterNode); int scopeIndex = asmCompiler.getCacheCompiler().reserveStaticScope(); ChildScopedBodyCompiler closureCompiler = new ChildScopedBodyCompiler19( asmCompiler, "__file__", asmCompiler.getClassname(), inspector, scope, scopeIndex); closureCompiler.beginMethod(argsNodeId == null ? null : closureArgs, scope); closureBody.call(closureCompiler); closureCompiler.endBody(); // __file__ method to call static version SkinnyMethodAdapter method = new SkinnyMethodAdapter( asmCompiler.getClassVisitor(), ACC_PUBLIC, "__file__", getMethodSignature(4), null, null); method.start(); // invoke static __file__ method.aload(THIS); method.aload(THREADCONTEXT_INDEX); method.aload(SELF_INDEX); method.aload(ARGS_INDEX); method.aload(ARGS_INDEX + 1); // block method.invokestatic( asmCompiler.getClassname(), "__file__", asmCompiler.getStaticMethodSignature(asmCompiler.getClassname(), 4)); method.areturn(); method.end(); asmCompiler.endScript(false, false); byte[] bytes = asmCompiler.getClassByteArray(); Class blockClass = new JRubyClassLoader(context.runtime.getJRubyClassLoader()) .defineClass(asmCompiler.getClassname(), bytes); try { final AbstractScript script = (AbstractScript) blockClass.newInstance(); script.setRootScope(scope); return new CompiledBlockCallback19() { @Override public IRubyObject call( ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { return script.__file__(context, self, args, block); } @Override public String getFile() { return iterNode.getPosition().getFile(); } @Override public int getLine() { return iterNode.getPosition().getLine(); } }; } catch (Exception e) { throw new RuntimeException(e); } }
public CompiledBlockCallback compileBlock( ThreadContext context, StandardASMCompiler asmCompiler, final IterNode iterNode) { final ASTCompiler astCompiler = new ASTCompiler(); final StaticScope scope = iterNode.getScope(); asmCompiler.startScript(scope); // create the closure class and instantiate it final CompilerCallback closureBody = new CompilerCallback() { public void call(BodyCompiler context) { if (iterNode.getBodyNode() != null) { astCompiler.compile(iterNode.getBodyNode(), context, true); } else { context.loadNil(); } } }; // create the closure class and instantiate it final CompilerCallback closureArgs = new CompilerCallback() { public void call(BodyCompiler context) { if (iterNode.getVarNode() != null) { astCompiler.compileAssignment(iterNode.getVarNode(), context); } else { context.consumeCurrentValue(); } if (iterNode.getBlockVarNode() != null) { astCompiler.compileAssignment(iterNode.getBlockVarNode(), context); } else { context.consumeCurrentValue(); } } }; ASTInspector inspector = new ASTInspector(); inspector.inspect(iterNode.getBodyNode()); inspector.inspect(iterNode.getVarNode()); int scopeIndex = asmCompiler.getCacheCompiler().reserveStaticScope(); ChildScopedBodyCompiler closureCompiler = new ChildScopedBodyCompiler( asmCompiler, "__file__", asmCompiler.getClassname(), inspector, scope, scopeIndex); closureCompiler.beginMethod(closureArgs, scope); closureBody.call(closureCompiler); closureCompiler.endBody(); // __file__ method with [] args; no-op SkinnyMethodAdapter method = new SkinnyMethodAdapter( asmCompiler.getClassVisitor(), ACC_PUBLIC, "__file__", getMethodSignature(4), null, null); method.start(); method.aload(SELF_INDEX); method.areturn(); method.end(); // __file__ method to call static version method = new SkinnyMethodAdapter( asmCompiler.getClassVisitor(), ACC_PUBLIC, "__file__", getMethodSignature(1), null, null); method.start(); // invoke static __file__ method.aload(THIS); method.aload(THREADCONTEXT_INDEX); method.aload(SELF_INDEX); method.aload(ARGS_INDEX); method.aload(ARGS_INDEX + 1); // block method.invokestatic( asmCompiler.getClassname(), "__file__", getStaticMethodSignature(asmCompiler.getClassname(), 1)); method.areturn(); method.end(); asmCompiler.endScript(false, false); byte[] bytes = asmCompiler.getClassByteArray(); Class blockClass = new JRubyClassLoader(context.runtime.getJRubyClassLoader()) .defineClass(asmCompiler.getClassname(), bytes); try { final AbstractScript script = (AbstractScript) blockClass.newInstance(); script.setRootScope(scope); return new CompiledBlockCallback() { @Override public IRubyObject call( ThreadContext context, IRubyObject self, IRubyObject args, Block block) { return script.__file__(context, self, args, block); } @Override public String getFile() { return "blah"; } @Override public int getLine() { return -1; } }; } catch (Exception e) { throw new RuntimeException(e); } }
public InterpretedBlock(IterNode iterNode, int argumentType) { this( iterNode, Arity.procArityOf(iterNode == null ? null : iterNode.getVarNode()), argumentType); }
/* * Determine what sort of assigner should be used for the provided 'iter' (e.g. block). * Assigner provides just the right logic for assigning values to local parameters of the * block. * * This method also has a second optimization which is to set 'noargblock' in the case that * the block is a block which accepts no arguments. The primary reason for this second * optimization is that in the case of a yield with a RubyArray we will bypass some logic * processing the RubyArray into a proper form (only to then not do anythign with it). A * secondary benefit is that a simple boolean seems to optimize by hotspot much faster * than the zero arg assigner. */ private void assignerFor(IterNode iter) { Node varNode = iter.getVarNode(); Node block = null; boolean hasBlock = block != null; if (varNode == null || varNode instanceof ZeroArgNode) { // No argument blocks noargblock = !hasBlock; assigner = hasBlock ? new Pre0Rest0Post0BlockAssigner(block) : new Pre0Rest0Post0Assigner(); } else if (varNode instanceof MultipleAsgnNode) { MultipleAsgnNode masgn = (MultipleAsgnNode) varNode; int preCount = masgn.getPreCount(); boolean isRest = masgn.getRest() != null; Node rest = masgn.getRest(); ListNode pre = masgn.getPre(); noargblock = false; switch (preCount) { case 0: // Not sure if this is actually possible, but better safe than sorry if (isRest) { assigner = hasBlock ? new Pre0Rest1Post0BlockAssigner(rest, block) : new Pre0Rest1Post0Assigner(rest); } else if (hasBlock) { assigner = new Pre0Rest0Post0BlockAssigner(block); } else { noargblock = true; assigner = new Pre0Rest0Post0Assigner(); } break; case 1: if (isRest) { assigner = hasBlock ? new Pre1Rest1Post0BlockAssigner(pre.get(0), rest, block) : new Pre1Rest1Post0Assigner(pre.get(0), rest); } else if (hasBlock) { assigner = new Pre1Rest0Post0BlockAssigner(pre.get(0), block); } else { assigner = new Pre1Rest0Post0Assigner(pre.get(0)); } break; case 2: if (isRest) { assigner = hasBlock ? new Pre2Rest1Post0BlockAssigner(pre.get(0), pre.get(1), rest, block) : new Pre2Rest1Post0Assigner(pre.get(0), pre.get(1), rest); } else if (hasBlock) { assigner = new Pre2Rest0Post0BlockAssigner(pre.get(0), pre.get(1), block); } else { assigner = new Pre2Rest0Post0Assigner(pre.get(0), pre.get(1)); } break; case 3: if (isRest) { assigner = hasBlock ? new Pre3Rest1Post0BlockAssigner( pre.get(0), pre.get(1), pre.get(2), rest, block) : new Pre3Rest1Post0Assigner(pre.get(0), pre.get(1), pre.get(2), rest); } else if (hasBlock) { assigner = new Pre3Rest0Post0BlockAssigner(pre.get(0), pre.get(1), pre.get(2), block); } else { assigner = new Pre3Rest0Post0Assigner(pre.get(0), pre.get(1), pre.get(2)); } break; default: if (isRest) { assigner = hasBlock ? new PreManyRest1Post0BlockAssigner(pre, preCount, rest, block) : new PreManyRest1Post0Assigner(pre, preCount, rest); } else if (hasBlock) { assigner = new PreManyRest0Post0BlockAssigner(pre, preCount, block); } else { assigner = new PreManyRest0Post0Assigner(pre, preCount); } break; } } else { assigner = hasBlock ? new Pre1ExpandedRest0Post0BlockAssigner(varNode, block) : new Pre1ExpandedRest0Post0Assigner(varNode); } }