Skip to content

Commit

Permalink
Fixes for AddCallProtocol pass.
Browse files Browse the repository at this point in the history
* Reenable frame-elimination logic.
* Modify IRBuilder to set procNew flag on "Proc.new" calls.
* Use scope flag alone to determine scope needs.

Note that OptimizeDynScopes is still disabled, so the scope
elimination is not happening yet.
  • Loading branch information
headius committed Oct 20, 2014
1 parent 981e602 commit 0a4f1ef
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 26 deletions.
9 changes: 9 additions & 0 deletions core/src/main/java/org/jruby/ir/IRBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,15 @@ public Operand buildCall(CallNode callNode, IRScope s) {
Operand block = setupCallClosure(callNode.getIterNode(), s);
Variable callResult = s.createTemporaryVariable();
CallInstr callInstr = CallInstr.create(callResult, new MethAddr(callNode.getName()), receiver, args.toArray(new Operand[args.size()]), block);

// This is to support the ugly Proc.new with no block, which must see caller's frame
if (
callNode.getName().equals("new") &&
receiverNode instanceof ConstNode &&
((ConstNode)receiverNode).getName().equals("Proc")) {
callInstr.setProcNew(true);
}

receiveBreakException(s, block, callInstr, callNode.getPosition().getStartLine());
return callResult;
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/IRManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
public class IRManager {
public static String SAFE_COMPILER_PASSES = "";
public static String DEFAULT_COMPILER_PASSES = "OptimizeTempVarsPass,LocalOptimizationPass";
// public static String DEFAULT_JIT_PASSES = "DeadCodeElimination,AddLocalVarLoadStoreInstructions,OptimizeDynScopesPass,AddCallProtocolInstructions,EnsureTempsAssigned";
// public static String DEFAULT_JIT_PASSES = "AddLocalVarLoadStoreInstructions,OptimizeDynScopesPass,AddCallProtocolInstructions,EnsureTempsAssigned";
public static String DEFAULT_JIT_PASSES = "AddLocalVarLoadStoreInstructions,AddCallProtocolInstructions,EnsureTempsAssigned";
public static String DEFAULT_INLINING_COMPILER_PASSES = "LocalOptimizationPass";

Expand Down
16 changes: 15 additions & 1 deletion core/src/main/java/org/jruby/ir/instructions/CallBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public abstract class CallBase extends Instr implements Specializeable, ClosureA
private boolean targetRequiresCallersFrame; // Does this call make use of the caller's frame?
private boolean dontInline;
private boolean containsArgSplat;
private boolean procNew;

protected CallBase(Operation op, CallType callType, MethAddr methAddr, Operand receiver, Operand[] args, Operand closure) {
super(op);
Expand All @@ -51,7 +52,7 @@ protected CallBase(Operation op, CallType callType, MethAddr methAddr, Operand r
targetRequiresCallersBinding = true;
targetRequiresCallersFrame = true;
dontInline = false;

procNew = false;
}

@Override
Expand Down Expand Up @@ -94,6 +95,14 @@ public boolean containsArgSplat() {
return containsArgSplat;
}

public boolean isProcNew() {
return procNew;
}

public void setProcNew(boolean procNew) {
this.procNew = procNew;
}

public void blockInlining() {
dontInline = true;
}
Expand Down Expand Up @@ -340,10 +349,15 @@ private boolean computeRequiresCallersFrameFlag() {
// and use it at a later point.
if (closure != null) return true;

if (procNew) return true;

String mname = getMethodAddr().getName();
if (MethodIndex.FRAME_AWARE_METHODS.contains(mname)) {
// Known frame-aware methods.
return true;

} else if (mname.equals("send") || mname.equals("__send__")) {
// Allow send to access full binding, since someone might send :eval and friends.
Operand[] args = getCallArgs();
if (args.length >= 1) {
Operand meth = args[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,33 +69,12 @@ public Object execute(IRScope scope, Object... data) {
}
}

/* ----------------------------------------------------------------------
* Turning this off for now since this code is buggy and fails a few tests
* See example below which fails:
*
def y; yield; end
y {
def revivify
Proc::new
end
y {
x = Proc.new {}
y = revivify(&x)
p x.object_id, y.object_id
}
}
*
boolean requireFrame = bindingHasEscaped || scope.usesEval();

for (IRFlags flag : scope.getFlags()) {
switch (flag) {
case BINDING_HAS_ESCAPED:
case CAN_CAPTURE_CALLERS_BINDING:
case CAN_RECEIVE_BREAKS:
case CAN_RECEIVE_NONLOCAL_RETURNS:
case HAS_NONLOCAL_RETURNS:
case REQUIRES_FRAME:
case REQUIRES_VISIBILITY:
case USES_BACKREF_OR_LASTLINE:
Expand All @@ -104,10 +83,8 @@ public Object execute(IRScope scope, Object... data) {
requireFrame = true;
}
}
* ---------------------------------------------------------------------- */

boolean requireFrame = true;
boolean requireBinding = bindingHasEscaped || scopeHasLocalVarStores || !scope.getFlags().contains(IRFlags.DYNSCOPE_ELIMINATED);
boolean requireBinding = !scope.getFlags().contains(IRFlags.DYNSCOPE_ELIMINATED);

// FIXME: Why do we need a push/pop for frame & binding for scopes with unrescued exceptions??
// 1. I think we need a different check for frames -- it is NOT scopeHasUnrescuedExceptions
Expand Down

0 comments on commit 0a4f1ef

Please sign in to comment.