Example #1
0
  @JRubyMethod
  public IRubyObject parameters(ThreadContext context) {
    BlockBody body = this.getBlock().getBody();

    return Helpers.argumentDescriptorsToParameters(
        context.runtime, body.getArgumentDescriptors(), isLambda());
  }
Example #2
0
 public IRubyObject yieldArray(ThreadContext context, IRubyObject value, IRubyObject self) {
   // SSS FIXME: Later on, we can move this code into IR insructions or
   // introduce a specialized entry-point when we know that this block has
   // explicit call protocol IR instructions.
   IRubyObject[] args;
   args = IRRuntimeHelpers.singleBlockArgToArray(value);
   return body.yield(context, this, args, self);
 }
Example #3
0
  /**
   * For Type.LAMBDA, ensures that the args have the correct arity.
   *
   * <p>For others, transforms the given arguments appropriately for the given arity (i.e. trimming
   * to one arg for fixed arity of one, etc.)
   */
  public static IRubyObject[] prepareArgs(
      ThreadContext context, Block.Type type, BlockBody blockBody, IRubyObject[] args) {
    Signature signature = blockBody.getSignature();

    if (args == null) return IRubyObject.NULL_ARRAY;

    if (type == Block.Type.LAMBDA) {
      signature.checkArity(context.runtime, args);
      return args;
    }

    boolean isFixed = signature.isFixed();
    int required = signature.required();
    int actual = args.length;
    boolean restKwargs =
        blockBody instanceof IRBlockBody && ((IRBlockBody) blockBody).getSignature().hasKwargs();

    // FIXME: This is a hot mess.  restkwargs factors into destructing a single element array as
    // well.  I just weaved it into this logic.
    // for procs and blocks, single array passed to multi-arg must be spread
    if ((signature != Signature.ONE_ARGUMENT
                && required != 0
                && (isFixed || signature != Signature.OPTIONAL)
            || restKwargs)
        && actual == 1
        && args[0].respondsTo("to_ary")) {
      IRubyObject newAry = Helpers.aryToAry(args[0]);

      // This is very common to yield in *IRBlockBody.  When we tackle call protocol for blocks this
      // will combine.
      if (newAry.isNil()) {
        args = new IRubyObject[] {args[0]};
      } else if (newAry instanceof RubyArray) {
        args = ((RubyArray) newAry).toJavaArrayMaybeUnsafe();
      } else {
        throw context.runtime.newTypeError(
            args[0].getType().getName() + "#to_ary should return Array");
      }
      actual = args.length;
    }

    // fixed arity > 0 with mismatch needs a new args array
    if (isFixed && required > 0 && required != actual) {
      IRubyObject[] newArgs = ArraySupport.newCopy(args, required);

      if (required > actual) { // Not enough required args pad.
        Helpers.fillNil(newArgs, actual, required, context.runtime);
      }

      args = newArgs;
    }

    return args;
  }
  // 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 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));
  }
Example #6
0
 public DynamicScope allocScope(DynamicScope parentScope) {
   // SSS: Important!  Use getStaticScope() to use a copy of the static-scope stored in the
   // block-body.
   // Do not use 'closure.getStaticScope()' -- that returns the original copy of the static scope.
   // This matters because blocks created for Thread bodies modify the static-scope field of the
   // block-body
   // that records additional state about the block body.
   //
   // FIXME: Rather than modify static-scope, it seems we ought to set a field in block-body which
   // is then
   // used to tell dynamic-scope that it is a dynamic scope for a thread body.  Anyway, to be
   // revisited later!
   EvalType evalType = ((IRBlockBody) body).getEvalType();
   DynamicScope newScope =
       DynamicScope.newDynamicScope(body.getStaticScope(), parentScope, evalType);
   if (type == Block.Type.LAMBDA) newScope.setLambda(true);
   return newScope;
 }
  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);
    }
  }
Example #9
0
 public Signature getSignature() {
   return body.getSignature();
 }
Example #10
0
 public IRubyObject call(ThreadContext context, Block blockArg) {
   return body.call(context, this, blockArg);
 }
Example #11
0
 public IRubyObject call(ThreadContext context, IRubyObject[] args) {
   return body.call(context, this, args);
 }
Example #12
0
 public IRubyObject yieldNonArray(ThreadContext context, IRubyObject value, IRubyObject self) {
   return body.yield(context, this, new IRubyObject[] {value}, self);
 }
Example #13
0
 public IRubyObject yield(ThreadContext context, IRubyObject value) {
   return body.yield(context, this, value);
 }
Example #14
0
 public IRubyObject yieldSpecific(
     ThreadContext context, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
   return body.yieldSpecific(context, this, arg0, arg1, arg2);
 }
Example #15
0
 public IRubyObject call(
     ThreadContext context, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block blockArg) {
   return body.call(context, this, arg0, arg1, arg2, blockArg);
 }
Example #16
0
 public IRubyObject call(
     ThreadContext context, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
   return body.call(context, this, arg0, arg1, arg2);
 }
Example #17
0
 public IRubyObject yieldSpecific(ThreadContext context) {
   return body.yieldSpecific(context, this);
 }
Example #18
0
 /**
  * What is the arity of this block?
  *
  * @return the arity
  */
 @Deprecated
 public Arity arity() {
   return body.getSignature().arity();
 }
Example #19
0
 public void setEvalType(EvalType evalType) {
   body.setEvalType(evalType);
 }
Example #20
0
 public IRubyObject call(ThreadContext context) {
   return body.call(context, this);
 }