2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "alloc/CardTable.h"
19 #include "alloc/HeapBitmap.h"
20 #include "alloc/HeapBitmapInlines.h"
21 #include "alloc/HeapInternal.h"
22 #include "alloc/HeapSource.h"
23 #include "alloc/MarkSweep.h"
24 #include "alloc/Visit.h"
25 #include "alloc/VisitInlines.h"
26 #include <limits.h> // for ULONG_MAX
27 #include <sys/mman.h> // for madvise(), mmap()
30 typedef unsigned long Word;
31 const size_t kWordSize = sizeof(Word);
34 * Returns true if the given object is marked.
36 static bool isMarked(const Object *obj, const GcMarkContext *ctx)
38 return dvmHeapBitmapIsObjectBitSet(ctx->bitmap, obj);
42 * Initializes the stack top and advises the mark stack pages as needed.
44 static bool createMarkStack(GcMarkStack *stack)
46 assert(stack != NULL);
47 size_t length = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
48 (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
49 madvise(stack->base, length, MADV_NORMAL);
50 stack->top = stack->base;
55 * Assigns NULL to the stack top and advises the mark stack pages as
58 static void destroyMarkStack(GcMarkStack *stack)
60 assert(stack != NULL);
61 madvise(stack->base, stack->length, MADV_DONTNEED);
66 * Pops an object from the mark stack.
68 static void markStackPush(GcMarkStack *stack, const Object *obj)
70 assert(stack != NULL);
71 assert(stack->base <= stack->top);
72 assert(stack->limit > stack->top);
79 * Pushes an object on the mark stack.
81 static const Object *markStackPop(GcMarkStack *stack)
83 assert(stack != NULL);
84 assert(stack->base < stack->top);
85 assert(stack->limit > stack->top);
90 bool dvmHeapBeginMarkStep(bool isPartial)
92 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
94 if (!createMarkStack(&ctx->stack)) {
98 ctx->immuneLimit = (char*)dvmHeapSourceGetImmuneLimit(isPartial);
102 static long setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
104 return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
107 static void markObjectNonNull(const Object *obj, GcMarkContext *ctx,
112 assert(dvmIsValidObject(obj));
113 if (obj < (Object *)ctx->immuneLimit) {
114 assert(isMarked(obj, ctx));
117 if (!setAndReturnMarkBit(ctx, obj)) {
118 /* This object was not previously marked.
120 if (checkFinger && (void *)obj < ctx->finger) {
121 /* This object will need to go on the mark stack.
123 markStackPush(&ctx->stack, obj);
128 /* Used to mark objects when recursing. Recursion is done by moving
129 * the finger across the bitmaps in address order and marking child
130 * objects. Any newly-marked objects whose addresses are lower than
131 * the finger won't be visited by the bitmap scan, so those objects
132 * need to be added to the mark stack.
134 static void markObject(const Object *obj, GcMarkContext *ctx)
137 markObjectNonNull(obj, ctx, true);
142 * Callback applied to root references during the initial root
143 * marking. Marks white objects but does not push them on the mark
146 static void rootMarkObjectVisitor(void *addr, u4 thread, RootType type,
149 assert(addr != NULL);
151 Object *obj = *(Object **)addr;
152 GcMarkContext *ctx = (GcMarkContext *)arg;
154 markObjectNonNull(obj, ctx, false);
159 * Visits all objects that start on the given card.
161 static void visitCard(Visitor *visitor, u1 *card, void *arg)
163 assert(visitor != NULL);
164 assert(card != NULL);
165 assert(dvmIsValidCard(card));
166 u1 *addr= (u1*)dvmAddrFromCard(card);
167 u1 *limit = addr + GC_CARD_SIZE;
168 for (; addr < limit; addr += HB_OBJECT_ALIGNMENT) {
169 Object *obj = (Object *)addr;
170 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
171 if (isMarked(obj, ctx)) {
172 (*visitor)(obj, arg);
178 * Visits objects on dirty cards marked the mod union table.
180 static void visitModUnionTable(Visitor *visitor, u1 *base, u1 *limit, void *arg)
182 assert(visitor != NULL);
183 assert(base != NULL);
184 assert(limit != NULL);
185 assert(base <= limit);
186 u1 *heapBase = (u1*)dvmHeapSourceGetBase();
187 /* compute the start address in the bit table */
188 assert(base >= heapBase);
189 u4 *bits = (u4*)gDvm.gcHeap->modUnionTableBase;
190 /* compute the end address in the bit table */
191 size_t byteLength = (limit - base) / GC_CARD_SIZE / CHAR_BIT;
192 assert(byteLength <= gDvm.gcHeap->modUnionTableLength);
193 assert(byteLength % sizeof(*bits) == 0);
194 size_t wordLength = byteLength / sizeof(*bits);
195 for (size_t i = 0; i < wordLength; ++i) {
201 for (size_t j = 0; j < sizeof(u4)*CHAR_BIT; ++j) {
202 if (word & (1 << j)) {
203 /* compute the base of the card */
204 size_t offset = (i*sizeof(u4)*CHAR_BIT + j) * GC_CARD_SIZE;
205 u1* addr = heapBase + offset;
206 u1* card = dvmCardFromAddr(addr);
207 /* visit all objects on the card */
208 visitCard(visitor, card, arg);
215 * Visits objects on dirty cards marked in the card table.
217 static void visitCardTable(Visitor *visitor, u1 *base, u1 *limit, void *arg)
219 assert(visitor != NULL);
220 assert(base != NULL);
221 assert(limit != NULL);
222 u1 *start = dvmCardFromAddr(base);
223 u1 *end = dvmCardFromAddr(limit);
224 while (start < end) {
225 u1 *dirty = (u1 *)memchr(start, GC_CARD_DIRTY, end - start);
229 assert(dirty >= start);
230 assert(dirty <= end);
231 assert(dvmIsValidCard(dirty));
232 visitCard(visitor, dirty, arg);
238 Object *threatenBoundary;
240 } ScanImmuneObjectContext;
243 * Marks the referent of an immune object it is threatened.
245 static void scanImmuneObjectReferent(void *addr, void *arg)
247 assert(addr != NULL);
249 Object *obj = *(Object **)addr;
250 ScanImmuneObjectContext *ctx = (ScanImmuneObjectContext *)arg;
254 if (obj >= ctx->threatenBoundary) {
255 /* TODO: set a bit in the mod union table instead. */
256 dvmMarkCard(ctx->currObject);
257 markObjectNonNull(obj, &gDvm.gcHeap->markContext, false);
262 * This function is poorly named, as is its callee.
264 static void scanImmuneObject(void *addr, void *arg)
266 ScanImmuneObjectContext *ctx = (ScanImmuneObjectContext *)arg;
267 Object *obj = (Object *)addr;
268 ctx->currObject = obj;
269 visitObject(scanImmuneObjectReferent, obj, arg);
273 * Verifies that immune objects have their referents marked.
275 static void verifyImmuneObjectsVisitor(void *addr, void *arg)
277 assert(addr != NULL);
279 Object *obj = *(Object **)addr;
280 GcMarkContext *ctx = (GcMarkContext *)arg;
281 if (obj == NULL || obj < (Object *)ctx->immuneLimit) {
284 assert(dvmIsValidObject(obj));
285 if (!isMarked(obj, ctx)) {
286 LOGE("Immune reference %p points to a white threatened object %p",
293 * Visitor that searches for immune objects and verifies that all
294 * threatened referents are marked.
296 static void verifyImmuneObjectsCallback(void *addr, void *arg)
298 assert(addr != NULL);
300 Object *obj = (Object *)addr;
301 GcMarkContext *ctx = (GcMarkContext *)arg;
302 if (obj->clazz == NULL) {
303 LOGI("uninitialized object @ %p (has null clazz pointer)", obj);
306 if (obj < (Object *)ctx->immuneLimit) {
307 visitObject(verifyImmuneObjectsVisitor, obj, ctx);
312 * Verify that immune objects refer to marked objects.
314 static void verifyImmuneObjects()
316 const HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
317 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
318 dvmHeapBitmapWalk(bitmap, verifyImmuneObjectsCallback, ctx);
321 /* Mark the set of root objects.
323 * Things we need to scan:
324 * - System classes defined by root classloader
326 * - Interpreted stack, from top to "curFrame"
327 * - Dalvik registers (args + local vars)
328 * - JNI local references
329 * - Automatic VM local references (TrackedAlloc)
330 * - Associated Thread/VMThread object
331 * - ThreadGroups (could track & start with these instead of working
332 * upward from Threads)
333 * - Exception currently being thrown, if present
334 * - JNI global references
335 * - Interned string table
336 * - Primitive classes
338 * - gDvm.outOfMemoryObj
339 * - Objects in debugger object registry
342 * - Native stack (for in-progress stuff in the VM)
343 * - The TrackedAlloc stuff watches all native VM references.
347 * Blackens the root set.
349 void dvmHeapMarkRootSet()
351 GcHeap *gcHeap = gDvm.gcHeap;
352 dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
353 dvmVisitRoots(rootMarkObjectVisitor, &gcHeap->markContext);
357 * Callback applied to root references during root remarking. Marks
358 * white objects and pushes them on the mark stack.
360 static void rootReMarkObjectVisitor(void *addr, u4 thread, RootType type,
363 assert(addr != NULL);
365 Object *obj = *(Object **)addr;
366 GcMarkContext *ctx = (GcMarkContext *)arg;
368 markObjectNonNull(obj, ctx, true);
373 * Grays all references in the roots.
375 void dvmHeapReMarkRootSet(void)
377 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
378 assert(ctx->finger == (void *)ULONG_MAX);
379 dvmVisitRoots(rootReMarkObjectVisitor, ctx);
383 * Scans instance fields.
385 static void scanFields(const Object *obj, GcMarkContext *ctx)
388 assert(obj->clazz != NULL);
390 if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
391 unsigned int refOffsets = obj->clazz->refOffsets;
392 while (refOffsets != 0) {
393 size_t rshift = CLZ(refOffsets);
394 size_t offset = CLASS_OFFSET_FROM_CLZ(rshift);
395 Object *ref = dvmGetFieldObject((Object*)obj, offset);
396 markObject(ref, ctx);
397 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
400 for (ClassObject *clazz = obj->clazz;
402 clazz = clazz->super) {
403 InstField *field = clazz->ifields;
404 for (int i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
405 void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
406 Object *ref = (Object *)((JValue *)addr)->l;
407 markObject(ref, ctx);
414 * Scans the static fields of a class object.
416 static void scanStaticFields(const ClassObject *clazz, GcMarkContext *ctx)
418 assert(clazz != NULL);
420 for (int i = 0; i < clazz->sfieldCount; ++i) {
421 char ch = clazz->sfields[i].field.signature[0];
422 if (ch == '[' || ch == 'L') {
423 Object *obj = (Object *)clazz->sfields[i].value.l;
424 markObject(obj, ctx);
430 * Visit the interfaces of a class object.
432 static void scanInterfaces(const ClassObject *clazz, GcMarkContext *ctx)
434 assert(clazz != NULL);
436 for (int i = 0; i < clazz->interfaceCount; ++i) {
437 markObject((const Object *)clazz->interfaces[i], ctx);
442 * Scans the header, static field references, and interface
443 * pointers of a class object.
445 static void scanClassObject(const Object *obj, GcMarkContext *ctx)
448 assert(obj->clazz == gDvm.classJavaLangClass);
450 markObject((const Object *)obj->clazz, ctx);
451 const ClassObject *asClass = (const ClassObject *)obj;
452 if (IS_CLASS_FLAG_SET(asClass, CLASS_ISARRAY)) {
453 markObject((const Object *)asClass->elementClass, ctx);
455 /* Do super and the interfaces contain Objects and not dex idx values? */
456 if (asClass->status > CLASS_IDX) {
457 markObject((const Object *)asClass->super, ctx);
459 markObject((const Object *)asClass->classLoader, ctx);
460 scanFields(obj, ctx);
461 scanStaticFields(asClass, ctx);
462 if (asClass->status > CLASS_IDX) {
463 scanInterfaces(asClass, ctx);
468 * Scans the header of all array objects. If the array object is
469 * specialized to a reference type, scans the array data as well.
471 static void scanArrayObject(const Object *obj, GcMarkContext *ctx)
474 assert(obj->clazz != NULL);
476 markObject((const Object *)obj->clazz, ctx);
477 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISOBJECTARRAY)) {
478 const ArrayObject *array = (const ArrayObject *)obj;
479 const Object **contents = (const Object **)(void *)array->contents;
480 for (size_t i = 0; i < array->length; ++i) {
481 markObject(contents[i], ctx);
487 * Returns class flags relating to Reference subclasses.
489 static int referenceClassFlags(const Object *obj)
491 int flags = CLASS_ISREFERENCE |
492 CLASS_ISWEAKREFERENCE |
493 CLASS_ISFINALIZERREFERENCE |
494 CLASS_ISPHANTOMREFERENCE;
495 return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
499 * Returns true if the object derives from SoftReference.
501 static bool isSoftReference(const Object *obj)
503 return referenceClassFlags(obj) == CLASS_ISREFERENCE;
507 * Returns true if the object derives from WeakReference.
509 static bool isWeakReference(const Object *obj)
511 return referenceClassFlags(obj) & CLASS_ISWEAKREFERENCE;
515 * Returns true if the object derives from FinalizerReference.
517 static bool isFinalizerReference(const Object *obj)
519 return referenceClassFlags(obj) & CLASS_ISFINALIZERREFERENCE;
523 * Returns true if the object derives from PhantomReference.
525 static bool isPhantomReference(const Object *obj)
527 return referenceClassFlags(obj) & CLASS_ISPHANTOMREFERENCE;
531 * Adds a reference to the tail of a circular queue of references.
533 static void enqueuePendingReference(Object *ref, Object **list)
536 assert(list != NULL);
537 size_t offset = gDvm.offJavaLangRefReference_pendingNext;
539 dvmSetFieldObject(ref, offset, ref);
542 Object *head = dvmGetFieldObject(*list, offset);
543 dvmSetFieldObject(ref, offset, head);
544 dvmSetFieldObject(*list, offset, ref);
549 * Removes the reference at the head of a circular queue of
552 static Object *dequeuePendingReference(Object **list)
554 assert(list != NULL);
555 assert(*list != NULL);
556 size_t offset = gDvm.offJavaLangRefReference_pendingNext;
557 Object *head = dvmGetFieldObject(*list, offset);
563 Object *next = dvmGetFieldObject(head, offset);
564 dvmSetFieldObject(*list, offset, next);
567 dvmSetFieldObject(ref, offset, NULL);
572 * Process the "referent" field in a java.lang.ref.Reference. If the
573 * referent has not yet been marked, put it on the appropriate list in
574 * the gcHeap for later processing.
576 static void delayReferenceReferent(Object *obj, GcMarkContext *ctx)
579 assert(obj->clazz != NULL);
580 assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
582 GcHeap *gcHeap = gDvm.gcHeap;
583 size_t pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
584 size_t referentOffset = gDvm.offJavaLangRefReference_referent;
585 Object *pending = dvmGetFieldObject(obj, pendingNextOffset);
586 Object *referent = dvmGetFieldObject(obj, referentOffset);
587 if (pending == NULL && referent != NULL && !isMarked(referent, ctx)) {
588 Object **list = NULL;
589 if (isSoftReference(obj)) {
590 list = &gcHeap->softReferences;
591 } else if (isWeakReference(obj)) {
592 list = &gcHeap->weakReferences;
593 } else if (isFinalizerReference(obj)) {
594 list = &gcHeap->finalizerReferences;
595 } else if (isPhantomReference(obj)) {
596 list = &gcHeap->phantomReferences;
598 assert(list != NULL);
599 enqueuePendingReference(obj, list);
604 * Scans the header and field references of a data object.
606 static void scanDataObject(const Object *obj, GcMarkContext *ctx)
609 assert(obj->clazz != NULL);
611 markObject((const Object *)obj->clazz, ctx);
612 scanFields(obj, ctx);
613 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE)) {
614 delayReferenceReferent((Object *)obj, ctx);
619 * Scans an object reference. Determines the type of the reference
620 * and dispatches to a specialized scanning routine.
622 static void scanObject(const Object *obj, GcMarkContext *ctx)
625 assert(obj->clazz != NULL);
627 assert(isMarked(obj, ctx));
628 if (obj->clazz == gDvm.classJavaLangClass) {
629 scanClassObject(obj, ctx);
630 } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
631 scanArrayObject(obj, ctx);
633 scanDataObject(obj, ctx);
638 * Scan anything that's on the mark stack. We can't use the bitmaps
639 * anymore, so use a finger that points past the end of them.
641 static void processMarkStack(GcMarkContext *ctx)
644 assert(ctx->finger == (void *)ULONG_MAX);
645 assert(ctx->stack.top >= ctx->stack.base);
646 GcMarkStack *stack = &ctx->stack;
647 while (stack->top > stack->base) {
648 const Object *obj = markStackPop(stack);
649 scanObject(obj, ctx);
654 * Blackens gray objects found on dirty cards.
656 static void scanGrayObjects(GcMarkContext *ctx)
659 assert(ctx->bitmap != NULL);
660 HeapBitmap *bitmap = ctx->bitmap;
661 u1 *base = (u1 *)bitmap->base;
662 u1 *limit = (u1 *)ALIGN_UP(bitmap->max, GC_CARD_SIZE);
663 visitCardTable((Visitor *)scanObject, base, limit, ctx);
667 * Iterate through the immune objects and mark their referents. Uses
668 * the mod union table to save scanning time.
670 void dvmHeapScanImmuneObjects(const GcMarkContext *ctx)
673 ScanImmuneObjectContext scanCtx;
674 memset(&scanCtx, 0, sizeof(scanCtx));
675 scanCtx.threatenBoundary = (Object*)ctx->immuneLimit;
676 visitModUnionTable(scanImmuneObject,
677 (u1*)ctx->bitmap->base, (u1*)ctx->immuneLimit,
679 if (gDvm.verifyCardTable) {
680 verifyImmuneObjects();
685 * Callback for scanning each object in the bitmap. The finger is set
686 * to the address corresponding to the lowest address in the next word
687 * of bits in the bitmap.
689 static void scanBitmapCallback(void *addr, void *finger, void *arg)
691 GcMarkContext *ctx = (GcMarkContext *)arg;
692 ctx->finger = (void *)finger;
693 scanObject((Object *)addr, ctx);
696 /* Given bitmaps with the root set marked, find and mark all
697 * reachable objects. When this returns, the entire set of
698 * live objects will be marked and the mark stack will be empty.
700 void dvmHeapScanMarkedObjects(bool isPartial)
702 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
705 assert(ctx->finger == NULL);
708 if (isPartial && dvmHeapSourceGetNumHeaps() > 1) {
709 dvmHeapScanImmuneObjects(ctx);
710 start = (u1 *)ctx->immuneLimit;
712 start = (u1*)ctx->bitmap->base;
715 * All objects reachable from the root set have a bit set in the
716 * mark bitmap. Walk the mark bitmap and blacken these objects.
718 dvmHeapBitmapScanWalk(ctx->bitmap,
719 (uintptr_t)start, ctx->bitmap->max,
723 ctx->finger = (void *)ULONG_MAX;
725 /* Process gray objects until the mark stack it is empty. */
726 processMarkStack(ctx);
729 void dvmHeapReScanMarkedObjects(void)
731 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
734 * The finger must have been set to the maximum value to ensure
735 * that gray objects will be pushed onto the mark stack.
737 assert(ctx->finger == (void *)ULONG_MAX);
738 scanGrayObjects(ctx);
739 processMarkStack(ctx);
743 * Clear the referent field.
745 static void clearReference(Object *reference)
747 size_t offset = gDvm.offJavaLangRefReference_referent;
748 dvmSetFieldObject(reference, offset, NULL);
752 * Returns true if the reference was registered with a reference queue
753 * and has not yet been enqueued.
755 static bool isEnqueuable(const Object *reference)
757 assert(reference != NULL);
758 Object *queue = dvmGetFieldObject(reference,
759 gDvm.offJavaLangRefReference_queue);
760 Object *queueNext = dvmGetFieldObject(reference,
761 gDvm.offJavaLangRefReference_queueNext);
762 return queue != NULL && queueNext == NULL;
766 * Schedules a reference to be appended to its reference queue.
768 static void enqueueReference(Object *ref)
771 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
772 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
773 enqueuePendingReference(ref, &gDvm.gcHeap->clearedReferences);
777 * Walks the reference list marking any references subject to the
778 * reference clearing policy. References with a black referent are
779 * removed from the list. References with white referents biased
780 * toward saving are blackened and also removed from the list.
782 static void preserveSomeSoftReferences(Object **list)
784 assert(list != NULL);
785 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
786 size_t referentOffset = gDvm.offJavaLangRefReference_referent;
787 Object *clear = NULL;
789 while (*list != NULL) {
790 Object *ref = dequeuePendingReference(list);
791 Object *referent = dvmGetFieldObject(ref, referentOffset);
792 if (referent == NULL) {
793 /* Referent was cleared by the user during marking. */
796 bool marked = isMarked(referent, ctx);
797 if (!marked && ((++counter) & 1)) {
798 /* Referent is white and biased toward saving, mark it. */
799 markObject(referent, ctx);
803 /* Referent is white, queue it for clearing. */
804 enqueuePendingReference(ref, &clear);
809 * Restart the mark with the newly black references added to the
812 processMarkStack(ctx);
816 * Unlink the reference list clearing references objects with white
817 * referents. Cleared references registered to a reference queue are
818 * scheduled for appending by the heap worker thread.
820 static void clearWhiteReferences(Object **list)
822 assert(list != NULL);
823 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
824 size_t referentOffset = gDvm.offJavaLangRefReference_referent;
825 while (*list != NULL) {
826 Object *ref = dequeuePendingReference(list);
827 Object *referent = dvmGetFieldObject(ref, referentOffset);
828 if (referent != NULL && !isMarked(referent, ctx)) {
829 /* Referent is white, clear it. */
831 if (isEnqueuable(ref)) {
832 enqueueReference(ref);
836 assert(*list == NULL);
840 * Enqueues finalizer references with white referents. White
841 * referents are blackened, moved to the zombie field, and the
842 * referent field is cleared.
844 static void enqueueFinalizerReferences(Object **list)
846 assert(list != NULL);
847 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
848 size_t referentOffset = gDvm.offJavaLangRefReference_referent;
849 size_t zombieOffset = gDvm.offJavaLangRefFinalizerReference_zombie;
850 bool hasEnqueued = false;
851 while (*list != NULL) {
852 Object *ref = dequeuePendingReference(list);
853 Object *referent = dvmGetFieldObject(ref, referentOffset);
854 if (referent != NULL && !isMarked(referent, ctx)) {
855 markObject(referent, ctx);
856 /* If the referent is non-null the reference must queuable. */
857 assert(isEnqueuable(ref));
858 dvmSetFieldObject(ref, zombieOffset, referent);
860 enqueueReference(ref);
865 processMarkStack(ctx);
867 assert(*list == NULL);
871 * This object is an instance of a class that overrides finalize(). Mark
874 * This is called when Object.<init> completes normally. It's also
875 * called for clones of finalizable objects.
877 void dvmSetFinalizable(Object *obj)
880 Thread *self = dvmThreadSelf();
881 assert(self != NULL);
882 Method *meth = gDvm.methJavaLangRefFinalizerReferenceAdd;
883 assert(meth != NULL);
885 dvmCallMethod(self, meth, NULL, &unusedResult, obj);
889 * Process reference class instances and schedule finalizations.
891 void dvmHeapProcessReferences(Object **softReferences, bool clearSoftRefs,
892 Object **weakReferences,
893 Object **finalizerReferences,
894 Object **phantomReferences)
896 assert(softReferences != NULL);
897 assert(weakReferences != NULL);
898 assert(finalizerReferences != NULL);
899 assert(phantomReferences != NULL);
901 * Unless we are in the zygote or required to clear soft
902 * references with white references, preserve some white
905 if (!gDvm.zygote && !clearSoftRefs) {
906 preserveSomeSoftReferences(softReferences);
909 * Clear all remaining soft and weak references with white
912 clearWhiteReferences(softReferences);
913 clearWhiteReferences(weakReferences);
915 * Preserve all white objects with finalize methods and schedule
916 * them for finalization.
918 enqueueFinalizerReferences(finalizerReferences);
920 * Clear all f-reachable soft and weak references with white
923 clearWhiteReferences(softReferences);
924 clearWhiteReferences(weakReferences);
926 * Clear all phantom references with white referents.
928 clearWhiteReferences(phantomReferences);
930 * At this point all reference lists should be empty.
932 assert(*softReferences == NULL);
933 assert(*weakReferences == NULL);
934 assert(*finalizerReferences == NULL);
935 assert(*phantomReferences == NULL);
939 * Pushes a list of cleared references out to the managed heap.
941 void dvmEnqueueClearedReferences(Object **cleared)
943 assert(cleared != NULL);
944 if (*cleared != NULL) {
945 Thread *self = dvmThreadSelf();
946 assert(self != NULL);
947 Method *meth = gDvm.methJavaLangRefReferenceQueueAdd;
948 assert(meth != NULL);
950 Object *reference = *cleared;
951 dvmCallMethod(self, meth, NULL, &unused, reference);
956 void dvmHeapFinishMarkStep()
958 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
960 /* The mark bits are now not needed.
962 dvmHeapSourceZeroMarkBitmap();
964 /* Clean up everything else associated with the marking process.
966 destroyMarkStack(&ctx->stack);
977 static void sweepBitmapCallback(size_t numPtrs, void **ptrs, void *arg)
980 SweepContext *ctx = (SweepContext *)arg;
981 if (ctx->isConcurrent) {
984 ctx->numBytes += dvmHeapSourceFreeList(numPtrs, ptrs);
985 ctx->numObjects += numPtrs;
986 if (ctx->isConcurrent) {
992 * Returns true if the given object is unmarked. This assumes that
993 * the bitmaps have not yet been swapped.
995 static int isUnmarkedObject(void *obj)
997 return !isMarked((Object *)obj, &gDvm.gcHeap->markContext);
1000 void sweepWeakJniGlobals(void)
1002 IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
1003 Object **entry = table->table;
1004 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
1005 int numEntries = dvmIndirectRefTableEntries(table);
1006 for (int i = 0; i < numEntries; ++i) {
1007 if (entry[i] != NULL && !isMarked(entry[i], ctx)) {
1014 * Process all the internal system structures that behave like
1015 * weakly-held objects.
1017 void dvmHeapSweepSystemWeaks(void)
1019 dvmGcDetachDeadInternedStrings(isUnmarkedObject);
1020 dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
1021 sweepWeakJniGlobals();
1025 * Walk through the list of objects that haven't been marked and free
1026 * them. Assumes the bitmaps have been swapped.
1028 void dvmHeapSweepUnmarkedObjects(bool isPartial, bool isConcurrent,
1029 size_t *numObjects, size_t *numBytes)
1031 uintptr_t base[HEAP_SOURCE_MAX_HEAP_COUNT];
1032 uintptr_t max[HEAP_SOURCE_MAX_HEAP_COUNT];
1034 HeapBitmap *prevLive, *prevMark;
1035 size_t numHeaps, numSweepHeaps;
1037 numHeaps = dvmHeapSourceGetNumHeaps();
1038 dvmHeapSourceGetRegions(base, max, NULL, numHeaps);
1040 assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == base[0]);
1043 numSweepHeaps = numHeaps;
1045 ctx.numObjects = ctx.numBytes = 0;
1046 ctx.isConcurrent = isConcurrent;
1047 prevLive = dvmHeapSourceGetMarkBits();
1048 prevMark = dvmHeapSourceGetLiveBits();
1049 for (size_t i = 0; i < numSweepHeaps; ++i) {
1050 dvmHeapBitmapSweepWalk(prevLive, prevMark, base[i], max[i],
1051 sweepBitmapCallback, &ctx);
1053 *numObjects = ctx.numObjects;
1054 *numBytes = ctx.numBytes;
1055 if (gDvm.allocProf.enabled) {
1056 gDvm.allocProf.freeCount += ctx.numObjects;
1057 gDvm.allocProf.freeSize += ctx.numBytes;