<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>src/org/jruby/runtime/ConstantCacheMap.java</filename>
    </added>
    <added>
      <filename>src/org/jruby/runtime/callsite/ConstantSite.java</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -32,6 +32,7 @@
  ***** END LICENSE BLOCK *****/
 package org.jruby;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
@@ -270,43 +271,15 @@ public final class IncludedModuleWrapper extends RubyClass {
         // this _is_ legal (when removing an undef)
         return delegate.constantTableRemove(name);
     }
-
-    @Override
-    protected ConstantTableEntry[] constantTableGetTable() {
-        return delegate.constantTableGetTable();
-    }
-
-    @Override
-    protected int constantTableGetSize() {
-        return delegate.constantTableGetSize();
-    }
-
-    @Override
-    protected void constantTableSync(List&lt;Variable&lt;IRubyObject&gt;&gt; vars) {
-        // FIXME: legal here? may want UnsupportedOperationException
-        delegate.constantTableSync(vars);
-    }
-
-    /**
-     * Method to help ease transition to new variables implementation.
-     * Will likely be deprecated in the near future.
-     */
-    @SuppressWarnings(&quot;unchecked&quot;)
+    
     @Override
-    @Deprecated // born deprecated
-    protected Map constantTableGetMap() {
-        return delegate.constantTableGetMap();
+    @Deprecated
+    public List&lt;String&gt; getStoredConstantNameList() {
+        return delegate.getStoredConstantNameList();
     }
-
-    /**
-     * Method to help ease transition to new variables implementation.
-     * Will likely be deprecated in the near future.
-     */
-    @SuppressWarnings(&quot;unchecked&quot;)
+    
     @Override
-    @Deprecated // born deprecated
-    protected Map constantTableGetMap(Map map) {
-        return delegate.constantTableGetMap(map);
+    public Collection&lt;String&gt; getConstantNames() {
+        return delegate.getConstantNames();
     }
-
 }</diff>
      <filename>src/org/jruby/IncludedModuleWrapper.java</filename>
    </modified>
    <modified>
      <diff>@@ -104,6 +104,7 @@ import org.jruby.runtime.Block;
 import org.jruby.runtime.CacheMap;
 import org.jruby.runtime.CallSite;
 import org.jruby.runtime.CallbackFactory;
+import org.jruby.runtime.ConstantCacheMap;
 import org.jruby.runtime.DynamicScope;
 import org.jruby.runtime.EventHook;
 import org.jruby.runtime.GlobalVariable;
@@ -182,6 +183,7 @@ public final class Ruby {
         config.setError(err);
         return newInstance(config);
     }
+    private ConstantCacheMap constantCacheMap;
     
     /**
      * Create and initialize a new JRuby runtime. The properties of the
@@ -214,6 +216,7 @@ public final class Ruby {
         this.beanManager.register(new ClassCache(this));
         
         this.cacheMap = new CacheMap(this);
+        this.constantCacheMap = new ConstantCacheMap(this);
     }
     
     /**
@@ -1302,6 +1305,10 @@ public final class Ruby {
         return cacheMap;
     }
 
+    public ConstantCacheMap getConstantCacheMap() {
+        return constantCacheMap;
+    }
+
     /** Getter for property rubyTopSelf.
      * @return Value of property rubyTopSelf.
      */</diff>
      <filename>src/org/jruby/Ruby.java</filename>
    </modified>
    <modified>
      <diff>@@ -41,15 +41,14 @@ import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.ReentrantLock;
 
 import org.jruby.anno.JRubyMethod;
@@ -88,8 +87,8 @@ import org.jruby.exceptions.RaiseException;
 import org.jruby.internal.runtime.methods.JavaMethod;
 import org.jruby.javasupport.util.RuntimeHelpers;
 import org.jruby.runtime.ClassIndex;
+import org.jruby.runtime.ConstantCacheMap;
 import org.jruby.runtime.MethodFactory;
-import org.jruby.runtime.MethodIndex;
 import org.jruby.util.collections.WeakHashSet;
 
 /**
@@ -186,15 +185,8 @@ public class RubyModule extends RubyObject {
     // write methods are overridden here to use this lock rather than Java
     // synchronization for faster concurrent writes for modules/classes.
     protected final ReentrantLock variableWriteLock = new ReentrantLock();
-    
-    protected transient volatile ConstantTableEntry[] constantTable =
-        new ConstantTableEntry[CONSTANT_TABLE_DEFAULT_CAPACITY];
-
-    protected transient int constantTableSize;
-
-    protected transient int constantTableThreshold = 
-        (int)(CONSTANT_TABLE_DEFAULT_CAPACITY * CONSTANT_TABLE_LOAD_FACTOR);
 
+    private final Map&lt;String, IRubyObject&gt; constants = new ConcurrentHashMap&lt;String, IRubyObject&gt;();
     private final Map&lt;String, DynamicMethod&gt; methods = new ConcurrentHashMap&lt;String, DynamicMethod&gt;(12, 0.75f, 1);
     private final Map&lt;String, CacheEntry&gt; cachedMethods = new ConcurrentHashMap&lt;String, CacheEntry&gt;(12, 0.75f, 1);
     
@@ -500,10 +492,21 @@ public class RubyModule extends RubyObject {
 
         infectBy(module);
 
+        flushConstants();
         doIncludeModule(module);
         invalidateCacheDescendants();
     }
 
+    private void flushConstants() {
+        ConstantCacheMap map = getRuntime().getConstantCacheMap();
+
+        for (RubyModule p = this; p != null; p = p.getSuperClass()) {
+            for (String name : p.getConstantNames()) {
+                map.remove(name);
+            }
+        }
+    }
+
     public void defineMethod(String name, Callback method) {
         Visibility visibility = name.equals(&quot;initialize&quot;) ?
                 PRIVATE : PUBLIC;
@@ -527,7 +530,7 @@ public class RubyModule extends RubyObject {
     public void defineAnnotatedConstants(Class clazz) {
         Field[] declaredFields = clazz.getDeclaredFields();
         for (Field field : declaredFields) {
-            if(Modifier.isStatic(field.getModifiers())) {
+            if (Modifier.isStatic(field.getModifiers())) {
                 defineAnnotatedConstant(field);
             }
         }
@@ -862,17 +865,15 @@ public class RubyModule extends RubyObject {
             callMethod(context, &quot;method_undefined&quot;, runtime.newSymbol(name));
         }
     }
-    
+
     @JRubyMethod(name = &quot;include?&quot;, required = 1)
     public IRubyObject include_p(ThreadContext context, IRubyObject arg) {
-        if (!arg.isModule()) {
-            throw context.getRuntime().newTypeError(arg, context.getRuntime().getModule());
-        }
-        
-        for (RubyModule p = this; p != null; p = p.getSuperClass()) {
-            if ((p instanceof IncludedModuleWrapper) &amp;&amp; ((IncludedModuleWrapper) p).getNonIncludedClass() == arg) {
-                return context.getRuntime().getTrue();
-            }
+        if (!arg.isModule()) throw context.getRuntime().newTypeError(arg, context.getRuntime().getModule());
+        RubyModule moduleToCompare = (RubyModule) arg;
+
+        // See if module is in chain...Cannot match against itself so start at superClass.
+        for (RubyModule p = getSuperClass(); p != null; p = p.getSuperClass()) {
+            if (p.isSame(moduleToCompare)) return context.getRuntime().getTrue();
         }
         
         return context.getRuntime().getFalse();
@@ -1005,10 +1006,8 @@ public class RubyModule extends RubyObject {
      * @return The method, or UndefinedMethod if not found
      */
     public RubyModule findImplementer(RubyModule clazz) {
-        for (RubyModule searchModule = this; searchModule != null; searchModule = searchModule.getSuperClass()) {
-            if (searchModule.isSame(clazz)) {
-                return searchModule;
-            }
+        for (RubyModule module = this; module != null; module = module.getSuperClass()) {
+            if (module.isSame(clazz)) return module;
         }
 
         return null;
@@ -1454,16 +1453,18 @@ public class RubyModule extends RubyObject {
 
         if (!getMetaClass().isSingleton()) setMetaClass(originalModule.getSingletonClassClone());
         setSuperClass(originalModule.getSuperClass());
-
-        if (originalModule.hasVariables()){
-            syncVariables(originalModule.getVariableList());
-        }
+        if (originalModule.hasVariables()) syncVariables(originalModule.getVariableList());
+        syncConstants(originalModule);
 
         originalModule.cloneMethods(this);
 
         return this;
     }
 
+    public void syncConstants(RubyModule other) {
+        constants.putAll(other.constants);
+    }
+
     /** rb_mod_included_modules
      *
      */
@@ -1496,10 +1497,8 @@ public class RubyModule extends RubyObject {
     public List&lt;IRubyObject&gt; getAncestorList() {
         ArrayList&lt;IRubyObject&gt; list = new ArrayList&lt;IRubyObject&gt;();
 
-        for (RubyModule p = this; p != null; p = p.getSuperClass()) {
-            if(!p.isSingleton()) {
-                list.add(p.getNonIncludedClass());
-            }
+        for (RubyModule module = this; module != null; module = module.getSuperClass()) {
+            if(!module.isSingleton()) list.add(module.getNonIncludedClass());
         }
 
         return list;
@@ -1510,8 +1509,8 @@ public class RubyModule extends RubyObject {
         // when scanning the hierarchy. However the == check may be safe; we should only ever have
         // one instance bound to a given type/constant. If it's found to be unsafe, examine ways
         // to avoid the == call.
-        for (RubyModule p = this; p != null; p = p.getSuperClass()) {
-            if (p.getNonIncludedClass() == type) return true;
+        for (RubyModule module = this; module != null; module = module.getSuperClass()) {
+            if (module.getNonIncludedClass() == type) return true;
         }
 
         return false;
@@ -1584,11 +1583,8 @@ public class RubyModule extends RubyObject {
             throw getRuntime().newTypeError(&quot;compared with non class/module&quot;);
         }
 
-        if (isKindOfModule((RubyModule) obj)) {
-            return getRuntime().getTrue();
-        } else if (((RubyModule) obj).isKindOfModule(this)) {
-            return getRuntime().getFalse();
-        }
+        if (isKindOfModule((RubyModule) obj)) return getRuntime().getTrue();
+        if (((RubyModule) obj).isKindOfModule(this)) return getRuntime().getFalse();
 
         return getRuntime().getNil();
     }
@@ -1631,20 +1627,15 @@ public class RubyModule extends RubyObject {
 
         RubyModule module = (RubyModule) obj;
 
-        if (module.isKindOfModule(this)) {
-            return getRuntime().newFixnum(1);
-        } else if (this.isKindOfModule(module)) {
-            return getRuntime().newFixnum(-1);
-        }
+        if (module.isKindOfModule(this)) return getRuntime().newFixnum(1);
+        if (this.isKindOfModule(module)) return getRuntime().newFixnum(-1);
 
         return getRuntime().getNil();
     }
 
     public boolean isKindOfModule(RubyModule type) {
-        for (RubyModule p = this; p != null; p = p.getSuperClass()) {
-            if (p.isSame(type)) {
-                return true;
-            }
+        for (RubyModule module = this; module != null; module = module.getSuperClass()) {
+            if (module.isSame(type)) return true;
         }
 
         return false;
@@ -1692,9 +1683,7 @@ public class RubyModule extends RubyObject {
         return getRuntime().getNil();
     }
 
-    /**
-     * @deprecated
-     */
+    @Deprecated
     public IRubyObject attr_reader(IRubyObject[] args) {
         return attr_reader(getRuntime().getCurrentContext(), args);
     }
@@ -1723,9 +1712,8 @@ public class RubyModule extends RubyObject {
         return context.getRuntime().getNil();
     }
 
-    /**
-     * @deprecated
-     */
+
+    @Deprecated
     public IRubyObject attr_accessor(IRubyObject[] args) {
         return attr_accessor(getRuntime().getCurrentContext(), args);
     }
@@ -1761,14 +1749,13 @@ public class RubyModule extends RubyObject {
 
         for (RubyModule type = this; type != null; type = type.getSuperClass()) {
             RubyModule realType = type.getNonIncludedClass();
-            for (Iterator iter = type.getMethods().entrySet().iterator(); iter.hasNext();) {
-                Map.Entry entry = (Map.Entry) iter.next();
-                DynamicMethod method = (DynamicMethod) entry.getValue();
+            for (Map.Entry entry : type.getMethods().entrySet()) {
                 String methodName = (String) entry.getKey();
 
                 if (! seen.contains(methodName)) {
                     seen.add(methodName);
-                    
+
+                    DynamicMethod method = (DynamicMethod) entry.getValue();
                     if (method.getImplementationClass() == realType &amp;&amp;
                         (!not &amp;&amp; method.getVisibility() == visibility || (not &amp;&amp; method.getVisibility() != visibility)) &amp;&amp;
                         ! method.isUndefined()) {
@@ -2233,17 +2220,12 @@ public class RubyModule extends RubyObject {
         Set&lt;String&gt; names = new HashSet&lt;String&gt;();
 
         for (RubyModule p = this; p != null; p = p.getSuperClass()) {
-            for (String name : p.getClassVariableNameList()) {
-                names.add(name);
-            }
+            names.addAll(p.getClassVariableNameList());
         }
 
-        Ruby runtime = context.getRuntime();
-        RubyArray ary = runtime.newArray();
+        RubyArray ary = context.getRuntime().newArray();
 
-        for (String name : names) {
-            ary.append(runtime.newString(name));
-        }
+        ary.addAll(names);
 
         return ary;
     }
@@ -2267,7 +2249,7 @@ public class RubyModule extends RubyObject {
      */
     @JRubyMethod(name = &quot;const_get&quot;, required = 1)
     public IRubyObject const_get(IRubyObject symbol) {
-        return fastGetConstant(validateConstant(symbol.asJavaString()).intern());
+        return getConstant(validateConstant(symbol.asJavaString()));
     }
 
     /** rb_mod_const_set
@@ -2279,31 +2261,32 @@ public class RubyModule extends RubyObject {
     }
 
     @JRubyMethod(name = &quot;remove_const&quot;, required = 1, visibility = PRIVATE)
-    public IRubyObject remove_const(ThreadContext context, IRubyObject name) {
-        String id = validateConstant(name.asJavaString());
+    public IRubyObject remove_const(ThreadContext context, IRubyObject rubyName) {
+        String name = validateConstant(rubyName.asJavaString());
         IRubyObject value;
-        if ((value = deleteConstant(id)) != null) {
+        if ((value = deleteConstant(name)) != null) {
+            getRuntime().getConstantCacheMap().remove(name);
             if (value != UNDEF) {
                 return value;
             }
-            context.getRuntime().getLoadService().removeAutoLoadFor(getName() + &quot;::&quot; + id);
+            context.getRuntime().getLoadService().removeAutoLoadFor(getName() + &quot;::&quot; + name);
             // FIXME: I'm not sure this is right, but the old code returned
             // the undef, which definitely isn't right...
             return context.getRuntime().getNil();
         }
 
-        if (hasConstantInHierarchy(id)) {
-            throw cannotRemoveError(id);
+        if (hasConstantInHierarchy(name)) {
+            throw cannotRemoveError(name);
         }
 
-        throw context.getRuntime().newNameError(&quot;constant &quot; + id + &quot; not defined for &quot; + getName(), id);
+        throw context.getRuntime().newNameError(&quot;constant &quot; + name + &quot; not defined for &quot; + getName(), name);
     }
 
     private boolean hasConstantInHierarchy(final String name) {
         for (RubyModule p = this; p != null; p = p.getSuperClass()) {
             if (p.hasConstant(name)) {
                 return true;
-            }
+        }
         }
         return false;
     }
@@ -2315,13 +2298,17 @@ public class RubyModule extends RubyObject {
      * @return Nothing! Absolutely nothing! (though subclasses might choose to return something)
      */
     @JRubyMethod(name = &quot;const_missing&quot;, required = 1, frame = true)
-    public IRubyObject const_missing(ThreadContext context, IRubyObject name, Block block) {
-        /* Uninitialized constant */
-        if (this != context.getRuntime().getObject()) {
-            throw context.getRuntime().newNameError(&quot;uninitialized constant &quot; + getName() + &quot;::&quot; + name.asJavaString(), &quot;&quot; + getName() + &quot;::&quot; + name.asJavaString());
+    public IRubyObject const_missing(ThreadContext context, IRubyObject rubyName, Block block) {
+        Ruby runtime = context.getRuntime();
+        String name;
+        
+        if (this != runtime.getObject()) {
+            name = getName() + &quot;::&quot; + rubyName.asJavaString();
+        } else {
+            name = rubyName.asJavaString();
         }
 
-        throw context.getRuntime().newNameError(&quot;uninitialized constant &quot; + name.asJavaString(), name.asJavaString());
+        throw runtime.newNameError(&quot;uninitialized constant &quot; + name, name);
     }
 
     /** rb_mod_constants
@@ -2333,30 +2320,14 @@ public class RubyModule extends RubyObject {
         RubyArray array = runtime.newArray();
         RubyModule objectClass = runtime.getObject();
 
-        if (getRuntime().getModule() == this) {
-
-            for (String name : objectClass.getStoredConstantNameList()) {
-                array.append(runtime.newString(name));
-            }
-
-        } else if (objectClass == this) {
-
-            for (String name : getStoredConstantNameList()) {
-                array.append(runtime.newString(name));
-            }
-
+        if (getRuntime().getModule() == this || objectClass == this) {
+            array.addAll(objectClass.getConstantNames());
         } else {
             Set&lt;String&gt; names = new HashSet&lt;String&gt;();
-            for (RubyModule p = this; p != null; p = p.getSuperClass()) {
-                if (objectClass != p) {
-                    for (String name : p.getStoredConstantNameList()) {
-                        names.add(name);
-                    }
-                }
-            }
-            for (String name : names) {
-                array.append(runtime.newString(name));
+            for (RubyModule module = this; module != null &amp;&amp; module != objectClass; module = module.getSuperClass()) {
+                names.addAll(module.getConstantNames());
             }
+            array.addAll(names);
         }
 
         return array;
@@ -2484,22 +2455,16 @@ public class RubyModule extends RubyObject {
     //
 
     public IRubyObject getConstantAt(String name) {
-        IRubyObject value;
-        if ((value = fetchConstant(name)) != UNDEF) {
-            return value;
-        }
-        deleteConstant(name);
-        return getRuntime().getLoadService().autoload(getName() + &quot;::&quot; + name);
+        IRubyObject value = fetchConstant(name);
+        
+        return value == UNDEF ? resolveUndefConstant(getRuntime(), name) : value;
     }
 
     public IRubyObject fastGetConstantAt(String internedName) {
         assert internedName == internedName.intern() : internedName + &quot; is not interned&quot;;
-        IRubyObject value;
-        if ((value = fastFetchConstant(internedName)) != UNDEF) {
-            return value;
-        }
-        deleteConstant(internedName);
-        return getRuntime().getLoadService().autoload(getName() + &quot;::&quot; + internedName);
+        IRubyObject value = fastFetchConstant(internedName);
+
+        return value == UNDEF ? resolveUndefConstant(getRuntime(), internedName) : value;
     }
 
     /**
@@ -2509,74 +2474,43 @@ public class RubyModule extends RubyObject {
      * @return The value for the constant, or null if not found
      */
     public IRubyObject getConstant(String name) {
+        return fastGetConstant(name);
+    }
+    
+    public IRubyObject fastGetConstant(String internedName) {
+        IRubyObject value = getConstantNoConstMissing(internedName);
+        Ruby runtime = getRuntime();
+        
+        return value == null ? callMethod(runtime.getCurrentContext(), &quot;const_missing&quot;,
+                runtime.fastNewSymbol(internedName)) : value;
+    }
+    
+    public IRubyObject getConstantNoConstMissing(String name) {
         assert IdUtil.isConstant(name);
-        boolean retryForModule = false;
-        IRubyObject value;
-        RubyModule p = this;
 
-        retry: while (true) {
-            while (p != null) {
-                if ((value = p.constantTableFetch(name)) != null) {
-                    if (value != UNDEF) {
-                        return value;
-                    }
-                    p.deleteConstant(name);
-                    if (getRuntime().getLoadService().autoload(
-                            p.getName() + &quot;::&quot; + name) == null) {
-                        break;
-                    }
-                    continue;
-                }
-                p = p.getSuperClass();
-            }
+        for (RubyModule p = this; p != null; p = p.getSuperClass()) {
+            IRubyObject value = p.getConstantInner(name);
 
-            if (!retryForModule &amp;&amp; !isClass()) {
-                retryForModule = true;
-                p = getRuntime().getObject();
-                continue retry;
-            }
+            if (value != null) return value == UNDEF ? null : value;
+        }
+
+        if (!isClass()) {
+            IRubyObject value = getRuntime().getObject().getConstantInner(name);
 
-            break;
+            return value == UNDEF ? null : value;
         }
 
-        return callMethod(getRuntime().getCurrentContext(),
-                &quot;const_missing&quot;, getRuntime().newSymbol(name));
+        return null;
     }
     
-    public IRubyObject fastGetConstant(String internedName) {
-        assert internedName == internedName.intern() : internedName + &quot; is not interned&quot;;
-        assert IdUtil.isConstant(internedName);
-        boolean retryForModule = false;
-        IRubyObject value;
-        RubyModule p = this;
+    protected IRubyObject getConstantInner(String name) {
+        IRubyObject value = constantTableFetch(name);
 
-        retry: while (true) {
-            while (p != null) {
-                if ((value = p.constantTableFastFetch(internedName)) != null) {
-                    if (value != UNDEF) {
-                        return value;
-                    }
-                    p.deleteConstant(internedName);
-                    if (getRuntime().getLoadService().autoload(
-                            p.getName() + &quot;::&quot; + internedName) == null) {
-                        break;
-                    }
-                    continue;
-                }
-                p = p.getSuperClass();
-            }
-
-            if (!retryForModule &amp;&amp; !isClass()) {
-                retryForModule = true;
-                p = getRuntime().getObject();
-                continue retry;
-            }
-
-            break;
+        for (; value == UNDEF; value = constantTableFetch(name)) {
+            if (resolveUndefConstant(getRuntime(), name) == null) return UNDEF;
         }
-
-        return callMethod(getRuntime().getCurrentContext(),
-                &quot;const_missing&quot;, getRuntime().fastNewSymbol(internedName));
+        
+        return value;
     }
 
     // not actually called anywhere (all known uses call the fast version)
@@ -2587,27 +2521,26 @@ public class RubyModule extends RubyObject {
     public IRubyObject fastGetConstantFrom(String internedName) {
         assert internedName == internedName.intern() : internedName + &quot; is not interned&quot;;
         assert IdUtil.isConstant(internedName);
-        RubyClass objectClass = getRuntime().getObject();
+        Ruby runtime = getRuntime();
+        RubyClass objectClass = runtime.getObject();
         IRubyObject value;
 
         RubyModule p = this;
         
         while (p != null) {
             if ((value = p.constantTableFastFetch(internedName)) != null) {
-                if (value != UNDEF) {
-                    if (p == objectClass &amp;&amp; this != objectClass) {
-                        String badCName = getName() + &quot;::&quot; + internedName;
-                        getRuntime().getWarnings().warn(ID.CONSTANT_BAD_REFERENCE, &quot;toplevel constant &quot; + 
-                                internedName + &quot; referenced by &quot; + badCName, badCName);
-                    }
-                    return value;
+                if (value == UNDEF) {
+                    if (p.resolveUndefConstant(runtime, internedName) == null) break;
+                    continue; // Not that is loaded loop around to resolve it next pass
                 }
-                p.deleteConstant(internedName);
-                if (getRuntime().getLoadService().autoload(
-                        p.getName() + &quot;::&quot; + internedName) == null) {
-                    break;
+
+                if (p == objectClass &amp;&amp; this != objectClass) {
+                    String badCName = getName() + &quot;::&quot; + internedName;
+                    runtime.getWarnings().warn(ID.CONSTANT_BAD_REFERENCE, &quot;toplevel constant &quot; +
+                            internedName + &quot; referenced by &quot; + badCName, badCName);
                 }
-                continue;
+
+                return value;
             }
             p = p.getSuperClass();
         }
@@ -2615,6 +2548,13 @@ public class RubyModule extends RubyObject {
         return callMethod(getRuntime().getCurrentContext(),
                 &quot;const_missing&quot;, getRuntime().fastNewSymbol(internedName));
     }
+    
+    public IRubyObject resolveUndefConstant(Ruby runtime, String name) {
+        deleteConstant(name);
+        
+        return runtime.getLoadService().autoload(getName() + &quot;::&quot; + name);
+    }
+    
     /**
      * Set the named constant on this module. Also, if the value provided is another Module and
      * that module has not yet been named, assign it the specified name.
@@ -2624,12 +2564,14 @@ public class RubyModule extends RubyObject {
      * @return The result of setting the variable.
      */
     public IRubyObject setConstant(String name, IRubyObject value) {
-        IRubyObject oldValue;
-        if ((oldValue = fetchConstant(name)) != null) {
+        IRubyObject oldValue = fetchConstant(name);
+        if (oldValue != null) {
+            Ruby runtime = getRuntime();
+            runtime.getConstantCacheMap().remove(name);
             if (oldValue == UNDEF) {
-                getRuntime().getLoadService().removeAutoLoadFor(getName() + &quot;::&quot; + name);
+                runtime.getLoadService().removeAutoLoadFor(getName() + &quot;::&quot; + name);
             } else {
-                getRuntime().getWarnings().warn(ID.CONSTANT_ALREADY_INITIALIZED, &quot;already initialized constant &quot; + name, name);
+                runtime.getWarnings().warn(ID.CONSTANT_ALREADY_INITIALIZED, &quot;already initialized constant &quot; + name, name);
             }
         }
 
@@ -2642,38 +2584,12 @@ public class RubyModule extends RubyObject {
                 module.setBaseName(name);
                 module.setParent(this);
             }
-            /*
-            module.setParent(this);
-            */
         }
         return value;
     }
 
     public IRubyObject fastSetConstant(String internedName, IRubyObject value) {
-        assert internedName == internedName.intern() : internedName + &quot; is not interned&quot;;
-        IRubyObject oldValue;
-        if ((oldValue = fastFetchConstant(internedName)) != null) {
-            if (oldValue == UNDEF) {
-                getRuntime().getLoadService().removeAutoLoadFor(getName() + &quot;::&quot; + internedName);
-            } else {
-                getRuntime().getWarnings().warn(ID.CONSTANT_ALREADY_INITIALIZED, &quot;already initialized constant &quot; + internedName, internedName);
-            }
-        }
-
-        fastStoreConstant(internedName, value);
-
-        // if adding a module under a constant name, set that module's basename to the constant name
-        if (value instanceof RubyModule) {
-            RubyModule module = (RubyModule)value;
-            if (module.getBaseName() == null) {
-                module.setBaseName(internedName);
-                module.setParent(this);
-            }
-            /*
-            module.setParent(this);
-            */
-        }
-        return value;
+        return setConstant(internedName, value);
     }
     
     /** rb_define_const
@@ -2759,12 +2675,9 @@ public class RubyModule extends RubyObject {
      * @see #setInternalModuleVariable(String, IRubyObject)
      */
     public boolean hasInternalModuleVariable(final String name) {
-        RubyModule module = this;
-        do {
-            if (module.hasInternalVariable(name)) {
-                return true;
-            }
-        } while ((module = module.getSuperClass()) != null);
+        for (RubyModule module = this; module != null; module = module.getSuperClass()) {
+            if (module.hasInternalVariable(name)) return true;
+        }
 
         return false;
     }
@@ -2778,13 +2691,10 @@ public class RubyModule extends RubyObject {
      * @see #setInternalModuleVariable(String, IRubyObject)
      */
     public IRubyObject searchInternalModuleVariable(final String name) {
-        RubyModule module = this;
-        IRubyObject value;
-        do {
-            if ((value = module.getInternalVariable(name)) != null) {
-                return value;
-            }
-        } while ((module = module.getSuperClass()) != null);
+        for (RubyModule module = this; module != null; module = module.getSuperClass()) {
+            IRubyObject value = module.getInternalVariable(name);
+            if (value != null) return value;
+        }
 
         return null;
     }
@@ -2799,13 +2709,12 @@ public class RubyModule extends RubyObject {
      * @see #searchInternalModuleVariable(String)
      */
     public void setInternalModuleVariable(final String name, final IRubyObject value) {
-        RubyModule module = this;
-        do {
+        for (RubyModule module = this; module != null; module = module.getSuperClass()) {
             if (module.hasInternalVariable(name)) {
                 module.setInternalVariable(name, value);
                 return;
             }
-        } while ((module = module.getSuperClass()) != null);
+        }
 
         setInternalVariable(name, value);
     }
@@ -2958,26 +2867,22 @@ public class RubyModule extends RubyObject {
         return constantTableRemove(name);
     }
 
+
+    @Deprecated
     public List&lt;Variable&lt;IRubyObject&gt;&gt; getStoredConstantList() {
-        ArrayList&lt;Variable&lt;IRubyObject&gt;&gt; list = new ArrayList&lt;Variable&lt;IRubyObject&gt;&gt;();
-        ConstantTableEntry[] table = constantTableGetTable();
-        for (int i = table.length; --i &gt;= 0; ) {
-            for (ConstantTableEntry e = table[i]; e != null; e = e.next) {
-                list.add(e);
-            }
-        }
-        return list;
+        return null;
     }
 
+    @Deprecated
     public List&lt;String&gt; getStoredConstantNameList() {
-        ArrayList&lt;String&gt; list = new ArrayList&lt;String&gt;();
-        ConstantTableEntry[] table = constantTableGetTable();
-        for (int i = table.length; --i &gt;= 0; ) {
-            for (ConstantTableEntry e = table[i]; e != null; e = e.next) {
-                list.add(e.name);
-            }
-        }
-        return list;
+        return new ArrayList&lt;String&gt;(constants.keySet());
+    }
+
+    /**
+     * @return a list of constant names that exists at time this was called
+     */
+    public Collection&lt;String&gt; getConstantNames() {
+        return constants.keySet();
     }
 
     protected static final String ERR_INSECURE_SET_CONSTANT  = &quot;Insecure: can't modify constant&quot;;
@@ -2991,583 +2896,41 @@ public class RubyModule extends RubyObject {
     }
 
     protected final void ensureConstantsSettable() {
-        Ruby runtime = getRuntime();
-        
-        if (!isFrozen() &amp;&amp; (runtime.getSafeLevel() &lt; 4 || isTaint())) {
-            return;
-        }
-        
-        if (runtime.getSafeLevel() &gt;= 4 &amp;&amp; !isTaint()) {
-            throw runtime.newSecurityError(ERR_INSECURE_SET_CONSTANT);
-        }
-        if (isFrozen()) {
-            if (this instanceof RubyModule) {
-                throw runtime.newFrozenError(ERR_FROZEN_CONST_TYPE);
-            } else {
-                throw runtime.newFrozenError(&quot;&quot;);
-            }
-        }
-    }
-
-     
-    //
-    ////////////////// VARIABLE TABLE METHODS ////////////////
-    //
-    // Overridden to use variableWriteLock in place of synchronization  
-    //
-
-    @Override
-    protected IRubyObject variableTableStore(String name, IRubyObject value) {
-        int hash = name.hashCode();
-        ReentrantLock lock;
-        (lock = variableWriteLock).lock();
-        try {
-            VariableTableEntry[] table;
-            VariableTableEntry e;
-            if ((table = variableTable) == null) {
-                table =  new VariableTableEntry[VARIABLE_TABLE_DEFAULT_CAPACITY];
-                e = new VariableTableEntry(hash, name.intern(), value, null);
-                table[hash &amp; (VARIABLE_TABLE_DEFAULT_CAPACITY - 1)] = e;
-                variableTableThreshold = (int)(VARIABLE_TABLE_DEFAULT_CAPACITY * VARIABLE_TABLE_LOAD_FACTOR);
-                variableTableSize = 1;
-                variableTable = table;
-                return value;
-            }
-            int potentialNewSize;
-            if ((potentialNewSize = variableTableSize + 1) &gt; variableTableThreshold) {
-                table = variableTableRehash();
-            }
-            int index;
-            for (e = table[index = hash &amp; (table.length - 1)]; e != null; e = e.next) {
-                if (hash == e.hash &amp;&amp; name.equals(e.name)) {
-                    e.value = value;
-                    return value;
-                }
-            }
-            // external volatile value initialization intended to obviate the need for
-            // readValueUnderLock technique used in ConcurrentHashMap. may be a little
-            // slower, but better to pay a price on first write rather than all reads.
-            e = new VariableTableEntry(hash, name.intern(), value, table[index]);
-            table[index] = e;
-            variableTableSize = potentialNewSize;
-            variableTable = table; // write-volatile
-        } finally {
-            lock.unlock();
-        }
-        return value;
-    }
-    
-    @Override
-    protected IRubyObject variableTableFastStore(String internedName, IRubyObject value) {
-        assert internedName == internedName.intern() : internedName + &quot; not interned&quot;;
-        int hash = internedName.hashCode();
-        ReentrantLock lock;
-        (lock = variableWriteLock).lock();
-        try {
-            VariableTableEntry[] table;
-            VariableTableEntry e;
-            if ((table = variableTable) == null) {
-                table =  new VariableTableEntry[VARIABLE_TABLE_DEFAULT_CAPACITY];
-                e = new VariableTableEntry(hash, internedName, value, null);
-                table[hash &amp; (VARIABLE_TABLE_DEFAULT_CAPACITY - 1)] = e;
-                variableTableThreshold = (int)(VARIABLE_TABLE_DEFAULT_CAPACITY * VARIABLE_TABLE_LOAD_FACTOR);
-                variableTableSize = 1;
-                variableTable = table;
-                return value;
-            }
-            int potentialNewSize;
-            if ((potentialNewSize = variableTableSize + 1) &gt; variableTableThreshold) {
-                table = variableTableRehash();
-            }
-            int index;
-            for (e = table[index = hash &amp; (table.length - 1)]; e != null; e = e.next) {
-                if (internedName == e.name) {
-                    e.value = value;
-                    return value;
-                }
-            }
-            // external volatile value initialization intended to obviate the need for
-            // readValueUnderLock technique used in ConcurrentHashMap. may be a little
-            // slower, but better to pay a price on first write rather than all reads.
-            e = new VariableTableEntry(hash, internedName, value, table[index]);
-            table[index] = e;
-            variableTableSize = potentialNewSize;
-            variableTable = table; // write-volatile
-        } finally {
-            lock.unlock();
-        }
-        return value;
-    }
-
-    @Override   
-    protected IRubyObject variableTableRemove(String name) {
-        ReentrantLock lock;
-        (lock = variableWriteLock).lock();
-        try {
-            VariableTableEntry[] table;
-            if ((table = variableTable) != null) {
-                int hash = name.hashCode();
-                int index = hash &amp; (table.length - 1);
-                VariableTableEntry first = table[index];
-                VariableTableEntry e;
-                for (e = first; e != null; e = e.next) {
-                    if (hash == e.hash &amp;&amp; name.equals(e.name)) {
-                        IRubyObject oldValue = e.value;
-                        // All entries following removed node can stay
-                        // in list, but all preceding ones need to be
-                        // cloned.
-                        VariableTableEntry newFirst = e.next;
-                        for (VariableTableEntry p = first; p != e; p = p.next) {
-                            newFirst = new VariableTableEntry(p.hash, p.name, p.value, newFirst);
-                        }
-                        table[index] = newFirst;
-                        variableTableSize--;
-                        variableTable = table; // write-volatile 
-                        return oldValue;
-                    }
-                }
-            }
-        } finally {
-            lock.unlock();
-        }
-        return null;
-    }
-    
-    @Override
-    protected IRubyObject variableTableReadLocked(VariableTableEntry entry) {
-        ReentrantLock lock;
-        (lock = variableWriteLock).lock();
-        try {
-            return entry.value;
-        } finally {
-            lock.unlock();
-        }
-    }
-    
-    @Override
-    protected void variableTableSync(List&lt;Variable&lt;IRubyObject&gt;&gt; vars) {
-        ReentrantLock lock;
-        (lock = variableWriteLock).lock();
-        try {
-            variableTableSize = 0;
-            variableTableThreshold = (int)(VARIABLE_TABLE_DEFAULT_CAPACITY * VARIABLE_TABLE_LOAD_FACTOR);
-            variableTable =  new VariableTableEntry[VARIABLE_TABLE_DEFAULT_CAPACITY];
-            for (Variable&lt;IRubyObject&gt; var : vars) {
-                assert !var.isConstant() &amp;&amp; var.getValue() != null;
-                variableTableStore(var.getName(), var.getValue());
-            }
-        } finally {
-            lock.unlock();
-        }
-    }
-    
-    @Override
-    public void syncVariables(List&lt;Variable&lt;IRubyObject&gt;&gt; variables) {
-        ArrayList&lt;Variable&lt;IRubyObject&gt;&gt; constants = new ArrayList&lt;Variable&lt;IRubyObject&gt;&gt;(variables.size());
-        Variable&lt;IRubyObject&gt; var;
-        for (Iterator&lt;Variable&lt;IRubyObject&gt;&gt; iter = variables.iterator(); iter.hasNext(); ) {
-            if ((var = iter.next()).isConstant()) {
-                constants.add(var);
-                iter.remove();
-            }
-        }
-        ReentrantLock lock;
-        (lock = variableWriteLock).lock();
-        try {
-            variableTableSync(variables);
-            constantTableSync(constants);
-        } finally {
-            lock.unlock();
-        }
-    }
-
-    @Override
-    @SuppressWarnings(&quot;unchecked&quot;)
-    @Deprecated // born deprecated
-    public Map getVariableMap() {
-        Map map = variableTableGetMap();
-        constantTableGetMap(map);
-        return map;
-    }
-
-    @Override
-    public boolean hasVariables() {
-        return variableTableGetSize() &gt; 0 || constantTableGetSize() &gt; 0;
-    }
-
-    @Override
-    public int getVariableCount() {
-        return variableTableGetSize() + constantTableGetSize();
-    }
-    
-    @Override
-    public List&lt;Variable&lt;IRubyObject&gt;&gt; getVariableList() {
-        VariableTableEntry[] vtable = variableTableGetTable();
-        ConstantTableEntry[] ctable = constantTableGetTable();
-        ArrayList&lt;Variable&lt;IRubyObject&gt;&gt; list = new ArrayList&lt;Variable&lt;IRubyObject&gt;&gt;();
-        IRubyObject readValue;
-        for (int i = vtable.length; --i &gt;= 0; ) {
-            for (VariableTableEntry e = vtable[i]; e != null; e = e.next) {
-                if ((readValue = e.value) == null) readValue = variableTableReadLocked(e);
-                list.add(new VariableEntry&lt;IRubyObject&gt;(e.name, readValue));
-            }
-        }
-        for (int i = ctable.length; --i &gt;= 0; ) {
-            for (ConstantTableEntry e = ctable[i]; e != null; e = e.next) {
-                list.add(e);
-            }
-        }
-        return list;
-    }
+        boolean isSecure = getRuntime().getSafeLevel() &gt;= 4 &amp;&amp; !isTaint();
 
-    @Override
-    public List&lt;String&gt; getVariableNameList() {
-        VariableTableEntry[] vtable = variableTableGetTable();
-        ConstantTableEntry[] ctable = constantTableGetTable();
-        ArrayList&lt;String&gt; list = new ArrayList&lt;String&gt;();
-        for (int i = vtable.length; --i &gt;= 0; ) {
-            for (VariableTableEntry e = vtable[i]; e != null; e = e.next) {
-                list.add(e.name);
-            }
-        }
-        for (int i = ctable.length; --i &gt;= 0; ) {
-            for (ConstantTableEntry e = ctable[i]; e != null; e = e.next) {
-                list.add(e.name);
-            }
-        }
-        return list;
-    }
-    
-
-    //
-    ////////////////// CONSTANT TABLE METHODS, ETC. ////////////////
-    //
-    
-    protected static final int CONSTANT_TABLE_DEFAULT_CAPACITY = 8; // MUST be power of 2!
-    protected static final int CONSTANT_TABLE_MAXIMUM_CAPACITY = 1 &lt;&lt; 30;
-    protected static final float CONSTANT_TABLE_LOAD_FACTOR = 0.75f;
-
-    protected static final class ConstantTableEntry implements Variable&lt;IRubyObject&gt; {
-        final int hash;
-        final String name;
-        final IRubyObject value;
-        final ConstantTableEntry next;
-
-        // constant table entry values are final; if a constant is redefined, the
-        // entry will be removed and replaced with a new entry.
-        ConstantTableEntry(
-                int hash,
-                String name,
-                IRubyObject value,
-                ConstantTableEntry next) {
-            this.hash = hash;
-            this.name = name;
-            this.value = value;
-            this.next = next;
-        }
-        
-        public String getName() {
-            return name;
-        }
-        
-        public IRubyObject getValue() {
-            return value;
-        }
-        public final boolean isClassVariable() {
-            return false;
-        }
-        
-        public final boolean isConstant() {
-            return true;
-        }
-        
-        public final boolean isInstanceVariable() {
-            return false;
-        }
-
-        public final boolean isRubyVariable() {
-            return true;
-        }
+        if (isSecure) throw getRuntime().newSecurityError(ERR_INSECURE_SET_CONSTANT);
+        if (isFrozen()) throw getRuntime().newFrozenError(ERR_FROZEN_CONST_TYPE);
     }
 
     protected boolean constantTableContains(String name) {
-        int hash = name.hashCode();
-        ConstantTableEntry[] table;
-        for (ConstantTableEntry e = (table = constantTable)[hash &amp; (table.length - 1)]; e != null; e = e.next) {
-            if (hash == e.hash &amp;&amp; name.equals(e.name)) {
-                return true;
-            }
-        }
-        return false;
+        return constants.containsKey(name);
     }
     
     protected boolean constantTableFastContains(String internedName) {
-        ConstantTableEntry[] table;
-        for (ConstantTableEntry e = (table = constantTable)[internedName.hashCode() &amp; (table.length - 1)]; e != null; e = e.next) {
-            if (internedName == e.name) {
-                return true;
-            }
-        }
-        return false;
+        return constants.containsKey(internedName);
     }
     
     protected IRubyObject constantTableFetch(String name) {
-        int hash = name.hashCode();
-        ConstantTableEntry[] table;
-        for (ConstantTableEntry e = (table = constantTable)[hash &amp; (table.length - 1)]; e != null; e = e.next) {
-            if (hash == e.hash &amp;&amp; name.equals(e.name)) {
-                return e.value;
-            }
-        }
-        return null;
+        return constants.get(name);
     }
     
     protected IRubyObject constantTableFastFetch(String internedName) {
-        ConstantTableEntry[] table;
-        for (ConstantTableEntry e = (table = constantTable)[internedName.hashCode() &amp; (table.length - 1)]; e != null; e = e.next) {
-            if (internedName == e.name) {
-                return e.value;
-            }
-        }
-        return null;
+        return constants.get(internedName);
     }
     
     protected IRubyObject constantTableStore(String name, IRubyObject value) {
-        int hash = name.hashCode();
-        ReentrantLock lock;
-        (lock = variableWriteLock).lock();
-        try {
-            ConstantTableEntry[] table;
-            ConstantTableEntry e;
-            ConstantTableEntry first;
-            int potentialNewSize;
-            if ((potentialNewSize = constantTableSize + 1) &gt; constantTableThreshold) {
-                table = constantTableRehash();
-            } else {
-                table = constantTable;
-            }
-            int index;
-            for (e = first = table[index = hash &amp; (table.length - 1)]; e != null; e = e.next) {
-                if (hash == e.hash &amp;&amp; name.equals(e.name)) {
-                    // if value is unchanged, do nothing
-                    if (value == e.value) {
-                        return value;
-                    }
-                    // create new entry, prepend to any trailing entries
-                    ConstantTableEntry newFirst = new ConstantTableEntry(e.hash, e.name, value, e.next);
-                    // all entries before this one must be cloned
-                    for (ConstantTableEntry n = first; n != e; n = n.next) {
-                        newFirst = new ConstantTableEntry(n.hash, n.name, n.value, newFirst);
-                    }
-                    table[index] = newFirst;
-                    constantTable = table; // write-volatile
-                    return value;
-                }
-            }
-            table[index] = new ConstantTableEntry(hash, name.intern(), value, table[index]);
-            constantTableSize = potentialNewSize;
-            constantTable = table; // write-volatile
-        } finally {
-            lock.unlock();
-        }
+        constants.put(name, value);
         return value;
     }
     
     protected IRubyObject constantTableFastStore(String internedName, IRubyObject value) {
-        assert internedName == internedName.intern() : internedName + &quot; not interned&quot;;
-        int hash = internedName.hashCode();
-        ReentrantLock lock;
-        (lock = variableWriteLock).lock();
-        try {
-            ConstantTableEntry[] table;
-            ConstantTableEntry e;
-            ConstantTableEntry first;
-            int potentialNewSize;
-            if ((potentialNewSize = constantTableSize + 1) &gt; constantTableThreshold) {
-                table = constantTableRehash();
-            } else {
-                table = constantTable;
-            }
-            int index;
-            for (e = first = table[index = hash &amp; (table.length - 1)]; e != null; e = e.next) {
-                if (internedName == e.name) {
-                    // if value is unchanged, do nothing
-                    if (value == e.value) {
-                        return value;
-                    }
-                    // create new entry, prepend to any trailing entries
-                    ConstantTableEntry newFirst = new ConstantTableEntry(e.hash, e.name, value, e.next);
-                    // all entries before this one must be cloned
-                    for (ConstantTableEntry n = first; n != e; n = n.next) {
-                        newFirst = new ConstantTableEntry(n.hash, n.name, n.value, newFirst);
-                    }
-                    table[index] = newFirst;
-                    constantTable = table; // write-volatile
-                    return value;
-                }
-            }
-            table[index] = new ConstantTableEntry(hash, internedName, value, table[index]);
-            constantTableSize = potentialNewSize;
-            constantTable = table; // write-volatile
-        } finally {
-            lock.unlock();
-        }
+        constants.put(internedName, value);
         return value;
     }
         
     protected IRubyObject constantTableRemove(String name) {
-        ReentrantLock lock;
-        (lock = variableWriteLock).lock();
-        try {
-            ConstantTableEntry[] table;
-            if ((table = constantTable) != null) {
-                int hash = name.hashCode();
-                int index = hash &amp; (table.length - 1);
-                ConstantTableEntry first = table[index];
-                ConstantTableEntry e;
-                for (e = first; e != null; e = e.next) {
-                    if (hash == e.hash &amp;&amp; name.equals(e.name)) {
-                        IRubyObject oldValue = e.value;
-                        // All entries following removed node can stay
-                        // in list, but all preceding ones need to be
-                        // cloned.
-                        ConstantTableEntry newFirst = e.next;
-                        for (ConstantTableEntry p = first; p != e; p = p.next) {
-                            newFirst = new ConstantTableEntry(p.hash, p.name, p.value, newFirst);
-                        }
-                        table[index] = newFirst;
-                        constantTableSize--;
-                        constantTable = table; // write-volatile 
-                        return oldValue;
-                    }
-                }
-            }
-        } finally {
-            lock.unlock();
-        }
-        return null;
-    }
-    
-
-    protected ConstantTableEntry[] constantTableGetTable() {
-        return constantTable;
+        return constants.remove(name);
     }
-    
-    protected int constantTableGetSize() {
-        if (constantTable != null) {
-            return constantTableSize;
-        }
-        return 0;
-    }
-    
-    protected void constantTableSync(List&lt;Variable&lt;IRubyObject&gt;&gt; vars) {
-        ReentrantLock lock;
-        (lock = variableWriteLock).lock();
-        try {
-            constantTableSize = 0;
-            constantTableThreshold = (int)(CONSTANT_TABLE_DEFAULT_CAPACITY * CONSTANT_TABLE_LOAD_FACTOR);
-            constantTable =  new ConstantTableEntry[CONSTANT_TABLE_DEFAULT_CAPACITY];
-            for (Variable&lt;IRubyObject&gt; var : vars) {
-                assert var.isConstant() &amp;&amp; var.getValue() != null;
-                constantTableStore(var.getName(), var.getValue());
-            }
-        } finally {
-            lock.unlock();
-        }
-    }
-    
-    // MUST be called from synchronized/locked block!
-    // should only be called by constantTableStore/constantTableFastStore
-    private final ConstantTableEntry[] constantTableRehash() {
-        ConstantTableEntry[] oldTable = constantTable;
-        int oldCapacity;
-        if ((oldCapacity = oldTable.length) &gt;= CONSTANT_TABLE_MAXIMUM_CAPACITY) {
-            return oldTable;
-        }
-        
-        int newCapacity = oldCapacity &lt;&lt; 1;
-        ConstantTableEntry[] newTable = new ConstantTableEntry[newCapacity];
-        constantTableThreshold = (int)(newCapacity * CONSTANT_TABLE_LOAD_FACTOR);
-        int sizeMask = newCapacity - 1;
-        ConstantTableEntry e;
-        for (int i = oldCapacity; --i &gt;= 0; ) {
-            // We need to guarantee that any existing reads of old Map can
-            //  proceed. So we cannot yet null out each bin.
-            e = oldTable[i];
-
-            if (e != null) {
-                ConstantTableEntry next = e.next;
-                int idx = e.hash &amp; sizeMask;
-
-                //  Single node on list
-                if (next == null)
-                    newTable[idx] = e;
-
-                else {
-                    // Reuse trailing consecutive sequence at same slot
-                    ConstantTableEntry lastRun = e;
-                    int lastIdx = idx;
-                    for (ConstantTableEntry last = next;
-                         last != null;
-                         last = last.next) {
-                        int k = last.hash &amp; sizeMask;
-                        if (k != lastIdx) {
-                            lastIdx = k;
-                            lastRun = last;
-                        }
-                    }
-                    newTable[lastIdx] = lastRun;
-
-                    // Clone all remaining nodes
-                    for (ConstantTableEntry p = e; p != lastRun; p = p.next) {
-                        int k = p.hash &amp; sizeMask;
-                        ConstantTableEntry m = new ConstantTableEntry(p.hash, p.name, p.value, newTable[k]);
-                        newTable[k] = m;
-                    }
-                }
-            }
-        }
-        constantTable = newTable;
-        return newTable;
-    }
-    
-
-    /**
-     * Method to help ease transition to new variables implementation.
-     * Will likely be deprecated in the near future.
-     */
-    @SuppressWarnings(&quot;unchecked&quot;)
-    protected Map constantTableGetMap() {
-        HashMap map = new HashMap();
-        ConstantTableEntry[] table;
-        if ((table = constantTable) != null) {
-            for (int i = table.length; --i &gt;= 0; ) {
-                for (ConstantTableEntry e = table[i]; e != null; e = e.next) {
-                    map.put(e.name, e.value);
-                }
-            }
-        }
-        return map;
-    }
-    
-    /**
-     * Method to help ease transition to new variables implementation.
-     * Will likely be deprecated in the near future.
-     */
-    @SuppressWarnings(&quot;unchecked&quot;)
-    protected Map constantTableGetMap(Map map) {
-        ConstantTableEntry[] table;
-        if ((table = constantTable) != null) {
-            for (int i = table.length; --i &gt;= 0; ) {
-                for (ConstantTableEntry e = table[i]; e != null; e = e.next) {
-                    map.put(e.name, e.value);
-                }
-            }
-        }
-        return map;
-    }
-
-    private CacheEntry UNDEFINED_METHOD = new CacheEntry(-1, UndefinedMethod.getInstance());
 
     public static class CacheEntry {
         private int generation;</diff>
      <filename>src/org/jruby/RubyModule.java</filename>
    </modified>
    <modified>
      <diff>@@ -631,9 +631,8 @@ public class RubyObject implements Cloneable, IRubyObject, Serializable, CoreObj
 
        clone.setSuperClass(klass.getSuperClass());
 
-       if (klass.hasVariables()) {
-           clone.syncVariables(klass.getVariableList());
-       }
+       if (klass.hasVariables()) clone.syncVariables(klass.getVariableList());
+       clone.syncConstants(klass);
 
        klass.cloneMethods(clone);
 
@@ -654,9 +653,8 @@ public class RubyObject implements Cloneable, IRubyObject, Serializable, CoreObj
 
         original.copySpecialInstanceVariables(clone);
 
-        if (original.hasVariables()) {
-            clone.syncVariables(original.getVariableList());
-        }
+        if (original.hasVariables()) clone.syncVariables(original.getVariableList());
+        if (original instanceof RubyModule) ((RubyModule) clone).syncConstants((RubyModule) original);
 
         /* FIXME: finalizer should be dupped here */
         clone.callMethod(clone.getRuntime().getCurrentContext(), &quot;initialize_copy&quot;, original);
@@ -1528,16 +1526,7 @@ public class RubyObject implements Cloneable, IRubyObject, Serializable, CoreObj
     @JRubyMethod(name = &quot;inspect&quot;)
     public IRubyObject inspect() {
         Ruby runtime = getRuntime();
-        if ((!isImmediate()) &amp;&amp;
-                // TYPE(obj) == T_OBJECT
-                !(this instanceof RubyClass) &amp;&amp;
-                this != runtime.getObject() &amp;&amp;
-                this != runtime.getModule() &amp;&amp;
-                !(this instanceof RubyModule) &amp;&amp;
-                // TODO: should have #hasInstanceVariables method, though
-                // this will work here:
-                hasVariables()) {
-
+        if ((!isImmediate()) &amp;&amp; !(this instanceof RubyModule) &amp;&amp; hasVariables()) {
             StringBuilder part = new StringBuilder();
             String cname = getMetaClass().getRealClass().getName();
             part.append(&quot;#&lt;&quot;).append(cname).append(&quot;:0x&quot;);
@@ -2716,7 +2705,6 @@ public class RubyObject implements Cloneable, IRubyObject, Serializable, CoreObj
      * @return the object or null if not found
      */
     protected IRubyObject variableTableFastFetch(String internedName) {
-        assert internedName == internedName.intern() : internedName + &quot; not interned&quot;;
         VariableTableEntry[] table;
         IRubyObject readValue;
         if ((table = variableTable) != null) {
@@ -2771,6 +2759,8 @@ public class RubyObject implements Cloneable, IRubyObject, Serializable, CoreObj
      * needs to be an interned Java String.
      */
     protected IRubyObject variableTableFastStore(String internedName, IRubyObject value) {
+        if (IdUtil.isConstant(internedName)) new Exception().printStackTrace();
+
         assert internedName == internedName.intern() : internedName + &quot; not interned&quot;;
         int hash = internedName.hashCode();
         synchronized(this) {</diff>
      <filename>src/org/jruby/RubyObject.java</filename>
    </modified>
    <modified>
      <diff>@@ -41,12 +41,16 @@ import org.jruby.lexer.yacc.ISourcePosition;
 import org.jruby.runtime.Block;
 import org.jruby.runtime.ThreadContext;
 import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.runtime.callsite.ConstantSite;
 
 /**
  * The access to a Constant.
  */
-public class ConstNode extends Node implements INameNode {
+public class ConstNode extends Node implements INameNode, ConstantSite {
+    public static volatile int failedCallSites;
+
     private String name;
+    private transient IRubyObject cachedValue = null;
     
     public ConstNode(ISourcePosition position, String name) {
         super(position, NodeType.CONSTNODE);
@@ -84,11 +88,36 @@ public class ConstNode extends Node implements INameNode {
     
     @Override
     public IRubyObject interpret(Ruby runtime, ThreadContext context, IRubyObject self, Block aBlock) {
-        return context.getConstant(name);
+        IRubyObject value = getValue(context);
+
+        // We can callsite cache const_missing if we want
+        return value != null ? value :
+            context.getRubyClass().callMethod(context, &quot;const_missing&quot;, runtime.fastNewSymbol(name));
     }
 
     @Override
     public String definition(Ruby runtime, ThreadContext context, IRubyObject self, Block aBlock) {
         return context.getConstantDefined(name) ? &quot;constant&quot; : null;
     }
+    
+    public IRubyObject getValue(ThreadContext context) {
+        IRubyObject value = cachedValue; // Store to temp so it does null out on us mid-stream
+
+         return value == null ? reCache(context, name) : value;
+    }
+    
+    public IRubyObject reCache(ThreadContext context, String name) {
+        IRubyObject value = context.getConstant(name);
+            
+        cachedValue = value;
+            
+        if (value != null) context.getRuntime().getConstantCacheMap().add(name, this);
+        
+        return value;
+    }
+    
+    public void invalidate() {
+        cachedValue = null;
+        failedCallSites++;
+    }
 }</diff>
      <filename>src/org/jruby/ast/ConstNode.java</filename>
    </modified>
    <modified>
      <diff>@@ -310,7 +310,7 @@ public abstract class BaseBodyCompiler implements BodyCompiler {
     public void retrieveConstant(String name) {
         loadThreadContext();
         method.ldc(name);
-        invokeThreadContext(&quot;getConstant&quot;, sig(IRubyObject.class, params(String.class)));
+        invokeUtilityMethod(&quot;getConstant&quot;, sig(IRubyObject.class, params(ThreadContext.class, String.class)));
     }
 
     public void retrieveConstantFromModule(String name) {</diff>
      <filename>src/org/jruby/compiler/impl/BaseBodyCompiler.java</filename>
    </modified>
    <modified>
      <diff>@@ -445,6 +445,12 @@ public class RuntimeHelpers {
         return rubyClass.fastGetClassVar(internedName);
     }
     
+    public static IRubyObject getConstant(ThreadContext context, String internedName) {
+        Ruby runtime = context.getRuntime();
+
+        return context.getCurrentScope().getStaticScope().getConstantWithConstMissing(runtime, internedName, runtime.getObject());
+    }
+    
     public static IRubyObject nullToNil(IRubyObject value, Ruby runtime) {
         return value != null ? value : runtime.getNil();
     }</diff>
      <filename>src/org/jruby/javasupport/util/RuntimeHelpers.java</filename>
    </modified>
    <modified>
      <diff>@@ -119,12 +119,20 @@ public abstract class StaticScope implements Serializable {
         System.arraycopy(names, 0, variableNames, 0, names.length);
         variableCaptured = new boolean[variableNames.length];
     }
+
+    /* Note: Only used by compiler until it can use getConstant again or use some other refactoring */
+    public IRubyObject getConstantWithConstMissing(Ruby runtime, String internedName, RubyModule object) {
+        IRubyObject result = getConstantInner(runtime, internedName, object);
+
+        // If we could not find the constant from cref..then try getting from inheritence hierarchy
+        return result == null ? cref.fastGetConstant(internedName) : result;        
+    }
     
     public IRubyObject getConstant(Ruby runtime, String internedName, RubyModule object) {
         IRubyObject result = getConstantInner(runtime, internedName, object);
 
         // If we could not find the constant from cref..then try getting from inheritence hierarchy
-        return result == null ? cref.fastGetConstant(internedName) : result;
+        return result == null ? cref.getConstantNoConstMissing(internedName) : result;
     }
     
     private IRubyObject getConstantInner(Ruby runtime, String internedName, RubyModule object) {
@@ -142,9 +150,7 @@ public abstract class StaticScope implements Serializable {
 
     /* Try and unload the autoload specified from internedName */
     private IRubyObject getUndefConstant(Ruby runtime, String internedName, RubyModule object) {
-        cref.deleteConstant(internedName);
-
-        if (runtime.getLoadService().autoload(cref.getName() + &quot;::&quot; + internedName) == null) return null;
+        if (cref.resolveUndefConstant(runtime, internedName) == null) return null;
 
         return getConstantInner(runtime, internedName, object);
     }</diff>
      <filename>src/org/jruby/parser/StaticScope.java</filename>
    </modified>
    <modified>
      <diff>@@ -37,4 +37,9 @@ public class VariableEntry&lt;BaseObjectType&gt; implements Variable&lt;BaseObjectType&gt; {
         char c;
         return name.length() &gt; 0 &amp;&amp; ((c = name.charAt(0)) == '@' || (c &lt;= 'Z' &amp;&amp; c &gt;= 'A'));
     }
+
+    @Override
+    public String toString() {
+        return &quot;Name: &quot; + getName();
+    }
 }</diff>
      <filename>src/org/jruby/runtime/component/VariableEntry.java</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>2926e08846d813867a0ada780ff57c2e228d8a34</id>
    </parent>
  </parents>
  <author>
    <name>enebo</name>
    <email>enebo@961051c9-f516-0410-bf72-c9f7e237a7b7</email>
  </author>
  <url>http://github.com/vvs/jruby/commit/9f5833cfcd4baa7badf06f2026b588a1e6171d54</url>
  <id>9f5833cfcd4baa7badf06f2026b588a1e6171d54</id>
  <committed-date>2008-10-11T08:21:49-07:00</committed-date>
  <authored-date>2008-10-11T08:21:49-07:00</authored-date>
  <message>JRUBY-3052: Cache constants at their call site (const_node)

git-svn-id: https://svn.codehaus.org/jruby/trunk/jruby@7867 961051c9-f516-0410-bf72-c9f7e237a7b7</message>
  <tree>d1a6f0b83f2474b774124b0c1b633ed6531fa242</tree>
  <committer>
    <name>enebo</name>
    <email>enebo@961051c9-f516-0410-bf72-c9f7e237a7b7</email>
  </committer>
</commit>
