am 2c98747: Improve zygote heap sharing.

Merge commit '2c98747b403970ef4b3352e271633f93935b9825'

* commit '2c98747b403970ef4b3352e271633f93935b9825':
  Improve zygote heap sharing.
diff --git a/vm/Globals.h b/vm/Globals.h
index 0678ea2..1a81b93 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -145,6 +145,13 @@
     volatile int classSerialNumber;
 
     /*
+     * Classes with a low classSerialNumber are probably in the zygote, and
+     * their InitiatingLoaderList is not used, to promote sharing. The list is
+     * kept here instead.
+     */
+    InitiatingLoaderList* initiatingLoaderList;
+
+    /*
      * Interned strings.
      */
     HashTable*  internedStrings;
diff --git a/vm/oo/Class.c b/vm/oo/Class.c
index 4ee0b37..0832d99 100644
--- a/vm/oo/Class.c
+++ b/vm/oo/Class.c
@@ -151,6 +151,9 @@
 may not be worth the performance hit.
 */
 
+#define INITIAL_CLASS_SERIAL_NUMBER 0x50000000
+#define ZYGOTE_CLASS_CUTOFF 2000
+
 static ClassPathEntry* processClassPath(const char* pathStr, bool isBootstrap);
 static void freeCpeArray(ClassPathEntry* cpe);
 
@@ -293,8 +296,15 @@
      * Class serial number.  We start with a high value to make it distinct
      * in binary dumps (e.g. hprof).
      */
-    gDvm.classSerialNumber = 0x50000000;
+    gDvm.classSerialNumber = INITIAL_CLASS_SERIAL_NUMBER;
 
+    /* Set up the table we'll use for tracking initiating loaders for
+     * early classes.
+     * If it's NULL, we just fall back to the InitiatingLoaderList in the
+     * ClassObject, so it's not fatal to fail this allocation.
+     */
+    gDvm.initiatingLoaderList =
+        calloc(ZYGOTE_CLASS_CUTOFF, sizeof(InitiatingLoaderList));
 
     /* This placeholder class is used while a ClassObject is
      * loading/linking so those not in the know can still say
@@ -346,6 +356,8 @@
     gDvm.bootClassPath = NULL;
 
     dvmLinearAllocDestroy(NULL);
+
+    free(gDvm.initiatingLoaderList);
 }
 
 
@@ -797,6 +809,18 @@
 
 #define kInitLoaderInc  4       /* must be power of 2 */
 
+static InitiatingLoaderList *dvmGetInitiatingLoaderList(ClassObject* clazz)
+{
+    assert(clazz->serialNumber > INITIAL_CLASS_SERIAL_NUMBER);
+    int classIndex = clazz->serialNumber-INITIAL_CLASS_SERIAL_NUMBER;
+    if (gDvm.initiatingLoaderList != NULL &&
+        classIndex < ZYGOTE_CLASS_CUTOFF) {
+        return &(gDvm.initiatingLoaderList[classIndex]);
+    } else {
+        return &(clazz->initiatingLoaderList);
+    }
+}
+
 /*
  * Determine if "loader" appears in clazz' initiating loader list.
  *
@@ -820,9 +844,13 @@
     /*
      * Scan the list for a match.  The list is expected to be short.
      */
+    /* Cast to remove the const from clazz, but use const loaderList */
+    ClassObject* nonConstClazz = (ClassObject*) clazz;
+    const InitiatingLoaderList *loaderList =
+        dvmGetInitiatingLoaderList(nonConstClazz);
     int i;
-    for (i = clazz->initiatingLoaderCount-1; i >= 0; --i) {
-        if (clazz->initiatingLoaders[i] == loader) {
+    for (i = loaderList->initiatingLoaderCount-1; i >= 0; --i) {
+        if (loaderList->initiatingLoaders[i] == loader) {
             //LOGI("+++ found initiating match %p in %s\n",
             //    loader, clazz->descriptor);
             return true;
@@ -854,10 +882,10 @@
          * pretty minor, and probably outweighs the O(n^2) hit for
          * checking before every add, so we may not want to do this.
          */
-        if (false && dvmLoaderInInitiatingList(clazz, loader)) {
-            LOGW("WOW: simultaneous add of initiating class loader\n");
-            goto bail_unlock;
-        }
+        //if (dvmLoaderInInitiatingList(clazz, loader)) {
+        //    LOGW("WOW: simultaneous add of initiating class loader\n");
+        //    goto bail_unlock;
+        //}
 
         /*
          * The list never shrinks, so we just keep a count of the
@@ -867,25 +895,26 @@
          * The pointer is initially NULL, so we *do* want to call realloc
          * when count==0.
          */
-        if ((clazz->initiatingLoaderCount & (kInitLoaderInc-1)) == 0) {
+        InitiatingLoaderList *loaderList = dvmGetInitiatingLoaderList(clazz);
+        if ((loaderList->initiatingLoaderCount & (kInitLoaderInc-1)) == 0) {
             Object** newList;
 
-            newList = (Object**) realloc(clazz->initiatingLoaders,
-                        (clazz->initiatingLoaderCount + kInitLoaderInc)
+            newList = (Object**) realloc(loaderList->initiatingLoaders,
+                        (loaderList->initiatingLoaderCount + kInitLoaderInc)
                          * sizeof(Object*));
             if (newList == NULL) {
                 /* this is mainly a cache, so it's not the EotW */
                 assert(false);
                 goto bail_unlock;
             }
-            clazz->initiatingLoaders = newList;
+            loaderList->initiatingLoaders = newList;
 
             //LOGI("Expanded init list to %d (%s)\n",
-            //    clazz->initiatingLoaderCount+kInitLoaderInc,
+            //    loaderList->initiatingLoaderCount+kInitLoaderInc,
             //    clazz->descriptor);
         }
-
-        clazz->initiatingLoaders[clazz->initiatingLoaderCount++] = loader;
+        loaderList->initiatingLoaders[loaderList->initiatingLoaderCount++] =
+            loader;
 
 bail_unlock:
         dvmHashTableUnlock(gDvm.loadedClasses);
@@ -1939,8 +1968,9 @@
         dvmLinearFree(clazz->classLoader, virtualMethods);
     }
 
-    clazz->initiatingLoaderCount = -1;
-    NULL_AND_FREE(clazz->initiatingLoaders);
+    InitiatingLoaderList *loaderList = dvmGetInitiatingLoaderList(clazz);
+    loaderList->initiatingLoaderCount = -1;
+    NULL_AND_FREE(loaderList->initiatingLoaders);
 
     clazz->interfaceCount = -1;
     NULL_AND_LINEAR_FREE(clazz->interfaces);
diff --git a/vm/oo/Object.h b/vm/oo/Object.h
index 7ef8dac..18fbb36 100644
--- a/vm/oo/Object.h
+++ b/vm/oo/Object.h
@@ -24,6 +24,7 @@
 
 /* fwd decl */
 struct DataObject;
+struct InitiatingLoaderList;
 struct ClassObject;
 struct StringObject;
 struct ArrayObject;
@@ -35,6 +36,7 @@
 struct Field;
 struct RegisterMap;
 typedef struct DataObject DataObject;
+typedef struct InitiatingLoaderList InitiatingLoaderList;
 typedef struct ClassObject ClassObject;
 typedef struct StringObject StringObject;
 typedef struct ArrayObject ArrayObject;
@@ -248,6 +250,18 @@
 };
 
 /*
+ * For classes created early and thus probably in the zygote, the
+ * InitiatingLoaderList is kept in gDvm. Later classes use the structure in
+ * Object Class. This helps keep zygote pages shared.
+ */
+struct InitiatingLoaderList {
+    /* a list of initiating loader Objects; grown and initialized on demand */
+    Object**  initiatingLoaders;
+    /* count of loaders in the above list */
+    int       initiatingLoaderCount;
+};
+
+/*
  * Class objects have many additional fields.  This is used for both
  * classes and interfaces, including synthesized classes (arrays and
  * primitive types).
@@ -318,8 +332,9 @@
     Object*         classLoader;
 
     /* initiating class loader list */
-    Object**        initiatingLoaders;
-    int             initiatingLoaderCount;
+    /* NOTE: for classes with low serialNumber, these are unused, and the
+       values are kept in a table in gDvm. */
+    InitiatingLoaderList initiatingLoaderList;
 
     /* array of interfaces this class implements directly */
     int             interfaceCount;