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