@Override public Instr cloneForInlining(InlinerInfo ii) { return new BreakInstr(returnValue.cloneForInlining(ii), scopeToReturnTo); }
@Override public Instr clone(CloneInfo info) { if (info instanceof SimpleCloneInfo) return new BreakInstr(getReturnValue().cloneForInlining(info), scopeName); return (v == null) ? null : new CopyInstr(v, getReturnValue().cloneForInlining(ii)); return new BreakInstr(getReturnValue().cloneForInlining(ii), scopeName); } else { throw new UnsupportedOperationException("Break instructions shouldn't show up outside closures.");
public Operand getReturnValue() { return getOperand1(); }
@Override public void encode(IRWriterEncoder e) { super.encode(e); e.encode(getReturnValue()); e.encode(getScopeName()); }
@Override public void BreakInstr(BreakInstr breakInstr) { IRBytecodeAdapter m = jvm.method(); SkinnyMethodAdapter a = m.adapter; m.loadLocal(0); // context a.aload(1); // current scope // FIXME: This can also be done in the helper itself m.invokeVirtual(Type.getType(IRScope.class), Method.getMethod("org.jruby.ir.IRScope getIRScope()")); a.ldc(breakInstr.getScopeToReturnTo().getScopeId()); visit(breakInstr.getReturnValue()); // FIXME: emit block-type for the scope that is currently executing // For now, it is null m.pushNil(); a.invokestatic(p(IRubyObject.class), "initiateBreak", sig(ThreadContext.class, IRScope.class, IRScope.class, IRubyObject.class, Block.Type.class)); }
@Override public void BreakInstr(BreakInstr breakInstr) { jvmMethod().loadContext(); jvmLoadLocal(DYNAMIC_SCOPE); visit(breakInstr.getReturnValue()); jvmMethod().loadSelfBlock(); jvmAdapter().invokestatic(p(IRRuntimeHelpers.class), "initiateBreak", sig(IRubyObject.class, ThreadContext.class, DynamicScope.class, IRubyObject.class, Block.class)); jvmMethod().returnValue(); }
@Override public String toString() { return getOperation() + "(" + returnValue + (scopeToReturnTo == null ? "" : ", " + scopeToReturnTo) + ")"; }
@Override public Instr cloneForInlinedScope(InlinerInfo ii) { if (ii.getInlineHostScope() == scopeToReturnTo) { // If the break got inlined into the scope we had to break to, replace the break // with a COPY of the break-value into the call's result var. // Ex: v = foo { ..; break n; ..}. So, "break n" is replaced with "v = n" // The CFG for the closure will be such that after break, control goes to the // scope exit block. So, we know that after the copy, we'll continue with the // instruction after the call. Variable v = ii.getCallResultVariable(); return (v == null) ? null : new CopyInstr(v, returnValue.cloneForInlining(ii)); } else { return cloneForInlining(ii); } }
case BLOCK_GIVEN: return BlockGivenInstr.decode(this); case BNE: return BNEInstr.decode(this); case BREAK: return BreakInstr.decode(this); case BUILD_BACKREF: return BuildBackrefInstr.decode(this); case BUILD_COMPOUND_ARRAY: return BuildCompoundArrayInstr.decode(this);
@Override public void BreakInstr(BreakInstr breakInstr) { IRBytecodeAdapter m = jvm.method(); SkinnyMethodAdapter a = m.adapter; m.loadLocal(0); // context a.aload(1); // current scope // FIXME: This can also be done in the helper itself m.invokeVirtual(Type.getType(IRScope.class), Method.getMethod("org.jruby.ir.IRScope getIRScope()")); a.ldc(breakInstr.getScopeToReturnTo().getScopeId()); visit(breakInstr.getReturnValue()); // FIXME: emit block-type for the scope that is currently executing // For now, it is null m.pushNil(); a.invokestatic(p(IRubyObject.class), "initiateBreak", sig(ThreadContext.class, IRScope.class, IRScope.class, IRubyObject.class, Block.Type.class)); }
@Override public void encode(IRWriterEncoder e) { super.encode(e); e.encode(getReturnValue()); e.encode(getScopeName()); }
@Override public void BreakInstr(BreakInstr breakInstr) { jvmMethod().loadContext(); jvmLoadLocal(DYNAMIC_SCOPE); visit(breakInstr.getReturnValue()); jvmMethod().loadSelfBlock(); jvmAdapter().invokestatic(p(IRRuntimeHelpers.class), "initiateBreak", sig(IRubyObject.class, ThreadContext.class, DynamicScope.class, IRubyObject.class, Block.class)); jvmMethod().returnValue(); }
@Override public String toString() { return getOperation() + "(" + returnValue + (scopeToReturnTo == null ? "" : ", " + scopeToReturnTo) + ")"; }
@Override public Instr cloneForInlinedScope(InlinerInfo ii) { if (ii.getInlineHostScope() == scopeToReturnTo) { // If the break got inlined into the scope we had to break to, replace the break // with a COPY of the break-value into the call's result var. // Ex: v = foo { ..; break n; ..}. So, "break n" is replaced with "v = n" // The CFG for the closure will be such that after break, control goes to the // scope exit block. So, we know that after the copy, we'll continue with the // instruction after the call. Variable v = ii.getCallResultVariable(); return (v == null) ? null : new CopyInstr(v, returnValue.cloneForInlining(ii)); } else { return cloneForInlining(ii); } }
case BLOCK_GIVEN: return BlockGivenInstr.decode(this); case BNE: return BNEInstr.decode(this); case BREAK: return BreakInstr.decode(this); case BUILD_BACKREF: return BuildBackrefInstr.decode(this); case BUILD_COMPOUND_ARRAY: return BuildCompoundArrayInstr.decode(this);
IRubyObject rv = (IRubyObject)bi.getReturnValue().retrieve(context, self, currDynScope, temp); return IRRuntimeHelpers.initiateBreak(context, scope, bi.getScopeToReturnTo().getScopeId(), rv, blockType);
@Override public Instr cloneForInlining(InlinerInfo ii) { return new BreakInstr(returnValue.cloneForInlining(ii), scopeToReturnTo); }
@Override public Instr clone(CloneInfo info) { if (info instanceof SimpleCloneInfo) return new BreakInstr(getReturnValue().cloneForInlining(info), scopeName); return (v == null) ? null : new CopyInstr(v, getReturnValue().cloneForInlining(ii)); return new BreakInstr(getReturnValue().cloneForInlining(ii), scopeName); } else { throw new UnsupportedOperationException("Break instructions shouldn't show up outside closures.");
protected static IRubyObject processReturnOp(ThreadContext context, Block block, Instr instr, Operation operation, DynamicScope currDynScope, Object[] temp, IRubyObject self, StaticScope currScope) { switch(operation) { // --------- Return flavored instructions -------- case RETURN: { return (IRubyObject)retrieveOp(((ReturnBase)instr).getReturnValue(), context, self, currDynScope, currScope, temp); } case BREAK: { BreakInstr bi = (BreakInstr)instr; IRubyObject rv = (IRubyObject)bi.getReturnValue().retrieve(context, self, currScope, currDynScope, temp); // This also handles breaks in lambdas -- by converting them to a return // // This assumes that scopes with break instr. have a frame / dynamic scope // pushed so that we can get to its static scope. For-loops now always have // a dyn-scope pushed onto stack which makes this work in all scenarios. return IRRuntimeHelpers.initiateBreak(context, currDynScope, rv, block); } case NONLOCAL_RETURN: { NonlocalReturnInstr ri = (NonlocalReturnInstr)instr; IRubyObject rv = (IRubyObject)retrieveOp(ri.getReturnValue(), context, self, currDynScope, currScope, temp); return IRRuntimeHelpers.initiateNonLocalReturn(context, currDynScope, block, rv); } case RETURN_OR_RETHROW_SAVED_EXC: { IRubyObject retVal = (IRubyObject) retrieveOp(((ReturnBase) instr).getReturnValue(), context, self, currDynScope, currScope, temp); return IRRuntimeHelpers.returnOrRethrowSavedException(context, retVal); } } return null; }
public Operand getReturnValue() { return getOperand1(); }