Here's an experimental patch that specializes DynamicScope into a few
subtypes. The primary goal here is to reduce some decision overhead
(local scopes should never need to confirm depth == 0) and limit memory
consumption for certain scopes (local scopes don't need parent; block
scopes don't need binding scope).
This patch appears to be either a little faster or about the same. But I
thought I'd throw it out there for others to experiment with.
It also adds a factory methods to *StaticScope types, which might be a
good thing to do anyway.
- Charlie
Index: src/org/jruby/runtime/DynamicScope.java
===================================================================
--- src/org/jruby/runtime/DynamicScope.java (revision 3914)
+++ src/org/jruby/runtime/DynamicScope.java (working copy)
@@ -20,42 +20,15 @@
* 1. Fix all callers
* 2. Check parent that is passed in and make if new instance is local, then
its parent is not local
*/
-public class DynamicScope {
- // Our values holder (name of variables are kept in staticScope)
- private IRubyObject[] variableValues;
-
+public abstract class DynamicScope {
// Static scoping information for this scope
private StaticScope staticScope;
-
- // Captured dyanmic scopes
- private DynamicScope parent;
-
- // A place to store that special hiding space that bindings need to
implement things like:
- // eval("a = 1", binding); eval("p a"). All binding instances must get
access to this
- // hidden shared scope. We store it here. This will be null if no
binding has yet
- // been called.
- private DynamicScope bindingScope;
- public DynamicScope(StaticScope staticScope, DynamicScope parent) {
- this(staticScope);
- this.parent = parent;
- }
-
public DynamicScope(StaticScope staticScope) {
this.staticScope = staticScope;
-
}
-
- private void lazy() {
- if(variableValues == null) {
- int size = staticScope.getNumberOfVariables();
- variableValues = new IRubyObject[size];
- }
- }
- public DynamicScope cloneScope() {
- return new DynamicScope(staticScope, parent);
- }
+ public abstract DynamicScope cloneScope();
/**
* Get all variable names captured (visible) by this scope (sans $~ and
$_).
@@ -66,10 +39,7 @@
return staticScope.getAllNamesInScope(this);
}
- public IRubyObject[] getValues() {
- lazy();
- return variableValues;
- }
+ public abstract IRubyObject[] getValues();
/**
* Get value from current scope or one of its captured scopes.
@@ -81,17 +51,7 @@
* @param depth how many captured scopes down this variable should be set
* @return the value here
*/
- public IRubyObject getValue(int offset, int depth) {
- if (depth > 0) {
- return parent.getValue(offset, depth - 1);
- }
- lazy();
- assert variableValues != null : "No variables in getValue for Off: " +
offset + ", Dep: " + depth;
- assert offset < variableValues.length : "Index to big for getValue
Off: " + offset + ", Dep: " + depth + ", O: " + this;
- // &foo are not getting set from somewhere...I want the following
assert to be true though
- //assert variableValues[offset] != null : "Getting unassigned: " +
staticScope.getVariables()[offset];
- return variableValues[offset];
- }
+ public abstract IRubyObject getValue(int offset, int depth);
/**
* Set value in current dynamic scope or one of its captured scopes.
@@ -100,19 +60,8 @@
* @param value to set
* @param depth how many captured scopes down this variable should be set
*/
- public void setValue(int offset, IRubyObject value, int depth) {
- if (depth > 0) {
- assert parent != null : "If depth > 0, then parent should not ever
be null";
-
- parent.setValue(offset, value, depth - 1);
- } else {
- assert offset < variableValues.length : "Setting " + offset + " to
" + value + ", O: " + this;
+ public abstract void setValue(int offset, IRubyObject value, int depth);
- lazy();
- variableValues[offset] = value;
- }
- }
-
/**
* Set all values which represent 'normal' parameters in a call list to
this dynamic
* scope. Function calls bind to local scopes by assuming that the
indexes or the
@@ -124,25 +73,12 @@
* @param values up to size specified to be mapped as ordinary parm values
* @param size is the number of values to assign as ordinary parm values
*/
- public void setArgValues(IRubyObject[] values, int size) {
- lazy();
- System.arraycopy(values, 0, variableValues, 2, size);
- }
-
- public void setBlockArgValues(IRubyObject[] blockArgValues, int size) {
- lazy();
- System.arraycopy(blockArgValues, 0, variableValues, 0, size);
- }
+ public abstract void setArgValues(IRubyObject[] values, int size);
/**
* Copy variable values back for ZSuper call.
*/
- public void getArgValues(IRubyObject[] args, int size) {
- lazy();
- if(variableValues != null && args != null &&
variableValues.length>=(size+2)) {
- System.arraycopy(variableValues, 2, args, 0, size);
- }
- }
+ public abstract void getArgValues(IRubyObject[] args, int size);
/**
*
@@ -152,60 +88,23 @@
* things like 'eval "b = 2", binding' happens.
*
*/
- public void growIfNeeded() {
- lazy();
- int dynamicSize = variableValues == null ? 0: variableValues.length;
-
- if (staticScope.getNumberOfVariables() > dynamicSize) {
- IRubyObject values[] = new
IRubyObject[staticScope.getNumberOfVariables()];
-
- if (dynamicSize > 0) {
- System.arraycopy(variableValues, 0, values, 0, dynamicSize);
- }
-
- variableValues = values;
- }
- }
+ public abstract void growIfNeeded();
// FIXME: Depending on profiling we may want to cache information on
location and depth of
// both $_ and/or $~ since in some situations they may happen a lot.
isDefined should be
// fairly cheap, but you never know...
- public void setLastLine(IRubyObject value) {
- lazy();
- int location = staticScope.isDefined("$_");
-
- setValue(location & 0xffff, value, location >> 16);
- }
+ public abstract void setLastLine(IRubyObject value);
- public IRubyObject getLastLine() {
- lazy();
- int location = staticScope.isDefined("$_");
+ public abstract IRubyObject getLastLine();
- return getValue(location & 0xffff, location >> 16);
- }
-
- public void setBackRef(IRubyObject value) {
- lazy();
- int location = staticScope.isDefined("$~");
-
- setValue(location & 0xffff, value, location >> 16);
- }
+ public abstract void setBackRef(IRubyObject value);
- public IRubyObject getBackRef() {
- lazy();
- int location = staticScope.isDefined("$~");
-
- return getValue(location & 0xffff, location >> 16);
- }
+ public abstract IRubyObject getBackRef();
- public DynamicScope getBindingScope() {
- return bindingScope;
- }
+ public abstract DynamicScope getBindingScope();
- public void setBindingScope(DynamicScope bindingScope) {
- this.bindingScope = bindingScope;
- }
+ public abstract void setBindingScope(DynamicScope bindingScope);
/**
* Get next 'captured' scope.
@@ -214,7 +113,7 @@
*
*/
public DynamicScope getNextCapturedScope() {
- return parent;
+ return null;
}
/**
@@ -225,50 +124,514 @@
public StaticScope getStaticScope() {
return staticScope;
}
+
+ public static class ArbitrarySizeLocalScope extends DynamicScope {
+ // Our values holder (name of variables are kept in staticScope)
+ private IRubyObject[] variableValues;
+
+ // A place to store that special hiding space that bindings need to
implement things like:
+ // eval("a = 1", binding); eval("p a"). All binding instances must
get access to this
+ // hidden shared scope. We store it here. This will be null if no
binding has yet
+ // been called.
+ private DynamicScope bindingScope;
- public String toString() {
- return toString(new StringBuffer(), "");
- }
+ public ArbitrarySizeLocalScope(StaticScope staticScope) {
+ super(staticScope);
+ }
+
+ private void lazy() {
+ if(variableValues == null) {
+ int size = getStaticScope().getNumberOfVariables();
+ variableValues = new IRubyObject[size];
+ }
+ }
+
+ public DynamicScope cloneScope() {
+ return new ArbitrarySizeLocalScope(getStaticScope());
+ }
+
+ public DynamicScope getBindingScope() {
+ return bindingScope;
+ }
+
+ public void setBindingScope(DynamicScope bindingScope) {
+ this.bindingScope = bindingScope;
+ }
+
+ /**
+ * Get all variable names captured (visible) by this scope (sans $~
and $_).
+ *
+ * @return a list of variable names
+ */
+ public String[] getAllNamesInScope() {
+ return getStaticScope().getAllNamesInScope(this);
+ }
+
+ public IRubyObject[] getValues() {
+ lazy();
+ return variableValues;
+ }
+
+ /**
+ * Get value from current scope or one of its captured scopes.
+ *
+ * FIXME: block variables are not getting primed to nil so we need to
null check those
+ * until we prime them properly. Also add assert back in.
+ *
+ * @param offset zero-indexed value that represents where variable
lives
+ * @param depth how many captured scopes down this variable should be
set
+ * @return the value here
+ */
+ public IRubyObject getValue(int offset, int depth) {
+ lazy();
+ assert depth == 0;
+ assert variableValues != null : "No variables in getValue for Off:
" + offset + ", Dep: " + depth;
+ assert offset < variableValues.length : "Index to big for getValue
Off: " + offset + ", Dep: " + depth + ", O: " + this;
+ // &foo are not getting set from somewhere...I want the following
assert to be true though
+ //assert variableValues[offset] != null : "Getting unassigned: " +
staticScope.getVariables()[offset];
+ return variableValues[offset];
+ }
+
+ /**
+ * Set value in current dynamic scope or one of its captured scopes.
+ *
+ * @param offset zero-indexed value that represents where variable
lives
+ * @param value to set
+ * @param depth how many captured scopes down this variable should be
set
+ */
+ public void setValue(int offset, IRubyObject value, int depth) {
+ assert depth == 0;
+ assert offset < variableValues.length : "Setting " + offset + " to
" + value + ", O: " + this;
- // Helper function to give a good view of current dynamic scope with
captured scopes
- private String toString(StringBuffer buf, String indent) {
- lazy();
- buf.append(indent).append("Static Type[" + hashCode() + "]: " +
- (staticScope instanceof BlockStaticScope ? "block" :
"local")+" [");
- int size = staticScope.getNumberOfVariables();
+ lazy();
+ variableValues[offset] = value;
+ }
+
+ /**
+ * Set all values which represent 'normal' parameters in a call list
to this dynamic
+ * scope. Function calls bind to local scopes by assuming that the
indexes or the
+ * arg list correspond to that of the local scope (plus 2 since $_ and
$~ always take
+ * the first two slots). We pass in a second argument because we
sometimes get more
+ * values than we are expecting. The rest get compacted by original
caller into
+ * rest args.
+ *
+ * @param values up to size specified to be mapped as ordinary parm
values
+ * @param size is the number of values to assign as ordinary parm
values
+ */
+ public void setArgValues(IRubyObject[] values, int size) {
+ lazy();
+ System.arraycopy(values, 0, variableValues, 2, size);
+ }
+
+ /**
+ * Copy variable values back for ZSuper call.
+ */
+ public void getArgValues(IRubyObject[] args, int size) {
+ lazy();
+ if(variableValues != null && args != null &&
variableValues.length>=(size+2)) {
+ System.arraycopy(variableValues, 2, args, 0, size);
+ }
+ }
+
+ /**
+ *
+ * Make a larger dynamic scope if the static scope grew.
+ *
+ * Eval's with bindings require us to possibly change the size of the
dynamic scope if
+ * things like 'eval "b = 2", binding' happens.
+ *
+ */
+ public void growIfNeeded() {
+ lazy();
+ int dynamicSize = variableValues == null ? 0:
variableValues.length;
+
+ if (getStaticScope().getNumberOfVariables() > dynamicSize) {
+ IRubyObject values[] = new
IRubyObject[getStaticScope().getNumberOfVariables()];
+
+ if (dynamicSize > 0) {
+ System.arraycopy(variableValues, 0, values, 0,
dynamicSize);
+ }
+
+ variableValues = values;
+ }
+ }
+
+ // FIXME: Depending on profiling we may want to cache information on
location and depth of
+ // both $_ and/or $~ since in some situations they may happen a lot.
isDefined should be
+ // fairly cheap, but you never know...
- if (size != 0) {
- String names[] = staticScope.getVariables();
- for (int i = 0; i < size-1; i++) {
- buf.append(names[i]).append("=");
-
- if (variableValues[i] == null) {
+ public void setLastLine(IRubyObject value) {
+ lazy();
+ int location = getStaticScope().isDefined("$_");
+
+ setValue(location & 0xffff, value, location >> 16);
+ }
+
+ public IRubyObject getLastLine() {
+ lazy();
+ int location = getStaticScope().isDefined("$_");
+
+ return getValue(location & 0xffff, location >> 16);
+ }
+
+ public void setBackRef(IRubyObject value) {
+ lazy();
+ int location = getStaticScope().isDefined("$~");
+
+ setValue(location & 0xffff, value, location >> 16);
+ }
+
+ public IRubyObject getBackRef() {
+ lazy();
+ int location = getStaticScope().isDefined("$~");
+
+ return getValue(location & 0xffff, location >> 16);
+ }
+
+ public String toString() {
+ return toString(new StringBuffer(), "");
+ }
+
+ // Helper function to give a good view of current dynamic scope with
captured scopes
+ private String toString(StringBuffer buf, String indent) {
+ lazy();
+ buf.append(indent).append("Static Type[" + hashCode() + "]: " +
+ (getStaticScope() instanceof BlockStaticScope ? "block" :
"local")+" [");
+ int size = getStaticScope().getNumberOfVariables();
+
+ if (size != 0) {
+ String names[] = getStaticScope().getVariables();
+ for (int i = 0; i < size-1; i++) {
+ buf.append(names[i]).append("=");
+
+ if (variableValues[i] == null) {
+ buf.append("null");
+ } else {
+ buf.append(variableValues[i]);
+ }
+
+ buf.append(",");
+ }
+ buf.append(names[size-1]).append("=");
+
+ assert variableValues.length == names.length : "V: " +
variableValues.length +
+ " != N: " + names.length + " for " + buf;
+
+ if (variableValues[size-1] == null) {
buf.append("null");
} else {
- buf.append(variableValues[i]);
+ buf.append(variableValues[size-1]);
}
- buf.append(",");
}
- buf.append(names[size-1]).append("=");
- assert variableValues.length == names.length : "V: " +
variableValues.length +
- " != N: " + names.length + " for " + buf;
+ buf.append("]");
- if (variableValues[size-1] == null) {
- buf.append("null");
+ return buf.toString();
+ }
+ }
+
+ public static class EmptyBlockScope extends DynamicScope {
+ // Captured parent scopes
+ protected DynamicScope parent;
+
+ public EmptyBlockScope(StaticScope staticScope, DynamicScope parent) {
+ super(staticScope);
+ this.parent = parent;
+ }
+
+ public DynamicScope getBindingScope() {
+ return parent.getBindingScope();
+ }
+
+ public void setBindingScope(DynamicScope bindingScope) {
+ parent.setBindingScope(bindingScope);
+ }
+
+ /**
+ * Get next 'captured' scope.
+ *
+ * @return the scope captured by this scope for implementing closures
+ *
+ */
+ public DynamicScope getNextCapturedScope() {
+ return parent;
+ }
+
+ public DynamicScope cloneScope() {
+ return new EmptyBlockScope(getStaticScope(),
getNextCapturedScope());
+ }
+
+ /**
+ * Get all variable names captured (visible) by this scope (sans $~
and $_).
+ *
+ * @return a list of variable names
+ */
+ public String[] getAllNamesInScope() {
+ return getStaticScope().getAllNamesInScope(this);
+ }
+
+ public IRubyObject[] getValues() {
+ return IRubyObject.NULL_ARRAY;
+ }
+
+ /**
+ * Get value from current scope or one of its captured scopes.
+ *
+ * FIXME: block variables are not getting primed to nil so we need to
null check those
+ * until we prime them properly. Also add assert back in.
+ *
+ * @param offset zero-indexed value that represents where variable
lives
+ * @param depth how many captured scopes down this variable should be
set
+ * @return the value here
+ */
+ public IRubyObject getValue(int offset, int depth) {
+ if (depth == 0) {
+ // NOTE: Empty means empty!
+ return null;
+ } else {
+ return parent.getValue(offset, depth - 1);
+ }
+ }
+
+ /**
+ * Set value in current dynamic scope or one of its captured scopes.
+ *
+ * @param offset zero-indexed value that represents where variable
lives
+ * @param value to set
+ * @param depth how many captured scopes down this variable should be
set
+ */
+ public void setValue(int offset, IRubyObject value, int depth) {
+ if (depth == 0) {
} else {
- buf.append(variableValues[size-1]);
+ assert parent != null : "If depth > 0, then parent should not
ever be null";
+
+ parent.setValue(offset, value, depth - 1);
}
+ }
+
+ /**
+ * Set all values which represent 'normal' parameters in a call list
to this dynamic
+ * scope. Function calls bind to local scopes by assuming that the
indexes or the
+ * arg list correspond to that of the local scope (plus 2 since $_ and
$~ always take
+ * the first two slots). We pass in a second argument because we
sometimes get more
+ * values than we are expecting. The rest get compacted by original
caller into
+ * rest args.
+ *
+ * @param values up to size specified to be mapped as ordinary parm
values
+ * @param size is the number of values to assign as ordinary parm
values
+ */
+ public void setArgValues(IRubyObject[] values, int size) {
+ }
+
+ /**
+ * Copy variable values back for ZSuper call.
+ */
+ public void getArgValues(IRubyObject[] args, int size) {
+ }
+
+ /**
+ *
+ * Make a larger dynamic scope if the static scope grew.
+ *
+ * Eval's with bindings require us to possibly change the size of the
dynamic scope if
+ * things like 'eval "b = 2", binding' happens.
+ *
+ */
+ public void growIfNeeded() {
+ // FIXME: perhaps should raise an error here? We do not grow!
+ }
+
+ public void setLastLine(IRubyObject value) {
+ parent.setLastLine(value);
+ }
+
+ public IRubyObject getLastLine() {
+ return parent.getLastLine();
+ }
+
+ public void setBackRef(IRubyObject value) {
+ parent.setBackRef(value);
+ }
+
+ public IRubyObject getBackRef() {
+ return parent.getBackRef();
+ }
+
+ public String toString() {
+ return toString(new StringBuffer(), "");
+ }
+
+ // Helper function to give a good view of current dynamic scope with
captured scopes
+ private String toString(StringBuffer buf, String indent) {
+ buf.append(indent).append("Static Type[" + hashCode() + "]: " +
+ (getStaticScope() instanceof BlockStaticScope ? "block" :
"local")+" [");
+ return buf.toString();
}
+ }
+
+ public static class ArbitrarySizeBlockScope extends EmptyBlockScope {
+ // Our values holder (name of variables are kept in staticScope)
+ private IRubyObject[] variableValues;
+
+ public ArbitrarySizeBlockScope(StaticScope staticScope, DynamicScope
parent) {
+ super(staticScope, parent);
+ }
+
+ private void lazy() {
+ if(variableValues == null) {
+ int size = getStaticScope().getNumberOfVariables();
+ variableValues = new IRubyObject[size];
+ }
+ }
- buf.append("]");
- if (parent != null) {
- buf.append("\n");
- parent.toString(buf, indent + " ");
+ public DynamicScope cloneScope() {
+ return new ArbitrarySizeBlockScope(getStaticScope(),
getNextCapturedScope());
}
+
+ public IRubyObject[] getValues() {
+ lazy();
+ return variableValues;
+ }
- return buf.toString();
+ /**
+ * Get value from current scope or one of its captured scopes.
+ *
+ * FIXME: block variables are not getting primed to nil so we need to
null check those
+ * until we prime them properly. Also add assert back in.
+ *
+ * @param offset zero-indexed value that represents where variable
lives
+ * @param depth how many captured scopes down this variable should be
set
+ * @return the value here
+ */
+ public IRubyObject getValue(int offset, int depth) {
+ if (depth == 0) {
+ lazy();
+ assert variableValues != null : "No variables in getValue for
Off: " + offset + ", Dep: " + depth;
+ assert offset < variableValues.length : "Index to big for
getValue Off: " + offset + ", Dep: " + depth + ", O: " + this;
+ // &foo are not getting set from somewhere...I want the
following assert to be true though
+ //assert variableValues[offset] != null : "Getting unassigned:
" + staticScope.getVariables()[offset];
+ return variableValues[offset];
+ } else {
+ return parent.getValue(offset, depth - 1);
+ }
+ }
+
+ /**
+ * Set value in current dynamic scope or one of its captured scopes.
+ *
+ * @param offset zero-indexed value that represents where variable
lives
+ * @param value to set
+ * @param depth how many captured scopes down this variable should be
set
+ */
+ public void setValue(int offset, IRubyObject value, int depth) {
+ if (depth == 0) {
+ assert offset < variableValues.length : "Setting " + offset +
" to " + value + ", O: " + this;
+
+ lazy();
+ variableValues[offset] = value;
+ } else {
+ assert parent != null : "If depth > 0, then parent should not
ever be null";
+
+ parent.setValue(offset, value, depth - 1);
+ }
+ }
+
+ /**
+ * Set all values which represent 'normal' parameters in a call list
to this dynamic
+ * scope. Function calls bind to local scopes by assuming that the
indexes or the
+ * arg list correspond to that of the local scope (plus 2 since $_ and
$~ always take
+ * the first two slots). We pass in a second argument because we
sometimes get more
+ * values than we are expecting. The rest get compacted by original
caller into
+ * rest args.
+ *
+ * @param values up to size specified to be mapped as ordinary parm
values
+ * @param size is the number of values to assign as ordinary parm
values
+ */
+ public void setArgValues(IRubyObject[] values, int size) {
+ lazy();
+ System.arraycopy(values, 0, variableValues, 0, size);
+ }
+
+ /**
+ * Copy variable values back for ZSuper call.
+ */
+ public void getArgValues(IRubyObject[] args, int size) {
+ // NOTE: Block args never get used in ZSuper, so this impl is just
here for consistency
+ lazy();
+ if(variableValues != null && args != null &&
variableValues.length>=(size)) {
+ System.arraycopy(variableValues, 0, args, 0, size);
+ }
+ }
+
+ /**
+ *
+ * Make a larger dynamic scope if the static scope grew.
+ *
+ * Eval's with bindings require us to possibly change the size of the
dynamic scope if
+ * things like 'eval "b = 2", binding' happens.
+ *
+ */
+ public void growIfNeeded() {
+ lazy();
+ int dynamicSize = variableValues == null ? 0:
variableValues.length;
+
+ if (getStaticScope().getNumberOfVariables() > dynamicSize) {
+ IRubyObject values[] = new
IRubyObject[getStaticScope().getNumberOfVariables()];
+
+ if (dynamicSize > 0) {
+ System.arraycopy(variableValues, 0, values, 0,
dynamicSize);
+ }
+
+ variableValues = values;
+ }
+ }
+
+ public String toString() {
+ return toString(new StringBuffer(), "");
+ }
+
+ // Helper function to give a good view of current dynamic scope with
captured scopes
+ private String toString(StringBuffer buf, String indent) {
+ lazy();
+ buf.append(indent).append("Static Type[" + hashCode() + "]: " +
+ (getStaticScope() instanceof BlockStaticScope ? "block" :
"local")+" [");
+ int size = getStaticScope().getNumberOfVariables();
+
+ if (size != 0) {
+ String names[] = getStaticScope().getVariables();
+ for (int i = 0; i < size-1; i++) {
+ buf.append(names[i]).append("=");
+
+ if (variableValues[i] == null) {
+ buf.append("null");
+ } else {
+ buf.append(variableValues[i]);
+ }
+
+ buf.append(",");
+ }
+ buf.append(names[size-1]).append("=");
+
+ assert variableValues.length == names.length : "V: " +
variableValues.length +
+ " != N: " + names.length + " for " + buf;
+
+ if (variableValues[size-1] == null) {
+ buf.append("null");
+ } else {
+ buf.append(variableValues[size-1]);
+ }
+
+ }
+
+ buf.append("]");
+ if (parent != null) {
+ buf.append("\n");
+ buf.append(parent.toString());
+ }
+
+ return buf.toString();
+ }
}
}
Index: src/org/jruby/runtime/ThreadContext.java
===================================================================
--- src/org/jruby/runtime/ThreadContext.java (revision 3914)
+++ src/org/jruby/runtime/ThreadContext.java (working copy)
@@ -121,7 +121,7 @@
// TOPLEVEL self and a few others want a top-level scope. We create
this one right
// away and then pass it into top-level parse so it ends up being the
top level.
- pushScope(new DynamicScope(new LocalStaticScope(null), null));
+ pushScope(new LocalStaticScope(null).createDynamicScope(null));
}
CallType lastCallType;
@@ -694,7 +694,7 @@
pushRubyClass(type);
pushFrameCopy();
getCurrentFrame().setVisibility(Visibility.PUBLIC);
- pushScope(new DynamicScope(staticScope, null));
+ pushScope(staticScope.createDynamicScope(null));
}
public void postClassEval() {
@@ -732,7 +732,7 @@
RubyModule implementationClass = (RubyModule)cref.getValue();
setCRef(cref);
pushCallFrame(noSuper ? null : clazz, name, self, args, req, block,
jumpTarget);
- pushScope(new DynamicScope(staticScope));
+ pushScope(staticScope.createDynamicScope(null));
pushRubyClass(implementationClass);
}
Index: src/org/jruby/runtime/Block.java
===================================================================
--- src/org/jruby/runtime/Block.java (revision 3914)
+++ src/org/jruby/runtime/Block.java (working copy)
@@ -160,7 +160,7 @@
if (parent != null && parent.getBindingScope() == dynamicScope) {
extraScope = dynamicScope;
} else {
- extraScope = new DynamicScope(new
BlockStaticScope(dynamicScope.getStaticScope()), dynamicScope);
+ extraScope = new
BlockStaticScope(dynamicScope.getStaticScope()).createDynamicScope(dynamicScope);
dynamicScope.setBindingScope(extraScope);
}
}
Index: src/org/jruby/evaluator/EvaluationState.java
===================================================================
--- src/org/jruby/evaluator/EvaluationState.java (revision 3914)
+++ src/org/jruby/evaluator/EvaluationState.java (working copy)
@@ -1599,7 +1599,7 @@
// since serialization cannot serialize an eval (which is the only
thing
// which is capable of having a non-empty dynamic scope).
if (scope == null) {
- scope = new DynamicScope(iVisited.getStaticScope());
+ scope = iVisited.getStaticScope().createDynamicScope(null);
}
// Each root node has a top-level scope that we need to push
@@ -1913,7 +1913,7 @@
// Create block for this iter node
// FIXME: We shouldn't use the current scope if it's not actually
from the same hierarchy of static scopes
return Block.createBlock(context, iterNode,
- new DynamicScope(iterNode.getScope(),
context.getCurrentScope()), self);
+
iterNode.getScope().createDynamicScope(context.getCurrentScope()), self);
} else if (blockNode instanceof BlockPassNode) {
BlockPassNode blockPassNode = (BlockPassNode) blockNode;
IRubyObject proc = evalInternal(runtime,context,
blockPassNode.getBodyNode(), self, currentBlock);
Index: src/org/jruby/internal/runtime/methods/YARVMethod.java
===================================================================
--- src/org/jruby/internal/runtime/methods/YARVMethod.java (revision 3914)
+++ src/org/jruby/internal/runtime/methods/YARVMethod.java (working copy)
@@ -97,7 +97,7 @@
traceCall(context, runtime, name);
}
- DynamicScope sc = new DynamicScope(staticScope);
+ DynamicScope sc = staticScope.createDynamicScope(null);
for(int i = 0; i<args.length; i++) {
sc.setValue(i,args[i],0);
}
Index: src/org/jruby/javasupport/util/CompilerHelpers.java
===================================================================
--- src/org/jruby/javasupport/util/CompilerHelpers.java (revision 3914)
+++ src/org/jruby/javasupport/util/CompilerHelpers.java (working copy)
@@ -42,7 +42,7 @@
new BlockStaticScope(context.getCurrentScope().getStaticScope(),
staticScopeNames);
return new CompiledBlock(context, self, Arity.createArity(arity),
- new DynamicScope(staticScope, context.getCurrentScope()),
callback);
+ staticScope.createDynamicScope(context.getCurrentScope()),
callback);
}
public static IRubyObject def(ThreadContext context, Visibility
visibility, IRubyObject self, Class compiledClass, String name, String
javaName, String[] scopeNames, int arity) {
Index: src/org/jruby/parser/StaticScope.java
===================================================================
--- src/org/jruby/parser/StaticScope.java (revision 3914)
+++ src/org/jruby/parser/StaticScope.java (working copy)
@@ -51,6 +51,8 @@
this.variableNames = names;
}
+ public abstract DynamicScope createDynamicScope(DynamicScope parent);
+
public int addVariable(String name) {
int slot = isDefined(name);
Index: src/org/jruby/parser/RubyParserConfiguration.java
===================================================================
--- src/org/jruby/parser/RubyParserConfiguration.java (revision 3914)
+++ src/org/jruby/parser/RubyParserConfiguration.java (working copy)
@@ -60,6 +60,6 @@
// of the AST before parsing. This makes us end up needing to readjust
// this dynamic scope coming out of parse (and for local static scopes
it
// will always happen because of $~ and $_).
- return new DynamicScope(new LocalStaticScope(null), existingScope);
+ return new LocalStaticScope(null).createDynamicScope(existingScope);
}
}
Index: src/org/jruby/parser/BlockStaticScope.java
===================================================================
--- src/org/jruby/parser/BlockStaticScope.java (revision 3914)
+++ src/org/jruby/parser/BlockStaticScope.java (working copy)
@@ -48,6 +48,15 @@
super(parentScope, names);
}
+ public DynamicScope createDynamicScope(DynamicScope parent) {
+ switch (getNumberOfVariables()) {
+ case 0:
+ return new DynamicScope.EmptyBlockScope(this, parent);
+ default:
+ return new DynamicScope.ArbitrarySizeBlockScope(this, parent);
+ }
+ }
+
public StaticScope getLocalScope() {
return getEnclosingScope().getLocalScope();
}
Index: src/org/jruby/parser/LocalStaticScope.java
===================================================================
--- src/org/jruby/parser/LocalStaticScope.java (revision 3914)
+++ src/org/jruby/parser/LocalStaticScope.java (working copy)
@@ -51,6 +51,10 @@
public LocalStaticScope(StaticScope enclosingScope, String[] names) {
super(enclosingScope, names);
}
+
+ public DynamicScope createDynamicScope(DynamicScope parent) {
+ return new DynamicScope.ArbitrarySizeLocalScope(this);
+ }
public StaticScope getLocalScope() {
return this;
Index: src/org/jruby/ast/executable/YARVMachine.java
===================================================================
--- src/org/jruby/ast/executable/YARVMachine.java (revision 3914)
+++ src/org/jruby/ast/executable/YARVMachine.java (working copy)
@@ -119,7 +119,7 @@
}
public IRubyObject exec(ThreadContext context, IRubyObject self,
StaticScope scope, Instruction[] bytecodes) {
- return exec(context,self, new DynamicScope(scope),bytecodes);
+ return exec(context,self, scope.createDynamicScope(null),bytecodes);
}
public IRubyObject exec(ThreadContext context, IRubyObject self,
DynamicScope scope, Instruction[] bytecodes) {
Index: src/org/jruby/ast/executable/YARVCompiledRunner.java
===================================================================
--- src/org/jruby/ast/executable/YARVCompiledRunner.java (revision 3914)
+++ src/org/jruby/ast/executable/YARVCompiledRunner.java (working copy)
@@ -86,7 +86,7 @@
StaticScope scope = new LocalStaticScope(null);
scope.setVariables(iseq.locals);
context.setPosition(new ISeqPosition(iseq));
- return ym.exec(context, runtime.getObject(), new
DynamicScope(scope,null), iseq.body);
+ return ym.exec(context, runtime.getObject(),
scope.createDynamicScope(null), iseq.body);
}
private YARVMachine.InstructionSequence transformIntoSequence(IRubyObject
arr) {
---------------------------------------------------------------------
To unsubscribe from this list please visit:
http://xircles.codehaus.org/manage_email