summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--vm/Dvm.mk2
-rw-r--r--vm/Globals.h24
-rw-r--r--vm/Init.c3
-rw-r--r--vm/InitRefs.c22
-rw-r--r--vm/Thread.c6
-rw-r--r--vm/alloc/Alloc.c43
-rw-r--r--vm/alloc/Alloc.h1
-rw-r--r--vm/alloc/Heap.c98
-rw-r--r--vm/alloc/HeapInternal.h32
-rw-r--r--vm/alloc/HeapTable.c168
-rw-r--r--vm/alloc/HeapTable.h36
-rw-r--r--vm/alloc/HeapWorker.c472
-rw-r--r--vm/alloc/HeapWorker.h70
-rw-r--r--vm/alloc/MarkSweep.c54
-rw-r--r--vm/alloc/MarkSweep.h1
-rw-r--r--vm/alloc/Visit.c15
-rw-r--r--vm/alloc/Visit.h2
-rw-r--r--vm/hprof/Hprof.h6
18 files changed, 106 insertions, 949 deletions
diff --git a/vm/Dvm.mk b/vm/Dvm.mk
index c9b0e277c..d655a3a09 100644
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -120,8 +120,6 @@ LOCAL_SRC_FILES := \
alloc/CardTable.c \
alloc/HeapBitmap.c.arm \
alloc/HeapDebug.c \
- alloc/HeapTable.c \
- alloc/HeapWorker.c \
alloc/Heap.c.arm \
alloc/DdmHeap.c \
alloc/Verify.c \
diff --git a/vm/Globals.h b/vm/Globals.h
index 1cb4526d4..faafcc646 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -367,11 +367,14 @@ struct DvmGlobals {
int offJavaLangRefReference_queueNext;
int offJavaLangRefReference_pendingNext;
- /* method pointers - java.lang.ref.Reference */
- Method* methJavaLangRefReference_enqueueInternal;
+ /* field offsets - java.lang.ref.FinalizerReference */
+ int offJavaLangRefFinalizerReference_zombie;
- /* more method pointers - java.lang.ref.FinalizerReference */
- Method* methJavaLangRefFinalizerReferenceAdd;
+ /* method pointers - java.lang.ref.ReferenceQueue */
+ Method* methJavaLangRefReferenceQueueAdd;
+
+ /* method pointers - java.lang.ref.FinalizerReference */
+ Method* methJavaLangRefFinalizerReferenceAdd;
/* constructor method pointers; no vtable involved, so use Method* */
Method* methJavaLangStackTraceElement_init;
@@ -581,19 +584,6 @@ struct DvmGlobals {
*/
LinearAllocHdr* pBootLoaderAlloc;
-
- /*
- * Heap worker thread.
- */
- bool heapWorkerInitialized;
- bool heapWorkerReady;
- bool haltHeapWorker;
- pthread_t heapWorkerHandle;
- pthread_mutex_t heapWorkerLock;
- pthread_cond_t heapWorkerCond;
- pthread_cond_t heapWorkerIdleCond;
- pthread_mutex_t heapWorkerListLock;
-
/*
* Compute some stats on loaded classes.
*/
diff --git a/vm/Init.c b/vm/Init.c
index f1afa85ec..a8cf258b3 100644
--- a/vm/Init.c
+++ b/vm/Init.c
@@ -1314,6 +1314,9 @@ int dvmStartup(int argc, const char* const argv[], bool ignoreUnrecognized,
if (!dvmDebuggerStartup())
goto fail;
+ if (!dvmGcStartupClasses())
+ goto fail;
+
/*
* Init for either zygote mode or non-zygote mode. The key difference
* is that we don't start any additional threads in Zygote mode.
diff --git a/vm/InitRefs.c b/vm/InitRefs.c
index b5b75266d..5a9ba2ad5 100644
--- a/vm/InitRefs.c
+++ b/vm/InitRefs.c
@@ -320,6 +320,11 @@ static bool initFieldOffsets(void) {
{ NULL, NULL, NULL }
};
+ static struct FieldInfo infoFinalizerReference[] = {
+ { &gDvm.offJavaLangRefFinalizerReference_zombie, "zombie", "Ljava/lang/Object;" },
+ { NULL, NULL, NULL }
+ };
+
static struct FieldInfo infoConstructor[] = {
{ &gDvm.offJavaLangReflectConstructor_slot, "slot", "I" },
{ &gDvm.offJavaLangReflectConstructor_declClass, "declaringClass", "Ljava/lang/Class;" },
@@ -357,6 +362,7 @@ static bool initFieldOffsets(void) {
{ "Ljava/lang/ThreadGroup;", infoThreadGroup },
{ "Ljava/lang/Throwable;", infoThrowable },
{ "Ljava/lang/VMThread;", infoVMThread },
+ { "Ljava/lang/ref/FinalizerReference;", infoFinalizerReference },
{ "Ljava/lang/reflect/Constructor;", infoConstructor },
{ "Ljava/lang/reflect/Field;", infoField },
{ "Ljava/lang/reflect/Method;", infoMethod },
@@ -468,6 +474,8 @@ static bool initDirectMethodReferences(void) {
"Lorg/apache/harmony/dalvik/ddmc/DdmServer;", "dispatch", "(I[BII)Lorg/apache/harmony/dalvik/ddmc/Chunk;" },
{ &gDvm.methDalvikDdmcServer_broadcast,
"Lorg/apache/harmony/dalvik/ddmc/DdmServer;", "broadcast", "(I)V" },
+ { &gDvm.methJavaLangRefReferenceQueueAdd,
+ "Ljava/lang/ref/ReferenceQueue;", "add", "(Ljava/lang/ref/Reference;)V" },
{ NULL, NULL, NULL, NULL }
};
@@ -587,26 +595,16 @@ bool dvmFindRequiredClassesAndMembers(void) {
/* (documented in header) */
bool dvmFindReferenceMembers(ClassObject* classReference) {
- if (gDvm.methJavaLangRefReference_enqueueInternal != NULL) {
- LOGE("Attempt to set up class Reference more than once\n");
- return false;
- }
-
if (strcmp(classReference->descriptor, "Ljava/lang/ref/Reference;") != 0) {
LOGE("Attempt to set up the wrong class as Reference\n");
return false;
}
-
- /* Note: enqueueInternal() is private and thus a direct method. */
-
return initFieldOffset(classReference, &gDvm.offJavaLangRefReference_pendingNext,
- "pendingNext", "Ljava/lang/Object;")
+ "pendingNext", "Ljava/lang/ref/Reference;")
&& initFieldOffset(classReference, &gDvm.offJavaLangRefReference_queue,
"queue", "Ljava/lang/ref/ReferenceQueue;")
&& initFieldOffset(classReference, &gDvm.offJavaLangRefReference_queueNext,
"queueNext", "Ljava/lang/ref/Reference;")
&& initFieldOffset(classReference, &gDvm.offJavaLangRefReference_referent,
- "referent", "Ljava/lang/Object;")
- && initDirectMethodReferenceByClass(&gDvm.methJavaLangRefReference_enqueueInternal,
- classReference, "enqueueInternal", "()Z");
+ "referent", "Ljava/lang/Object;");
}
diff --git a/vm/Thread.c b/vm/Thread.c
index cdf49bc2d..087c2e0d3 100644
--- a/vm/Thread.c
+++ b/vm/Thread.c
@@ -3467,13 +3467,11 @@ void dvmDumpAllThreadsEx(const DebugOutputTarget* target, bool grabLock)
#ifdef HAVE_ANDROID_OS
dvmPrintDebugMessage(target,
- "(mutexes: tll=%x tsl=%x tscl=%x ghl=%x hwl=%x hwll=%x)\n",
+ "(mutexes: tll=%x tsl=%x tscl=%x ghl=%x)\n",
gDvm.threadListLock.value,
gDvm._threadSuspendLock.value,
gDvm.threadSuspendCountLock.value,
- gDvm.gcHeapLock.value,
- gDvm.heapWorkerLock.value,
- gDvm.heapWorkerListLock.value);
+ gDvm.gcHeapLock.value);
#endif
if (grabLock)
diff --git a/vm/alloc/Alloc.c b/vm/alloc/Alloc.c
index 6286f8db7..33f45e86f 100644
--- a/vm/alloc/Alloc.c
+++ b/vm/alloc/Alloc.c
@@ -20,7 +20,6 @@
#include "alloc/Heap.h"
#include "alloc/HeapInternal.h"
#include "alloc/HeapSource.h"
-#include "alloc/HeapWorker.h"
/*
* Initialize the GC universe.
@@ -41,9 +40,6 @@ bool dvmGcStartup(void)
*/
bool dvmGcStartupAfterZygote(void)
{
- if (!dvmHeapWorkerStartup()) {
- return false;
- }
return dvmHeapStartupAfterZygote();
}
@@ -52,7 +48,6 @@ bool dvmGcStartupAfterZygote(void)
*/
void dvmGcThreadShutdown(void)
{
- dvmHeapWorkerShutdown();
dvmHeapThreadShutdown();
}
@@ -73,6 +68,44 @@ bool dvmGcPreZygoteFork(void)
return dvmHeapSourceStartupBeforeFork();
}
+bool dvmGcStartupClasses(void)
+{
+ {
+ const char *klassName = "Ljava/lang/ref/ReferenceQueueThread;";
+ ClassObject *klass = dvmFindSystemClass(klassName);
+ if (klass == NULL) {
+ return false;
+ }
+ const char *methodName = "startReferenceQueue";
+ Method *method = dvmFindDirectMethodByDescriptor(klass, methodName, "()V");
+ if (method == NULL) {
+ return false;
+ }
+ Thread *self = dvmThreadSelf();
+ assert(self != NULL);
+ JValue unusedResult;
+ dvmCallMethod(self, method, NULL, &unusedResult);
+ }
+ {
+ const char *klassName = "Ljava/lang/FinalizerThread;";
+ ClassObject *klass = dvmFindSystemClass(klassName);
+ if (klass == NULL) {
+ return false;
+ }
+ const char *methodName = "startFinalizer";
+ Method *method = dvmFindDirectMethodByDescriptor(klass, methodName, "()V");
+ if (method == NULL) {
+ return false;
+ }
+ Thread *self = dvmThreadSelf();
+ assert(self != NULL);
+ JValue unusedResult;
+ dvmCallMethod(self, method, NULL, &unusedResult);
+ }
+
+ return true;
+}
+
/*
* Create a "stock instance" of an exception class.
*/
diff --git a/vm/alloc/Alloc.h b/vm/alloc/Alloc.h
index 2dc2ae62d..aeba3f5d9 100644
--- a/vm/alloc/Alloc.h
+++ b/vm/alloc/Alloc.h
@@ -29,6 +29,7 @@ bool dvmCreateStockExceptions(void);
bool dvmGcStartupAfterZygote(void);
void dvmGcShutdown(void);
void dvmGcThreadShutdown(void);
+bool dvmGcStartupClasses(void);
/*
* Do any last-minute preparation before we call fork() for the first time.
diff --git a/vm/alloc/Heap.c b/vm/alloc/Heap.c
index 5d88bc395..f38eb121d 100644
--- a/vm/alloc/Heap.c
+++ b/vm/alloc/Heap.c
@@ -19,12 +19,10 @@
#include "Dalvik.h"
#include "alloc/HeapBitmap.h"
#include "alloc/Verify.h"
-#include "alloc/HeapTable.h"
#include "alloc/Heap.h"
#include "alloc/HeapInternal.h"
#include "alloc/DdmHeap.h"
#include "alloc/HeapSource.h"
-#include "alloc/HeapWorker.h"
#include "alloc/MarkSweep.h"
#include "utils/threads.h" // need Android thread priorities
@@ -91,9 +89,6 @@ bool dvmHeapStartup()
if (gcHeap == NULL) {
return false;
}
- gcHeap->heapWorkerCurrentObject = NULL;
- gcHeap->heapWorkerCurrentMethod = NULL;
- gcHeap->heapWorkerInterpStartTime = 0LL;
gcHeap->ddmHpifWhen = 0;
gcHeap->ddmHpsgWhen = 0;
gcHeap->ddmHpsgWhat = 0;
@@ -101,22 +96,15 @@ bool dvmHeapStartup()
gcHeap->ddmNhsgWhat = 0;
gDvm.gcHeap = gcHeap;
- /* Set up the lists and lock we'll use for finalizable
- * and reference objects.
+ /* Set up the lists we'll use for cleared reference objects.
*/
- dvmInitMutex(&gDvm.heapWorkerListLock);
- gcHeap->referenceOperations = NULL;
+ gcHeap->clearedReferences = NULL;
if (!dvmCardTableStartup(gDvm.heapMaximumSize)) {
LOGE_HEAP("card table startup failed.");
return false;
}
- /* Initialize the HeapWorker locks and other state
- * that the GC uses.
- */
- dvmInitializeHeapWorkerState();
-
return true;
}
@@ -130,13 +118,6 @@ void dvmHeapShutdown()
//TODO: make sure we're locked
if (gDvm.gcHeap != NULL) {
dvmCardTableShutdown();
- /* Tables are allocated on the native heap; they need to be
- * cleaned up explicitly. The process may stick around, so we
- * don't want to leak any native memory.
- */
- dvmHeapFreeLargeTable(gDvm.gcHeap->referenceOperations);
- gDvm.gcHeap->referenceOperations = NULL;
-
/* Destroy the heap. Any outstanding pointers will point to
* unmapped memory (unless/until someone else maps it). This
* frees gDvm.gcHeap as a side-effect.
@@ -177,33 +158,6 @@ void dvmUnlockHeap()
dvmUnlockMutex(&gDvm.gcHeapLock);
}
-/* Pop an object from the list of pending finalizations and
- * reference clears/enqueues, and return the object.
- * The caller must call dvmReleaseTrackedAlloc()
- * on the object when finished.
- *
- * Typically only called by the heap worker thread.
- */
-Object *dvmGetNextHeapWorkerObject()
-{
- Object *obj;
- GcHeap *gcHeap = gDvm.gcHeap;
-
- dvmLockMutex(&gDvm.heapWorkerListLock);
-
- obj = dvmHeapGetNextObjectFromLargeTable(&gcHeap->referenceOperations);
- if (obj != NULL) {
- /* Don't let the GC collect the object until the
- * worker thread is done with it.
- */
- dvmAddTrackedAlloc(obj, NULL);
- }
-
- dvmUnlockMutex(&gDvm.heapWorkerListLock);
-
- return obj;
-}
-
/* Do a full garbage collection, which may grow the
* heap as a side-effect if the live set is large.
*/
@@ -577,13 +531,6 @@ void dvmCollectGarbageInternal(const GcSpec* spec)
gcHeap->gcRunning = true;
- /*
- * Grab the heapWorkerLock to prevent the HeapWorker thread from
- * doing work. If it's executing a finalizer or an enqueue operation
- * it won't be holding the lock, so this should return quickly.
- */
- dvmLockMutex(&gDvm.heapWorkerLock);
-
rootSuspend = dvmGetRelativeTimeMsec();
dvmSuspendAllThreads(SUSPEND_FOR_GC);
rootStart = dvmGetRelativeTimeMsec();
@@ -596,21 +543,6 @@ void dvmCollectGarbageInternal(const GcSpec* spec)
if (!spec->isConcurrent) {
oldThreadPriority = raiseThreadPriority();
}
-
- /* Make sure that the HeapWorker thread hasn't become
- * wedged inside interp code. If it has, this call will
- * print a message and abort the VM.
- */
- dvmAssertHeapWorkerThreadRunning();
-
- /* Lock the pendingFinalizationRefs list.
- *
- * Acquire the lock after suspending so the finalizer
- * thread can't block in the RUNNING state while
- * we try to suspend.
- */
- dvmLockMutex(&gDvm.heapWorkerListLock);
-
if (gDvm.preVerify) {
LOGV_HEAP("Verifying roots and heap before GC");
verifyRootsAndHeap();
@@ -634,9 +566,11 @@ void dvmCollectGarbageInternal(const GcSpec* spec)
/* dvmHeapScanMarkedObjects() will build the lists of known
* instances of the Reference classes.
*/
- gcHeap->softReferences = NULL;
- gcHeap->weakReferences = NULL;
- gcHeap->phantomReferences = NULL;
+ assert(gcHeap->softReferences == NULL);
+ assert(gcHeap->weakReferences == NULL);
+ assert(gcHeap->finalizerReferences == NULL);
+ assert(gcHeap->phantomReferences == NULL);
+ assert(gcHeap->clearedReferences == NULL);
if (spec->isConcurrent) {
/*
@@ -747,25 +681,12 @@ void dvmCollectGarbageInternal(const GcSpec* spec)
currAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
currFootprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
- /* Now that we've freed up the GC heap, return any large
- * free chunks back to the system. They'll get paged back
- * in the next time they're used. Don't do it immediately,
- * though; if the process is still allocating a bunch of
- * memory, we'll be taking a ton of page faults that we don't
- * necessarily need to.
- *
- * Cancel any old scheduled trims, and schedule a new one.
- */
- dvmScheduleHeapSourceTrim(5); // in seconds
-
dvmMethodTraceGCEnd();
LOGV_HEAP("GC finished");
gcHeap->gcRunning = false;
LOGV_HEAP("Resuming threads");
- dvmUnlockMutex(&gDvm.heapWorkerListLock);
- dvmUnlockMutex(&gDvm.heapWorkerLock);
if (spec->isConcurrent) {
/*
@@ -787,6 +708,11 @@ void dvmCollectGarbageInternal(const GcSpec* spec)
}
}
+ /*
+ * Move queue of pending references back into Java.
+ */
+ dvmEnqueueClearedReferences(&gDvm.gcHeap->clearedReferences);
+
percentFree = 100 - (size_t)(100.0f * (float)currAllocated / currFootprint);
if (!spec->isConcurrent) {
u4 markSweepTime = dirtyEnd - rootStart;
diff --git a/vm/alloc/HeapInternal.h b/vm/alloc/HeapInternal.h
index 7f8c9c5e3..1d1be0756 100644
--- a/vm/alloc/HeapInternal.h
+++ b/vm/alloc/HeapInternal.h
@@ -19,9 +19,6 @@
#ifndef _DALVIK_ALLOC_HEAP_INTERNAL
#define _DALVIK_ALLOC_HEAP_INTERNAL
-#include <time.h> // for struct timespec
-
-#include "HeapTable.h"
#include "MarkSweep.h"
typedef struct HeapSource HeapSource;
@@ -39,34 +36,9 @@ struct GcHeap {
Object *finalizerReferences;
Object *phantomReferences;
- /* The list of Reference objects that need to be cleared and/or
- * enqueued. The bottom two bits of the object pointers indicate
- * whether they should be cleared and/or enqueued.
- *
- * This table is protected by gDvm.heapWorkerListLock, which must
- * be acquired after the heap lock.
- */
- LargeHeapRefTable *referenceOperations;
-
- /* If non-null, the method that the HeapWorker is currently
- * executing.
- */
- Object *heapWorkerCurrentObject;
- Method *heapWorkerCurrentMethod;
-
- /* If heapWorkerCurrentObject is non-null, this gives the time when
- * HeapWorker started executing that method. The time value must come
- * from dvmGetRelativeTimeUsec().
- *
- * The "Cpu" entry tracks the per-thread CPU timer (when available).
- */
- u8 heapWorkerInterpStartTime;
- u8 heapWorkerInterpCpuStartTime;
-
- /* If any fields are non-zero, indicates the next (absolute) time that
- * the HeapWorker thread should call dvmHeapSourceTrim().
+ /* The list of Reference objects that need to be enqueued.
*/
- struct timespec heapWorkerNextTrim;
+ Object *clearedReferences;
/* The current state of the mark step.
* Only valid during a GC.
diff --git a/vm/alloc/HeapTable.c b/vm/alloc/HeapTable.c
deleted file mode 100644
index 6c9034a12..000000000
--- a/vm/alloc/HeapTable.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Dalvik.h"
-#include "alloc/HeapTable.h"
-#include "alloc/HeapInternal.h"
-
-#include <limits.h> // for INT_MAX
-
-static const int kLargeHeapRefTableNElems = 1024;
-static const int kFinalizableRefDefault = 128;
-
-bool dvmHeapInitHeapRefTable(ReferenceTable *refs)
-{
- return dvmInitReferenceTable(refs, kFinalizableRefDefault, INT_MAX);
-}
-
-/*
- * Large, non-contiguous reference tables
- */
-
-bool dvmHeapAddRefToLargeTable(LargeHeapRefTable **tableP, Object *ref)
-{
- LargeHeapRefTable *table;
-
- assert(tableP != NULL);
- assert(ref != NULL);
-
- /* Make sure that a table with a free slot is
- * at the head of the list.
- */
- if (*tableP != NULL) {
- table = *tableP;
- LargeHeapRefTable *prevTable;
-
- /* Find an empty slot for this reference.
- */
- prevTable = NULL;
- while (table != NULL && dvmIsReferenceTableFull(&table->refs)) {
- prevTable = table;
- table = table->next;
- }
- if (table != NULL) {
- if (prevTable != NULL) {
- /* Move the table to the head of the list.
- */
- prevTable->next = table->next;
- table->next = *tableP;
- *tableP = table;
- }
- /* else it's already at the head. */
-
- goto insert;
- }
- /* else all tables are already full;
- * fall through to the alloc case.
- */
- }
-
- /* Allocate a new table.
- */
- table = (LargeHeapRefTable *)calloc(1, sizeof(LargeHeapRefTable));
- if (table == NULL) {
- LOGE_HEAP("Can't allocate a new large ref table\n");
- return false;
- }
- if (!dvmInitReferenceTable(&table->refs,
- kLargeHeapRefTableNElems,
- INT_MAX)) {
- LOGE_HEAP("Can't initialize a new large ref table\n");
- free(table);
- return false;
- }
-
- /* Stick it at the head.
- */
- table->next = *tableP;
- *tableP = table;
-
-insert:
- /* Insert the reference.
- */
- assert(table == *tableP);
- assert(table != NULL);
- assert(!dvmIsReferenceTableFull(&table->refs));
- *table->refs.nextEntry++ = ref;
-
- return true;
-}
-
-bool dvmHeapAddTableToLargeTable(LargeHeapRefTable **tableP, ReferenceTable *refs)
-{
- LargeHeapRefTable *table;
-
- /* Allocate a node.
- */
- table = (LargeHeapRefTable *)calloc(1, sizeof(LargeHeapRefTable));
- if (table == NULL) {
- LOGE_HEAP("Can't allocate a new large ref table\n");
- return false;
- }
- table->refs = *refs;
-
- /* Insert the table into the list.
- */
- table->next = *tableP;
- *tableP = table;
-
- return true;
-}
-
-/* Frees everything associated with the LargeHeapRefTable.
- */
-void dvmHeapFreeLargeTable(LargeHeapRefTable *table)
-{
- while (table != NULL) {
- LargeHeapRefTable *next = table->next;
- dvmClearReferenceTable(&table->refs);
- free(table);
- table = next;
- }
-}
-
-Object *dvmHeapGetNextObjectFromLargeTable(LargeHeapRefTable **pTable)
-{
- LargeHeapRefTable *table;
- Object *obj;
-
- assert(pTable != NULL);
-
- obj = NULL;
- table = *pTable;
- if (table != NULL) {
- ReferenceTable *refs = &table->refs;
-
- /* We should never have an empty table node in the list.
- */
- assert(dvmReferenceTableEntries(refs) != 0);
-
- /* Remove and return the last entry in the list.
- */
- obj = *--refs->nextEntry;
-
- /* If this was the last entry in the table node,
- * free it and patch up the list.
- */
- if (refs->nextEntry == refs->table) {
- *pTable = table->next;
- dvmClearReferenceTable(refs);
- free(table);
- }
- }
-
- return obj;
-}
diff --git a/vm/alloc/HeapTable.h b/vm/alloc/HeapTable.h
deleted file mode 100644
index 175111df1..000000000
--- a/vm/alloc/HeapTable.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef _DALVIK_ALLOC_HEAP_TABLE
-#define _DALVIK_ALLOC_HEAP_TABLE
-
-#include "ReferenceTable.h"
-
-struct LargeHeapRefTable {
- struct LargeHeapRefTable *next;
- ReferenceTable refs;
-};
-
-typedef struct LargeHeapRefTable LargeHeapRefTable;
-
-bool dvmHeapInitHeapRefTable(ReferenceTable *refs);
-void dvmHeapFreeLargeTable(LargeHeapRefTable *table);
-bool dvmHeapAddRefToLargeTable(LargeHeapRefTable **tableP, Object *ref);
-void dvmHeapMarkLargeTableRefs(LargeHeapRefTable *table);
-bool dvmHeapAddTableToLargeTable(LargeHeapRefTable **tableP,
- ReferenceTable *refs);
-Object *dvmHeapGetNextObjectFromLargeTable(LargeHeapRefTable **pTable);
-
-#endif // _DALVIK_ALLOC_HEAP_TABLE
diff --git a/vm/alloc/HeapWorker.c b/vm/alloc/HeapWorker.c
deleted file mode 100644
index 60173818e..000000000
--- a/vm/alloc/HeapWorker.c
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * An async worker thread to handle certain heap operations that need
- * to be done in a separate thread to avoid synchronization problems.
- * HeapWorkers and reference enqueuing are handled by this thread.
- * The VM does all clearing.
- */
-#include "Dalvik.h"
-#include "alloc/HeapInternal.h"
-#include "alloc/HeapWorker.h"
-
-#include <sys/time.h>
-#include <stdlib.h>
-#include <pthread.h>
-#include <signal.h>
-#include <errno.h> // for ETIMEDOUT, etc.
-
-static void* heapWorkerThreadStart(void* arg);
-
-/*
- * Initialize any HeapWorker state that Heap.c
- * cares about. This lets the GC start before the
- * HeapWorker thread is initialized.
- */
-void dvmInitializeHeapWorkerState()
-{
- assert(!gDvm.heapWorkerInitialized);
-
- dvmInitMutex(&gDvm.heapWorkerLock);
- pthread_cond_init(&gDvm.heapWorkerCond, NULL);
- pthread_cond_init(&gDvm.heapWorkerIdleCond, NULL);
-
- gDvm.heapWorkerInitialized = true;
-}
-
-/*
- * Crank up the heap worker thread.
- *
- * Does not return until the thread is ready for business.
- */
-bool dvmHeapWorkerStartup(void)
-{
- assert(!gDvm.haltHeapWorker);
- assert(!gDvm.heapWorkerReady);
- assert(gDvm.heapWorkerHandle == 0);
- assert(gDvm.heapWorkerInitialized);
-
- /* use heapWorkerLock/heapWorkerCond to communicate readiness */
- dvmLockMutex(&gDvm.heapWorkerLock);
-
-//BUG: If a GC happens in here or in the new thread while we hold the lock,
-// the GC will deadlock when trying to acquire heapWorkerLock.
- if (!dvmCreateInternalThread(&gDvm.heapWorkerHandle,
- "HeapWorker", heapWorkerThreadStart, NULL))
- {
- dvmUnlockMutex(&gDvm.heapWorkerLock);
- return false;
- }
-
- /*
- * Wait for the heap worker to come up. We know the thread was created,
- * so this should not get stuck.
- */
- while (!gDvm.heapWorkerReady) {
- dvmWaitCond(&gDvm.heapWorkerCond, &gDvm.heapWorkerLock);
- }
-
- dvmUnlockMutex(&gDvm.heapWorkerLock);
- return true;
-}
-
-/*
- * Shut down the heap worker thread if it was started.
- */
-void dvmHeapWorkerShutdown(void)
-{
- void* threadReturn;
-
- /* note: assuming that (pthread_t)0 is not a valid thread handle */
- if (gDvm.heapWorkerHandle != 0) {
- gDvm.haltHeapWorker = true;
- dvmSignalHeapWorker(true);
-
- /*
- * We may not want to wait for the heapWorkers to complete. It's
- * a good idea to do so, in case they're holding some sort of OS
- * resource that doesn't get reclaimed when the process exits
- * (e.g. an open temp file).
- */
- if (pthread_join(gDvm.heapWorkerHandle, &threadReturn) != 0)
- LOGW("HeapWorker thread join failed\n");
- else if (gDvm.verboseShutdown)
- LOGD("HeapWorker thread has shut down\n");
-
- gDvm.heapWorkerReady = false;
- }
-}
-
-/* Make sure that the HeapWorker thread hasn't spent an inordinate
- * amount of time inside a finalizer.
- *
- * Aborts the VM if the thread appears to be wedged.
- *
- * The caller must hold the heapWorkerLock to guarantee an atomic
- * read of the watchdog values.
- */
-void dvmAssertHeapWorkerThreadRunning()
-{
- if (gDvm.gcHeap->heapWorkerCurrentObject != NULL) {
- static const u8 HEAP_WORKER_WATCHDOG_TIMEOUT = 10*1000*1000LL; // 10sec
-
- u8 heapWorkerInterpStartTime = gDvm.gcHeap->heapWorkerInterpStartTime;
- u8 now = dvmGetRelativeTimeUsec();
- u8 delta = now - heapWorkerInterpStartTime;
-
- if (delta > HEAP_WORKER_WATCHDOG_TIMEOUT &&
- (gDvm.debuggerActive || gDvm.nativeDebuggerActive))
- {
- /*
- * Debugger suspension can block the thread indefinitely. For
- * best results we should reset this explicitly whenever the
- * HeapWorker thread is resumed. Unfortunately this is also
- * affected by native debuggers, and we have no visibility
- * into how they're manipulating us. So, we ignore the
- * watchdog and just reset the timer.
- */
- LOGI("Debugger is attached -- suppressing HeapWorker watchdog\n");
- gDvm.gcHeap->heapWorkerInterpStartTime = now; /* reset timer */
- } else if (delta > HEAP_WORKER_WATCHDOG_TIMEOUT) {
- /*
- * Before we give up entirely, see if maybe we're just not
- * getting any CPU time because we're stuck in a background
- * process group. If we successfully move the thread into the
- * foreground we'll just leave it there (it doesn't do anything
- * if the process isn't GCing).
- */
- dvmLockThreadList(NULL);
- Thread* thread = dvmGetThreadByHandle(gDvm.heapWorkerHandle);
- dvmUnlockThreadList();
-
- if (thread != NULL) {
- int priChangeFlags, threadPrio;
- SchedPolicy threadPolicy;
- priChangeFlags = dvmRaiseThreadPriorityIfNeeded(thread,
- &threadPrio, &threadPolicy);
- if (priChangeFlags != 0) {
- LOGI("HeapWorker watchdog expired, raising priority"
- " and retrying\n");
- gDvm.gcHeap->heapWorkerInterpStartTime = now;
- return;
- }
- }
-
- char* desc = dexProtoCopyMethodDescriptor(
- &gDvm.gcHeap->heapWorkerCurrentMethod->prototype);
- LOGE("HeapWorker is wedged: %lldms spent inside %s.%s%s\n",
- delta / 1000,
- gDvm.gcHeap->heapWorkerCurrentObject->clazz->descriptor,
- gDvm.gcHeap->heapWorkerCurrentMethod->name, desc);
- free(desc);
- dvmDumpAllThreads(true);
-
- /* try to get a debuggerd dump from the target thread */
- dvmNukeThread(thread);
-
- /* abort the VM */
- dvmAbort();
- } else if (delta > HEAP_WORKER_WATCHDOG_TIMEOUT / 2) {
- char* desc = dexProtoCopyMethodDescriptor(
- &gDvm.gcHeap->heapWorkerCurrentMethod->prototype);
- LOGW("HeapWorker may be wedged: %lldms spent inside %s.%s%s\n",
- delta / 1000,
- gDvm.gcHeap->heapWorkerCurrentObject->clazz->descriptor,
- gDvm.gcHeap->heapWorkerCurrentMethod->name, desc);
- free(desc);
- }
- }
-}
-
-/*
- * Acquires a mutex, transitioning to the VMWAIT state if the mutex is
- * held. This allows the thread to suspend while it waits for another
- * thread to release the mutex.
- */
-static void lockMutex(pthread_mutex_t *mu)
-{
- Thread *self;
- ThreadStatus oldStatus;
-
- assert(mu != NULL);
- if (dvmTryLockMutex(mu) != 0) {
- self = dvmThreadSelf();
- assert(self != NULL);
- oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
- dvmLockMutex(mu);
- dvmChangeStatus(self, oldStatus);
- }
-}
-
-static void callMethod(Thread *self, Object *obj, Method *method)
-{
- JValue unused;
-
- /* Keep track of the method we're about to call and
- * the current time so that other threads can detect
- * when this thread wedges and provide useful information.
- */
- gDvm.gcHeap->heapWorkerInterpStartTime = dvmGetRelativeTimeUsec();
- gDvm.gcHeap->heapWorkerInterpCpuStartTime = dvmGetThreadCpuTimeUsec();
- gDvm.gcHeap->heapWorkerCurrentMethod = method;
- gDvm.gcHeap->heapWorkerCurrentObject = obj;
-
- /* Call the method.
- *
- * Don't hold the lock when executing interpreted
- * code. It may suspend, and the GC needs to grab
- * heapWorkerLock.
- */
- dvmUnlockMutex(&gDvm.heapWorkerLock);
- if (false) {
- /* Log entry/exit; this will likely flood the log enough to
- * cause "logcat" to drop entries.
- */
- char tmpTag[16];
- sprintf(tmpTag, "HW%d", self->systemTid);
- LOG(LOG_DEBUG, tmpTag, "Call %s\n", method->clazz->descriptor);
- dvmCallMethod(self, method, obj, &unused);
- LOG(LOG_DEBUG, tmpTag, " done\n");
- } else {
- dvmCallMethod(self, method, obj, &unused);
- }
- /*
- * Reacquire the heap worker lock in a suspend-friendly way.
- */
- lockMutex(&gDvm.heapWorkerLock);
-
- gDvm.gcHeap->heapWorkerCurrentObject = NULL;
- gDvm.gcHeap->heapWorkerCurrentMethod = NULL;
- gDvm.gcHeap->heapWorkerInterpStartTime = 0LL;
-
- /* Exceptions thrown during these calls interrupt
- * the method, but are otherwise ignored.
- */
- if (dvmCheckException(self)) {
-#if DVM_SHOW_EXCEPTION >= 1
- LOGI("Uncaught exception thrown by finalizer (will be discarded):\n");
- dvmLogExceptionStackTrace();
-#endif
- dvmClearException(self);
- }
-}
-
-/* Process all enqueued heap work, including finalizers and reference
- * enqueueing. Clearing has already been done by the VM.
- *
- * Caller must hold gDvm.heapWorkerLock.
- */
-static void doHeapWork(Thread *self)
-{
- Object *obj;
- size_t numReferencesEnqueued;
-
- assert(gDvm.methJavaLangRefReference_enqueueInternal != NULL);
- numReferencesEnqueued = 0;
- while ((obj = dvmGetNextHeapWorkerObject()) != NULL) {
- /* Make sure the object hasn't been collected since
- * being scheduled.
- */
- assert(dvmIsValidObject(obj));
-
- /* Call the appropriate method(s).
- */
- assert(dvmGetFieldObject(
- obj, gDvm.offJavaLangRefReference_queue) != NULL);
- assert(dvmGetFieldObject(
- obj, gDvm.offJavaLangRefReference_queueNext) == NULL);
- numReferencesEnqueued++;
- callMethod(self, obj, gDvm.methJavaLangRefReference_enqueueInternal);
-
- /* Let the GC collect the object.
- */
- dvmReleaseTrackedAlloc(obj, self);
- }
- LOGV("Enqueued %zd references", numReferencesEnqueued);
-}
-
-/*
- * The heap worker thread sits quietly until the GC tells it there's work
- * to do.
- */
-static void* heapWorkerThreadStart(void* arg)
-{
- Thread *self = dvmThreadSelf();
-
- UNUSED_PARAMETER(arg);
-
- LOGV("HeapWorker thread started (threadid=%d)\n", self->threadId);
-
- /* tell the main thread that we're ready */
- lockMutex(&gDvm.heapWorkerLock);
- gDvm.heapWorkerReady = true;
- dvmSignalCond(&gDvm.heapWorkerCond);
- dvmUnlockMutex(&gDvm.heapWorkerLock);
-
- lockMutex(&gDvm.heapWorkerLock);
- while (!gDvm.haltHeapWorker) {
- struct timespec trimtime;
- bool timedwait = false;
-
- /* We're done running interpreted code for now. */
- dvmChangeStatus(NULL, THREAD_VMWAIT);
-
- /* Signal anyone who wants to know when we're done. */
- dvmBroadcastCond(&gDvm.heapWorkerIdleCond);
-
- /* Trim the heap if we were asked to. */
- trimtime = gDvm.gcHeap->heapWorkerNextTrim;
- if (trimtime.tv_sec != 0 && trimtime.tv_nsec != 0) {
- struct timespec now;
-
-#ifdef HAVE_TIMEDWAIT_MONOTONIC
- clock_gettime(CLOCK_MONOTONIC, &now); // relative time
-#else
- struct timeval tvnow;
- gettimeofday(&tvnow, NULL); // absolute time
- now.tv_sec = tvnow.tv_sec;
- now.tv_nsec = tvnow.tv_usec * 1000;
-#endif
-
- if (trimtime.tv_sec < now.tv_sec ||
- (trimtime.tv_sec == now.tv_sec &&
- trimtime.tv_nsec <= now.tv_nsec))
- {
- size_t madvisedSizes[HEAP_SOURCE_MAX_HEAP_COUNT];
-
- /*
- * Acquire the gcHeapLock. The requires releasing the
- * heapWorkerLock before the gcHeapLock is acquired.
- * It is possible that the gcHeapLock may be acquired
- * during a concurrent GC in which case heapWorkerLock
- * is held by the GC and we are unable to make forward
- * progress. We avoid deadlock by releasing the
- * gcHeapLock and then waiting to be signaled when the
- * GC completes. There is no guarantee that the next
- * time we are run will coincide with GC inactivity so
- * the check and wait must be performed within a loop.
- */
- dvmUnlockMutex(&gDvm.heapWorkerLock);
- dvmLockHeap();
- dvmWaitForConcurrentGcToComplete();
- dvmLockMutex(&gDvm.heapWorkerLock);
-
- memset(madvisedSizes, 0, sizeof(madvisedSizes));
- dvmHeapSourceTrim(madvisedSizes, HEAP_SOURCE_MAX_HEAP_COUNT);
-
- dvmUnlockHeap();
-
- trimtime.tv_sec = 0;
- trimtime.tv_nsec = 0;
- gDvm.gcHeap->heapWorkerNextTrim = trimtime;
- } else {
- timedwait = true;
- }
- }
-
- /* sleep until signaled */
- if (timedwait) {
- int cc __attribute__ ((__unused__));
-#ifdef HAVE_TIMEDWAIT_MONOTONIC
- cc = pthread_cond_timedwait_monotonic(&gDvm.heapWorkerCond,
- &gDvm.heapWorkerLock, &trimtime);
-#else
- cc = pthread_cond_timedwait(&gDvm.heapWorkerCond,
- &gDvm.heapWorkerLock, &trimtime);
-#endif
- assert(cc == 0 || cc == ETIMEDOUT);
- } else {
- dvmWaitCond(&gDvm.heapWorkerCond, &gDvm.heapWorkerLock);
- }
-
- /*
- * Return to the running state before doing heap work. This
- * will block if the GC has initiated a suspend. We release
- * the heapWorkerLock beforehand for the GC to make progress
- * and wait to be signaled after the GC completes. There is
- * no guarantee that the next time we are run will coincide
- * with GC inactivity so the check and wait must be performed
- * within a loop.
- */
- dvmUnlockMutex(&gDvm.heapWorkerLock);
- dvmChangeStatus(NULL, THREAD_RUNNING);
- dvmLockHeap();
- dvmWaitForConcurrentGcToComplete();
- dvmLockMutex(&gDvm.heapWorkerLock);
- dvmUnlockHeap();
- LOGV("HeapWorker is awake\n");
-
- /* Process any events in the queue.
- */
- doHeapWork(self);
- }
- dvmUnlockMutex(&gDvm.heapWorkerLock);
-
- if (gDvm.verboseShutdown)
- LOGD("HeapWorker thread shutting down\n");
- return NULL;
-}
-
-/*
- * Wake up the heap worker to let it know that there's work to be done.
- */
-void dvmSignalHeapWorker(bool shouldLock)
-{
- if (shouldLock) {
- dvmLockMutex(&gDvm.heapWorkerLock);
- }
-
- dvmSignalCond(&gDvm.heapWorkerCond);
-
- if (shouldLock) {
- dvmUnlockMutex(&gDvm.heapWorkerLock);
- }
-}
-
-/*
- * Requests that dvmHeapSourceTrim() be called no sooner
- * than timeoutSec seconds from now. If timeoutSec
- * is zero, any pending trim is cancelled.
- *
- * Caller must hold heapWorkerLock.
- */
-void dvmScheduleHeapSourceTrim(size_t timeoutSec)
-{
- GcHeap *gcHeap = gDvm.gcHeap;
- struct timespec timeout;
-
- if (timeoutSec == 0) {
- timeout.tv_sec = 0;
- timeout.tv_nsec = 0;
- /* Don't wake up the thread just to tell it to cancel.
- * If it wakes up naturally, we can avoid the extra
- * context switch.
- */
- } else {
-#ifdef HAVE_TIMEDWAIT_MONOTONIC
- clock_gettime(CLOCK_MONOTONIC, &timeout);
- timeout.tv_sec += timeoutSec;
-#else
- struct timeval now;
- gettimeofday(&now, NULL);
- timeout.tv_sec = now.tv_sec + timeoutSec;
- timeout.tv_nsec = now.tv_usec * 1000;
-#endif
- dvmSignalHeapWorker(false);
- }
- gcHeap->heapWorkerNextTrim = timeout;
-}
diff --git a/vm/alloc/HeapWorker.h b/vm/alloc/HeapWorker.h
deleted file mode 100644
index 67babc3b5..000000000
--- a/vm/alloc/HeapWorker.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/*
- * Manage async heap tasks.
- */
-#ifndef _DALVIK_ALLOC_HEAP_WORKER
-#define _DALVIK_ALLOC_HEAP_WORKER
-
-/*
- * Initialize any HeapWorker state that Heap.c
- * cares about. This lets the GC start before the
- * HeapWorker thread is initialized.
- */
-void dvmInitializeHeapWorkerState(void);
-
-/*
- * Initialization. Starts/stops the worker thread.
- */
-bool dvmHeapWorkerStartup(void);
-void dvmHeapWorkerShutdown(void);
-
-/*
- * Tell the worker thread to wake up and do work.
- * If shouldLock is false, the caller must have already
- * acquired gDvm.heapWorkerLock.
- */
-void dvmSignalHeapWorker(bool shouldLock);
-
-/*
- * Requests that dvmHeapSourceTrim() be called no sooner
- * than timeoutSec seconds from now. If timeoutSec
- * is zero, any pending trim is cancelled.
- *
- * Caller must hold heapWorkerLock.
- */
-void dvmScheduleHeapSourceTrim(size_t timeoutSec);
-
-/* Make sure that the HeapWorker thread hasn't spent an inordinate
- * amount of time inside interpreted code.
- *
- * Aborts the VM if the thread appears to be wedged.
- *
- * The caller must hold the heapWorkerLock.
- */
-void dvmAssertHeapWorkerThreadRunning();
-
-/*
- * Called by the worker thread to get the next object
- * to finalize/enqueue/clear. Implemented in Heap.c.
- *
- * @param op The operation to perform on the returned object.
- * Must be non-NULL.
- * @return The object to operate on, or NULL.
- */
-Object *dvmGetNextHeapWorkerObject();
-
-#endif /*_DALVIK_ALLOC_HEAP_WORKER*/
diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c
index 69b75de3f..e26394c85 100644
--- a/vm/alloc/MarkSweep.c
+++ b/vm/alloc/MarkSweep.c
@@ -20,7 +20,6 @@
#include "alloc/HeapBitmapInlines.h"
#include "alloc/HeapInternal.h"
#include "alloc/HeapSource.h"
-#include "alloc/HeapWorker.h"
#include "alloc/MarkSweep.h"
#include "alloc/Visit.h"
#include "alloc/VisitInlines.h"
@@ -342,8 +341,6 @@ static void verifyImmuneObjects()
* - Primitive classes
* - Special objects
* - gDvm.outOfMemoryObj
- * - Objects allocated with ALLOC_NO_GC
- * - Objects pending finalization (but not yet finalized)
* - Objects in debugger object registry
*
* Don't need:
@@ -795,11 +792,7 @@ static void enqueueReference(Object *ref)
assert(ref != NULL);
assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
- if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
- LOGE_HEAP("enqueueReference(): no room for any more "
- "reference operations\n");
- dvmAbort();
- }
+ enqueuePendingReference(ref, &gDvm.gcHeap->clearedReferences);
}
/*
@@ -857,11 +850,9 @@ static void clearWhiteReferences(Object **list)
GcMarkContext *ctx;
Object *ref, *referent;
size_t referentOffset;
- bool doSignal;
ctx = &gDvm.gcHeap->markContext;
referentOffset = gDvm.offJavaLangRefReference_referent;
- doSignal = false;
while (*list != NULL) {
ref = dequeuePendingReference(list);
referent = dvmGetFieldObject(ref, referentOffset);
@@ -870,31 +861,23 @@ static void clearWhiteReferences(Object **list)
clearReference(ref);
if (isEnqueuable(ref)) {
enqueueReference(ref);
- doSignal = true;
}
}
}
- /*
- * If we cleared a reference with a reference queue we must notify
- * the heap worker to append the reference.
- */
- if (doSignal) {
- dvmSignalHeapWorker(false);
- }
assert(*list == NULL);
}
/*
* Enqueues finalizer references with white referents. White
- * referents are blackened, moved to the pendingNext field, and the
+ * referents are blackened, moved to the zombie field, and the
* referent field is cleared.
*/
static void enqueueFinalizerReferences(Object **list)
{
GcMarkContext *ctx = &gDvm.gcHeap->markContext;
size_t referentOffset = gDvm.offJavaLangRefReference_referent;
- size_t pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
- bool doSignal = false;
+ size_t zombieOffset = gDvm.offJavaLangRefFinalizerReference_zombie;
+ bool hasEnqueued = false;
while (*list != NULL) {
Object *ref = dequeuePendingReference(list);
Object *referent = dvmGetFieldObject(ref, referentOffset);
@@ -902,15 +885,14 @@ static void enqueueFinalizerReferences(Object **list)
markObject(referent, ctx);
/* If the referent is non-null the reference must queuable. */
assert(isEnqueuable(ref));
- dvmSetFieldObject(ref, pendingNextOffset, referent);
+ dvmSetFieldObject(ref, zombieOffset, referent);
clearReference(ref);
enqueueReference(ref);
- doSignal = true;
+ hasEnqueued = true;
}
}
- if (doSignal) {
+ if (hasEnqueued) {
processMarkStack(ctx);
- dvmSignalHeapWorker(false);
}
assert(*list == NULL);
}
@@ -928,8 +910,8 @@ void dvmSetFinalizable(Object *obj)
assert(self != NULL);
Method *meth = gDvm.methJavaLangRefFinalizerReferenceAdd;
assert(meth != NULL);
- JValue unused;
- dvmCallMethod(self, meth, obj, &unused, obj);
+ JValue unusedResult;
+ dvmCallMethod(self, meth, NULL, &unusedResult, obj);
}
/*
@@ -982,6 +964,24 @@ void dvmHeapProcessReferences(Object **softReferences, bool clearSoftRefs,
assert(*phantomReferences == NULL);
}
+/*
+ * Pushes a list of cleared references out to the managed heap.
+ */
+void dvmEnqueueClearedReferences(Object **cleared)
+{
+ assert(cleared != NULL);
+ if (*cleared != NULL) {
+ Thread *self = dvmThreadSelf();
+ assert(self != NULL);
+ Method *meth = gDvm.methJavaLangRefReferenceQueueAdd;
+ assert(meth != NULL);
+ JValue unused;
+ Object *reference = *cleared;
+ dvmCallMethod(self, meth, NULL, &unused, reference);
+ *cleared = NULL;
+ }
+}
+
void dvmHeapFinishMarkStep()
{
GcMarkContext *ctx;
diff --git a/vm/alloc/MarkSweep.h b/vm/alloc/MarkSweep.h
index c9f11e487..94bf3ad69 100644
--- a/vm/alloc/MarkSweep.h
+++ b/vm/alloc/MarkSweep.h
@@ -59,5 +59,6 @@ void dvmHeapFinishMarkStep(void);
void dvmHeapSweepSystemWeaks(void);
void dvmHeapSweepUnmarkedObjects(bool isPartial, bool isConcurrent,
size_t *numObjects, size_t *numBytes);
+void dvmEnqueueClearedReferences(Object **references);
#endif // _DALVIK_ALLOC_MARK_SWEEP
diff --git a/vm/alloc/Visit.c b/vm/alloc/Visit.c
index 634611cde..6ca143992 100644
--- a/vm/alloc/Visit.c
+++ b/vm/alloc/Visit.c
@@ -83,20 +83,6 @@ static void visitIndirectRefTable(RootVisitor *visitor, IndirectRefTable *table,
}
/*
- * Visits a large heap reference table. These objects are list heads.
- * As such, it is valid for table to be NULL.
- */
-static void visitLargeHeapRefTable(RootVisitor *visitor,
- LargeHeapRefTable *table,
- RootType type, void *arg)
-{
- assert(visitor != NULL);
- for (; table != NULL; table = table->next) {
- visitReferenceTable(visitor, &table->refs, 0, type, arg);
- }
-}
-
-/*
* Visits all stack slots except those belonging to native method
* arguments.
*/
@@ -250,7 +236,6 @@ void dvmVisitRoots(RootVisitor *visitor, void *arg)
dvmLockMutex(&gDvm.jniPinRefLock);
visitReferenceTable(visitor, &gDvm.jniPinRefTable, 0, ROOT_VM_INTERNAL, arg);
dvmUnlockMutex(&gDvm.jniPinRefLock);
- visitLargeHeapRefTable(visitor, gDvm.gcHeap->referenceOperations, ROOT_REFERENCE_CLEANUP, arg);
visitThreads(visitor, arg);
(*visitor)(&gDvm.outOfMemoryObj, 0, ROOT_VM_INTERNAL, arg);
(*visitor)(&gDvm.internalErrorObj, 0, ROOT_VM_INTERNAL, arg);
diff --git a/vm/alloc/Visit.h b/vm/alloc/Visit.h
index e7c52e58f..a66839d14 100644
--- a/vm/alloc/Visit.h
+++ b/vm/alloc/Visit.h
@@ -30,9 +30,7 @@ typedef enum {
ROOT_MONITOR_USED,
ROOT_THREAD_OBJECT,
ROOT_INTERNED_STRING,
- ROOT_FINALIZING,
ROOT_DEBUGGER,
- ROOT_REFERENCE_CLEANUP,
ROOT_VM_INTERNAL,
ROOT_JNI_MONITOR,
} RootType;
diff --git a/vm/hprof/Hprof.h b/vm/hprof/Hprof.h
index c79a3df0e..c62dd9cc8 100644
--- a/vm/hprof/Hprof.h
+++ b/vm/hprof/Hprof.h
@@ -84,12 +84,12 @@ typedef enum hprof_heap_tag_t {
/* Android */
HPROF_HEAP_DUMP_INFO = 0xfe,
HPROF_ROOT_INTERNED_STRING = 0x89,
- HPROF_ROOT_FINALIZING = 0x8a,
+ HPROF_ROOT_FINALIZING = 0x8a, /* obsolete */
HPROF_ROOT_DEBUGGER = 0x8b,
- HPROF_ROOT_REFERENCE_CLEANUP = 0x8c,
+ HPROF_ROOT_REFERENCE_CLEANUP = 0x8c, /* obsolete */
HPROF_ROOT_VM_INTERNAL = 0x8d,
HPROF_ROOT_JNI_MONITOR = 0x8e,
- HPROF_UNREACHABLE = 0x90, /* deprecated */
+ HPROF_UNREACHABLE = 0x90, /* obsolete */
HPROF_PRIMITIVE_ARRAY_NODATA_DUMP = 0xc3,
} hprof_heap_tag_t;