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

Reply via email to