Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions core/src/main/java/org/jruby/RubyModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -772,9 +772,8 @@ private static RubyClass refinementSuperclass(Ruby runtime, RubyModule superClas
}

private void yieldRefineBlock(ThreadContext context, RubyModule refinement, Block block) {
block = block.cloneBlockAndFrame();
block = block.cloneBlockAndFrame(EvalType.MODULE_EVAL);

block.setEvalType(EvalType.MODULE_EVAL);
block.getBinding().setSelf(refinement);

RubyModule overlayModule = block.getBody().getStaticScope().getOverlayModuleForWrite(context);
Expand Down
66 changes: 56 additions & 10 deletions core/src/main/java/org/jruby/RubyProc.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.marshal.DataType;

import static org.jruby.runtime.Helpers.arrayOf;
import static org.jruby.util.RubyStringBuilder.types;

/**
Expand Down Expand Up @@ -174,7 +175,7 @@ private void setup(Block procBlock) {
oldBinding.getMethod(),
oldBinding.getFile(),
oldBinding.getLine());
block = new Block(procBlock.getBody(), newBinding);
block = new Block(procBlock.getBody(), newBinding, type);

// Mark as escaped, so non-local flow errors immediately
block.escape();
Expand All @@ -184,15 +185,18 @@ private void setup(Block procBlock) {
StaticScope newScope = oldScope.duplicate();
block.getBody().setStaticScope(newScope);
} else {
// just use as is
block = procBlock;
// just use as is unless type differs
if (type != procBlock.type) {
block = procBlock.cloneBlockAsType(type);
} else {
block = procBlock;
}
}

// force file/line info into the new block's binding
block.getBinding().setFile(block.getBody().getFile());
block.getBinding().setLine(block.getBody().getLine());

block.type = type;
block.setProcObject(this);

// pre-request dummy scope to avoid clone overhead in lightweight blocks
Expand Down Expand Up @@ -258,11 +262,52 @@ public static IRubyObject[] prepareArgs(ThreadContext context, Block.Type type,
return args;
}

private static IRubyObject[] checkArityForLambda(ThreadContext context, Block.Type type, BlockBody blockBody, IRubyObject... args) {
if (type == Block.Type.LAMBDA) {
blockBody.getSignature().checkArity(context.runtime, args);
}

return args;
}

@JRubyMethod(name = {"call", "[]", "yield", "==="}, rest = true, omit = true)
public final IRubyObject call(ThreadContext context, IRubyObject[] args, Block blockCallArg) {
IRubyObject[] preppedArgs = prepareArgs(context, type, block.getBody(), args);
return block.call(
context,
prepareArgs(context, type, block.getBody(), args),
blockCallArg);
}

@JRubyMethod(name = {"call", "[]", "yield", "==="}, omit = true)
public final IRubyObject call(ThreadContext context, Block blockCallArg) {
return block.call(
context,
checkArityForLambda(context, type, block.getBody(), NULL_ARRAY),
blockCallArg);
}

return call(context, preppedArgs, null, blockCallArg);
@JRubyMethod(name = {"call", "[]", "yield", "==="}, omit = true)
public final IRubyObject call(ThreadContext context, IRubyObject arg0, Block blockCallArg) {
return block.call(
context,
prepareArgs(context, type, block.getBody(), arrayOf(arg0)),
blockCallArg);
}

@JRubyMethod(name = {"call", "[]", "yield", "==="}, omit = true)
public final IRubyObject call(ThreadContext context, IRubyObject arg0, IRubyObject arg1, Block blockCallArg) {
return block.call(
context,
checkArityForLambda(context, type, block.getBody(), arg0, arg1),
blockCallArg);
}

@JRubyMethod(name = {"call", "[]", "yield", "==="}, omit = true)
public final IRubyObject call(ThreadContext context, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block blockCallArg) {
return block.call(
context,
checkArityForLambda(context, type, block.getBody(), arg0, arg1, arg2),
blockCallArg);
}

public final IRubyObject call(ThreadContext context, IRubyObject arg) {
Expand All @@ -273,10 +318,6 @@ public final IRubyObject call(ThreadContext context, IRubyObject... args) {
return block.call(context, args);
}

public final IRubyObject call(ThreadContext context, IRubyObject[] args, IRubyObject self, Block passedBlock) {
return call(context, args, self, null, passedBlock);
}

public final IRubyObject call(ThreadContext context, IRubyObject[] args, IRubyObject self, RubyModule sourceModule, Block passedBlock) {
assert args != null;

Expand Down Expand Up @@ -369,4 +410,9 @@ public IRubyObject to_s19() {
return to_s();
}

@Deprecated
public final IRubyObject call(ThreadContext context, IRubyObject[] args, IRubyObject self, Block passedBlock) {
return block.call(context, args, passedBlock);
}

}
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/RubyStruct.java
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ public static RubyClass newInstance(IRubyObject recv, IRubyObject[] args, Block

if (block.isGiven()) {
// Since this defines a new class, run the block as a module-eval.
block.setEvalType(EvalType.MODULE_EVAL);
block = block.cloneBlockForEval(newStruct, EvalType.MODULE_EVAL);
// Struct bodies should be public by default, so set block visibility to public. JRUBY-1185.
block.getBinding().setVisibility(Visibility.PUBLIC);
block.yieldNonArray(runtime.getCurrentContext(), newStruct, newStruct);
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/instructions/CallBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public abstract class CallBase extends NOperandInstr implements ClosureAccepting
private transient boolean targetRequiresCallersFrame; // Does this call make use of the caller's frame?
private transient boolean dontInline;
private transient boolean[] splatMap;
private transient boolean procNew;
protected transient boolean procNew;
private boolean potentiallyRefined;
private transient Set<FrameField> frameReads;
private transient Set<FrameField> frameWrites;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,12 @@ public ZeroOperandArgNoBlockCallInstr(IRScope scope, CallType callType, Variable

@Override
public Instr clone(CloneInfo ii) {
return new ZeroOperandArgNoBlockCallInstr(ii.getScope(), getOperation(), getCallType(), ii.getRenamedVariable(result), getName(),
ZeroOperandArgNoBlockCallInstr zeroOperandArgNoBlockCallInstr = new ZeroOperandArgNoBlockCallInstr(ii.getScope(), getOperation(), getCallType(), ii.getRenamedVariable(result), getName(),
getReceiver().cloneForInlining(ii), cloneCallArgs(ii), isPotentiallyRefined(), getCallSite(), getCallSiteId());

zeroOperandArgNoBlockCallInstr.setProcNew(procNew);

return zeroOperandArgNoBlockCallInstr;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ public Object execute(IRScope scope, Object... data) {
// to allocate a dynamic scope for it and add binding push/pop instructions.
if (!explicitCallProtocolSupported(scope)) return null;

scope.getFlags().remove(IRFlags.FLAGS_COMPUTED);
scope.computeScopeFlags();

CFG cfg = scope.getCFG();

// For now, we always require frame for closures
Expand Down
3 changes: 0 additions & 3 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -2050,9 +2050,6 @@ public static IRubyObject updateBlockState(Block block, IRubyObject self) {
self = useBindingSelf(block.getBinding());
}

// Clear block's eval type
block.setEvalType(EvalType.NONE);

// Return self in case it has been updated
return self;
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/targets/Bootstrap.java
Original file line number Diff line number Diff line change
Expand Up @@ -1370,7 +1370,7 @@ static String logMethod(DynamicMethod method) {
}

static String logBlock(Block block) {
return "[" + block.getBody() + " " + block.getFrame() + "]";
return "[" + block.getBody().getFile() + ":" + block.getBody().getLine() + "]";
}

private static final Binder BINDING_MAKER_BINDER = Binder.from(Binding.class, ThreadContext.class, IRubyObject.class, DynamicScope.class);
Expand Down
99 changes: 57 additions & 42 deletions core/src/main/java/org/jruby/ir/targets/YieldSite.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
*/
public class YieldSite extends MutableCallSite {
private final boolean unwrap;
private int bindCount;

private static final int MAX_REBIND = 2;

private static final Logger LOG = LoggerFactory.getLogger(YieldSite.class);

Expand Down Expand Up @@ -71,71 +74,83 @@ public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, Metho

public IRubyObject yield(ThreadContext context, Block block, IRubyObject arg) throws Throwable {
if (Options.INVOKEDYNAMIC_YIELD.load()) {
BlockBody body = block.getBody();
MethodHandle target;

if (block.getBody() instanceof CompiledIRBlockBody) {
CompiledIRBlockBody compiledBody = (CompiledIRBlockBody) block.getBody();

if (++bindCount >= MAX_REBIND) {
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) {
LOG.info("yield \tbound directly as yield:" + Bootstrap.logBlock(block));
LOG.info("yield \tdisabled due to polymorphism:" + Bootstrap.logBlock(block));
}

target = unwrap ? compiledBody.getNormalYieldUnwrapHandle() : compiledBody.getNormalYieldHandle();
} else {
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) {
LOG.info("yield \tbound indirectly as yield:" + Bootstrap.logBlock(block));
}
BlockBody body = block.getBody();
MethodHandle target;

target = Binder.from(type())
.append(unwrap)
.invokeStaticQuiet(MethodHandles.lookup(), IRRuntimeHelpers.class, "yield");
}
if (block.getBody() instanceof CompiledIRBlockBody) {
CompiledIRBlockBody compiledBody = (CompiledIRBlockBody) block.getBody();

if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) {
LOG.info("yield \tbound directly as yield:" + Bootstrap.logBlock(block));
}

target = unwrap ? compiledBody.getNormalYieldUnwrapHandle() : compiledBody.getNormalYieldHandle();
} else {
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) {
LOG.info("yield \tbound indirectly as yield:" + Bootstrap.logBlock(block));
}

MethodHandle fallback = getTarget();
MethodHandle test = body.getTestBlockBody();
target = Binder.from(type())
.append(unwrap)
.invokeStaticQuiet(MethodHandles.lookup(), IRRuntimeHelpers.class, "yield");
}

MethodHandle fallback = getTarget();
MethodHandle test = body.getTestBlockBody();

MethodHandle guard = MethodHandles.guardWithTest(test, target, fallback);
MethodHandle guard = MethodHandles.guardWithTest(test, target, fallback);

setTarget(guard);
setTarget(guard);

return (IRubyObject) target.invokeExact(context, block, arg);
return (IRubyObject) target.invokeExact(context, block, arg);
}
}

return IRRuntimeHelpers.yield(context, block, arg, unwrap);
}

public IRubyObject yieldSpecific(ThreadContext context, Block block) throws Throwable {
if (Options.INVOKEDYNAMIC_YIELD.load()) {
BlockBody body = block.getBody();
MethodHandle target;

if (block.getBody() instanceof CompiledIRBlockBody) {
CompiledIRBlockBody compiledBody = (CompiledIRBlockBody) block.getBody();

if (++bindCount >= MAX_REBIND) {
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) {
LOG.info("yield \tbound directly as yieldSpecific:" + Bootstrap.logBlock(block));
LOG.info("yield \tdisabled due to polymorphism:" + Bootstrap.logBlock(block));
}

target = compiledBody.getNormalYieldSpecificHandle();
} else {
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) {
LOG.info("yield \tbound indirectly as yieldSpecific:" + Bootstrap.logBlock(block));
}
BlockBody body = block.getBody();
MethodHandle target;

target = Binder.from(type())
.permute(1, 0)
.invokeVirtualQuiet(MethodHandles.lookup(), "yieldSpecific");
}
if (block.getBody() instanceof CompiledIRBlockBody) {
CompiledIRBlockBody compiledBody = (CompiledIRBlockBody) block.getBody();

MethodHandle fallback = getTarget();
MethodHandle test = body.getTestBlockBody();
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) {
LOG.info("yield \tbound directly as yieldSpecific:" + Bootstrap.logBlock(block));
}

MethodHandle guard = MethodHandles.guardWithTest(test, target, fallback);
target = compiledBody.getNormalYieldSpecificHandle();
} else {
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) {
LOG.info("yield \tbound indirectly as yieldSpecific:" + Bootstrap.logBlock(block));
}

setTarget(guard);
target = Binder.from(type())
.permute(1, 0)
.invokeVirtualQuiet(MethodHandles.lookup(), "yieldSpecific");
}

MethodHandle fallback = getTarget();
MethodHandle test = body.getTestBlockBody();

MethodHandle guard = MethodHandles.guardWithTest(test, target, fallback);

return (IRubyObject) target.invokeExact(context, block);
setTarget(guard);

return (IRubyObject) target.invokeExact(context, block);
}
}

return block.yieldSpecific(context);
Expand Down
Loading