Skip to content

Commit

Permalink
Showing 2 changed files with 79 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package org.jruby.ir.instructions;

import java.util.Arrays;
import org.jruby.ir.IRVisitor;
import org.jruby.ir.Operation;
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 +34,66 @@ 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;
}

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;
}

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) {
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);

// 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,25 @@ 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;
}

// 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) {
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);

0 comments on commit 5bb351f

Please sign in to comment.