diff options
-rw-r--r-- | vm/Dvm.mk | 2 | ||||
-rw-r--r-- | vm/Globals.h | 24 | ||||
-rw-r--r-- | vm/Init.c | 3 | ||||
-rw-r--r-- | vm/InitRefs.c | 22 | ||||
-rw-r--r-- | vm/Thread.c | 6 | ||||
-rw-r--r-- | vm/alloc/Alloc.c | 43 | ||||
-rw-r--r-- | vm/alloc/Alloc.h | 1 | ||||
-rw-r--r-- | vm/alloc/Heap.c | 98 | ||||
-rw-r--r-- | vm/alloc/HeapInternal.h | 32 | ||||
-rw-r--r-- | vm/alloc/HeapTable.c | 168 | ||||
-rw-r--r-- | vm/alloc/HeapTable.h | 36 | ||||
-rw-r--r-- | vm/alloc/HeapWorker.c | 472 | ||||
-rw-r--r-- | vm/alloc/HeapWorker.h | 70 | ||||
-rw-r--r-- | vm/alloc/MarkSweep.c | 54 | ||||
-rw-r--r-- | vm/alloc/MarkSweep.h | 1 | ||||
-rw-r--r-- | vm/alloc/Visit.c | 15 | ||||
-rw-r--r-- | vm/alloc/Visit.h | 2 | ||||
-rw-r--r-- | vm/hprof/Hprof.h | 6 |
18 files changed, 106 insertions, 949 deletions
@@ -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. */ @@ -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; |