Skip to content

Instantly share code, notes, and snippets.

@headius
Created January 9, 2015 20:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save headius/5be78335c9dd9121fe15 to your computer and use it in GitHub Desktop.
Save headius/5be78335c9dd9121fe15 to your computer and use it in GitHub Desktop.
Switching closure instrs to operands for jruby/jruby#2447.
commit 7fcd16e2e39fc6319c67f83a96f999eef916384e
Author: Charles Oliver Nutter <headius@headius.com>
Date: Fri Jan 9 14:10:14 2015 -0600
Switch closure loads to operands.
LoadImplicitClosure = PassedBlock, for the directly-passed block.
LoadFrameCLosure = ImplicitBlock for the implicitly-passed block.
Note that this patch does not quite work; unresolved_super ends up
with PassedBlock as an operand, but since Operand#retrieve does
not get the passed block, it can't be returned.
diff --git a/core/src/main/java/org/jruby/ir/IRBuilder.java b/core/src/main/java/org/jruby/ir/IRBuilder.java
index b9e4ddf..ef0cbe2 100644
--- a/core/src/main/java/org/jruby/ir/IRBuilder.java
+++ b/core/src/main/java/org/jruby/ir/IRBuilder.java
@@ -1844,8 +1844,7 @@ public class IRBuilder {
Variable blockVar = s.getLocalVariable(blockArgName, 0);
if (s instanceof IRMethod) ((IRMethod) s).addArgDesc(IRMethodArgs.ArgType.block, blockArgName);
Variable tmp = s.createTemporaryVariable();
- addInstr(s, new LoadImplicitClosureInstr(tmp));
- addInstr(s, new ReifyClosureInstr(blockVar, tmp));
+ addInstr(s, new ReifyClosureInstr(blockVar, PassedBlock.INSTANCE));
}
}
@@ -1861,9 +1860,9 @@ public class IRBuilder {
// used for yields; metaclass body (sclass) inherits yield var from surrounding, and accesses it as implicit
if (s instanceof IRMethod || s instanceof IRMetaClassBody) {
- addInstr(s, new LoadImplicitClosureInstr(s.getYieldClosureVariable()));
+ addInstr(s, new CopyInstr(s.getYieldClosureVariable(), PassedBlock.INSTANCE));
} else {
- addInstr(s, new LoadFrameClosureInstr(s.getYieldClosureVariable()));
+ addInstr(s, new CopyInstr(s.getYieldClosureVariable(), ImplicitBlock.INSTANCE));
}
}
diff --git a/core/src/main/java/org/jruby/ir/IRVisitor.java b/core/src/main/java/org/jruby/ir/IRVisitor.java
index d00a733..277e8a7 100644
--- a/core/src/main/java/org/jruby/ir/IRVisitor.java
+++ b/core/src/main/java/org/jruby/ir/IRVisitor.java
@@ -73,8 +73,6 @@ public abstract class IRVisitor {
public void LexicalSearchConstInstr(LexicalSearchConstInstr lexicalsearchconstinstr) { error(lexicalsearchconstinstr); }
public void LineNumberInstr(LineNumberInstr linenumberinstr) { error(linenumberinstr); }
public void LoadLocalVarInstr(LoadLocalVarInstr loadlocalvarinstr) { error(loadlocalvarinstr); }
- public void LoadImplicitClosure(LoadImplicitClosureInstr loadimplicitclosureinstr) { error(loadimplicitclosureinstr); }
- public void LoadFrameClosure(LoadFrameClosureInstr loadframeclosureinstr) { error(loadframeclosureinstr); }
public void Match2Instr(Match2Instr match2instr) { error(match2instr); }
public void Match3Instr(Match3Instr match3instr) { error(match3instr); }
public void MatchInstr(MatchInstr matchinstr) { error(matchinstr); }
@@ -161,12 +159,14 @@ public abstract class IRVisitor {
public void GlobalVariable(GlobalVariable globalvariable) { error(globalvariable); }
public void Hash(Hash hash) { error(hash); }
public void IRException(IRException irexception) { error(irexception); }
+ public void ImplicitBlock(ImplicitBlock implicitblock) { error(implicitblock); }
public void Label(Label label) { error(label); }
public void LocalVariable(LocalVariable localvariable) { error(localvariable); }
public void Nil(Nil nil) { error(nil); }
public void NthRef(NthRef nthref) { error(nthref); }
public void NullBlock(NullBlock nullblock) { error(nullblock); }
public void ObjectClass(ObjectClass objectclass) { error(objectclass); }
+ public void PassedBlock(PassedBlock passedBlock) { error(passedBlock); }
public void Rational(Rational rational) { error(rational); }
public void Regexp(Regexp regexp) { error(regexp); }
public void ScopeModule(ScopeModule scopemodule) { error(scopemodule); }
diff --git a/core/src/main/java/org/jruby/ir/instructions/LoadFrameClosureInstr.java b/core/src/main/java/org/jruby/ir/instructions/LoadFrameClosureInstr.java
deleted file mode 100644
index 90929d7..0000000
--- a/core/src/main/java/org/jruby/ir/instructions/LoadFrameClosureInstr.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.jruby.ir.instructions;
-
-import org.jruby.ir.IRVisitor;
-import org.jruby.ir.Operation;
-import org.jruby.ir.operands.Operand;
-import org.jruby.ir.operands.Variable;
-import org.jruby.ir.operands.WrappedIRClosure;
-import org.jruby.ir.transformations.inlining.CloneInfo;
-import org.jruby.ir.transformations.inlining.InlineCloneInfo;
-import org.jruby.ir.transformations.inlining.SimpleCloneInfo;
-
-/**
- * Load the block passed to this scope via the on-heap frame (or similar cross-call structure).
- * This is typically used to access the "yieldable" target for blocks and evals. Only used
- * when within a scope that will use an on-heap frame.
- */
-public class LoadFrameClosureInstr extends Instr implements ResultInstr, FixedArityInstr {
- private Variable result;
-
- public LoadFrameClosureInstr(Variable result) {
- super(Operation.LOAD_FRAME_CLOSURE);
-
- assert result != null : "LoadFrameClosureInstr result is null";
-
- this.result = result;
- }
-
- @Override
- public Operand[] getOperands() {
- return EMPTY_OPERANDS;
- }
-
- @Override
- public Variable getResult() {
- return result;
- }
-
- @Override
- public void updateResult(Variable v) {
- this.result = v;
- }
-
- @Override
- public Instr clone(CloneInfo info) {
- if (info instanceof SimpleCloneInfo) return new LoadFrameClosureInstr(info.getRenamedVariable(result));
-
- // SSS FIXME: This code below is for inlining and is untested.
-
- InlineCloneInfo ii = (InlineCloneInfo) info;
-
- // SSS FIXME: This is not strictly correct -- we have to wrap the block into an
- // operand type that converts the static code block to a proc which is a closure.
- if (ii.getCallClosure() instanceof WrappedIRClosure) return NopInstr.NOP;
-
- return new CopyInstr(ii.getRenamedVariable(result), ii.getCallClosure());
- }
-
- @Override
- public void visit(IRVisitor visitor) {
- visitor.LoadFrameClosure(this);
- }
-}
diff --git a/core/src/main/java/org/jruby/ir/instructions/LoadImplicitClosureInstr.java b/core/src/main/java/org/jruby/ir/instructions/LoadImplicitClosureInstr.java
deleted file mode 100644
index 4cfe706..0000000
--- a/core/src/main/java/org/jruby/ir/instructions/LoadImplicitClosureInstr.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.jruby.ir.instructions;
-
-import org.jruby.ir.IRVisitor;
-import org.jruby.ir.Operation;
-import org.jruby.ir.operands.Operand;
-import org.jruby.ir.operands.Variable;
-import org.jruby.ir.operands.WrappedIRClosure;
-import org.jruby.ir.transformations.inlining.CloneInfo;
-import org.jruby.ir.transformations.inlining.InlineCloneInfo;
-import org.jruby.ir.transformations.inlining.SimpleCloneInfo;
-
-/**
- * Load the "implicit" closure for this scope. Currently this is always the "block" passed
- * to a body of code on the JVM stack.
- */
-public class LoadImplicitClosureInstr extends Instr implements ResultInstr, FixedArityInstr {
- private Variable result;
-
- public LoadImplicitClosureInstr(Variable result) {
- super(Operation.LOAD_IMPLICIT_CLOSURE);
-
- assert result != null : "LoadImplicitClosureInstr result is null";
-
- this.result = result;
- }
-
- @Override
- public Operand[] getOperands() {
- return EMPTY_OPERANDS;
- }
-
- @Override
- public Variable getResult() {
- return result;
- }
-
- @Override
- public void updateResult(Variable v) {
- this.result = v;
- }
-
- @Override
- public Instr clone(CloneInfo info) {
- if (info instanceof SimpleCloneInfo) return new LoadImplicitClosureInstr(info.getRenamedVariable(result));
-
- // SSS FIXME: This code below is for inlining and is untested.
-
- InlineCloneInfo ii = (InlineCloneInfo) info;
-
- // SSS FIXME: This is not strictly correct -- we have to wrap the block into an
- // operand type that converts the static code block to a proc which is a closure.
- if (ii.getCallClosure() instanceof WrappedIRClosure) return NopInstr.NOP;
-
- return new CopyInstr(ii.getRenamedVariable(result), ii.getCallClosure());
- }
-
- @Override
- public void visit(IRVisitor visitor) {
- visitor.LoadImplicitClosure(this);
- }
-}
diff --git a/core/src/main/java/org/jruby/ir/instructions/ProcessModuleBodyInstr.java b/core/src/main/java/org/jruby/ir/instructions/ProcessModuleBodyInstr.java
index 68e5d69..309f9ee 100644
--- a/core/src/main/java/org/jruby/ir/instructions/ProcessModuleBodyInstr.java
+++ b/core/src/main/java/org/jruby/ir/instructions/ProcessModuleBodyInstr.java
@@ -32,7 +32,7 @@ public class ProcessModuleBodyInstr extends Instr implements ResultInstr, FixedA
@Override
public Operand[] getOperands() {
- return new Operand[]{moduleBody,block};
+ return new Operand[]{moduleBody, block};
}
@Override
@@ -52,6 +52,7 @@ public class ProcessModuleBodyInstr extends Instr implements ResultInstr, FixedA
@Override
public void simplifyOperands(Map<Operand, Operand> valueMap, boolean force) {
moduleBody = moduleBody.getSimplifiedOperand(valueMap, force);
+ block = block.getSimplifiedOperand(valueMap, force);
}
@Override
diff --git a/core/src/main/java/org/jruby/ir/instructions/ReifyClosureInstr.java b/core/src/main/java/org/jruby/ir/instructions/ReifyClosureInstr.java
index 2cb9bfb..a6e92f6 100644
--- a/core/src/main/java/org/jruby/ir/instructions/ReifyClosureInstr.java
+++ b/core/src/main/java/org/jruby/ir/instructions/ReifyClosureInstr.java
@@ -21,10 +21,10 @@ import java.util.Map;
/* Receive the closure argument (either implicit or explicit in Ruby source code) */
public class ReifyClosureInstr extends Instr implements ResultInstr, FixedArityInstr {
- private Variable source;
+ private Operand source;
private Variable result;
- public ReifyClosureInstr(Variable result, Variable source) {
+ public ReifyClosureInstr(Variable result, Operand source) {
super(Operation.REIFY_CLOSURE);
assert result != null: "ReceiveClosureInstr result is null";
@@ -43,7 +43,7 @@ public class ReifyClosureInstr extends Instr implements ResultInstr, FixedArityI
return new Operand[]{source};
}
- public Variable getSource() {
+ public Operand getSource() {
return source;
}
@@ -54,7 +54,7 @@ public class ReifyClosureInstr extends Instr implements ResultInstr, FixedArityI
@Override
public void simplifyOperands(Map<Operand, Operand> valueMap, boolean force) {
- source = (Variable)source.getSimplifiedOperand(valueMap, force);
+ source = source.getSimplifiedOperand(valueMap, force);
}
@Override
@@ -70,7 +70,7 @@ public class ReifyClosureInstr extends Instr implements ResultInstr, FixedArityI
@Override
public Instr clone(CloneInfo info) {
- if (info instanceof SimpleCloneInfo) return new ReifyClosureInstr(info.getRenamedVariable(result), info.getRenamedVariable(source));
+ if (info instanceof SimpleCloneInfo) return new ReifyClosureInstr(info.getRenamedVariable(result), source);
// SSS FIXME: This code below is for inlining and is untested.
diff --git a/core/src/main/java/org/jruby/ir/interpreter/Interpreter.java b/core/src/main/java/org/jruby/ir/interpreter/Interpreter.java
index 22a0f2b..bbb67b5 100644
--- a/core/src/main/java/org/jruby/ir/interpreter/Interpreter.java
+++ b/core/src/main/java/org/jruby/ir/interpreter/Interpreter.java
@@ -127,7 +127,7 @@ public class Interpreter extends IRTranslator<IRubyObject, IRubyObject> {
}
}
- private static Object retrieveOp(Operand r, ThreadContext context, IRubyObject self, DynamicScope currDynScope, StaticScope currScope, Object[] temp) {
+ private static Object retrieveOp(Operand r, ThreadContext context, IRubyObject self, DynamicScope currDynScope, StaticScope currScope, Object[] temp, Block block) {
Object res;
if (r instanceof Self) {
return self;
@@ -135,9 +135,11 @@ public class Interpreter extends IRTranslator<IRubyObject, IRubyObject> {
res = temp[((TemporaryLocalVariable)r).offset];
return res == null ? context.nil : res;
} else if (r instanceof LocalVariable) {
- LocalVariable lv = (LocalVariable)r;
+ LocalVariable lv = (LocalVariable) r;
res = currDynScope.getValue(lv.getLocation(), lv.getScopeDepth());
return res == null ? context.nil : res;
+ } else if (r instanceof PassedBlock) { // FIXME: hacky to special-case this in interpreter
+ return block;
} else {
return r.retrieve(context, self, currScope, currDynScope, temp);
}
@@ -264,27 +266,27 @@ public class Interpreter extends IRTranslator<IRubyObject, IRubyObject> {
}
}
- private static void processCall(ThreadContext context, Instr instr, Operation operation, DynamicScope currDynScope, StaticScope currScope, Object[] temp, IRubyObject self) {
+ private static void processCall(ThreadContext context, Instr instr, Operation operation, DynamicScope currDynScope, StaticScope currScope, Object[] temp, IRubyObject self, Block block) {
Object result;
switch(operation) {
case CALL_1F: {
OneFixnumArgNoBlockCallInstr call = (OneFixnumArgNoBlockCallInstr)instr;
- IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp);
+ IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp, block);
result = call.getCallSite().call(context, self, r, call.getFixnumArg());
setResult(temp, currDynScope, call.getResult(), result);
break;
}
case CALL_1D: {
OneFloatArgNoBlockCallInstr call = (OneFloatArgNoBlockCallInstr)instr;
- IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp);
+ IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp, block);
result = call.getCallSite().call(context, self, r, call.getFloatArg());
setResult(temp, currDynScope, call.getResult(), result);
break;
}
case CALL_1O: {
OneOperandArgNoBlockCallInstr call = (OneOperandArgNoBlockCallInstr)instr;
- IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp);
+ IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp, block);
IRubyObject o = (IRubyObject)call.getArg1().retrieve(context, self, currScope, currDynScope, temp);
result = call.getCallSite().call(context, self, r, o);
setResult(temp, currDynScope, call.getResult(), result);
@@ -292,7 +294,7 @@ public class Interpreter extends IRTranslator<IRubyObject, IRubyObject> {
}
case CALL_1OB: {
OneOperandArgBlockCallInstr call = (OneOperandArgBlockCallInstr)instr;
- IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp);
+ IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp, block);
IRubyObject o = (IRubyObject)call.getArg1().retrieve(context, self, currScope, currDynScope, temp);
Block preparedBlock = call.prepareBlock(context, self, currScope, currDynScope, temp);
result = call.getCallSite().call(context, self, r, o, preparedBlock);
@@ -301,14 +303,14 @@ public class Interpreter extends IRTranslator<IRubyObject, IRubyObject> {
}
case CALL_0O: {
ZeroOperandArgNoBlockCallInstr call = (ZeroOperandArgNoBlockCallInstr)instr;
- IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp);
+ IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp, block);
result = call.getCallSite().call(context, self, r);
setResult(temp, currDynScope, call.getResult(), result);
break;
}
case NORESULT_CALL_1O: {
OneOperandArgNoBlockNoResultCallInstr call = (OneOperandArgNoBlockNoResultCallInstr)instr;
- IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp);
+ IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp, block);
IRubyObject o = (IRubyObject)call.getArg1().retrieve(context, self, currScope, currDynScope, temp);
call.getCallSite().call(context, self, r, o);
break;
@@ -365,12 +367,12 @@ public class Interpreter extends IRTranslator<IRubyObject, IRubyObject> {
}
}
- private static IRubyObject processReturnOp(ThreadContext context, Instr instr, Operation operation, DynamicScope currDynScope, Object[] temp, IRubyObject self, Block.Type blockType, StaticScope currScope)
+ private static IRubyObject processReturnOp(ThreadContext context, Instr instr, Operation operation, DynamicScope currDynScope, Object[] temp, IRubyObject self, Block block, Block.Type blockType, StaticScope currScope)
{
switch(operation) {
// --------- Return flavored instructions --------
case RETURN: {
- return (IRubyObject)retrieveOp(((ReturnBase)instr).getReturnValue(), context, self, currDynScope, currScope, temp);
+ return (IRubyObject)retrieveOp(((ReturnBase)instr).getReturnValue(), context, self, currDynScope, currScope, temp, block);
}
case BREAK: {
BreakInstr bi = (BreakInstr)instr;
@@ -384,14 +386,14 @@ public class Interpreter extends IRTranslator<IRubyObject, IRubyObject> {
}
case NONLOCAL_RETURN: {
NonlocalReturnInstr ri = (NonlocalReturnInstr)instr;
- IRubyObject rv = (IRubyObject)retrieveOp(ri.getReturnValue(), context, self, currDynScope, currScope, temp);
+ IRubyObject rv = (IRubyObject)retrieveOp(ri.getReturnValue(), context, self, currDynScope, currScope, temp, block);
return IRRuntimeHelpers.initiateNonLocalReturn(context, currDynScope, blockType, rv);
}
}
return null;
}
- private static void processOtherOp(ThreadContext context, Instr instr, Operation operation, DynamicScope currDynScope, StaticScope currScope, Object[] temp, IRubyObject self, Block.Type blockType, double[] floats, long[] fixnums, boolean[] booleans)
+ private static void processOtherOp(ThreadContext context, Instr instr, Operation operation, DynamicScope currDynScope, StaticScope currScope, Object[] temp, IRubyObject self, Block block, Block.Type blockType, double[] floats, long[] fixnums, boolean[] booleans)
{
Object result;
switch(operation) {
@@ -404,7 +406,7 @@ public class Interpreter extends IRTranslator<IRubyObject, IRubyObject> {
} else if (res instanceof TemporaryFixnumVariable) {
setFixnumVar(fixnums, (TemporaryFixnumVariable)res, getFixnumArg(fixnums, src));
} else {
- setResult(temp, currDynScope, res, retrieveOp(src, context, self, currDynScope, currScope, temp));
+ setResult(temp, currDynScope, res, retrieveOp(src, context, self, currDynScope, currScope, temp, block));
}
break;
}
@@ -465,7 +467,7 @@ public class Interpreter extends IRTranslator<IRubyObject, IRubyObject> {
case UNBOX_FLOAT: {
UnboxInstr ui = (UnboxInstr)instr;
- Object val = retrieveOp(ui.getValue(), context, self, currDynScope, currScope, temp);
+ Object val = retrieveOp(ui.getValue(), context, self, currDynScope, currScope, temp, block);
if (val instanceof RubyFloat) {
floats[((TemporaryLocalVariable)ui.getResult()).offset] = ((RubyFloat)val).getValue();
} else {
@@ -476,7 +478,7 @@ public class Interpreter extends IRTranslator<IRubyObject, IRubyObject> {
case UNBOX_FIXNUM: {
UnboxInstr ui = (UnboxInstr)instr;
- Object val = retrieveOp(ui.getValue(), context, self, currDynScope, currScope, temp);
+ Object val = retrieveOp(ui.getValue(), context, self, currDynScope, currScope, temp, block);
if (val instanceof RubyFloat) {
fixnums[((TemporaryLocalVariable)ui.getResult()).offset] = ((RubyFloat)val).getLongValue();
} else {
@@ -540,10 +542,10 @@ public class Interpreter extends IRTranslator<IRubyObject, IRubyObject> {
break;
case CALL_OP:
if (profile) Profiler.updateCallSite(instr, scope, scopeVersion);
- processCall(context, instr, operation, currDynScope, currScope, temp, self);
+ processCall(context, instr, operation, currDynScope, currScope, temp, self, block);
break;
case RET_OP:
- return processReturnOp(context, instr, operation, currDynScope, temp, self, blockType, currScope);
+ return processReturnOp(context, instr, operation, currDynScope, temp, self, block, blockType, currScope);
case BRANCH_OP:
switch (operation) {
case JUMP: ipc = ((JumpInstr)instr).getJumpTarget().getTargetPC(); break;
@@ -562,7 +564,7 @@ public class Interpreter extends IRTranslator<IRubyObject, IRubyObject> {
}
break;
case OTHER_OP:
- processOtherOp(context, instr, operation, currDynScope, currScope, temp, self, blockType, floats, fixnums, booleans);
+ processOtherOp(context, instr, operation, currDynScope, currScope, temp, self, block, blockType, floats, fixnums, booleans);
break;
}
} catch (Throwable t) {
diff --git a/core/src/main/java/org/jruby/ir/operands/ImplicitBlock.java b/core/src/main/java/org/jruby/ir/operands/ImplicitBlock.java
new file mode 100644
index 0000000..eb1c48a
--- /dev/null
+++ b/core/src/main/java/org/jruby/ir/operands/ImplicitBlock.java
@@ -0,0 +1,48 @@
+package org.jruby.ir.operands;
+
+import org.jruby.ir.IRVisitor;
+import org.jruby.ir.transformations.inlining.CloneInfo;
+import org.jruby.parser.StaticScope;
+import org.jruby.runtime.DynamicScope;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+import java.util.List;
+
+/**
+ * The Block available to this scope via some off-stack structure like a call frame.
+ *
+ * This is used for yields in blocks and most other non-method forms.
+ */
+public class ImplicitBlock extends Operand {
+ public static final ImplicitBlock INSTANCE = new ImplicitBlock();
+
+ private ImplicitBlock() {
+ super(OperandType.PASSED_BLOCK);
+ }
+
+ @Override
+ public void addUsedVariables(List<Variable> l) {
+ /* Nothing to do */
+ }
+
+ @Override
+ public Operand cloneForInlining(CloneInfo ii) {
+ return this;
+ }
+
+ @Override
+ public boolean canCopyPropagate() {
+ return true;
+ }
+
+ @Override
+ public Object retrieve(ThreadContext context, IRubyObject self, StaticScope currScope, DynamicScope currDynScope, Object[] temp) {
+ return context.getFrameBlock();
+ }
+
+ @Override
+ public void visit(IRVisitor visitor) {
+ visitor.ImplicitBlock(this);
+ }
+}
diff --git a/core/src/main/java/org/jruby/ir/operands/OperandType.java b/core/src/main/java/org/jruby/ir/operands/OperandType.java
index 11c2626..7d0470f 100644
--- a/core/src/main/java/org/jruby/ir/operands/OperandType.java
+++ b/core/src/main/java/org/jruby/ir/operands/OperandType.java
@@ -47,6 +47,8 @@ public enum OperandType {
WRAPPED_IR_CLOSURE((byte) 'w'),
FROZEN_STRING((byte) 'z'),
NULL_BLOCK((byte) 'o'),
+ PASSED_BLOCK((byte) 'p'),
+ IMPLICIT_BLOCK((byte) 'i')
;
private final byte coded;
diff --git a/core/src/main/java/org/jruby/ir/operands/PassedBlock.java b/core/src/main/java/org/jruby/ir/operands/PassedBlock.java
new file mode 100644
index 0000000..5435fd4
--- /dev/null
+++ b/core/src/main/java/org/jruby/ir/operands/PassedBlock.java
@@ -0,0 +1,48 @@
+package org.jruby.ir.operands;
+
+import org.jruby.ir.IRVisitor;
+import org.jruby.ir.transformations.inlining.CloneInfo;
+import org.jruby.parser.StaticScope;
+import org.jruby.runtime.DynamicScope;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+import java.util.List;
+
+/**
+ * The Block passed directly to this scope, as opposed to via an external frame.
+ *
+ * This is used for yields in normal method bodies, block arguments, etc.
+ */
+public class PassedBlock extends Operand {
+ public static final PassedBlock INSTANCE = new PassedBlock();
+
+ private PassedBlock() {
+ super(OperandType.PASSED_BLOCK);
+ }
+
+ @Override
+ public void addUsedVariables(List<Variable> l) {
+ /* Nothing to do */
+ }
+
+ @Override
+ public Operand cloneForInlining(CloneInfo ii) {
+ return this;
+ }
+
+ @Override
+ public boolean canCopyPropagate() {
+ return true;
+ }
+
+ @Override
+ public Object retrieve(ThreadContext context, IRubyObject self, StaticScope currScope, DynamicScope currDynScope, Object[] temp) {
+ return super.retrieve(context, self, currScope, currDynScope, temp);
+ }
+
+ @Override
+ public void visit(IRVisitor visitor) {
+ visitor.PassedBlock(this);
+ }
+}
diff --git a/core/src/main/java/org/jruby/ir/persistence/OperandDecoderMap.java b/core/src/main/java/org/jruby/ir/persistence/OperandDecoderMap.java
index 7e28a25..323ebae 100644
--- a/core/src/main/java/org/jruby/ir/persistence/OperandDecoderMap.java
+++ b/core/src/main/java/org/jruby/ir/persistence/OperandDecoderMap.java
@@ -41,12 +41,14 @@ class OperandDecoderMap {
case FLOAT: return new org.jruby.ir.operands.Float(d.decodeDouble());
case GLOBAL_VARIABLE: return new GlobalVariable(d.decodeString());
case HASH: return decodeHash();
+ case IMPLICIT_BLOCK: return ImplicitBlock.INSTANCE;
case IR_EXCEPTION: return IRException.getExceptionFromOrdinal(d.decodeByte());
case LABEL: return decodeLabel();
case LOCAL_VARIABLE: return d.getCurrentScope().getLocalVariable(d.decodeString(), d.decodeInt());
case NIL: return manager.getNil();
case NTH_REF: return new NthRef(d.decodeInt());
case OBJECT_CLASS: return new ObjectClass();
+ case PASSED_BLOCK: return PassedBlock.INSTANCE;
case REGEXP: return decodeRegexp();
case SCOPE_MODULE: return new ScopeModule(d.decodeInt());
case SELF: return Self.SELF;
diff --git a/core/src/main/java/org/jruby/ir/persistence/OperandEncoderMap.java b/core/src/main/java/org/jruby/ir/persistence/OperandEncoderMap.java
index a0cd323..f2420c4 100644
--- a/core/src/main/java/org/jruby/ir/persistence/OperandEncoderMap.java
+++ b/core/src/main/java/org/jruby/ir/persistence/OperandEncoderMap.java
@@ -65,6 +65,8 @@ class OperandEncoderMap extends IRVisitor {
}
}
+ @Override public void ImplicitBlock(ImplicitBlock implicitblock) {} // No data
+
@Override public void IRException(IRException irexception) { encoder.encode((byte) irexception.getType().ordinal()); }
@Override public void Label(Label label) {
@@ -85,6 +87,8 @@ class OperandEncoderMap extends IRVisitor {
@Override public void ObjectClass(ObjectClass objectclass) {} // No data
+ @Override public void PassedBlock(PassedBlock passedBlock) {} // No data
+
@Override public void Regexp(Regexp regexp) {
encode(regexp.getRegexp());
encoder.encode(regexp.options.isEncodingNone());
diff --git a/core/src/main/java/org/jruby/ir/targets/JVMVisitor.java b/core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
index c4a258a..727b950 100644
--- a/core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
+++ b/core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
@@ -1243,19 +1243,6 @@ public class JVMVisitor extends IRVisitor {
}
@Override
- public void LoadImplicitClosure(LoadImplicitClosureInstr loadimplicitclosureinstr) {
- jvmMethod().loadBlock();
- jvmStoreLocal(loadimplicitclosureinstr.getResult());
- }
-
- @Override
- public void LoadFrameClosure(LoadFrameClosureInstr loadframeclosureinstr) {
- jvmMethod().loadContext();
- jvmAdapter().invokevirtual(p(ThreadContext.class), "getFrameBlock", sig(Block.class));
- jvmStoreLocal(loadframeclosureinstr.getResult());
- }
-
- @Override
public void Match2Instr(Match2Instr match2instr) {
visit(match2instr.getReceiver());
jvmMethod().loadContext();
@@ -2067,6 +2054,12 @@ public class JVMVisitor extends IRVisitor {
}
@Override
+ public void ImplicitBlock(ImplicitBlock implicitblock) {
+ jvmMethod().loadContext();
+ jvmAdapter().invokevirtual(p(ThreadContext.class), "getFrameBlock", sig(Block.class));
+ }
+
+ @Override
public void LocalVariable(LocalVariable localvariable) {
// CON FIXME: This isn't as efficient as it could be, but we should not see these in optimized JIT scopes
jvmLoadLocal(DYNAMIC_SCOPE);
@@ -2099,6 +2092,11 @@ public class JVMVisitor extends IRVisitor {
}
@Override
+ public void PassedBlock(PassedBlock passedblock) {
+ jvmMethod().loadBlock();
+ }
+
+ @Override
public void Rational(Rational rational) {
jvmMethod().loadRuntime();
jvmAdapter().ldc(rational.getNumerator());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment