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;