Change Class layout to allocate an array of StaticField objects
immediately after the ClassObject, rather than use calloc.

This has the rather surprising and pleasing effect of increasing
charing about 150K per zygote-launced application, as measured at
start-up, after waiting and no-touching.

Change-Id: I6a6c9079f946eb99111326ed45f13ecfe544e4bb
diff --git a/vm/oo/Class.c b/vm/oo/Class.c
index f3cfde2..bbb8a35 100644
--- a/vm/oo/Class.c
+++ b/vm/oo/Class.c
@@ -1674,7 +1674,9 @@
      * Note that we assume that java.lang.Class does not override
      * finalize().
      */
-    newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT);
+    newClass = (ClassObject*) dvmMalloc(sizeof(*newClass) +
+                 sizeof(StaticField) * pHeader->staticFieldsSize,
+                                        ALLOC_DEFAULT);
     if (newClass == NULL)
         return NULL;
 
@@ -1729,11 +1731,12 @@
     /* load field definitions */
 
     /*
-     * TODO: consider over-allocating the class object and appending the
-     * static field info onto the end.  It's fixed-size and known at alloc
-     * time.  This would save a couple of native heap allocations, but it
-     * would also make heap compaction more difficult because we pass Field
-     * pointers around internally.
+     * Over-allocate the class object and append static field info
+     * onto the end.  It's fixed-size and known at alloc time.  This
+     * seems to increase zygote sharing.  Heap compaction will have to
+     * be careful if it ever tries to move ClassObject instances,
+     * because we pass Field pointers around internally. But at least
+     * now these Field pointers are in the object heap.
      */
 
     if (pHeader->staticFieldsSize != 0) {
@@ -1743,8 +1746,6 @@
         DexField field;
 
         newClass->sfieldCount = count;
-        newClass->sfields =
-            (StaticField*) calloc(count, sizeof(StaticField));
         for (i = 0; i < count; i++) {
             dexReadClassDataField(&pEncodedData, &field, &lastIndex);
             loadSFieldFromDex(newClass, &field, &newClass->sfields[i]);
@@ -2002,7 +2003,8 @@
     NULL_AND_LINEAR_FREE(clazz->ifviPool);
 
     clazz->sfieldCount = -1;
-    NULL_AND_FREE(clazz->sfields);
+    /* The sfields are attached to the ClassObject, and will be freed
+     * with it. */
 
     clazz->ifieldCount = -1;
     NULL_AND_LINEAR_FREE(clazz->ifields);
diff --git a/vm/oo/Object.c b/vm/oo/Object.c
index eff0983..fdb1a69 100644
--- a/vm/oo/Object.c
+++ b/vm/oo/Object.c
@@ -95,7 +95,7 @@
      * fields, the VM allows you to have two fields with the same name so
      * long as they have different types.
      */
-    pField = clazz->sfields;
+    pField = &clazz->sfields[0];
     for (i = 0; i < clazz->sfieldCount; i++, pField++) {
         if (strcmp(fieldName, pField->field.name) == 0 &&
             strcmp(signature, pField->field.signature) == 0)
@@ -739,4 +739,3 @@
         clazz = clazz->super;
     }
 }
-
diff --git a/vm/oo/Object.h b/vm/oo/Object.h
index df167d5..be2c9f2 100644
--- a/vm/oo/Object.h
+++ b/vm/oo/Object.h
@@ -320,6 +320,45 @@
 };
 
 /*
+ * Generic field header.  We pass this around when we want a generic Field
+ * pointer (e.g. for reflection stuff).  Testing the accessFlags for
+ * ACC_STATIC allows a proper up-cast.
+ */
+struct Field {
+    ClassObject*    clazz;          /* class in which the field is declared */
+    const char*     name;
+    const char*     signature;      /* e.g. "I", "[C", "Landroid/os/Debug;" */
+    u4              accessFlags;
+#ifdef PROFILE_FIELD_ACCESS
+    u4              gets;
+    u4              puts;
+#endif
+};
+
+/*
+ * Static field.
+ */
+struct StaticField {
+    Field           field;          /* MUST be first item */
+    JValue          value;          /* initially set from DEX for primitives */
+};
+
+/*
+ * Instance field.
+ */
+struct InstField {
+    Field           field;          /* MUST be first item */
+
+    /*
+     * This field indicates the byte offset from the beginning of the
+     * (Object *) to the actual instance data; e.g., byteOffset==0 is
+     * the same as the object pointer (bug!), and byteOffset==4 is 4
+     * bytes farther.
+     */
+    int             byteOffset;
+};
+
+/*
  * This defines the amount of space we leave for field slots in the
  * java.lang.Class definition.  If we alter the class to have more than
  * this many fields, the VM will abort at startup.
@@ -443,10 +482,6 @@
     int             ifviPoolCount;
     int*            ifviPool;
 
-    /* static fields */
-    int             sfieldCount;
-    StaticField*    sfields;
-
     /* instance fields
      *
      * These describe the layout of the contents of a DataObject-compatible
@@ -467,6 +502,10 @@
 
     /* source file name, if known */
     const char*     sourceFile;
+
+    /* static fields */
+    int             sfieldCount;
+    StaticField     sfields[]; /* MUST be last item */
 };
 
 /*
@@ -555,45 +594,6 @@
 #endif
 };
 
-/*
- * Generic field header.  We pass this around when we want a generic Field
- * pointer (e.g. for reflection stuff).  Testing the accessFlags for
- * ACC_STATIC allows a proper up-cast.
- */
-struct Field {
-    ClassObject*    clazz;          /* class in which the field is declared */
-    const char*     name;
-    const char*     signature;      /* e.g. "I", "[C", "Landroid/os/Debug;" */
-    u4              accessFlags;
-#ifdef PROFILE_FIELD_ACCESS
-    u4              gets;
-    u4              puts;
-#endif
-};
-
-/*
- * Static field.
- */
-struct StaticField {
-    Field           field;          /* MUST be first item */
-    JValue          value;          /* initially set from DEX for primitives */
-};
-
-/*
- * Instance field.
- */
-struct InstField {
-    Field           field;          /* MUST be first item */
-
-    /*
-     * This field indicates the byte offset from the beginning of the
-     * (Object *) to the actual instance data; e.g., byteOffset==0 is
-     * the same as the object pointer (bug!), and byteOffset==4 is 4
-     * bytes farther.
-     */
-    int             byteOffset;
-};
-
 
 /*
  * Find a method within a class.  The superclass is not searched.