Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 581abfc2320a
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 3bc5357f1c45
Choose a head ref
  • 11 commits
  • 15 files changed
  • 2 contributors

Commits on Dec 5, 2015

  1. Handle default block arg preparation logic

    * This was not as bad as I thought.
    * The only thing left to handle now is making sure these prepare args
      instructions handle lambdas as well.
    subbuss committed Dec 5, 2015
    Copy the full SHA
    5bb351f View commit details
  2. Add additional yieldDirect wrappers where they were missing

    * Also added FIXME for dealing with RubyProc.call since the
      current prepareArgs methods only deal with Block.yield.
    subbuss committed Dec 5, 2015
    Copy the full SHA
    9e38d83 View commit details
  3. [Truffle] Array storage must be Object[] not DynamicObject[].

    * Avoid copying when only reading from the Encoding list.
    eregon committed Dec 5, 2015
    Copy the full SHA
    0104c31 View commit details
  4. [Truffle] Check the class of Object[] storage strictly.

    * Avoids covariance problems and makes sure no type check is required on cast.
    eregon committed Dec 5, 2015
    Copy the full SHA
    3b3d19e View commit details

Commits on Dec 6, 2015

  1. Remove duplicate arity check when lambdas are call-ed

    * prepareArgumentsForCall does the arity check already.
    subbuss committed Dec 6, 2015
    Copy the full SHA
    926c76a View commit details
  2. Copy the full SHA
    47d6e92 View commit details
  3. Update prepareBlockArgs code to deal with lambdas & proc calls

    Added a new field to ThreadContext to pass additional information
    since Block.type and call/yield API calls may not be correlated.
    Something worth cleaning up in the future, but for now, the extra
    state in ThreadContext should be sufficient.
    subbuss committed Dec 6, 2015
    Copy the full SHA
    6e48810 View commit details
  4. Copy the full SHA
    28abe80 View commit details
  5. Copy the full SHA
    72b0912 View commit details
  6. [Truffle] PE: move the code in a method to make compilation faster.

    * Use a while loop to avoid compiling Kernel#loop.
    * Also remove Thread.pass which would be compiled every time.
    * Save the return value in a global variable.
    eregon committed Dec 6, 2015
    Copy the full SHA
    70603e3 View commit details
  7. Copy the full SHA
    3bc5357 View commit details
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package org.jruby.ir.instructions;

import java.util.Arrays;
import org.jruby.ir.IRVisitor;
import org.jruby.ir.Operation;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.ir.persistence.IRReaderDecoder;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.ir.transformations.inlining.SimpleCloneInfo;
import org.jruby.RubyHash;
import org.jruby.RubyArray;
import org.jruby.runtime.Block;
import org.jruby.runtime.BlockBody;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.Signature;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

@@ -28,9 +35,89 @@ public void visit(IRVisitor visitor) {
visitor.PrepareBlockArgsInstr(this);
}

protected IRubyObject[] toAry(ThreadContext context, IRubyObject[] args) {
if (args.length == 1 && args[0].respondsTo("to_ary")) {
IRubyObject newAry = Helpers.aryToAry(args[0]);
if (newAry.isNil()) {
args = new IRubyObject[] { args[0] };
} else if (newAry instanceof RubyArray) {
args = ((RubyArray) newAry).toJavaArray();
} else {
throw context.runtime.newTypeError(args[0].getType().getName() + "#to_ary should return Array");
}
}
return args;
}

protected IRubyObject[] prepareProcArgs(ThreadContext context, Block b, IRubyObject[] args) {
if (args.length == 1) {
int arityValue = b.getBody().getSignature().arityValue();
return IRRuntimeHelpers.convertValueIntoArgArray(context, args[0], arityValue, b.type == Block.Type.NORMAL && args[0] instanceof RubyArray);
} else {
return args;
}
}

public IRubyObject[] prepareBlockArgs(ThreadContext context, Block b, IRubyObject[] args) {
// SSS FIXME: Incomplete: This is the placeholder for
// scenarios not handled by specialized instructions.
// This is the placeholder for scenarios
// not handled by specialized instructions.
if (args == null) {
return IRubyObject.NULL_ARRAY;
}

boolean isProcCall = context.getCurrentBlockType() == Block.Type.PROC;
if (isProcCall) {
return prepareProcArgs(context, b, args);
}

boolean isLambda = b.type == Block.Type.LAMBDA;
if (isLambda && isProcCall) {
return args;
}

BlockBody body = b.getBody();
Signature sig = body.getSignature();

// blockArity == 0 and 1 have been handled in the specialized instructions
// This test is when we only have opt / rest arg (either keyword or non-keyword)
// but zero required args.
if (sig.arityValue() == -1) {
return args;
}

// We get here only when we have both required and optional/rest args
// (keyword or non-keyword in either case).
// So, convert a single value to an array if possible.
args = toAry(context, args);

// Nothing more to do for lambdas
if (isLambda) {
return args;
}

// Deal with keyword args that needs special handling
int needsKwargs = sig.hasKwargs() ? 1 - sig.getRequiredKeywordForArityCount() : 0;
int required = sig.required();
int actual = args.length;
if (needsKwargs == 0 || required > actual) {
// Nothing to do if we have fewer args in args than what is required
// The required arg instructions will return nil in those cases.
return args;
}

if (sig.isFixed() && required > 0 && required+needsKwargs != actual) {
// Make sure we have a ruby-hash
IRubyObject[] newArgs = Arrays.copyOf(args, required+needsKwargs);
if (actual < required+needsKwargs) {
// Not enough args and we need an empty {} for kwargs processing.
newArgs[newArgs.length - 1] = RubyHash.newHash(context.runtime);
} else {
// We have more args than we need and kwargs is always the last arg.
newArgs[newArgs.length - 1] = args[args.length - 1];
}
args = newArgs;
}

return args;
}
}
Original file line number Diff line number Diff line change
@@ -5,13 +5,10 @@
import org.jruby.ir.persistence.IRReaderDecoder;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.ir.transformations.inlining.SimpleCloneInfo;
import org.jruby.RubyArray;
import org.jruby.runtime.Block;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

//
public class PrepareFixedBlockArgsInstr extends PrepareBlockArgsInstr {
public PrepareFixedBlockArgsInstr() {
super(Operation.PREPARE_FIXED_BLOCK_ARGS);
@@ -28,22 +25,34 @@ public static PrepareFixedBlockArgsInstr decode(IRReaderDecoder d) {

public IRubyObject[] prepareBlockArgs(ThreadContext context, Block b, IRubyObject[] args) {
if (args == null) {
args = IRubyObject.NULL_ARRAY;
} else if (args.length == 1 && args[0].respondsTo("to_ary")) {
IRubyObject newAry = Helpers.aryToAry(args[0]);
if (newAry.isNil()) {
args = new IRubyObject[] { args[0] };
} else if (newAry instanceof RubyArray) {
args = ((RubyArray) newAry).toJavaArray();
} else {
throw context.runtime.newTypeError(args[0].getType().getName() + "#to_ary should return Array");
}
return IRubyObject.NULL_ARRAY;
}

boolean isProcCall = context.getCurrentBlockType() == Block.Type.PROC;
if (isProcCall) {
return prepareProcArgs(context, b, args);
}

boolean isLambda = b.type == Block.Type.LAMBDA;
if (isLambda && isProcCall) {
return args;
}

// SSS FIXME: This check here is not required as long as
// the single-instruction cases always uses PreapreSingleBlockArgInstr
// But, including this here for robustness for now.
if (b.getBody().getSignature().arityValue() == 1) {
return args;
}

// Since we have more than 1 required arg,
// convert a single value to an array if possible.
args = toAry(context, args);

// If there are insufficient args, ReceivePreReqdInstr will return nil
return args;
}

@Override
public void visit(IRVisitor visitor) {
visitor.PrepareFixedBlockArgsInstr(this);
Original file line number Diff line number Diff line change
@@ -25,6 +25,18 @@ public static PrepareSingleBlockArgInstr decode(IRReaderDecoder d) {

public IRubyObject[] prepareBlockArgs(ThreadContext context, Block b, IRubyObject[] args) {
if (args == null) args = IRubyObject.NULL_ARRAY;

// Deal with proc calls
if (context.getCurrentBlockType() == Block.Type.PROC) {
if (args.length == 0) {
args = context.runtime.getSingleNilArray();
} else if (args.length == 1) {
args = prepareProcArgs(context, b, args);
} else {
args = new IRubyObject[] { args[0] };
}
}

// Nothing more to do! Hurray!
// If there are insufficient args, ReceivePreReqdInstr will return nil
return args;
Original file line number Diff line number Diff line change
@@ -205,6 +205,7 @@ public IRubyObject interpret(ThreadContext context, Block block, IRubyObject sel
case PREPARE_FIXED_BLOCK_ARGS:
case PREPARE_BLOCK_ARGS:
args = ((PrepareBlockArgsInstr)instr).prepareBlockArgs(context, block, args);
if (block.type == Block.Type.LAMBDA) block.getBody().getSignature().checkArity(context.runtime, args);
break;
default:
processBookKeepingOp(context, block, instr, operation, name, args, self, blockArg, implClass, currDynScope, temp, currScope);
70 changes: 49 additions & 21 deletions core/src/main/java/org/jruby/runtime/BlockBody.java
Original file line number Diff line number Diff line change
@@ -65,20 +65,28 @@ public boolean hasCallProtocolIR() {
return false;
}

protected IRubyObject callDirect(ThreadContext context, Block block, IRubyObject[] args, Block blockArg) {
throw new RuntimeException("callDirect not implemented in base class. We should never get here.");
}

protected IRubyObject yieldDirect(ThreadContext context, Block block, IRubyObject[] args, IRubyObject self) {
throw new RuntimeException("yieldDirect not implemented in base class. We should never get here.");
}

public IRubyObject call(ThreadContext context, Block block, IRubyObject[] args) {
args = prepareArgumentsForCall(context, args, block.type);

return yield(context, block, args, null);
if (hasCallProtocolIR()) {
return callDirect(context, block, args, Block.NULL_BLOCK);
} else {
return yield(context, block, prepareArgumentsForCall(context, args, block.type), null);
}
}

public IRubyObject call(ThreadContext context, Block block, IRubyObject[] args, Block blockArg) {
args = prepareArgumentsForCall(context, args, block.type);

return yield(context, block, args, null, blockArg);
if (hasCallProtocolIR()) {
return callDirect(context, block, args, blockArg);
} else {
return yield(context, block, prepareArgumentsForCall(context, args, block.type), null, blockArg);
}
}

public final IRubyObject yield(ThreadContext context, Block block, IRubyObject value) {
@@ -128,9 +136,11 @@ public IRubyObject yield(ThreadContext context, Block block, IRubyObject value,

public IRubyObject call(ThreadContext context, Block block) {
IRubyObject[] args = IRubyObject.NULL_ARRAY;
args = prepareArgumentsForCall(context, args, block.type);

return yield(context, block, args, null);
if (hasCallProtocolIR()) {
return callDirect(context, block, args, Block.NULL_BLOCK);
} else {
return yield(context, block, prepareArgumentsForCall(context, args, block.type), null);
}
}

public IRubyObject call(ThreadContext context, Block block, Block unusedBlock) {
@@ -146,42 +156,60 @@ public IRubyObject yieldSpecific(ThreadContext context, Block block) {
}
public IRubyObject call(ThreadContext context, Block block, IRubyObject arg0) {
IRubyObject[] args = new IRubyObject[] {arg0};
args = prepareArgumentsForCall(context, args, block.type);

return yield(context, block, args, null);
if (hasCallProtocolIR()) {
return callDirect(context, block, args, Block.NULL_BLOCK);
} else {
return yield(context, block, prepareArgumentsForCall(context, args, block.type), null);
}
}
public IRubyObject call(ThreadContext context, Block block, IRubyObject arg0, Block unusedBlock) {
return call(context, block, arg0);
}

public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0) {
return yield(context, block, arg0);
if (hasCallProtocolIR()) {
return yieldDirect(context, block, new IRubyObject[] { arg0 }, null);
} else {
return yield(context, block, arg0);
}
}
public IRubyObject call(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1) {
IRubyObject[] args = new IRubyObject[] {arg0, arg1};
args = prepareArgumentsForCall(context, args, block.type);

return yield(context, block, args, null);
if (hasCallProtocolIR()) {
return callDirect(context, block, args, Block.NULL_BLOCK);
} else {
return yield(context, block, prepareArgumentsForCall(context, args, block.type), null);
}
}
public IRubyObject call(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, Block unusedBlock) {
return call(context, block, arg0, arg1);
}

public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1) {
return yield(context, block, new IRubyObject[] { arg0, arg1 }, null);
if (hasCallProtocolIR()) {
return yieldDirect(context, block, new IRubyObject[] { arg0, arg1 }, null);
} else {
return yield(context, block, new IRubyObject[] { arg0, arg1 }, null);
}
}
public IRubyObject call(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
IRubyObject[] args = new IRubyObject[] {arg0, arg1, arg2};
args = prepareArgumentsForCall(context, args, block.type);

return yield(context, block, args, null);
if (hasCallProtocolIR()) {
return callDirect(context, block, args, Block.NULL_BLOCK);
} else {
return yield(context, block, prepareArgumentsForCall(context, args, block.type), null);
}
}
public IRubyObject call(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block unusedBlock) {
return call(context, block, arg0, arg1, arg2);
}

public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
return yield(context, block, new IRubyObject[] { arg0, arg1, arg2 }, null);
if (hasCallProtocolIR()) {
return yieldDirect(context, block, new IRubyObject[] { arg0, arg1, arg2 }, null);
} else {
return yield(context, block, new IRubyObject[] { arg0, arg1, arg2 }, null);
}
}


Loading