Pin modules in DevMode/DevModeBase until they are actually invoked.
Keep an effective-to-physical name mapping around in ModuleDefLoader
if a module needs to be reloaded after a GC.

Review by: jat, scottb



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6996 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/DevMode.java b/dev/core/src/com/google/gwt/dev/DevMode.java
index f2015bc..96fd661 100644
--- a/dev/core/src/com/google/gwt/dev/DevMode.java
+++ b/dev/core/src/com/google/gwt/dev/DevMode.java
@@ -325,6 +325,9 @@
       TreeLogger moduleBranch = branch.branch(TreeLogger.INFO, moduleName);
       try {
         ModuleDef module = loadModule(moduleBranch, moduleName, false);
+        // Create a hard reference to the module to avoid gc-ing it until we
+        // actually load the module from the browser.
+        startupModules.put(module.getName(), module);
         Util.recursiveDelete(options.getShellBaseWorkDir(module), false);
         validateServletTags(moduleBranch, servletValidator, module, webXml);
         TreeLogger loadLogger = moduleBranch.branch(TreeLogger.DEBUG,
diff --git a/dev/core/src/com/google/gwt/dev/DevModeBase.java b/dev/core/src/com/google/gwt/dev/DevModeBase.java
index 8725416..c5782e7 100644
--- a/dev/core/src/com/google/gwt/dev/DevModeBase.java
+++ b/dev/core/src/com/google/gwt/dev/DevModeBase.java
@@ -55,6 +55,7 @@
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.List;
@@ -96,6 +97,8 @@
         // Try to find an existing loaded version of the module def.
         ModuleDef moduleDef = loadModule(logger, moduleName, true);
         assert (moduleDef != null);
+        // Release the hard reference to the module if it is present.
+        startupModules.remove(moduleDef.getName());
 
         ShellModuleSpaceHost host = doCreateShellModuleSpaceHost(logger,
             moduleDef.getCompilationState(logger), moduleDef);
@@ -354,6 +357,8 @@
     }
   }
 
+  protected static final Map<String, ModuleDef> startupModules = new HashMap<String, ModuleDef>();
+  
   /**
    * Handles the -whitelist command line flag.
    */
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
index 8455bff..72862ae 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
@@ -28,6 +28,7 @@
 import java.io.Reader;
 import java.net.URISyntaxException;
 import java.net.URL;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
@@ -60,11 +61,17 @@
 
   /**
    * Keep soft references to loaded modules so the VM can gc them when memory is
-   * tight.
+   * tight.  The module's physical name is used as a key.
    */
   @SuppressWarnings("unchecked")
   private static final Map<String, ModuleDef> loadedModules = new ReferenceMap(
       AbstractReferenceMap.HARD, AbstractReferenceMap.SOFT);
+  
+  /**
+   * A mapping from effective to physical module names.
+   */
+  private static final Map<String, String> moduleEffectiveNameToPhysicalName =
+    new HashMap<String, String>();
 
   /**
    * Creates a module in memory that is not associated with a
@@ -96,7 +103,8 @@
   }
 
   /**
-   * Loads a new module from the class path.
+   * Loads a new module from the class path.  Equivalent to
+   * {@link #loadFromClassPath(logger, moduleName, false)}.
    * 
    * @param logger logs the process
    * @param moduleName the module to load
@@ -107,7 +115,7 @@
       throws UnableToCompleteException {
     return loadFromClassPath(logger, moduleName, false);
   }
-
+  
   /**
    * Loads a new module from the class path.
    * 
@@ -119,6 +127,12 @@
    */
   public static ModuleDef loadFromClassPath(TreeLogger logger,
       String moduleName, boolean refresh) throws UnableToCompleteException {
+    // Look up the module's physical name; if null, we are either encountering
+    // the module for the first time, or else the name is already physical
+    String physicalName = moduleEffectiveNameToPhysicalName.get(moduleName);
+    if (physicalName != null) {
+      moduleName = physicalName;
+    }
     ModuleDef moduleDef = tryGetLoadedModule(logger, moduleName, refresh);
     if (moduleDef != null) {
       return moduleDef;
@@ -275,8 +289,8 @@
     // Add the "physical" module name: com.google.Module
     loadedModules.put(moduleName, moduleDef);
 
-    // Add the module's effective name: some.other.Module
-    loadedModules.put(moduleDef.getName(), moduleDef);
+    // Add a mapping from the module's effective name to its physical name
+    moduleEffectiveNameToPhysicalName.put(moduleDef.getName(), moduleName);
     return moduleDef;
   }
 }