Replace large calloc() with ashmem-backed anonymous mmap

This change eliminates a large amount of memory duplication arising from the
use of a calloc() to initialize auxiliary data structures.  Calloc() calls
memset() to zero out memory after it has been allocated.  That memory may
either be gotten via an anonymous mmap (in which case the memset() is
unnecessary, as the kernel zeros out the memory before handing it to user
space), or it can get recycled by the heap (in which case the memset() is
necessary.)

This becomes a problem for large callocs in any case. In addition, when
initializing aux structures, we create a large sparse array for each DEX file.
The data in each array tends to remain mostly zeroed out, which leads to a lot
of duplicated zero pages.

By switching to anonymous mmaps() instead of calloc(), we keep the zeroed-out
pages together and minimize duplication.

Change-Id: Ic38b78e54acc782a863513a7b1972492e50e099c
Signed-off-by: Iliyan Malchev <malchev@google.com>
diff --git a/vm/DvmDex.cpp b/vm/DvmDex.cpp
index 4bad999..79c81f3 100644
--- a/vm/DvmDex.cpp
+++ b/vm/DvmDex.cpp
@@ -18,7 +18,7 @@
  * VM-specific state associated with a DEX file.
  */
 #include "Dalvik.h"
-
+#include <sys/mman.h>
 
 /*
  * Create auxillary data structures.
@@ -37,61 +37,49 @@
  * invoke-virtual-quick), creating the possibility of some space reduction
  * at dexopt time.
  */
+
 static DvmDex* allocateAuxStructures(DexFile* pDexFile)
 {
     DvmDex* pDvmDex;
     const DexHeader* pHeader;
-    u4 stringCount, classCount, methodCount, fieldCount;
+    u4 stringSize, classSize, methodSize, fieldSize;
 
-    pDvmDex = (DvmDex*) calloc(1, sizeof(DvmDex));
-    if (pDvmDex == NULL)
+    pHeader = pDexFile->pHeader;
+
+    stringSize = pHeader->stringIdsSize * sizeof(struct StringObject*);
+    classSize  = pHeader->typeIdsSize * sizeof(struct ClassObject*);
+    methodSize = pHeader->methodIdsSize * sizeof(struct Method*);
+    fieldSize  = pHeader->fieldIdsSize * sizeof(struct Field*);
+
+    u4 totalSize = sizeof(DvmDex) +
+                   stringSize + classSize + methodSize + fieldSize;
+
+    u1 *blob = (u1 *)dvmAllocRegion(totalSize,
+                              PROT_READ | PROT_WRITE, "dalvik-aux-structure");
+    if ((void *)blob == MAP_FAILED)
         return NULL;
 
+    pDvmDex = (DvmDex*)blob;
+    blob += sizeof(DvmDex);
+
     pDvmDex->pDexFile = pDexFile;
-    pDvmDex->pHeader = pDexFile->pHeader;
+    pDvmDex->pHeader = pHeader;
 
-    pHeader = pDvmDex->pHeader;
+    pDvmDex->pResStrings = (struct StringObject**)blob;
+    blob += stringSize;
+    pDvmDex->pResClasses = (struct ClassObject**)blob;
+    blob += classSize;
+    pDvmDex->pResMethods = (struct Method**)blob;
+    blob += methodSize;
+    pDvmDex->pResFields = (struct Field**)blob;
 
-    stringCount = pHeader->stringIdsSize;
-    classCount = pHeader->typeIdsSize;
-    methodCount = pHeader->methodIdsSize;
-    fieldCount = pHeader->fieldIdsSize;
-
-    pDvmDex->pResStrings = (struct StringObject**)
-        calloc(stringCount, sizeof(struct StringObject*));
-
-    pDvmDex->pResClasses = (struct ClassObject**)
-        calloc(classCount, sizeof(struct ClassObject*));
-
-    pDvmDex->pResMethods = (struct Method**)
-        calloc(methodCount, sizeof(struct Method*));
-
-    pDvmDex->pResFields = (struct Field**)
-        calloc(fieldCount, sizeof(struct Field*));
-
-    ALOGV("+++ DEX %p: allocateAux %d+%d+%d+%d * 4 = %d bytes",
-        pDvmDex, stringCount, classCount, methodCount, fieldCount,
-        (stringCount + classCount + methodCount + fieldCount) * 4);
+    ALOGV("+++ DEX %p: allocateAux (%d+%d+%d+%d)*4 = %d bytes",
+        pDvmDex, stringSizei/4, classSize/4, methodSize/4, fieldSize/4,
+        stringSize + classSize + methodSize + fieldSize);
 
     pDvmDex->pInterfaceCache = dvmAllocAtomicCache(DEX_INTERFACE_CACHE_SIZE);
 
-    if (pDvmDex->pResStrings == NULL ||
-        pDvmDex->pResClasses == NULL ||
-        pDvmDex->pResMethods == NULL ||
-        pDvmDex->pResFields == NULL ||
-        pDvmDex->pInterfaceCache == NULL)
-    {
-        ALOGE("Alloc failure in allocateAuxStructures");
-        free(pDvmDex->pResStrings);
-        free(pDvmDex->pResClasses);
-        free(pDvmDex->pResMethods);
-        free(pDvmDex->pResFields);
-        free(pDvmDex);
-        return NULL;
-    }
-
     return pDvmDex;
-
 }
 
 /*
@@ -191,20 +179,23 @@
  */
 void dvmDexFileFree(DvmDex* pDvmDex)
 {
+    u4 totalSize;
+
     if (pDvmDex == NULL)
         return;
 
+    totalSize  = pDvmDex->pHeader->stringIdsSize * sizeof(struct StringObject*);
+    totalSize += pDvmDex->pHeader->typeIdsSize * sizeof(struct ClassObject*);
+    totalSize += pDvmDex->pHeader->methodIdsSize * sizeof(struct Method*);
+    totalSize += pDvmDex->pHeader->fieldIdsSize * sizeof(struct Field*);
+    totalSize += sizeof(DvmDex);
+
     dexFileFree(pDvmDex->pDexFile);
 
     ALOGV("+++ DEX %p: freeing aux structs", pDvmDex);
-    free(pDvmDex->pResStrings);
-    free(pDvmDex->pResClasses);
-    free(pDvmDex->pResMethods);
-    free(pDvmDex->pResFields);
     dvmFreeAtomicCache(pDvmDex->pInterfaceCache);
-
     sysReleaseShmem(&pDvmDex->memMap);
-    free(pDvmDex);
+    munmap(pDvmDex, totalSize);
 }