Skip to content

Commit d8e4959

Browse files
committed
Keep track of original scopeDepth in ClosureLocalVariable
* Load/Store local var passes needed to know whether the local var being handled was defined in the same scope in which the var's load/store is being considered. So far, it used a 'definingScope' field for that. However, that requires that all nested closures be cloned whenever a scope is cloned. However, we are no longer doing that => definingScope field in nested scopes went out of sync and screwed around with placement of loads/stores. * This patch gets rid of the scope field and instead uses a boolean to track whether the variable was defined locally or not and updates it during cloneForDepth. Note that it is not sufficient to use a scopeDepth > 0 test because when dynamic scopes are eliminated, the scope depth for all closure local variables get decremented by 1 (=> a non-local variable can have scope depth 0).
1 parent afdae18 commit d8e4959

File tree

8 files changed

+33
-16
lines changed

8 files changed

+33
-16
lines changed

core/src/main/java/org/jruby/ir/IRBindingEvalScript.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public LocalVariable getLocalVariable(String name, int scopeDepth) {
7272
@Override
7373
public LocalVariable getNewLocalVariable(String name, int depth) {
7474
assert depth == nearestNonEvalScopeDepth: "Local variable depth in IREvalScript:getNewLocalVariable for " + name + " must be " + nearestNonEvalScopeDepth + ". Got " + depth;
75-
LocalVariable lvar = new ClosureLocalVariable(this, name, 0, nearestNonEvalScope.evalScopeVars.size());
75+
LocalVariable lvar = new ClosureLocalVariable(name, 0, nearestNonEvalScope.evalScopeVars.size());
7676
nearestNonEvalScope.evalScopeVars.put(name, lvar);
7777
// CON: unsure how to get static scope to reflect this name as in IRClosure and IRMethod
7878
return lvar;

core/src/main/java/org/jruby/ir/IRClosure.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ protected LocalVariable findExistingLocalVariable(String name, int scopeDepth) {
182182

183183
public LocalVariable getNewLocalVariable(String name, int depth) {
184184
if (depth == 0 && !(this instanceof IRFor)) {
185-
LocalVariable lvar = new ClosureLocalVariable(this, name, 0, getStaticScope().addVariableThisScope(name));
185+
LocalVariable lvar = new ClosureLocalVariable(name, 0, getStaticScope().addVariableThisScope(name));
186186
localVars.put(name, lvar);
187187
return lvar;
188188
} else {

core/src/main/java/org/jruby/ir/dataflow/analyses/LoadLocalVarPlacementNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ public void addLoads(Map<Operand, Operand> varRenameMap) {
248248
// System.out.println("\t--> Reqd loads : " + java.util.Arrays.toString(reqdLoads.toArray()));
249249
for (LocalVariable v : reqdLoads) {
250250
if (scope.usesLocalVariable(v) || scope.definesLocalVariable(v)) {
251-
if (isEvalScript || !(v instanceof ClosureLocalVariable) || (scope != ((ClosureLocalVariable)v).definingScope)) {
251+
if (isEvalScript || !(v instanceof ClosureLocalVariable) || !((ClosureLocalVariable)v).isDefinedLocally()) {
252252
it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
253253
}
254254
}

core/src/main/java/org/jruby/ir/dataflow/analyses/StoreLocalVarPlacementNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public void applyTransferFunction(Instr i) {
9191
// Allocate a new hash-set and modify it to get around ConcurrentModificationException on dirtyVars
9292
Set<LocalVariable> newDirtyVars = new HashSet<LocalVariable>(dirtyVars);
9393
for (LocalVariable v : dirtyVars) {
94-
if ((v instanceof ClosureLocalVariable) && ((ClosureLocalVariable)v).definingScope != scope) {
94+
if ((v instanceof ClosureLocalVariable) && !((ClosureLocalVariable)v).isDefinedLocally()) {
9595
newDirtyVars.remove(v);
9696
}
9797
}
@@ -217,7 +217,7 @@ public boolean addStores(Map<Operand, Operand> varRenameMap, Set<LocalVariable>
217217
// instance from a different depth and that could mislead us. See if there is a way to fix this.
218218
// If we introduced 'definingScope' in all local variables, we could simply check for scope match
219219
// without the instanceof check here.
220-
if ( (v instanceof ClosureLocalVariable && ((ClosureLocalVariable)v).definingScope != scope)
220+
if ( (v instanceof ClosureLocalVariable && !((ClosureLocalVariable)v).isDefinedLocally())
221221
|| (!(v instanceof ClosureLocalVariable) && scope.getScopeType().isClosureType()))
222222
{
223223
addedStores = true;

core/src/main/java/org/jruby/ir/dataflow/analyses/StoreLocalVarPlacementProblem.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ boolean addClosureExitStoreLocalVars(ListIterator<Instr> instrs, Set<LocalVariab
6767
boolean addedStores = false;
6868
boolean isEvalScript = scope instanceof IREvalScript;
6969
for (LocalVariable v : dirtyVars) {
70-
if (isEvalScript || !(v instanceof ClosureLocalVariable) || (scope != ((ClosureLocalVariable)v).definingScope)) {
70+
if (isEvalScript || !(v instanceof ClosureLocalVariable) || !((ClosureLocalVariable)v).isDefinedLocally()) {
7171
addedStores = true;
7272
instrs.add(new StoreLocalVarInstr(getLocalVarReplacement(v, varRenameMap), scope, v));
7373
}

core/src/main/java/org/jruby/ir/operands/ClosureLocalVariable.java

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,21 @@
55
import org.jruby.ir.transformations.inlining.SimpleCloneInfo;
66

77
/**
8-
* This represents a variable used in a closure that is
9-
* local to the closure and is not defined in any ancestor lexical scope
8+
* This represents a non-temporary variable used in a closure
9+
* and defined in this or a parent closure.
1010
*/
1111
public class ClosureLocalVariable extends LocalVariable {
12-
final public IRClosure definingScope;
12+
// Note that we cannot use (scopeDepth > 0) check to detect this.
13+
// When a dyn-scope is eliminated for a leaf scope, depths for all
14+
// closure local vars are decremented by 1 => a non-local variable
15+
// can have scope depth 0.
16+
//
17+
// Can only transition in one direction (from true to false)
18+
private boolean definedLocally;
1319

14-
public ClosureLocalVariable(IRClosure scope, String name, int scopeDepth, int location) {
20+
public ClosureLocalVariable(String name, int scopeDepth, int location) {
1521
super(name, scopeDepth, location);
16-
this.definingScope = scope;
22+
this.definedLocally = true;
1723
}
1824

1925
@Override
@@ -32,13 +38,23 @@ public int compareTo(Object arg0) {
3238
return a < b ? -1 : (a == b ? 0 : 1);
3339
}
3440

41+
public boolean isDefinedLocally() {
42+
return definedLocally;
43+
}
44+
3545
@Override
3646
public Variable clone(SimpleCloneInfo ii) {
37-
return new ClosureLocalVariable((IRClosure) ii.getScope(), name, scopeDepth, offset);
47+
ClosureLocalVariable lv = new ClosureLocalVariable(name, scopeDepth, offset);
48+
lv.definedLocally = definedLocally;
49+
return lv;
3850
}
3951

4052
public LocalVariable cloneForDepth(int n) {
41-
return new ClosureLocalVariable(definingScope, name, n, offset);
53+
ClosureLocalVariable lv = new ClosureLocalVariable(name, n, offset);
54+
if (definedLocally && n > 0) {
55+
lv.definedLocally = false;
56+
}
57+
return lv;
4258
}
4359

4460
@Override
@@ -48,6 +64,6 @@ public void visit(IRVisitor visitor) {
4864

4965
@Override
5066
public String toString() {
51-
return "<" + name + "(" + scopeDepth + ":" + offset + ")>";
67+
return "<" + name + "(" + scopeDepth + ":" + offset + ":local=" + definedLocally + ")>";
5268
}
5369
}

core/src/main/java/org/jruby/ir/persistence/IRReader.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ private static Map<String, LocalVariable> decodeScopeLocalVariables(IRReaderDeco
9292
int offset = decoder.decodeInt();
9393

9494
localVariables.put(name, scope instanceof IRClosure ?
95-
new ClosureLocalVariable((IRClosure) scope, name, 0, offset) : new LocalVariable(name, 0, offset));
95+
// SSS FIXME: do we need to read back locallyDefined boolean?
96+
new ClosureLocalVariable(name, 0, offset) : new LocalVariable(name, 0, offset));
9697
}
9798

9899
return localVariables;

core/src/main/java/org/jruby/ir/persistence/OperandEncoderMap.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public void encode(Operand operand) {
3939
@Override public void Boolean(Boolean booleanliteral) { encoder.encode(booleanliteral.isTrue()); }
4040

4141
@Override public void ClosureLocalVariable(ClosureLocalVariable variable) {
42-
// We can refigure out closure scope it is in.
42+
// SSS FIXME: Need to dump definedLocally?
4343
encoder.encode(variable.getName());
4444
encoder.encode(variable.getScopeDepth());
4545
}

0 commit comments

Comments
 (0)