Skip to content

Commit

Permalink
Showing 7 changed files with 79 additions and 71 deletions.
6 changes: 1 addition & 5 deletions core/src/main/java/org/jruby/ir/instructions/CallBase.java
Original file line number Diff line number Diff line change
@@ -423,11 +423,7 @@ public Object interpret(ThreadContext context, StaticScope currScope, DynamicSco
Block preparedBlock = prepareBlock(context, self, currScope, dynamicScope, temp);

if (hasLiteralClosure()) {
try {
return callSite.call(context, self, object, values, preparedBlock);
} finally {
preparedBlock.escape();
}
return callSite.callIter(context, self, object, values, preparedBlock);
}

return callSite.call(context, self, object, values, preparedBlock);
Original file line number Diff line number Diff line change
@@ -27,9 +27,15 @@ public Instr clone(CloneInfo ii) {

@Override
public Object interpret(ThreadContext context, StaticScope currScope, DynamicScope dynamicScope, IRubyObject self, Object[] temp) {
// NOTE: This logic shouod always match the CALL_10B logic in InterpreterEngine.processCall
IRubyObject object = (IRubyObject) getReceiver().retrieve(context, self, currScope, dynamicScope, temp);
IRubyObject arg1 = (IRubyObject) getArg1().retrieve(context, self, currScope, dynamicScope, temp);
Block preparedBlock = prepareBlock(context, self, currScope, dynamicScope, temp);

if (hasLiteralClosure()) {
return getCallSite().callIter(context, self, object, arg1, preparedBlock);
}

return getCallSite().call(context, self, object, arg1, preparedBlock);
}
}
Original file line number Diff line number Diff line change
@@ -57,6 +57,7 @@
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block;
import org.jruby.runtime.CallSite;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.Frame;
import org.jruby.runtime.Helpers;
@@ -325,11 +326,15 @@ protected static void processCall(ThreadContext context, Instr instr, Operation
break;
}
case CALL_1OB: {
// NOTE: This logic shouod always match OneOperandArgBlockCallInstr
OneOperandArgBlockCallInstr call = (OneOperandArgBlockCallInstr)instr;
IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp);
IRubyObject o = (IRubyObject)call.getArg1().retrieve(context, self, currScope, currDynScope, temp);
Block preparedBlock = call.prepareBlock(context, self, currScope, currDynScope, temp);
result = call.getCallSite().callIter(context, self, r, o, preparedBlock);
CallSite callSite = call.getCallSite();
result = call.hasLiteralClosure() ?
callSite.callIter(context, self, r, o, preparedBlock) :
callSite.call(context, self, r, o, preparedBlock);
setResult(temp, currDynScope, call.getResult(), result);
break;
}
45 changes: 10 additions & 35 deletions core/src/main/java/org/jruby/runtime/callsite/CachingCallSite.java
Original file line number Diff line number Diff line change
@@ -72,7 +72,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s
return cacheAndCall(caller, selfType, args, context, self);
}

private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject[] args, Block block) {
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject[] args, Block block) {
RubyClass selfType = getClass(self);
// This must be retrieved *once* to avoid racing with other threads.
CacheEntry cache = this.cache;
@@ -82,16 +82,11 @@ private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyOb
return cacheAndCall(caller, selfType, block, args, context, self);
}

@Override
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject[] args, Block block) {
return callBlock(context, caller, self, args, block);
}

@Override
public final IRubyObject callIter(ThreadContext context, IRubyObject caller, IRubyObject self,
IRubyObject[] args, Block block) {
try {
return callBlock(context, caller, self, args, block);
return call(context, caller, self, args, block);
} finally {
block.escape();
}
@@ -144,7 +139,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s
return cacheAndCall(caller, selfType, context, self);
}

private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyObject self, Block block) {
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, Block block) {
RubyClass selfType = getClass(self);
// This must be retrieved *once* to avoid racing with other threads.
CacheEntry cache = this.cache;
@@ -154,16 +149,11 @@ private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyOb
return cacheAndCall(caller, selfType, block, context, self);
}

@Override
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, Block block) {
return callBlock(context, caller, self, block);
}

@Override
public final IRubyObject callIter(ThreadContext context, IRubyObject caller, IRubyObject self,
Block block) {
try {
return callBlock(context, caller, self, block);
return call(context, caller, self, block);
} finally {
block.escape();
}
@@ -180,7 +170,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s
return cacheAndCall(caller, selfType, context, self, arg1);
}

private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, Block block) {
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, Block block) {
RubyClass selfType = getClass(self);
// This must be retrieved *once* to avoid racing with other threads.
CacheEntry cache = this.cache;
@@ -190,16 +180,11 @@ private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyOb
return cacheAndCall(caller, selfType, block, context, self, arg1);
}

@Override
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, Block block) {
return callBlock(context, caller, self, arg1, block);
}

@Override
public final IRubyObject callIter(ThreadContext context, IRubyObject caller, IRubyObject self,
IRubyObject arg1, Block block) {
try {
return callBlock(context, caller, self, arg1, block);
return call(context, caller, self, arg1, block);
} finally {
block.escape();
}
@@ -216,7 +201,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s
return cacheAndCall(caller, selfType, context, self, arg1, arg2);
}

private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, IRubyObject arg2, Block block) {
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, IRubyObject arg2, Block block) {
RubyClass selfType = getClass(self);
// This must be retrieved *once* to avoid racing with other threads.
CacheEntry cache = this.cache;
@@ -226,16 +211,11 @@ private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyOb
return cacheAndCall(caller, selfType, block, context, self, arg1, arg2);
}

@Override
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, IRubyObject arg2, Block block) {
return callBlock(context, caller, self, arg1, arg2, block);
}

@Override
public final IRubyObject callIter(ThreadContext context, IRubyObject caller, IRubyObject self,
IRubyObject arg1, IRubyObject arg2, Block block) {
try {
return callBlock(context, caller, self, arg1, arg2, block);
return call(context, caller, self, arg1, arg2, block);
} finally {
block.escape();
}
@@ -252,7 +232,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s
return cacheAndCall(caller, selfType, context, self, arg1, arg2, arg3);
}

private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, Block block) {
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, Block block) {
RubyClass selfType = getClass(self);
// This must be retrieved *once* to avoid racing with other threads.
CacheEntry cache = this.cache;
@@ -262,16 +242,11 @@ private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyOb
return cacheAndCall(caller, selfType, block, context, self, arg1, arg2, arg3);
}

@Override
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, Block block) {
return callBlock(context, caller, self, arg1, arg2, arg3, block);
}

@Override
public final IRubyObject callIter(ThreadContext context, IRubyObject caller, IRubyObject self,
IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, Block block) {
try {
return callBlock(context, caller, self, arg1, arg2, arg3, block);
return call(context, caller, self, arg1, arg2, arg3, block);
} finally {
block.escape();
}
40 changes: 10 additions & 30 deletions core/src/main/java/org/jruby/runtime/callsite/SuperCallSite.java
Original file line number Diff line number Diff line change
@@ -55,7 +55,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s
return cacheAndCall(caller, selfType, args, context, self, name);
}

private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject[] args, Block block) {
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject[] args, Block block) {
RubyModule klazz = context.getFrameKlazz();
String name = context.getFrameName();
RubyClass selfType = pollAndGetClass(context, self, klazz, name);
@@ -67,13 +67,9 @@ private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyOb
return cacheAndCall(caller, selfType, block, args, context, self, name);
}

public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject[] args, Block block) {
return callBlock(context, caller, self, args, block);
}

public IRubyObject callIter(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject[] args, Block block) {
try {
return callBlock(context, caller, self, args, block);
return call(context, caller, self, args, block);
} finally {
block.escape();
}
@@ -121,7 +117,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s
return cacheAndCall(caller, selfType, context, self, name);
}

private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyObject self, Block block) {
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, Block block) {
RubyModule klazz = context.getFrameKlazz();
String name = context.getFrameName();
RubyClass selfType = pollAndGetClass(context, self, klazz, name);
@@ -133,13 +129,9 @@ private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyOb
return cacheAndCall(caller, selfType, block, context, self, name);
}

public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, Block block) {
return callBlock(context, caller, self, block);
}

public IRubyObject callIter(ThreadContext context, IRubyObject caller, IRubyObject self, Block block) {
try {
return callBlock(context, caller, self, block);
return call(context, caller, self, block);
} finally {
block.escape();
}
@@ -157,7 +149,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s
return cacheAndCall(caller, selfType, context, self, name, arg1);
}

private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, Block block) {
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, Block block) {
RubyModule klazz = context.getFrameKlazz();
String name = context.getFrameName();
RubyClass selfType = pollAndGetClass(context, self, klazz, name);
@@ -169,13 +161,9 @@ private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyOb
return cacheAndCall(caller, selfType, block, context, self, name, arg1);
}

public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, Block block) {
return callBlock(context, caller, self, arg1, block);
}

public IRubyObject callIter(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, Block block) {
try {
return callBlock(context, caller, self, arg1, block);
return call(context, caller, self, arg1, block);
} finally {
block.escape();
}
@@ -193,7 +181,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s
return cacheAndCall(caller, selfType, context, self, name, arg1, arg2);
}

private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, IRubyObject arg2, Block block) {
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, IRubyObject arg2, Block block) {
RubyModule klazz = context.getFrameKlazz();
String name = context.getFrameName();
RubyClass selfType = pollAndGetClass(context, self, klazz, name);
@@ -205,13 +193,9 @@ private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyOb
return cacheAndCall(caller, selfType, block, context, self, name, arg1, arg2);
}

public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, IRubyObject arg2, Block block) {
return callBlock(context, caller, self, arg1, arg2, block);
}

public IRubyObject callIter(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, IRubyObject arg2, Block block) {
try {
return callBlock(context, caller, self, arg1, arg2, block);
return call(context, caller, self, arg1, arg2, block);
} finally {
block.escape();
}
@@ -229,7 +213,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s
return cacheAndCall(caller, selfType, context, self, name, arg1, arg2, arg3);
}

private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, Block block) {
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, Block block) {
RubyModule klazz = context.getFrameKlazz();
String name = context.getFrameName();
RubyClass selfType = pollAndGetClass(context, self, klazz, name);
@@ -241,13 +225,9 @@ private IRubyObject callBlock(ThreadContext context, IRubyObject caller, IRubyOb
return cacheAndCall(caller, selfType, block, context, self, name, arg1, arg2, arg3);
}

public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, Block block) {
return callBlock(context, caller, self, arg1, arg2, arg3, block);
}

public IRubyObject callIter(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, Block block) {
try {
return callBlock(context, caller, self, arg1, arg2, arg3, block);
return call(context, caller, self, arg1, arg2, arg3, block);
} finally {
block.escape();
}
18 changes: 18 additions & 0 deletions spec/ruby/language/break_spec.rb
Original file line number Diff line number Diff line change
@@ -24,6 +24,24 @@
value.should == :value
end
end

describe "captured and delegated to another method repeatedly" do
it "breaks out of the block" do
@program.looped_break_in_captured_block
ScratchPad.recorded.should == [:begin,
:preloop,
:predele,
:preyield,
:prebreak,
:postbreak,
:postyield,
:postdele,
:predele,
:preyield,
:prebreak,
:end]
end
end
end

describe "The break statement in a captured block" do
28 changes: 28 additions & 0 deletions spec/ruby/language/fixtures/break.rb
Original file line number Diff line number Diff line change
@@ -106,6 +106,34 @@ def break_in_yielding_method
note :d
end

def looped_break_in_captured_block
note :begin
looped_delegate_block do |i|
note :prebreak
break if i == 1
note :postbreak
end
note :end
end

def looped_delegate_block(&block)
note :preloop
2.times do |i|
note :predele
yield_value(i, &block)
note :postdele
end
note :postloop
end
private :looped_delegate_block

def yield_value(value)
note :preyield
yield value
note :postyield
end
private :yield_value

def method(v)
yield v
end

0 comments on commit 2e10a4e

Please sign in to comment.