diff options
29 files changed, 114 insertions, 337 deletions
diff --git a/libdex/InstrUtils.c b/libdex/InstrUtils.c index 0e72d435d..3770c6da0 100644 --- a/libdex/InstrUtils.c +++ b/libdex/InstrUtils.c @@ -313,7 +313,7 @@ static u1 gOpcodeFlagsTable[kNumPackedOpcodes] = { kInstrCanThrow, kInstrCanContinue|kInstrCanThrow, kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue, + kInstrCanContinue|kInstrCanThrow|kInstrInvoke, kInstrCanReturn, kInstrCanContinue|kInstrCanThrow, kInstrCanContinue|kInstrCanThrow, @@ -571,7 +571,7 @@ static u1 gOpcodeFlagsTable[kNumPackedOpcodes] = { 0, 0, 0, - kInstrCanContinue, + kInstrCanContinue|kInstrCanThrow|kInstrInvoke, kInstrCanContinue|kInstrCanThrow, kInstrCanContinue|kInstrCanThrow, kInstrCanContinue|kInstrCanThrow, diff --git a/opcode-gen/bytecode.txt b/opcode-gen/bytecode.txt index 7f6921433..89b8c8305 100644 --- a/opcode-gen/bytecode.txt +++ b/opcode-gen/bytecode.txt @@ -328,12 +328,7 @@ op ed ^throw-verification-error 20bc n varies optimized|throw op ee +execute-inline 35mi n inline-method optimized|continue|throw op ef +execute-inline/range 3rmi n inline-method optimized|continue|throw -# This opcode is marked neither as "invoke" nor "throw" since it -# doesn't invoke the method unless a debugger is attached. The verifier -# will ensure that Object.<init> is present and empty, so there is no -# opportunity for an exception to be thrown. -op f0 +invoke-object-init/range 35c n method-ref optimized|continue - +op f0 +invoke-object-init/range 35c n method-ref optimized|continue|throw|invoke op f1 +return-void-barrier 10x n none optimized|return op f2 +iget-quick 22cs y field-offset optimized|continue|throw op f3 +iget-wide-quick 22cs y field-offset optimized|continue|throw @@ -399,9 +394,7 @@ op 26ff invoke-interface/jumbo 5rc n method-ref continue|throw|invoke # Optimized opcodes (not valid in an unoptimized dex file) # -# See notes above invoke-object-init re: no "throw" or "invoke" -op f2ff +invoke-object-init/jumbo 5rc n method-ref optimized|continue - +op f2ff +invoke-object-init/jumbo 5rc n method-ref optimized|continue|throw|invoke op f3ff +iget-volatile/jumbo 52c y field-ref optimized|continue|throw op f4ff +iget-wide-volatile/jumbo 52c y field-ref optimized|continue|throw op f5ff +iget-object-volatile/jumbo 52c y field-ref optimized|continue|throw diff --git a/vm/Globals.h b/vm/Globals.h index ad28e147c..5287dadf4 100644 --- a/vm/Globals.h +++ b/vm/Globals.h @@ -285,6 +285,7 @@ struct DvmGlobals { ClassObject* classOrgApacheHarmonyLangAnnotationAnnotationFactory; ClassObject* classOrgApacheHarmonyLangAnnotationAnnotationMember; ClassObject* classOrgApacheHarmonyLangAnnotationAnnotationMemberArray; + ClassObject* classJavaLangRefFinalizerReference; /* * classes representing exception types. The names here don't include @@ -337,7 +338,6 @@ struct DvmGlobals { int voffJavaLangObject_equals; int voffJavaLangObject_hashCode; int voffJavaLangObject_toString; - int voffJavaLangObject_finalize; /* field offsets - Class */ int offJavaLangClass_pd; @@ -390,6 +390,9 @@ struct DvmGlobals { /* method pointers - java.lang.ref.Reference */ Method* methJavaLangRefReference_enqueueInternal; + /* more method pointers - java.lang.ref.FinalizerReference */ + Method* methJavaLangRefFinalizerReferenceAdd; + /* constructor method pointers; no vtable involved, so use Method* */ Method* methJavaLangStackTraceElement_init; Method* methJavaLangReflectConstructor_init; diff --git a/vm/InitRefs.c b/vm/InitRefs.c index 137a48116..953db8e46 100644 --- a/vm/InitRefs.c +++ b/vm/InitRefs.c @@ -340,6 +340,9 @@ static bool initDirectMethodReferences(void) { "Lorg/apache/harmony/lang/annotation/AnnotationFactory;", "createAnnotation", "(Ljava/lang/Class;[Lorg/apache/harmony/lang/annotation/AnnotationMember;)" "Ljava/lang/annotation/Annotation;" }, + { &gDvm.methodTraceClassPrepMethod, "Ldalvik/system/VMDebug;", "startClassPrep", "()V" }, + { &gDvm.methJavaLangRefFinalizerReferenceAdd, + "Ljava/lang/ref/FinalizerReference;", "add", "(Ljava/lang/Object;)V" }, { NULL, NULL, NULL, NULL } }; @@ -386,7 +389,6 @@ static bool initVirtualMethodOffsets(void) { "(Ljava/lang/String;)Ljava/lang/Class;" }, { &gDvm.voffJavaLangObject_equals, "Ljava/lang/Object;", "equals", "(Ljava/lang/Object;)Z" }, - { &gDvm.voffJavaLangObject_finalize, "Ljava/lang/Object;", "finalize", "()V" }, { &gDvm.voffJavaLangObject_hashCode, "Ljava/lang/Object;", "hashCode", "()I" }, { &gDvm.voffJavaLangObject_toString, "Ljava/lang/Object;", "toString", "()Ljava/lang/String;" }, @@ -407,6 +409,13 @@ static bool initVirtualMethodOffsets(void) { return true; } +static bool initFinalizerReference() +{ + gDvm.classJavaLangRefFinalizerReference = + dvmFindSystemClass("Ljava/lang/ref/FinalizerReference;"); + return gDvm.classJavaLangRefFinalizerReference != NULL; +} + static bool verifyStringOffset(const char* name, int actual, int expected) { if (actual != expected) { LOGE("InitRefs: String.%s offset = %d; expected %d\n", name, actual, expected); @@ -447,6 +456,7 @@ bool dvmFindRequiredClassesAndMembers(void) { && initConstructorReferences() && initDirectMethodReferences() && initVirtualMethodOffsets() + && initFinalizerReference() && verifyStringOffsets(); } @@ -465,7 +475,7 @@ bool dvmFindReferenceMembers(ClassObject* classReference) { /* Note: enqueueInternal() is private and thus a direct method. */ return initFieldOffset(classReference, &gDvm.offJavaLangRefReference_pendingNext, - "pendingNext", "Ljava/lang/ref/Reference;") + "pendingNext", "Ljava/lang/Object;") && initFieldOffset(classReference, &gDvm.offJavaLangRefReference_queue, "queue", "Ljava/lang/ref/ReferenceQueue;") && initFieldOffset(classReference, &gDvm.offJavaLangRefReference_queueNext, diff --git a/vm/Thread.c b/vm/Thread.c index eb026fde3..33d659941 100644 --- a/vm/Thread.c +++ b/vm/Thread.c @@ -1311,23 +1311,6 @@ bool dvmCreateInterpThread(Object* threadObj, int reqStackSize) assert(threadObj != NULL); - if(gDvm.zygote) { - // Allow the sampling profiler thread. We shut it down before forking. - StringObject* nameStr = (StringObject*) dvmGetFieldObject(threadObj, - gDvm.offJavaLangThread_name); - char* threadName = dvmCreateCstrFromString(nameStr); - bool profilerThread = strcmp(threadName, "SamplingProfiler") == 0; - if (!profilerThread) { - dvmThrowExceptionFmt(gDvm.exIllegalStateException, - "No new threads in -Xzygote mode. " - "Found thread named '%s'", threadName); - - free(threadName); - goto fail; - } - free(threadName); - } - self = dvmThreadSelf(); if (reqStackSize == 0) stackSize = gDvm.stackSize; diff --git a/vm/alloc/Alloc.c b/vm/alloc/Alloc.c index 8269290a3..370ac3576 100644 --- a/vm/alloc/Alloc.c +++ b/vm/alloc/Alloc.c @@ -169,6 +169,7 @@ Object* dvmAllocObject(ClassObject* clazz, int flags) { Object* newObj; + assert(clazz != NULL); assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz)); /* allocate on GC heap; memory is zeroed out */ diff --git a/vm/alloc/Heap.c b/vm/alloc/Heap.c index c0ef8fb55..1a38a76cc 100644 --- a/vm/alloc/Heap.c +++ b/vm/alloc/Heap.c @@ -104,8 +104,6 @@ bool dvmHeapStartup() * and reference objects. */ dvmInitMutex(&gDvm.heapWorkerListLock); - gcHeap->finalizableRefs = NULL; - gcHeap->pendingFinalizationRefs = NULL; gcHeap->referenceOperations = NULL; if (!dvmCardTableStartup(gDvm.heapMaximumSize)) { @@ -135,12 +133,6 @@ void dvmHeapShutdown() * cleaned up explicitly. The process may stick around, so we * don't want to leak any native memory. */ - dvmHeapFreeLargeTable(gDvm.gcHeap->finalizableRefs); - gDvm.gcHeap->finalizableRefs = NULL; - - dvmHeapFreeLargeTable(gDvm.gcHeap->pendingFinalizationRefs); - gDvm.gcHeap->pendingFinalizationRefs = NULL; - dvmHeapFreeLargeTable(gDvm.gcHeap->referenceOperations); gDvm.gcHeap->referenceOperations = NULL; @@ -191,27 +183,15 @@ void dvmUnlockHeap() * * Typically only called by the heap worker thread. */ -Object *dvmGetNextHeapWorkerObject(HeapWorkerOperation *op) +Object *dvmGetNextHeapWorkerObject() { Object *obj; GcHeap *gcHeap = gDvm.gcHeap; - assert(op != NULL); - dvmLockMutex(&gDvm.heapWorkerListLock); obj = dvmHeapGetNextObjectFromLargeTable(&gcHeap->referenceOperations); if (obj != NULL) { - *op = WORKER_ENQUEUE; - } else { - obj = dvmHeapGetNextObjectFromLargeTable( - &gcHeap->pendingFinalizationRefs); - if (obj != NULL) { - *op = WORKER_FINALIZE; - } - } - - if (obj != NULL) { /* Don't let the GC collect the object until the * worker thread is done with it. */ @@ -709,6 +689,7 @@ void dvmCollectGarbageInternal(const GcSpec* spec) dvmHeapProcessReferences(&gcHeap->softReferences, spec->softReferencePolicy == CLEAR, &gcHeap->weakReferences, + &gcHeap->finalizerReferences, &gcHeap->phantomReferences); #if defined(WITH_JIT) diff --git a/vm/alloc/HeapInternal.h b/vm/alloc/HeapInternal.h index d10a41708..7f8c9c5e3 100644 --- a/vm/alloc/HeapInternal.h +++ b/vm/alloc/HeapInternal.h @@ -29,37 +29,15 @@ typedef struct HeapSource HeapSource; struct GcHeap { HeapSource *heapSource; - /* List of heap objects that will require finalization when - * collected. I.e., instance objects - * - * a) whose class definitions override java.lang.Object.finalize() - * - * *** AND *** - * - * b) that have never been finalized. - * - * Note that this does not exclude non-garbage objects; this - * is not the list of pending finalizations, but of objects that - * potentially have finalization in their futures. - */ - LargeHeapRefTable *finalizableRefs; - - /* The list of objects that need to have finalize() called - * on themselves. These references are part of the root set. - * - * This table is protected by gDvm.heapWorkerListLock, which must - * be acquired after the heap lock. - */ - LargeHeapRefTable *pendingFinalizationRefs; - /* Linked lists of subclass instances of java/lang/ref/Reference * that we find while recursing. The "next" pointers are hidden * in the objects' <code>int Reference.vmData</code> fields. * These lists are cleared and rebuilt each time the GC runs. */ - Object *softReferences; - Object *weakReferences; - Object *phantomReferences; + Object *softReferences; + Object *weakReferences; + 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 diff --git a/vm/alloc/HeapWorker.c b/vm/alloc/HeapWorker.c index 57089f4f1..e0116d107 100644 --- a/vm/alloc/HeapWorker.c +++ b/vm/alloc/HeapWorker.c @@ -272,17 +272,11 @@ static void callMethod(Thread *self, Object *obj, Method *method) static void doHeapWork(Thread *self) { Object *obj; - HeapWorkerOperation op; - int numFinalizersCalled, numReferencesEnqueued; + size_t numReferencesEnqueued; - assert(gDvm.voffJavaLangObject_finalize >= 0); assert(gDvm.methJavaLangRefReference_enqueueInternal != NULL); - - numFinalizersCalled = 0; numReferencesEnqueued = 0; - while ((obj = dvmGetNextHeapWorkerObject(&op)) != NULL) { - Method *method = NULL; - + while ((obj = dvmGetNextHeapWorkerObject()) != NULL) { /* Make sure the object hasn't been collected since * being scheduled. */ @@ -290,30 +284,18 @@ static void doHeapWork(Thread *self) /* Call the appropriate method(s). */ - if (op == WORKER_FINALIZE) { - numFinalizersCalled++; - method = obj->clazz->vtable[gDvm.voffJavaLangObject_finalize]; - assert(dvmCompareNameDescriptorAndMethod("finalize", "()V", - method) == 0); - assert(method->clazz != gDvm.classJavaLangObject); - callMethod(self, obj, method); - } else { - assert(op == WORKER_ENQUEUE); - assert(dvmGetFieldObject( - obj, gDvm.offJavaLangRefReference_queue) != NULL); - assert(dvmGetFieldObject( - obj, gDvm.offJavaLangRefReference_queueNext) == NULL); - numReferencesEnqueued++; - callMethod(self, obj, - gDvm.methJavaLangRefReference_enqueueInternal); - } + 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("Called %d finalizers\n", numFinalizersCalled); - LOGV("Enqueued %d references\n", numReferencesEnqueued); + LOGV("Enqueued %zd references", numReferencesEnqueued); } /* @@ -455,54 +437,6 @@ void dvmSignalHeapWorker(bool shouldLock) } /* - * Block until all pending heap worker work has finished. - */ -void dvmWaitForHeapWorkerIdle() -{ - assert(gDvm.heapWorkerReady); - - dvmChangeStatus(NULL, THREAD_VMWAIT); - - dvmLockMutex(&gDvm.heapWorkerLock); - - /* Wake up the heap worker and wait for it to finish. */ - //TODO(http://b/issue?id=699704): This will deadlock if - // called from finalize(), enqueue(), or clear(). We - // need to detect when this is called from the HeapWorker - // context and just give up. - dvmSignalHeapWorker(false); - dvmWaitCond(&gDvm.heapWorkerIdleCond, &gDvm.heapWorkerLock); - - dvmUnlockMutex(&gDvm.heapWorkerLock); - - dvmChangeStatus(NULL, THREAD_RUNNING); -} - -/* - * Do not return until any pending heap work has finished. This may - * or may not happen in the context of the calling thread. - * No exceptions will escape. - */ -void dvmRunFinalizationSync() -{ - if (gDvm.zygote) { - assert(!gDvm.heapWorkerReady); - - /* When in zygote mode, there is no heap worker. - * Do the work in the current thread. - */ - dvmLockMutex(&gDvm.heapWorkerLock); - doHeapWork(dvmThreadSelf()); - dvmUnlockMutex(&gDvm.heapWorkerLock); - } else { - /* Outside of zygote mode, we can just ask the - * heap worker thread to do the work. - */ - dvmWaitForHeapWorkerIdle(); - } -} - -/* * Requests that dvmHeapSourceTrim() be called no sooner * than timeoutSec seconds from now. If timeoutSec * is zero, any pending trim is cancelled. diff --git a/vm/alloc/HeapWorker.h b/vm/alloc/HeapWorker.h index 45587ff12..67babc3b5 100644 --- a/vm/alloc/HeapWorker.h +++ b/vm/alloc/HeapWorker.h @@ -40,20 +40,6 @@ void dvmHeapWorkerShutdown(void); void dvmSignalHeapWorker(bool shouldLock); /* - * Block until all pending heap worker work has finished. - */ -void dvmWaitForHeapWorkerIdle(void); - -/* - * Does not return until any pending finalizers have been called. - * This may or may not happen in the context of the calling thread. - * No exceptions will escape. - * - * Used by zygote, which doesn't have a HeapWorker thread. - */ -void dvmRunFinalizationSync(void); - -/* * Requests that dvmHeapSourceTrim() be called no sooner * than timeoutSec seconds from now. If timeoutSec * is zero, any pending trim is cancelled. @@ -72,14 +58,6 @@ void dvmScheduleHeapSourceTrim(size_t timeoutSec); void dvmAssertHeapWorkerThreadRunning(); /* - * The type of operation for HeapWorker to perform on an object. - */ -typedef enum HeapWorkerOperation { - WORKER_FINALIZE = 0, - WORKER_ENQUEUE = 1, -} HeapWorkerOperation; - -/* * Called by the worker thread to get the next object * to finalize/enqueue/clear. Implemented in Heap.c. * @@ -87,6 +65,6 @@ typedef enum HeapWorkerOperation { * Must be non-NULL. * @return The object to operate on, or NULL. */ -Object *dvmGetNextHeapWorkerObject(HeapWorkerOperation *op); +Object *dvmGetNextHeapWorkerObject(); #endif /*_DALVIK_ALLOC_HEAP_WORKER*/ diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c index bd872dff2..e5994e698 100644 --- a/vm/alloc/MarkSweep.c +++ b/vm/alloc/MarkSweep.c @@ -508,6 +508,7 @@ static int referenceClassFlags(const Object *obj) { int flags = CLASS_ISREFERENCE | CLASS_ISWEAKREFERENCE | + CLASS_ISFINALIZERREFERENCE | CLASS_ISPHANTOMREFERENCE; return GET_CLASS_FLAG_GROUP(obj->clazz, flags); } @@ -529,6 +530,14 @@ static bool isWeakReference(const Object *obj) } /* + * Returns true if the object derives from FinalizerReference. + */ +static bool isFinalizerReference(const Object *obj) +{ + return referenceClassFlags(obj) & CLASS_ISFINALIZERREFERENCE; +} + +/* * Returns true if the object derives from PhantomReference. */ static bool isPhantomReference(const Object *obj) @@ -606,6 +615,8 @@ static void delayReferenceReferent(Object *obj, GcMarkContext *ctx) list = &gcHeap->softReferences; } else if (isWeakReference(obj)) { list = &gcHeap->weakReferences; + } else if (isFinalizerReference(obj)) { + list = &gcHeap->finalizerReferences; } else if (isPhantomReference(obj)) { list = &gcHeap->phantomReferences; } @@ -872,109 +883,35 @@ static void clearWhiteReferences(Object **list) assert(*list == NULL); } -/* Find unreachable objects that need to be finalized, - * and schedule them for finalization. +/* + * Enqueues finalizer references with white referents. White + * referents are blackened, moved to the pendingNext field, and the + * referent field is cleared. */ -static void scheduleFinalizations(void) +static void enqueueFinalizerReferences(Object **list) { - ReferenceTable newPendingRefs; - LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs; - Object **ref; - Object **lastRef; - size_t totalPendCount; GcMarkContext *ctx = &gDvm.gcHeap->markContext; - - /* - * All reachable objects have been marked. - * Any unmarked finalizable objects need to be finalized. - */ - - /* Create a table that the new pending refs will - * be added to. - */ - if (!dvmHeapInitHeapRefTable(&newPendingRefs)) { - //TODO: mark all finalizable refs and hope that - // we can schedule them next time. Watch out, - // because we may be expecting to free up space - // by calling finalizers. - LOGE("scheduleFinalizations(): no room for pending finalizations"); - dvmAbort(); - } - - /* Walk through finalizableRefs and move any unmarked references - * to the list of new pending refs. - */ - totalPendCount = 0; - while (finRefs != NULL) { - Object **gapRef; - size_t newPendCount = 0; - - gapRef = ref = finRefs->refs.table; - lastRef = finRefs->refs.nextEntry; - while (ref < lastRef) { - if (!isMarked(*ref, ctx)) { - if (!dvmAddToReferenceTable(&newPendingRefs, *ref)) { - //TODO: add the current table and allocate - // a new, smaller one. - LOGE("scheduleFinalizations(): " - "no room for any more pending finalizations: %zd", - dvmReferenceTableEntries(&newPendingRefs)); - dvmAbort(); - } - newPendCount++; - } else { - /* This ref is marked, so will remain on finalizableRefs. - */ - if (newPendCount > 0) { - /* Copy it up to fill the holes. - */ - *gapRef++ = *ref; - } else { - /* No holes yet; don't bother copying. - */ - gapRef++; - } - } - ref++; + size_t referentOffset = gDvm.offJavaLangRefReference_referent; + size_t pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext; + bool doSignal = false; + while (*list != NULL) { + Object *ref = dequeuePendingReference(list); + Object *referent = dvmGetFieldObject(ref, referentOffset); + if (referent != NULL && !isMarked(referent, ctx)) { + markObject(referent, ctx); + /* If the referent is non-null the reference must queuable. */ + assert(isEnqueuable(ref)); + dvmSetFieldObject(ref, pendingNextOffset, referent); + clearReference(ref); + enqueueReference(ref); + doSignal = true; } - finRefs->refs.nextEntry = gapRef; - //TODO: if the table is empty when we're done, free it. - totalPendCount += newPendCount; - finRefs = finRefs->next; - } - LOGV("scheduleFinalizations(): %zd finalizers triggered.", totalPendCount); - if (totalPendCount == 0) { - /* No objects required finalization. - * Free the empty temporary table. - */ - dvmClearReferenceTable(&newPendingRefs); - return; - } - - /* Add the new pending refs to the main list. - */ - if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs, - &newPendingRefs)) - { - LOGE("scheduleFinalizations(): can't insert new pending finalizations"); - dvmAbort(); } - - //TODO: try compacting the main list with a memcpy loop - - /* Mark the refs we just moved; we don't want them or their - * children to get swept yet. - */ - ref = newPendingRefs.table; - lastRef = newPendingRefs.nextEntry; - assert(ref < lastRef); - while (ref < lastRef) { - assert(*ref != NULL); - markObject(*ref, ctx); - ref++; + if (doSignal) { + processMarkStack(ctx); + dvmSignalHeapWorker(false); } - processMarkStack(ctx); - dvmSignalHeapWorker(false); + assert(*list == NULL); } /* @@ -984,15 +921,14 @@ static void scheduleFinalizations(void) * This is called when Object.<init> completes normally. It's also * called for clones of finalizable objects. */ -void dvmSetFinalizable(Object* obj) +void dvmSetFinalizable(Object *obj) { - dvmLockHeap(); - GcHeap* gcHeap = gDvm.gcHeap; - if (!dvmHeapAddRefToLargeTable(&gcHeap->finalizableRefs, obj)) { - LOGE_HEAP("No room for any more finalizable objects"); - dvmAbort(); - } - dvmUnlockHeap(); + Thread *self = dvmThreadSelf(); + assert(self != NULL); + Method *meth = gDvm.methJavaLangRefFinalizerReferenceAdd; + assert(meth != NULL); + JValue unused; + dvmCallMethod(self, meth, obj, &unused, obj); } /* @@ -1000,10 +936,12 @@ void dvmSetFinalizable(Object* obj) */ void dvmHeapProcessReferences(Object **softReferences, bool clearSoftRefs, Object **weakReferences, + Object **finalizerReferences, Object **phantomReferences) { assert(softReferences != NULL); assert(weakReferences != NULL); + assert(finalizerReferences != NULL); assert(phantomReferences != NULL); /* * Unless we are in the zygote or required to clear soft @@ -1023,7 +961,7 @@ void dvmHeapProcessReferences(Object **softReferences, bool clearSoftRefs, * Preserve all white objects with finalize methods and schedule * them for finalization. */ - scheduleFinalizations(); + enqueueFinalizerReferences(finalizerReferences); /* * Clear all f-reachable soft and weak references with white * referents. @@ -1039,6 +977,7 @@ void dvmHeapProcessReferences(Object **softReferences, bool clearSoftRefs, */ assert(*softReferences == NULL); assert(*weakReferences == NULL); + assert(*finalizerReferences == NULL); assert(*phantomReferences == NULL); } diff --git a/vm/alloc/MarkSweep.h b/vm/alloc/MarkSweep.h index 0672aa800..c9f11e487 100644 --- a/vm/alloc/MarkSweep.h +++ b/vm/alloc/MarkSweep.h @@ -53,6 +53,7 @@ void dvmHeapScanMarkedObjects(bool isPartial); void dvmHeapReScanMarkedObjects(void); void dvmHeapProcessReferences(Object **softReferences, bool clearSoftRefs, Object **weakReferences, + Object **finalizerReferences, Object **phantomReferences); void dvmHeapFinishMarkStep(void); void dvmHeapSweepSystemWeaks(void); diff --git a/vm/alloc/Visit.c b/vm/alloc/Visit.c index 1961fc9a7..e11d58378 100644 --- a/vm/alloc/Visit.c +++ b/vm/alloc/Visit.c @@ -251,7 +251,6 @@ void dvmVisitRoots(RootVisitor *visitor, void *arg) visitReferenceTable(visitor, &gDvm.jniPinRefTable, 0, ROOT_VM_INTERNAL, arg); dvmUnlockMutex(&gDvm.jniPinRefLock); visitLargeHeapRefTable(visitor, gDvm.gcHeap->referenceOperations, ROOT_REFERENCE_CLEANUP, arg); - visitLargeHeapRefTable(visitor, gDvm.gcHeap->pendingFinalizationRefs, ROOT_FINALIZING, arg); visitThreads(visitor, arg); (*visitor)(&gDvm.outOfMemoryObj, 0, ROOT_VM_INTERNAL, arg); (*visitor)(&gDvm.internalErrorObj, 0, ROOT_VM_INTERNAL, arg); diff --git a/vm/mterp/armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S b/vm/mterp/armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S index 67a3cc785..6e694d1fd 100644 --- a/vm/mterp/armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S +++ b/vm/mterp/armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S @@ -14,6 +14,7 @@ ldr r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags tst r2, #CLASS_ISFINALIZABLE @ is this class finalizable? beq 1f @ nope, done + EXPORT_PC() @ can throw bl dvmSetFinalizable @ call dvmSetFinalizable(obj) 1: FETCH_ADVANCE_INST(${cccc}+1) @ advance to next instr, load rINST GET_INST_OPCODE(ip) @ ip<- opcode from rINST diff --git a/vm/mterp/c/OP_INVOKE_OBJECT_INIT_RANGE.c b/vm/mterp/c/OP_INVOKE_OBJECT_INIT_RANGE.c index da0d762eb..4d2c50c5d 100644 --- a/vm/mterp/c/OP_INVOKE_OBJECT_INIT_RANGE.c +++ b/vm/mterp/c/OP_INVOKE_OBJECT_INIT_RANGE.c @@ -14,6 +14,7 @@ HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/) * (by virtue of being nothing but a return-void) and set it now. */ if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) { + EXPORT_PC(); dvmSetFinalizable(obj); } diff --git a/vm/mterp/out/InterpAsm-armv5te-vfp.S b/vm/mterp/out/InterpAsm-armv5te-vfp.S index 37bfa62bf..58f721600 100644 --- a/vm/mterp/out/InterpAsm-armv5te-vfp.S +++ b/vm/mterp/out/InterpAsm-armv5te-vfp.S @@ -7421,6 +7421,7 @@ dalvik_inst: ldr r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags tst r2, #CLASS_ISFINALIZABLE @ is this class finalizable? beq 1f @ nope, done + EXPORT_PC() @ can throw bl dvmSetFinalizable @ call dvmSetFinalizable(obj) 1: FETCH_ADVANCE_INST(2+1) @ advance to next instr, load rINST GET_INST_OPCODE(ip) @ ip<- opcode from rINST @@ -10480,6 +10481,7 @@ dalvik_inst: ldr r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags tst r2, #CLASS_ISFINALIZABLE @ is this class finalizable? beq 1f @ nope, done + EXPORT_PC() @ can throw bl dvmSetFinalizable @ call dvmSetFinalizable(obj) 1: FETCH_ADVANCE_INST(4+1) @ advance to next instr, load rINST GET_INST_OPCODE(ip) @ ip<- opcode from rINST diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S index f4a36d5aa..b09793ba1 100644 --- a/vm/mterp/out/InterpAsm-armv5te.S +++ b/vm/mterp/out/InterpAsm-armv5te.S @@ -7743,6 +7743,7 @@ d2i_doconv: ldr r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags tst r2, #CLASS_ISFINALIZABLE @ is this class finalizable? beq 1f @ nope, done + EXPORT_PC() @ can throw bl dvmSetFinalizable @ call dvmSetFinalizable(obj) 1: FETCH_ADVANCE_INST(2+1) @ advance to next instr, load rINST GET_INST_OPCODE(ip) @ ip<- opcode from rINST @@ -10802,6 +10803,7 @@ d2i_doconv: ldr r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags tst r2, #CLASS_ISFINALIZABLE @ is this class finalizable? beq 1f @ nope, done + EXPORT_PC() @ can throw bl dvmSetFinalizable @ call dvmSetFinalizable(obj) 1: FETCH_ADVANCE_INST(4+1) @ advance to next instr, load rINST GET_INST_OPCODE(ip) @ ip<- opcode from rINST diff --git a/vm/mterp/out/InterpAsm-armv7-a-neon.S b/vm/mterp/out/InterpAsm-armv7-a-neon.S index e04621c12..d5543a9f4 100644 --- a/vm/mterp/out/InterpAsm-armv7-a-neon.S +++ b/vm/mterp/out/InterpAsm-armv7-a-neon.S @@ -7379,6 +7379,7 @@ dalvik_inst: ldr r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags tst r2, #CLASS_ISFINALIZABLE @ is this class finalizable? beq 1f @ nope, done + EXPORT_PC() @ can throw bl dvmSetFinalizable @ call dvmSetFinalizable(obj) 1: FETCH_ADVANCE_INST(2+1) @ advance to next instr, load rINST GET_INST_OPCODE(ip) @ ip<- opcode from rINST @@ -10434,6 +10435,7 @@ dalvik_inst: ldr r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags tst r2, #CLASS_ISFINALIZABLE @ is this class finalizable? beq 1f @ nope, done + EXPORT_PC() @ can throw bl dvmSetFinalizable @ call dvmSetFinalizable(obj) 1: FETCH_ADVANCE_INST(4+1) @ advance to next instr, load rINST GET_INST_OPCODE(ip) @ ip<- opcode from rINST diff --git a/vm/mterp/out/InterpAsm-armv7-a.S b/vm/mterp/out/InterpAsm-armv7-a.S index 797646410..fc3528abc 100644 --- a/vm/mterp/out/InterpAsm-armv7-a.S +++ b/vm/mterp/out/InterpAsm-armv7-a.S @@ -7379,6 +7379,7 @@ dalvik_inst: ldr r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags tst r2, #CLASS_ISFINALIZABLE @ is this class finalizable? beq 1f @ nope, done + EXPORT_PC() @ can throw bl dvmSetFinalizable @ call dvmSetFinalizable(obj) 1: FETCH_ADVANCE_INST(2+1) @ advance to next instr, load rINST GET_INST_OPCODE(ip) @ ip<- opcode from rINST @@ -10434,6 +10435,7 @@ dalvik_inst: ldr r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags tst r2, #CLASS_ISFINALIZABLE @ is this class finalizable? beq 1f @ nope, done + EXPORT_PC() @ can throw bl dvmSetFinalizable @ call dvmSetFinalizable(obj) 1: FETCH_ADVANCE_INST(4+1) @ advance to next instr, load rINST GET_INST_OPCODE(ip) @ ip<- opcode from rINST diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c index 354cbd2b4..2768ba8f8 100644 --- a/vm/mterp/out/InterpC-allstubs.c +++ b/vm/mterp/out/InterpC-allstubs.c @@ -3064,6 +3064,7 @@ HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/) * (by virtue of being nothing but a return-void) and set it now. */ if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) { + EXPORT_PC(); dvmSetFinalizable(obj); } diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c index a77cf9eb0..348ca5d44 100644 --- a/vm/mterp/out/InterpC-portdbg.c +++ b/vm/mterp/out/InterpC-portdbg.c @@ -3427,6 +3427,7 @@ HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/) * (by virtue of being nothing but a return-void) and set it now. */ if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) { + EXPORT_PC(); dvmSetFinalizable(obj); } diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c index 33a7f31ae..5c3e5257f 100644 --- a/vm/mterp/out/InterpC-portstd.c +++ b/vm/mterp/out/InterpC-portstd.c @@ -3177,6 +3177,7 @@ HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/) * (by virtue of being nothing but a return-void) and set it now. */ if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) { + EXPORT_PC(); dvmSetFinalizable(obj); } diff --git a/vm/mterp/out/InterpC-x86-atom.c b/vm/mterp/out/InterpC-x86-atom.c index 7d9c1af10..77ee30f67 100644 --- a/vm/mterp/out/InterpC-x86-atom.c +++ b/vm/mterp/out/InterpC-x86-atom.c @@ -1423,6 +1423,7 @@ HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/) * (by virtue of being nothing but a return-void) and set it now. */ if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) { + EXPORT_PC(); dvmSetFinalizable(obj); } diff --git a/vm/mterp/out/InterpC-x86.c b/vm/mterp/out/InterpC-x86.c index 5152e85be..7ae06e366 100644 --- a/vm/mterp/out/InterpC-x86.c +++ b/vm/mterp/out/InterpC-x86.c @@ -1372,6 +1372,7 @@ HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/) * (by virtue of being nothing but a return-void) and set it now. */ if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) { + EXPORT_PC(); dvmSetFinalizable(obj); } diff --git a/vm/native/dalvik_system_VMRuntime.c b/vm/native/dalvik_system_VMRuntime.c index af0df7a9e..3642f9098 100644 --- a/vm/native/dalvik_system_VMRuntime.c +++ b/vm/native/dalvik_system_VMRuntime.c @@ -55,23 +55,6 @@ static void Dalvik_dalvik_system_VMRuntime_nativeSetTargetHeapUtilization( } /* - * public native void runFinalizationSync() - * - * Does not return until any pending finalizers have been called. - * This may or may not happen in the context of the calling thread. - * No exceptions will escape. - * - * Used by zygote, which doesn't have a HeapWorker thread. - */ -static void Dalvik_dalvik_system_VMRuntime_runFinalizationSync(const u4* args, - JValue* pResult) -{ - dvmRunFinalizationSync(); - - RETURN_VOID(); -} - -/* * public native void startJitCompilation() * * Callback function from the framework to indicate that an app has gone @@ -216,8 +199,6 @@ const DalvikNativeMethod dvm_dalvik_system_VMRuntime[] = { Dalvik_dalvik_system_VMRuntime_newNonMovableArray }, { "properties", "()[Ljava/lang/String;", Dalvik_dalvik_system_VMRuntime_properties }, - { "runFinalizationSync", "()V", - Dalvik_dalvik_system_VMRuntime_runFinalizationSync }, { "startJitCompilation", "()V", Dalvik_dalvik_system_VMRuntime_startJitCompilation }, { "vmVersion", "()Ljava/lang/String;", diff --git a/vm/native/dalvik_system_Zygote.c b/vm/native/dalvik_system_Zygote.c index 905eb9a51..6f7e6fa69 100644 --- a/vm/native/dalvik_system_Zygote.c +++ b/vm/native/dalvik_system_Zygote.c @@ -513,11 +513,11 @@ static void Dalvik_dalvik_system_Zygote_forkSystemServer( } const DalvikNativeMethod dvm_dalvik_system_Zygote[] = { - { "fork", "()I", - Dalvik_dalvik_system_Zygote_fork }, - { "forkAndSpecialize", "(II[II[[I)I", - Dalvik_dalvik_system_Zygote_forkAndSpecialize }, - { "forkSystemServer", "(II[II[[IJJ)I", - Dalvik_dalvik_system_Zygote_forkSystemServer }, + { "nativeFork", "()I", + Dalvik_dalvik_system_Zygote_fork }, + { "nativeForkAndSpecialize", "(II[II[[I)I", + Dalvik_dalvik_system_Zygote_forkAndSpecialize }, + { "nativeForkSystemServer", "(II[II[[IJJ)I", + Dalvik_dalvik_system_Zygote_forkSystemServer }, { NULL, NULL, NULL }, }; diff --git a/vm/native/java_lang_Runtime.c b/vm/native/java_lang_Runtime.c index b5c6a3362..112448c78 100644 --- a/vm/native/java_lang_Runtime.c +++ b/vm/native/java_lang_Runtime.c @@ -93,31 +93,6 @@ static void Dalvik_java_lang_Runtime_nativeLoad(const u4* args, } /* - * public void runFinalization(boolean forced) - * - * Requests that the VM runs finalizers for objects on the heap. If the - * parameter forced is true, then the VM needs to ensure finalization. - * Otherwise this only inspires the VM to make a best-effort attempt to - * run finalizers before returning, but it's not guaranteed to actually - * do anything. - */ -static void Dalvik_java_lang_Runtime_runFinalization(const u4* args, - JValue* pResult) -{ - bool forced = (args[0] != 0); - - dvmWaitForHeapWorkerIdle(); - if (forced) { - // TODO(Google) Need to explicitly implement this, - // although dvmWaitForHeapWorkerIdle() - // should usually provide the "forced" - // behavior already. - } - - RETURN_VOID(); -} - -/* * public long maxMemory() * * Returns GC heap max memory in bytes. @@ -166,8 +141,6 @@ const DalvikNativeMethod dvm_java_lang_Runtime[] = { Dalvik_java_lang_Runtime_nativeExit }, { "nativeLoad", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;", Dalvik_java_lang_Runtime_nativeLoad }, - { "runFinalization", "(Z)V", - Dalvik_java_lang_Runtime_runFinalization }, { "totalMemory", "()J", Dalvik_java_lang_Runtime_totalMemory }, { NULL, NULL, NULL }, diff --git a/vm/oo/Class.c b/vm/oo/Class.c index 54f63ee9f..a3f1d1c1d 100644 --- a/vm/oo/Class.c +++ b/vm/oo/Class.c @@ -2704,6 +2704,7 @@ bool dvmLinkClass(ClassObject* clazz) superRefFlags = GET_CLASS_FLAG_GROUP(clazz->super, CLASS_ISREFERENCE | CLASS_ISWEAKREFERENCE | + CLASS_ISFINALIZERREFERENCE | CLASS_ISPHANTOMREFERENCE); SET_CLASS_FLAG(clazz, superRefFlags); } else if (clazz->classLoader == NULL && @@ -2727,6 +2728,10 @@ bool dvmLinkClass(ClassObject* clazz) { refFlags |= CLASS_ISWEAKREFERENCE; } else if (strcmp(clazz->descriptor, + "Ljava/lang/ref/FinalizerReference;") == 0) + { + refFlags |= CLASS_ISFINALIZERREFERENCE; + } else if (strcmp(clazz->descriptor, "Ljava/lang/ref/PhantomReference;") == 0) { refFlags |= CLASS_ISPHANTOMREFERENCE; @@ -2744,6 +2749,7 @@ bool dvmLinkClass(ClassObject* clazz) assert(GET_CLASS_FLAG_GROUP(clazz, CLASS_ISREFERENCE | CLASS_ISWEAKREFERENCE | + CLASS_ISFINALIZERREFERENCE | CLASS_ISPHANTOMREFERENCE) == 0); SET_CLASS_FLAG(clazz, refFlags); diff --git a/vm/oo/Object.h b/vm/oo/Object.h index 7f2fbf662..b32d5b92e 100644 --- a/vm/oo/Object.h +++ b/vm/oo/Object.h @@ -80,12 +80,14 @@ typedef enum ClassFlags { CLASS_ISFINALIZABLE = (1<<31), // class/ancestor overrides finalize() CLASS_ISARRAY = (1<<30), // class is a "[*" CLASS_ISOBJECTARRAY = (1<<29), // class is a "[L*" or "[[*" + CLASS_ISREFERENCE = (1<<28), // class is a soft/weak/phantom ref // only ISREFERENCE is set --> soft CLASS_ISWEAKREFERENCE = (1<<27), // class is a weak reference - CLASS_ISPHANTOMREFERENCE = (1<<26), // class is a phantom reference + CLASS_ISFINALIZERREFERENCE = (1<<26), // class is a phantom reference + CLASS_ISPHANTOMREFERENCE = (1<<25), // class is a phantom reference - CLASS_MULTIPLE_DEFS = (1<<25), // DEX verifier: defs in multiple DEXs + CLASS_MULTIPLE_DEFS = (1<<24), // DEX verifier: defs in multiple DEXs /* unlike the others, these can be present in the optimized DEX file */ CLASS_ISOPTIMIZED = (1<<17), // class may contain opt instrs |
