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: 926c76ac1bb0
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 6e48810547fd
Choose a head ref
  • 2 commits
  • 8 files changed
  • 1 contributor

Commits on Dec 6, 2015

  1. Copy the full SHA
    47d6e92 View commit details
  2. 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
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
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;
@@ -48,24 +49,39 @@ protected IRubyObject[] toAry(ThreadContext context, IRubyObject[] args) {
return args;
}

// SSS FIXME: This code only works for block yields, not rubyproc calls.
// When a block is converted to a RubyProc and called, this code below
// needs to implement the logic in BlockBody:prepareArgumentsForCall.
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) {
// 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.
int blockArity = sig.arityValue();
if (blockArity == -1) {
if (sig.arityValue() == -1) {
return args;
}

@@ -74,6 +90,11 @@ public IRubyObject[] prepareBlockArgs(ThreadContext context, Block b, IRubyObjec
// 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();
Original file line number Diff line number Diff line change
@@ -28,11 +28,20 @@ public IRubyObject[] prepareBlockArgs(ThreadContext context, Block b, IRubyObjec
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.
int blockArity = b.getBody().getSignature().arityValue();
if (blockArity == 1) {
if (b.getBody().getSignature().arityValue() == 1) {
return args;
}

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);
52 changes: 34 additions & 18 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,9 +156,11 @@ 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);
@@ -163,9 +175,11 @@ public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject
}
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);
@@ -180,9 +194,11 @@ public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject
}
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);
6 changes: 5 additions & 1 deletion core/src/main/java/org/jruby/runtime/IRBlockBody.java
Original file line number Diff line number Diff line change
@@ -63,7 +63,11 @@ public IRubyObject call(ThreadContext context, Block block, IRubyObject[] args)

@Override
public IRubyObject call(ThreadContext context, Block block, IRubyObject[] args, Block blockArg) {
return commonYieldPath(context, block, prepareArgumentsForCall(context, args, block.type), null, blockArg);
if (hasCallProtocolIR()) {
return callDirect(context, block, args, blockArg);
} else {
return commonYieldPath(context, block, prepareArgumentsForCall(context, args, block.type), null, blockArg);
}
}

@Override
Original file line number Diff line number Diff line change
@@ -78,8 +78,15 @@ public String getName() {
return null;
}

@Override
protected IRubyObject callDirect(ThreadContext context, Block block, IRubyObject[] args, Block blockArg) {
context.setCurrentBlockType(Block.Type.PROC);
return Interpreter.INTERPRET_BLOCK(context, block, null, interpreterContext, args, block.getBinding().getMethod(), blockArg);
}

@Override
protected IRubyObject yieldDirect(ThreadContext context, Block block, IRubyObject[] args, IRubyObject self) {
context.setCurrentBlockType(Block.Type.NORMAL);
return Interpreter.INTERPRET_BLOCK(context, block, self, interpreterContext, args, block.getBinding().getMethod(), Block.NULL_BLOCK);
}

11 changes: 11 additions & 0 deletions core/src/main/java/org/jruby/runtime/ThreadContext.java
Original file line number Diff line number Diff line change
@@ -128,6 +128,8 @@ public static ThreadContext newContext(Ruby runtime) {

IRubyObject lastExitStatus;

private Block.Type currentBlockType;

public final SecureRandom secureRandom = getSecureRandom();

private static boolean trySHA1PRNG = true;
@@ -151,6 +153,7 @@ private static SecureRandom getSecureRandom() {
private ThreadContext(Ruby runtime) {
this.runtime = runtime;
this.nil = runtime.getNil();
this.currentBlockType = Block.Type.NORMAL;

if (runtime.getInstanceConfig().isProfilingEntireRun()) {
startProfiling();
@@ -207,6 +210,14 @@ public IRubyObject setErrorInfo(IRubyObject errorInfo) {
return errorInfo;
}

public Block.Type getCurrentBlockType() {
return currentBlockType;
}

public void setCurrentBlockType(Block.Type type) {
currentBlockType = type;
}

public CallType getLastCallType() {
return lastCallType;
}