Beispiel #1
0
  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);
  }
Beispiel #2
0
  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));
  }
Beispiel #4
0
  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);
    }
  }
Beispiel #9
0
 public InterpretedBlock(IterNode iterNode, int argumentType) {
   this(
       iterNode, Arity.procArityOf(iterNode == null ? null : iterNode.getVarNode()), argumentType);
 }
Beispiel #10
0
  /*
   * 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);
    }
  }