MarkSweep.cpp revision 259a8a5154c63a793ea0ee438d146acda7d990b6
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
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
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17#include "Dalvik.h"
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()
28#include <errno.h>
29
30typedef unsigned long Word;
31const size_t kWordSize = sizeof(Word);
32
33/*
34 * Returns true if the given object is marked.
35 */
36static bool isMarked(const Object *obj, const GcMarkContext *ctx)
37{
38    return dvmHeapBitmapIsObjectBitSet(ctx->bitmap, obj);
39}
40
41/*
42 * Initializes the stack top and advises the mark stack pages as needed.
43 */
44static bool createMarkStack(GcMarkStack *stack)
45{
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;
51    return true;
52}
53
54/*
55 * Assigns NULL to the stack top and advises the mark stack pages as
56 * not needed.
57 */
58static void destroyMarkStack(GcMarkStack *stack)
59{
60    assert(stack != NULL);
61    madvise(stack->base, stack->length, MADV_DONTNEED);
62    stack->top = NULL;
63}
64
65/*
66 * Pops an object from the mark stack.
67 */
68static void markStackPush(GcMarkStack *stack, const Object *obj)
69{
70    assert(stack != NULL);
71    assert(stack->base <= stack->top);
72    assert(stack->limit > stack->top);
73    assert(obj != NULL);
74    *stack->top = obj;
75    ++stack->top;
76}
77
78/*
79 * Pushes an object on the mark stack.
80 */
81static const Object *markStackPop(GcMarkStack *stack)
82{
83    assert(stack != NULL);
84    assert(stack->base < stack->top);
85    assert(stack->limit > stack->top);
86    --stack->top;
87    return *stack->top;
88}
89
90bool dvmHeapBeginMarkStep(bool isPartial)
91{
92    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
93
94    if (!createMarkStack(&ctx->stack)) {
95        return false;
96    }
97    ctx->finger = NULL;
98    ctx->immuneLimit = (char*)dvmHeapSourceGetImmuneLimit(isPartial);
99    return true;
100}
101
102static long setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
103{
104    return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
105}
106
107static void markObjectNonNull(const Object *obj, GcMarkContext *ctx,
108                              bool checkFinger)
109{
110    assert(ctx != NULL);
111    assert(obj != NULL);
112    assert(dvmIsValidObject(obj));
113    if (obj < (Object *)ctx->immuneLimit) {
114        assert(isMarked(obj, ctx));
115        return;
116    }
117    if (!setAndReturnMarkBit(ctx, obj)) {
118        /* This object was not previously marked.
119         */
120        if (checkFinger && (void *)obj < ctx->finger) {
121            /* This object will need to go on the mark stack.
122             */
123            markStackPush(&ctx->stack, obj);
124        }
125    }
126}
127
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.
133 */
134static void markObject(const Object *obj, GcMarkContext *ctx)
135{
136    if (obj != NULL) {
137        markObjectNonNull(obj, ctx, true);
138    }
139}
140
141/*
142 * Callback applied to root references during the initial root
143 * marking.  Marks white objects but does not push them on the mark
144 * stack.
145 */
146static void rootMarkObjectVisitor(void *addr, u4 thread, RootType type,
147                                  void *arg)
148{
149    assert(addr != NULL);
150    assert(arg != NULL);
151    Object *obj = *(Object **)addr;
152    GcMarkContext *ctx = (GcMarkContext *)arg;
153    if (obj != NULL) {
154        markObjectNonNull(obj, ctx, false);
155    }
156}
157
158/*
159 * Visits all objects that start on the given card.
160 */
161static void visitCard(Visitor *visitor, u1 *card, void *arg)
162{
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);
173        }
174    }
175}
176
177/*
178 * Visits objects on dirty cards marked the mod union table.
179 */
180static void visitModUnionTable(Visitor *visitor, u1 *base, u1 *limit, void *arg)
181{
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) {
196        if (bits[i] == 0) {
197            continue;
198        }
199        u4 word = bits[i];
200        bits[i] = 0;
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);
209            }
210        }
211    }
212}
213
214/*
215 * Visits objects on dirty cards marked in the card table.
216 */
217static void visitCardTable(Visitor *visitor, u1 *base, u1 *limit, void *arg)
218{
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);
226        if (dirty == NULL) {
227            break;
228        }
229        assert(dirty >= start);
230        assert(dirty <= end);
231        assert(dvmIsValidCard(dirty));
232        visitCard(visitor, dirty, arg);
233        start = dirty + 1;
234    }
235}
236
237struct ScanImmuneObjectContext {
238    Object *threatenBoundary;
239    Object *currObject;
240};
241
242/*
243 * Marks the referent of an immune object it is threatened.
244 */
245static void scanImmuneObjectReferent(void *addr, void *arg)
246{
247    assert(addr != NULL);
248    assert(arg != NULL);
249    Object *obj = *(Object **)addr;
250    ScanImmuneObjectContext *ctx = (ScanImmuneObjectContext *)arg;
251    if (obj == NULL) {
252        return;
253    }
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);
258   }
259}
260
261/*
262 * This function is poorly named, as is its callee.
263 */
264static void scanImmuneObject(void *addr, void *arg)
265{
266    ScanImmuneObjectContext *ctx = (ScanImmuneObjectContext *)arg;
267    Object *obj = (Object *)addr;
268    ctx->currObject = obj;
269    visitObject(scanImmuneObjectReferent, obj, arg);
270}
271
272/*
273 * Verifies that immune objects have their referents marked.
274 */
275static void verifyImmuneObjectsVisitor(void *addr, void *arg)
276{
277    assert(addr != NULL);
278    assert(arg != NULL);
279    Object *obj = *(Object **)addr;
280    GcMarkContext *ctx = (GcMarkContext *)arg;
281    if (obj == NULL || obj < (Object *)ctx->immuneLimit) {
282        return;
283    }
284    assert(dvmIsValidObject(obj));
285    if (!isMarked(obj, ctx)) {
286        LOGE("Immune reference %p points to a white threatened object %p",
287             addr, obj);
288        dvmAbort();
289    }
290}
291
292/*
293 * Visitor that searches for immune objects and verifies that all
294 * threatened referents are marked.
295 */
296static void verifyImmuneObjectsCallback(Object *obj, void *arg)
297{
298    assert(obj != NULL);
299    assert(arg != NULL);
300    GcMarkContext *ctx = (GcMarkContext *)arg;
301    if (obj->clazz == NULL) {
302        LOGI("uninitialized object @ %p (has null clazz pointer)", obj);
303        return;
304    }
305    if (obj < (Object *)ctx->immuneLimit) {
306        visitObject(verifyImmuneObjectsVisitor, obj, ctx);
307    }
308}
309
310/*
311 * Verify that immune objects refer to marked objects.
312 */
313static void verifyImmuneObjects()
314{
315    const HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
316    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
317    dvmHeapBitmapWalk(bitmap, verifyImmuneObjectsCallback, ctx);
318}
319
320/* Mark the set of root objects.
321 *
322 * Things we need to scan:
323 * - System classes defined by root classloader
324 * - For each thread:
325 *   - Interpreted stack, from top to "curFrame"
326 *     - Dalvik registers (args + local vars)
327 *   - JNI local references
328 *   - Automatic VM local references (TrackedAlloc)
329 *   - Associated Thread/VMThread object
330 *   - ThreadGroups (could track & start with these instead of working
331 *     upward from Threads)
332 *   - Exception currently being thrown, if present
333 * - JNI global references
334 * - Interned string table
335 * - Primitive classes
336 * - Special objects
337 *   - gDvm.outOfMemoryObj
338 * - Objects in debugger object registry
339 *
340 * Don't need:
341 * - Native stack (for in-progress stuff in the VM)
342 *   - The TrackedAlloc stuff watches all native VM references.
343 */
344
345/*
346 * Blackens the root set.
347 */
348void dvmHeapMarkRootSet()
349{
350    GcHeap *gcHeap = gDvm.gcHeap;
351    dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
352    dvmVisitRoots(rootMarkObjectVisitor, &gcHeap->markContext);
353}
354
355/*
356 * Callback applied to root references during root remarking.  Marks
357 * white objects and pushes them on the mark stack.
358 */
359static void rootReMarkObjectVisitor(void *addr, u4 thread, RootType type,
360                                    void *arg)
361{
362    assert(addr != NULL);
363    assert(arg != NULL);
364    Object *obj = *(Object **)addr;
365    GcMarkContext *ctx = (GcMarkContext *)arg;
366    if (obj != NULL) {
367        markObjectNonNull(obj, ctx, true);
368    }
369}
370
371/*
372 * Grays all references in the roots.
373 */
374void dvmHeapReMarkRootSet()
375{
376    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
377    assert(ctx->finger == (void *)ULONG_MAX);
378    dvmVisitRoots(rootReMarkObjectVisitor, ctx);
379}
380
381/*
382 * Scans instance fields.
383 */
384static void scanFields(const Object *obj, GcMarkContext *ctx)
385{
386    assert(obj != NULL);
387    assert(obj->clazz != NULL);
388    assert(ctx != NULL);
389    if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
390        unsigned int refOffsets = obj->clazz->refOffsets;
391        while (refOffsets != 0) {
392            size_t rshift = CLZ(refOffsets);
393            size_t offset = CLASS_OFFSET_FROM_CLZ(rshift);
394            Object *ref = dvmGetFieldObject(obj, offset);
395            markObject(ref, ctx);
396            refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
397        }
398    } else {
399        for (ClassObject *clazz = obj->clazz;
400             clazz != NULL;
401             clazz = clazz->super) {
402            InstField *field = clazz->ifields;
403            for (int i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
404                void *addr = BYTE_OFFSET(obj, field->byteOffset);
405                Object *ref = ((JValue *)addr)->l;
406                markObject(ref, ctx);
407            }
408        }
409    }
410}
411
412/*
413 * Scans the static fields of a class object.
414 */
415static void scanStaticFields(const ClassObject *clazz, GcMarkContext *ctx)
416{
417    assert(clazz != NULL);
418    assert(ctx != NULL);
419    for (int i = 0; i < clazz->sfieldCount; ++i) {
420        char ch = clazz->sfields[i].signature[0];
421        if (ch == '[' || ch == 'L') {
422            Object *obj = clazz->sfields[i].value.l;
423            markObject(obj, ctx);
424        }
425    }
426}
427
428/*
429 * Visit the interfaces of a class object.
430 */
431static void scanInterfaces(const ClassObject *clazz, GcMarkContext *ctx)
432{
433    assert(clazz != NULL);
434    assert(ctx != NULL);
435    for (int i = 0; i < clazz->interfaceCount; ++i) {
436        markObject((const Object *)clazz->interfaces[i], ctx);
437    }
438}
439
440/*
441 * Scans the header, static field references, and interface
442 * pointers of a class object.
443 */
444static void scanClassObject(const Object *obj, GcMarkContext *ctx)
445{
446    assert(obj != NULL);
447    assert(dvmIsClassObject(obj));
448    assert(ctx != NULL);
449    markObject((const Object *)obj->clazz, ctx);
450    const ClassObject *asClass = (const ClassObject *)obj;
451    if (IS_CLASS_FLAG_SET(asClass, CLASS_ISARRAY)) {
452        markObject((const Object *)asClass->elementClass, ctx);
453    }
454    /* Do super and the interfaces contain Objects and not dex idx values? */
455    if (asClass->status > CLASS_IDX) {
456        markObject((const Object *)asClass->super, ctx);
457    }
458    markObject((const Object *)asClass->classLoader, ctx);
459    scanFields(obj, ctx);
460    scanStaticFields(asClass, ctx);
461    if (asClass->status > CLASS_IDX) {
462        scanInterfaces(asClass, ctx);
463    }
464}
465
466/*
467 * Scans the header of all array objects.  If the array object is
468 * specialized to a reference type, scans the array data as well.
469 */
470static void scanArrayObject(const Object *obj, GcMarkContext *ctx)
471{
472    assert(obj != NULL);
473    assert(obj->clazz != NULL);
474    assert(ctx != NULL);
475    markObject((const Object *)obj->clazz, ctx);
476    if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISOBJECTARRAY)) {
477        const ArrayObject *array = (const ArrayObject *)obj;
478        const Object **contents = (const Object **)(void *)array->contents;
479        for (size_t i = 0; i < array->length; ++i) {
480            markObject(contents[i], ctx);
481        }
482    }
483}
484
485/*
486 * Returns class flags relating to Reference subclasses.
487 */
488static int referenceClassFlags(const Object *obj)
489{
490    int flags = CLASS_ISREFERENCE |
491                CLASS_ISWEAKREFERENCE |
492                CLASS_ISFINALIZERREFERENCE |
493                CLASS_ISPHANTOMREFERENCE;
494    return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
495}
496
497/*
498 * Returns true if the object derives from SoftReference.
499 */
500static bool isSoftReference(const Object *obj)
501{
502    return referenceClassFlags(obj) == CLASS_ISREFERENCE;
503}
504
505/*
506 * Returns true if the object derives from WeakReference.
507 */
508static bool isWeakReference(const Object *obj)
509{
510    return referenceClassFlags(obj) & CLASS_ISWEAKREFERENCE;
511}
512
513/*
514 * Returns true if the object derives from FinalizerReference.
515 */
516static bool isFinalizerReference(const Object *obj)
517{
518    return referenceClassFlags(obj) & CLASS_ISFINALIZERREFERENCE;
519}
520
521/*
522 * Returns true if the object derives from PhantomReference.
523 */
524static bool isPhantomReference(const Object *obj)
525{
526    return referenceClassFlags(obj) & CLASS_ISPHANTOMREFERENCE;
527}
528
529/*
530 * Adds a reference to the tail of a circular queue of references.
531 */
532static void enqueuePendingReference(Object *ref, Object **list)
533{
534    assert(ref != NULL);
535    assert(list != NULL);
536    size_t offset = gDvm.offJavaLangRefReference_pendingNext;
537    if (*list == NULL) {
538        dvmSetFieldObject(ref, offset, ref);
539        *list = ref;
540    } else {
541        Object *head = dvmGetFieldObject(*list, offset);
542        dvmSetFieldObject(ref, offset, head);
543        dvmSetFieldObject(*list, offset, ref);
544    }
545}
546
547/*
548 * Removes the reference at the head of a circular queue of
549 * references.
550 */
551static Object *dequeuePendingReference(Object **list)
552{
553    assert(list != NULL);
554    assert(*list != NULL);
555    size_t offset = gDvm.offJavaLangRefReference_pendingNext;
556    Object *head = dvmGetFieldObject(*list, offset);
557    Object *ref;
558    if (*list == head) {
559        ref = *list;
560        *list = NULL;
561    } else {
562        Object *next = dvmGetFieldObject(head, offset);
563        dvmSetFieldObject(*list, offset, next);
564        ref = head;
565    }
566    dvmSetFieldObject(ref, offset, NULL);
567    return ref;
568}
569
570/*
571 * Process the "referent" field in a java.lang.ref.Reference.  If the
572 * referent has not yet been marked, put it on the appropriate list in
573 * the gcHeap for later processing.
574 */
575static void delayReferenceReferent(Object *obj, GcMarkContext *ctx)
576{
577    assert(obj != NULL);
578    assert(obj->clazz != NULL);
579    assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
580    assert(ctx != NULL);
581    GcHeap *gcHeap = gDvm.gcHeap;
582    size_t pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
583    size_t referentOffset = gDvm.offJavaLangRefReference_referent;
584    Object *pending = dvmGetFieldObject(obj, pendingNextOffset);
585    Object *referent = dvmGetFieldObject(obj, referentOffset);
586    if (pending == NULL && referent != NULL && !isMarked(referent, ctx)) {
587        Object **list = NULL;
588        if (isSoftReference(obj)) {
589            list = &gcHeap->softReferences;
590        } else if (isWeakReference(obj)) {
591            list = &gcHeap->weakReferences;
592        } else if (isFinalizerReference(obj)) {
593            list = &gcHeap->finalizerReferences;
594        } else if (isPhantomReference(obj)) {
595            list = &gcHeap->phantomReferences;
596        }
597        assert(list != NULL);
598        enqueuePendingReference(obj, list);
599    }
600}
601
602/*
603 * Scans the header and field references of a data object.
604 */
605static void scanDataObject(const Object *obj, GcMarkContext *ctx)
606{
607    assert(obj != NULL);
608    assert(obj->clazz != NULL);
609    assert(ctx != NULL);
610    markObject((const Object *)obj->clazz, ctx);
611    scanFields(obj, ctx);
612    if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE)) {
613        delayReferenceReferent((Object *)obj, ctx);
614    }
615}
616
617/*
618 * Scans an object reference.  Determines the type of the reference
619 * and dispatches to a specialized scanning routine.
620 */
621static void scanObject(const Object *obj, GcMarkContext *ctx)
622{
623    assert(obj != NULL);
624    assert(obj->clazz != NULL);
625    assert(ctx != NULL);
626    assert(isMarked(obj, ctx));
627    if (dvmIsClassObject(obj)) {
628        scanClassObject(obj, ctx);
629    } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
630        scanArrayObject(obj, ctx);
631    } else {
632        scanDataObject(obj, ctx);
633    }
634}
635
636/*
637 * Scan anything that's on the mark stack.  We can't use the bitmaps
638 * anymore, so use a finger that points past the end of them.
639 */
640static void processMarkStack(GcMarkContext *ctx)
641{
642    assert(ctx != NULL);
643    assert(ctx->finger == (void *)ULONG_MAX);
644    assert(ctx->stack.top >= ctx->stack.base);
645    GcMarkStack *stack = &ctx->stack;
646    while (stack->top > stack->base) {
647        const Object *obj = markStackPop(stack);
648        scanObject(obj, ctx);
649    }
650}
651
652/*
653 * Blackens gray objects found on dirty cards.
654 */
655static void scanGrayObjects(GcMarkContext *ctx)
656{
657    assert(ctx != NULL);
658    assert(ctx->bitmap != NULL);
659    HeapBitmap *bitmap = ctx->bitmap;
660    u1 *base = (u1 *)bitmap->base;
661    u1 *limit = (u1 *)ALIGN_UP(bitmap->max, GC_CARD_SIZE);
662    visitCardTable((Visitor *)scanObject, base, limit, ctx);
663}
664
665/*
666 * Iterate through the immune objects and mark their referents.  Uses
667 * the mod union table to save scanning time.
668 */
669void dvmHeapScanImmuneObjects(const GcMarkContext *ctx)
670{
671    assert(ctx != NULL);
672    ScanImmuneObjectContext scanCtx;
673    memset(&scanCtx, 0, sizeof(scanCtx));
674    scanCtx.threatenBoundary = (Object*)ctx->immuneLimit;
675    visitModUnionTable(scanImmuneObject,
676                       (u1*)ctx->bitmap->base, (u1*)ctx->immuneLimit,
677                       (void *)&scanCtx);
678    if (gDvm.verifyCardTable) {
679        verifyImmuneObjects();
680    }
681}
682
683/*
684 * Callback for scanning each object in the bitmap.  The finger is set
685 * to the address corresponding to the lowest address in the next word
686 * of bits in the bitmap.
687 */
688static void scanBitmapCallback(Object *obj, void *finger, void *arg)
689{
690    GcMarkContext *ctx = (GcMarkContext *)arg;
691    ctx->finger = (void *)finger;
692    scanObject(obj, ctx);
693}
694
695/* Given bitmaps with the root set marked, find and mark all
696 * reachable objects.  When this returns, the entire set of
697 * live objects will be marked and the mark stack will be empty.
698 */
699void dvmHeapScanMarkedObjects(bool isPartial)
700{
701    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
702
703    assert(ctx != NULL);
704    assert(ctx->finger == NULL);
705
706    u1 *start;
707    if (isPartial && dvmHeapSourceGetNumHeaps() > 1) {
708        dvmHeapScanImmuneObjects(ctx);
709        start = (u1 *)ctx->immuneLimit;
710    } else {
711        start = (u1*)ctx->bitmap->base;
712    }
713    /*
714     * All objects reachable from the root set have a bit set in the
715     * mark bitmap.  Walk the mark bitmap and blacken these objects.
716     */
717    dvmHeapBitmapScanWalk(ctx->bitmap,
718                          (uintptr_t)start, ctx->bitmap->max,
719                          scanBitmapCallback,
720                          ctx);
721
722    ctx->finger = (void *)ULONG_MAX;
723
724    /* Process gray objects until the mark stack it is empty. */
725    processMarkStack(ctx);
726}
727
728void dvmHeapReScanMarkedObjects()
729{
730    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
731
732    /*
733     * The finger must have been set to the maximum value to ensure
734     * that gray objects will be pushed onto the mark stack.
735     */
736    assert(ctx->finger == (void *)ULONG_MAX);
737    scanGrayObjects(ctx);
738    processMarkStack(ctx);
739}
740
741/*
742 * Clear the referent field.
743 */
744static void clearReference(Object *reference)
745{
746    size_t offset = gDvm.offJavaLangRefReference_referent;
747    dvmSetFieldObject(reference, offset, NULL);
748}
749
750/*
751 * Returns true if the reference was registered with a reference queue
752 * and has not yet been enqueued.
753 */
754static bool isEnqueuable(const Object *reference)
755{
756    assert(reference != NULL);
757    Object *queue = dvmGetFieldObject(reference,
758            gDvm.offJavaLangRefReference_queue);
759    Object *queueNext = dvmGetFieldObject(reference,
760            gDvm.offJavaLangRefReference_queueNext);
761    return queue != NULL && queueNext == NULL;
762}
763
764/*
765 * Schedules a reference to be appended to its reference queue.
766 */
767static void enqueueReference(Object *ref)
768{
769    assert(ref != NULL);
770    assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
771    assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
772    enqueuePendingReference(ref, &gDvm.gcHeap->clearedReferences);
773}
774
775/*
776 * Walks the reference list marking any references subject to the
777 * reference clearing policy.  References with a black referent are
778 * removed from the list.  References with white referents biased
779 * toward saving are blackened and also removed from the list.
780 */
781static void preserveSomeSoftReferences(Object **list)
782{
783    assert(list != NULL);
784    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
785    size_t referentOffset = gDvm.offJavaLangRefReference_referent;
786    Object *clear = NULL;
787    size_t counter = 0;
788    while (*list != NULL) {
789        Object *ref = dequeuePendingReference(list);
790        Object *referent = dvmGetFieldObject(ref, referentOffset);
791        if (referent == NULL) {
792            /* Referent was cleared by the user during marking. */
793            continue;
794        }
795        bool marked = isMarked(referent, ctx);
796        if (!marked && ((++counter) & 1)) {
797            /* Referent is white and biased toward saving, mark it. */
798            markObject(referent, ctx);
799            marked = true;
800        }
801        if (!marked) {
802            /* Referent is white, queue it for clearing. */
803            enqueuePendingReference(ref, &clear);
804        }
805    }
806    *list = clear;
807    /*
808     * Restart the mark with the newly black references added to the
809     * root set.
810     */
811    processMarkStack(ctx);
812}
813
814/*
815 * Unlink the reference list clearing references objects with white
816 * referents.  Cleared references registered to a reference queue are
817 * scheduled for appending by the heap worker thread.
818 */
819static void clearWhiteReferences(Object **list)
820{
821    assert(list != NULL);
822    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
823    size_t referentOffset = gDvm.offJavaLangRefReference_referent;
824    while (*list != NULL) {
825        Object *ref = dequeuePendingReference(list);
826        Object *referent = dvmGetFieldObject(ref, referentOffset);
827        if (referent != NULL && !isMarked(referent, ctx)) {
828            /* Referent is white, clear it. */
829            clearReference(ref);
830            if (isEnqueuable(ref)) {
831                enqueueReference(ref);
832            }
833        }
834    }
835    assert(*list == NULL);
836}
837
838/*
839 * Enqueues finalizer references with white referents.  White
840 * referents are blackened, moved to the zombie field, and the
841 * referent field is cleared.
842 */
843static void enqueueFinalizerReferences(Object **list)
844{
845    assert(list != NULL);
846    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
847    size_t referentOffset = gDvm.offJavaLangRefReference_referent;
848    size_t zombieOffset = gDvm.offJavaLangRefFinalizerReference_zombie;
849    bool hasEnqueued = false;
850    while (*list != NULL) {
851        Object *ref = dequeuePendingReference(list);
852        Object *referent = dvmGetFieldObject(ref, referentOffset);
853        if (referent != NULL && !isMarked(referent, ctx)) {
854            markObject(referent, ctx);
855            /* If the referent is non-null the reference must queuable. */
856            assert(isEnqueuable(ref));
857            dvmSetFieldObject(ref, zombieOffset, referent);
858            clearReference(ref);
859            enqueueReference(ref);
860            hasEnqueued = true;
861        }
862    }
863    if (hasEnqueued) {
864        processMarkStack(ctx);
865    }
866    assert(*list == NULL);
867}
868
869/*
870 * This object is an instance of a class that overrides finalize().  Mark
871 * it as finalizable.
872 *
873 * This is called when Object.<init> completes normally.  It's also
874 * called for clones of finalizable objects.
875 */
876void dvmSetFinalizable(Object *obj)
877{
878    assert(obj != NULL);
879    Thread *self = dvmThreadSelf();
880    assert(self != NULL);
881    Method *meth = gDvm.methJavaLangRefFinalizerReferenceAdd;
882    assert(meth != NULL);
883    JValue unusedResult;
884    dvmCallMethod(self, meth, NULL, &unusedResult, obj);
885}
886
887/*
888 * Process reference class instances and schedule finalizations.
889 */
890void dvmHeapProcessReferences(Object **softReferences, bool clearSoftRefs,
891                              Object **weakReferences,
892                              Object **finalizerReferences,
893                              Object **phantomReferences)
894{
895    assert(softReferences != NULL);
896    assert(weakReferences != NULL);
897    assert(finalizerReferences != NULL);
898    assert(phantomReferences != NULL);
899    /*
900     * Unless we are in the zygote or required to clear soft
901     * references with white references, preserve some white
902     * referents.
903     */
904    if (!gDvm.zygote && !clearSoftRefs) {
905        preserveSomeSoftReferences(softReferences);
906    }
907    /*
908     * Clear all remaining soft and weak references with white
909     * referents.
910     */
911    clearWhiteReferences(softReferences);
912    clearWhiteReferences(weakReferences);
913    /*
914     * Preserve all white objects with finalize methods and schedule
915     * them for finalization.
916     */
917    enqueueFinalizerReferences(finalizerReferences);
918    /*
919     * Clear all f-reachable soft and weak references with white
920     * referents.
921     */
922    clearWhiteReferences(softReferences);
923    clearWhiteReferences(weakReferences);
924    /*
925     * Clear all phantom references with white referents.
926     */
927    clearWhiteReferences(phantomReferences);
928    /*
929     * At this point all reference lists should be empty.
930     */
931    assert(*softReferences == NULL);
932    assert(*weakReferences == NULL);
933    assert(*finalizerReferences == NULL);
934    assert(*phantomReferences == NULL);
935}
936
937/*
938 * Pushes a list of cleared references out to the managed heap.
939 */
940void dvmEnqueueClearedReferences(Object **cleared)
941{
942    assert(cleared != NULL);
943    if (*cleared != NULL) {
944        Thread *self = dvmThreadSelf();
945        assert(self != NULL);
946        Method *meth = gDvm.methJavaLangRefReferenceQueueAdd;
947        assert(meth != NULL);
948        JValue unused;
949        Object *reference = *cleared;
950        dvmCallMethod(self, meth, NULL, &unused, reference);
951        *cleared = NULL;
952    }
953}
954
955void dvmHeapFinishMarkStep()
956{
957    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
958
959    /* The mark bits are now not needed.
960     */
961    dvmHeapSourceZeroMarkBitmap();
962
963    /* Clean up everything else associated with the marking process.
964     */
965    destroyMarkStack(&ctx->stack);
966
967    ctx->finger = NULL;
968}
969
970struct SweepContext {
971    size_t numObjects;
972    size_t numBytes;
973    bool isConcurrent;
974};
975
976static void sweepBitmapCallback(size_t numPtrs, void **ptrs, void *arg)
977{
978    assert(arg != NULL);
979    SweepContext *ctx = (SweepContext *)arg;
980    if (ctx->isConcurrent) {
981        dvmLockHeap();
982    }
983    ctx->numBytes += dvmHeapSourceFreeList(numPtrs, ptrs);
984    ctx->numObjects += numPtrs;
985    if (ctx->isConcurrent) {
986        dvmUnlockHeap();
987    }
988}
989
990/*
991 * Returns true if the given object is unmarked.  This assumes that
992 * the bitmaps have not yet been swapped.
993 */
994static int isUnmarkedObject(void *obj)
995{
996    return !isMarked((Object *)obj, &gDvm.gcHeap->markContext);
997}
998
999static void sweepWeakJniGlobals()
1000{
1001    IndirectRefTable* table = &gDvm.jniWeakGlobalRefTable;
1002    GcMarkContext* ctx = &gDvm.gcHeap->markContext;
1003    typedef IndirectRefTable::iterator It; // TODO: C++0x auto
1004    for (It it = table->begin(), end = table->end(); it != end; ++it) {
1005        Object** entry = *it;
1006        if (!isMarked(*entry, ctx)) {
1007            *entry = kClearedJniWeakGlobal;
1008        }
1009    }
1010}
1011
1012/*
1013 * Process all the internal system structures that behave like
1014 * weakly-held objects.
1015 */
1016void dvmHeapSweepSystemWeaks()
1017{
1018    dvmGcDetachDeadInternedStrings(isUnmarkedObject);
1019    dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
1020    sweepWeakJniGlobals();
1021}
1022
1023/*
1024 * Walk through the list of objects that haven't been marked and free
1025 * them.  Assumes the bitmaps have been swapped.
1026 */
1027void dvmHeapSweepUnmarkedObjects(bool isPartial, bool isConcurrent,
1028                                 size_t *numObjects, size_t *numBytes)
1029{
1030    uintptr_t base[HEAP_SOURCE_MAX_HEAP_COUNT];
1031    uintptr_t max[HEAP_SOURCE_MAX_HEAP_COUNT];
1032    SweepContext ctx;
1033    HeapBitmap *prevLive, *prevMark;
1034    size_t numHeaps, numSweepHeaps;
1035
1036    numHeaps = dvmHeapSourceGetNumHeaps();
1037    dvmHeapSourceGetRegions(base, max, NULL, numHeaps);
1038    if (isPartial) {
1039        assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == base[0]);
1040        numSweepHeaps = 1;
1041    } else {
1042        numSweepHeaps = numHeaps;
1043    }
1044    ctx.numObjects = ctx.numBytes = 0;
1045    ctx.isConcurrent = isConcurrent;
1046    prevLive = dvmHeapSourceGetMarkBits();
1047    prevMark = dvmHeapSourceGetLiveBits();
1048    for (size_t i = 0; i < numSweepHeaps; ++i) {
1049        dvmHeapBitmapSweepWalk(prevLive, prevMark, base[i], max[i],
1050                               sweepBitmapCallback, &ctx);
1051    }
1052    *numObjects = ctx.numObjects;
1053    *numBytes = ctx.numBytes;
1054    if (gDvm.allocProf.enabled) {
1055        gDvm.allocProf.freeCount += ctx.numObjects;
1056        gDvm.allocProf.freeSize += ctx.numBytes;
1057    }
1058}
1059