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/clz.h"
     19 #include "alloc/HeapBitmap.h"
     20 #include "alloc/HeapInternal.h"
     21 #include "alloc/HeapSource.h"
     22 #include "alloc/MarkSweep.h"
     23 #include "alloc/Visit.h"
     24 #include <limits.h>     // for ULONG_MAX
     25 #include <sys/mman.h>   // for madvise(), mmap()
     26 #include <errno.h>
     27 
     28 #define GC_LOG_TAG      LOG_TAG "-gc"
     29 
     30 #if LOG_NDEBUG
     31 #define LOGV_GC(...)    ((void)0)
     32 #define LOGD_GC(...)    ((void)0)
     33 #else
     34 #define LOGV_GC(...)    LOG(LOG_VERBOSE, GC_LOG_TAG, __VA_ARGS__)
     35 #define LOGD_GC(...)    LOG(LOG_DEBUG, GC_LOG_TAG, __VA_ARGS__)
     36 #endif
     37 
     38 #define LOGI_GC(...)    LOG(LOG_INFO, GC_LOG_TAG, __VA_ARGS__)
     39 #define LOGW_GC(...)    LOG(LOG_WARN, GC_LOG_TAG, __VA_ARGS__)
     40 #define LOGE_GC(...)    LOG(LOG_ERROR, GC_LOG_TAG, __VA_ARGS__)
     41 
     42 #define LOG_SCAN(...)   LOGV_GC("SCAN: " __VA_ARGS__)
     43 
     44 #define ALIGN_UP(x, n) (((size_t)(x) + (n) - 1) & ~((n) - 1))
     45 #define ALIGN_UP_TO_PAGE_SIZE(p) ALIGN_UP(p, SYSTEM_PAGE_SIZE)
     46 
     47 /* Do not cast the result of this to a boolean; the only set bit
     48  * may be > 1<<8.
     49  */
     50 static inline long isMarked(const void *obj, const GcMarkContext *ctx)
     51 {
     52     return dvmHeapBitmapIsObjectBitSet(ctx->bitmap, obj);
     53 }
     54 
     55 static bool createMarkStack(GcMarkStack *stack)
     56 {
     57     const Object **limit;
     58     const char *name;
     59     size_t size;
     60 
     61     /* Create a stack big enough for the worst possible case,
     62      * where the heap is perfectly full of the smallest object.
     63      * TODO: be better about memory usage; use a smaller stack with
     64      *       overflow detection and recovery.
     65      */
     66     size = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
     67             (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
     68     size = ALIGN_UP_TO_PAGE_SIZE(size);
     69     name = "dalvik-mark-stack";
     70     limit = dvmAllocRegion(size, PROT_READ | PROT_WRITE, name);
     71     if (limit == NULL) {
     72         LOGE_GC("Could not mmap %zd-byte ashmem region '%s'", size, name);
     73         return false;
     74     }
     75     stack->limit = limit;
     76     stack->base = (const Object **)((uintptr_t)limit + size);
     77     stack->top = stack->base;
     78     return true;
     79 }
     80 
     81 static void destroyMarkStack(GcMarkStack *stack)
     82 {
     83     munmap((char *)stack->limit,
     84             (uintptr_t)stack->base - (uintptr_t)stack->limit);
     85     memset(stack, 0, sizeof(*stack));
     86 }
     87 
     88 #define MARK_STACK_PUSH(stack, obj) \
     89     do { \
     90         *--(stack).top = (obj); \
     91     } while (false)
     92 
     93 bool dvmHeapBeginMarkStep(GcMode mode)
     94 {
     95     GcMarkContext *ctx = &gDvm.gcHeap->markContext;
     96 
     97     if (!createMarkStack(&ctx->stack)) {
     98         return false;
     99     }
    100     ctx->finger = NULL;
    101     ctx->immuneLimit = dvmHeapSourceGetImmuneLimit(mode);
    102     return true;
    103 }
    104 
    105 static long setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
    106 {
    107     return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
    108 }
    109 
    110 static void markObjectNonNull(const Object *obj, GcMarkContext *ctx,
    111                               bool checkFinger)
    112 {
    113     assert(ctx != NULL);
    114     assert(obj != NULL);
    115     assert(dvmIsValidObject(obj));
    116 
    117     if (obj < (Object *)ctx->immuneLimit) {
    118         assert(isMarked(obj, ctx));
    119         return;
    120     }
    121     if (!setAndReturnMarkBit(ctx, obj)) {
    122         /* This object was not previously marked.
    123          */
    124         if (checkFinger && (void *)obj < ctx->finger) {
    125             /* This object will need to go on the mark stack.
    126              */
    127             MARK_STACK_PUSH(ctx->stack, obj);
    128         }
    129 
    130 #if WITH_HPROF
    131         if (gDvm.gcHeap->hprofContext != NULL) {
    132             hprofMarkRootObject(gDvm.gcHeap->hprofContext, obj, 0);
    133         }
    134 #endif
    135     }
    136 }
    137 
    138 /* Used to mark objects when recursing.  Recursion is done by moving
    139  * the finger across the bitmaps in address order and marking child
    140  * objects.  Any newly-marked objects whose addresses are lower than
    141  * the finger won't be visited by the bitmap scan, so those objects
    142  * need to be added to the mark stack.
    143  */
    144 static void markObject(const Object *obj, GcMarkContext *ctx)
    145 {
    146     if (obj != NULL) {
    147         markObjectNonNull(obj, ctx, true);
    148     }
    149 }
    150 
    151 /* If the object hasn't already been marked, mark it and
    152  * schedule it to be scanned for references.
    153  *
    154  * obj may not be NULL.  The macro dvmMarkObject() should
    155  * be used in situations where a reference may be NULL.
    156  *
    157  * This function may only be called when marking the root
    158  * set.  When recursing, use the internal markObject().
    159  */
    160 void dvmMarkObjectNonNull(const Object *obj)
    161 {
    162     assert(obj != NULL);
    163     markObjectNonNull(obj, &gDvm.gcHeap->markContext, false);
    164 }
    165 
    166 /* Mark the set of root objects.
    167  *
    168  * Things we need to scan:
    169  * - System classes defined by root classloader
    170  * - For each thread:
    171  *   - Interpreted stack, from top to "curFrame"
    172  *     - Dalvik registers (args + local vars)
    173  *   - JNI local references
    174  *   - Automatic VM local references (TrackedAlloc)
    175  *   - Associated Thread/VMThread object
    176  *   - ThreadGroups (could track & start with these instead of working
    177  *     upward from Threads)
    178  *   - Exception currently being thrown, if present
    179  * - JNI global references
    180  * - Interned string table
    181  * - Primitive classes
    182  * - Special objects
    183  *   - gDvm.outOfMemoryObj
    184  * - Objects allocated with ALLOC_NO_GC
    185  * - Objects pending finalization (but not yet finalized)
    186  * - Objects in debugger object registry
    187  *
    188  * Don't need:
    189  * - Native stack (for in-progress stuff in the VM)
    190  *   - The TrackedAlloc stuff watches all native VM references.
    191  */
    192 void dvmHeapMarkRootSet()
    193 {
    194     GcHeap *gcHeap = gDvm.gcHeap;
    195 
    196     HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_STICKY_CLASS, 0);
    197 
    198     LOG_SCAN("immune objects");
    199     dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
    200 
    201     LOG_SCAN("root class loader\n");
    202     dvmGcScanRootClassLoader();
    203     LOG_SCAN("primitive classes\n");
    204     dvmGcScanPrimitiveClasses();
    205 
    206     /* dvmGcScanRootThreadGroups() sets a bunch of
    207      * different scan states internally.
    208      */
    209     HPROF_CLEAR_GC_SCAN_STATE();
    210 
    211     LOG_SCAN("root thread groups\n");
    212     dvmGcScanRootThreadGroups();
    213 
    214     HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_INTERNED_STRING, 0);
    215 
    216     LOG_SCAN("interned strings\n");
    217     dvmGcScanInternedStrings();
    218 
    219     HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_GLOBAL, 0);
    220 
    221     LOG_SCAN("JNI global refs\n");
    222     dvmGcMarkJniGlobalRefs();
    223 
    224     HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
    225 
    226     LOG_SCAN("pending reference operations\n");
    227     dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations);
    228 
    229     HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
    230 
    231     LOG_SCAN("pending finalizations\n");
    232     dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs);
    233 
    234     HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_DEBUGGER, 0);
    235 
    236     LOG_SCAN("debugger refs\n");
    237     dvmGcMarkDebuggerRefs();
    238 
    239     HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_VM_INTERNAL, 0);
    240 
    241     /* Mark any special objects we have sitting around.
    242      */
    243     LOG_SCAN("special objects\n");
    244     dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
    245     dvmMarkObjectNonNull(gDvm.internalErrorObj);
    246     dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
    247 //TODO: scan object references sitting in gDvm;  use pointer begin & end
    248 
    249     HPROF_CLEAR_GC_SCAN_STATE();
    250 }
    251 
    252 /*
    253  * Callback applied to root references.  If the root location contains
    254  * a white reference it is pushed on the mark stack and grayed.
    255  */
    256 static void markObjectVisitor(void *addr, void *arg)
    257 {
    258     Object *obj;
    259 
    260     assert(addr != NULL);
    261     assert(arg != NULL);
    262     obj = *(Object **)addr;
    263     if (obj != NULL) {
    264         markObjectNonNull(obj, arg, true);
    265     }
    266 }
    267 
    268 /*
    269  * Grays all references in the roots.
    270  */
    271 void dvmHeapReMarkRootSet(void)
    272 {
    273     GcMarkContext *ctx = &gDvm.gcHeap->markContext;
    274     assert(ctx->finger == (void *)ULONG_MAX);
    275     dvmVisitRoots(markObjectVisitor, ctx);
    276 }
    277 
    278 /*
    279  * Nothing past this point is allowed to use dvmMarkObject() or
    280  * dvmMarkObjectNonNull(), which are for root-marking only.
    281  * Scanning/recursion must use markObject(), which takes the finger
    282  * into account.
    283  */
    284 #undef dvmMarkObject
    285 #define dvmMarkObject __dont_use_dvmMarkObject__
    286 #define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
    287 
    288 /*
    289  * Scans instance fields.
    290  */
    291 static void scanInstanceFields(const Object *obj, GcMarkContext *ctx)
    292 {
    293     assert(obj != NULL);
    294     assert(obj->clazz != NULL);
    295     assert(ctx != NULL);
    296 
    297     if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
    298         unsigned int refOffsets = obj->clazz->refOffsets;
    299         while (refOffsets != 0) {
    300             const int rshift = CLZ(refOffsets);
    301             refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
    302             markObject(dvmGetFieldObject((Object*)obj,
    303                                           CLASS_OFFSET_FROM_CLZ(rshift)), ctx);
    304         }
    305     } else {
    306         ClassObject *clazz;
    307         int i;
    308         for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
    309             InstField *field = clazz->ifields;
    310             for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
    311                 void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
    312                 markObject(((JValue *)addr)->l, ctx);
    313             }
    314         }
    315     }
    316 }
    317 
    318 /*
    319  * Scans the header, static field references, and interface
    320  * pointers of a class object.
    321  */
    322 static void scanClassObject(const ClassObject *obj, GcMarkContext *ctx)
    323 {
    324     int i;
    325 
    326     assert(obj != NULL);
    327     assert(obj->obj.clazz == gDvm.classJavaLangClass);
    328     assert(ctx != NULL);
    329 
    330     markObject((Object *)obj->obj.clazz, ctx);
    331     if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
    332         markObject((Object *)obj->elementClass, ctx);
    333     }
    334     /* Do super and the interfaces contain Objects and not dex idx values? */
    335     if (obj->status > CLASS_IDX) {
    336         markObject((Object *)obj->super, ctx);
    337     }
    338     markObject(obj->classLoader, ctx);
    339     /* Scan static field references. */
    340     for (i = 0; i < obj->sfieldCount; ++i) {
    341         char ch = obj->sfields[i].field.signature[0];
    342         if (ch == '[' || ch == 'L') {
    343             markObject(obj->sfields[i].value.l, ctx);
    344         }
    345     }
    346     /* Scan the instance fields. */
    347     scanInstanceFields((const Object *)obj, ctx);
    348     /* Scan interface references. */
    349     if (obj->status > CLASS_IDX) {
    350         for (i = 0; i < obj->interfaceCount; ++i) {
    351             markObject((Object *)obj->interfaces[i], ctx);
    352         }
    353     }
    354 }
    355 
    356 /*
    357  * Scans the header of all array objects.  If the array object is
    358  * specialized to a reference type, scans the array data as well.
    359  */
    360 static void scanArrayObject(const ArrayObject *obj, GcMarkContext *ctx)
    361 {
    362     size_t i;
    363 
    364     assert(obj != NULL);
    365     assert(obj->obj.clazz != NULL);
    366     assert(ctx != NULL);
    367     /* Scan the class object reference. */
    368     markObject((Object *)obj->obj.clazz, ctx);
    369     if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISOBJECTARRAY)) {
    370         /* Scan the array contents. */
    371         Object **contents = (Object **)obj->contents;
    372         for (i = 0; i < obj->length; ++i) {
    373             markObject(contents[i], ctx);
    374         }
    375     }
    376 }
    377 
    378 /*
    379  * Returns class flags relating to Reference subclasses.
    380  */
    381 static int referenceClassFlags(const Object *obj)
    382 {
    383     int flags = CLASS_ISREFERENCE |
    384                 CLASS_ISWEAKREFERENCE |
    385                 CLASS_ISPHANTOMREFERENCE;
    386     return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
    387 }
    388 
    389 /*
    390  * Returns true if the object derives from SoftReference.
    391  */
    392 static bool isSoftReference(const Object *obj)
    393 {
    394     return referenceClassFlags(obj) == CLASS_ISREFERENCE;
    395 }
    396 
    397 /*
    398  * Returns true if the object derives from WeakReference.
    399  */
    400 static bool isWeakReference(const Object *obj)
    401 {
    402     return referenceClassFlags(obj) & CLASS_ISWEAKREFERENCE;
    403 }
    404 
    405 /*
    406  * Returns true if the object derives from PhantomReference.
    407  */
    408 static bool isPhantomReference(const Object *obj)
    409 {
    410     return referenceClassFlags(obj) & CLASS_ISPHANTOMREFERENCE;
    411 }
    412 
    413 /*
    414  * Adds a reference to the tail of a circular queue of references.
    415  */
    416 static void enqueuePendingReference(Object *ref, Object **list)
    417 {
    418     size_t offset;
    419 
    420     assert(ref != NULL);
    421     assert(list != NULL);
    422     offset = gDvm.offJavaLangRefReference_pendingNext;
    423     if (*list == NULL) {
    424         dvmSetFieldObject(ref, offset, ref);
    425         *list = ref;
    426     } else {
    427         Object *head = dvmGetFieldObject(*list, offset);
    428         dvmSetFieldObject(ref, offset, head);
    429         dvmSetFieldObject(*list, offset, ref);
    430     }
    431 }
    432 
    433 /*
    434  * Removes the reference at the head of a circular queue of
    435  * references.
    436  */
    437 static Object *dequeuePendingReference(Object **list)
    438 {
    439     Object *ref, *head;
    440     size_t offset;
    441 
    442     assert(list != NULL);
    443     assert(*list != NULL);
    444     offset = gDvm.offJavaLangRefReference_pendingNext;
    445     head = dvmGetFieldObject(*list, offset);
    446     if (*list == head) {
    447         ref = *list;
    448         *list = NULL;
    449     } else {
    450         Object *next = dvmGetFieldObject(head, offset);
    451         dvmSetFieldObject(*list, offset, next);
    452         ref = head;
    453     }
    454     dvmSetFieldObject(ref, offset, NULL);
    455     return ref;
    456 }
    457 
    458 /*
    459  * Process the "referent" field in a java.lang.ref.Reference.  If the
    460  * referent has not yet been marked, put it on the appropriate list in
    461  * the gcHeap for later processing.
    462  */
    463 static void delayReferenceReferent(Object *obj, GcMarkContext *ctx)
    464 {
    465     GcHeap *gcHeap = gDvm.gcHeap;
    466     Object *pending, *referent;
    467     size_t pendingNextOffset, referentOffset;
    468 
    469     assert(obj != NULL);
    470     assert(obj->clazz != NULL);
    471     assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
    472     assert(ctx != NULL);
    473     pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
    474     referentOffset = gDvm.offJavaLangRefReference_referent;
    475     pending = dvmGetFieldObject(obj, pendingNextOffset);
    476     referent = dvmGetFieldObject(obj, referentOffset);
    477     if (pending == NULL && referent != NULL && !isMarked(referent, ctx)) {
    478         Object **list = NULL;
    479         if (isSoftReference(obj)) {
    480             list = &gcHeap->softReferences;
    481         } else if (isWeakReference(obj)) {
    482             list = &gcHeap->weakReferences;
    483         } else if (isPhantomReference(obj)) {
    484             list = &gcHeap->phantomReferences;
    485         }
    486         assert(list != NULL);
    487         enqueuePendingReference(obj, list);
    488     }
    489 }
    490 
    491 /*
    492  * Scans the header and field references of a data object.
    493  */
    494 static void scanDataObject(DataObject *obj, GcMarkContext *ctx)
    495 {
    496     assert(obj != NULL);
    497     assert(obj->obj.clazz != NULL);
    498     assert(ctx != NULL);
    499     /* Scan the class object. */
    500     markObject((Object *)obj->obj.clazz, ctx);
    501     /* Scan the instance fields. */
    502     scanInstanceFields((const Object *)obj, ctx);
    503     if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISREFERENCE)) {
    504         delayReferenceReferent((Object *)obj, ctx);
    505     }
    506 }
    507 
    508 /*
    509  * Scans an object reference.  Determines the type of the reference
    510  * and dispatches to a specialized scanning routine.
    511  */
    512 static void scanObject(const Object *obj, GcMarkContext *ctx)
    513 {
    514     assert(obj != NULL);
    515     assert(ctx != NULL);
    516     assert(obj->clazz != NULL);
    517 #if WITH_HPROF
    518     if (gDvm.gcHeap->hprofContext != NULL) {
    519         hprofDumpHeapObject(gDvm.gcHeap->hprofContext, obj);
    520     }
    521 #endif
    522     /* Dispatch a type-specific scan routine. */
    523     if (obj->clazz == gDvm.classJavaLangClass) {
    524         scanClassObject((ClassObject *)obj, ctx);
    525     } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
    526         scanArrayObject((ArrayObject *)obj, ctx);
    527     } else {
    528         scanDataObject((DataObject *)obj, ctx);
    529     }
    530 }
    531 
    532 static void
    533 processMarkStack(GcMarkContext *ctx)
    534 {
    535     const Object **const base = ctx->stack.base;
    536 
    537     /* Scan anything that's on the mark stack.
    538      * We can't use the bitmaps anymore, so use
    539      * a finger that points past the end of them.
    540      */
    541     ctx->finger = (void *)ULONG_MAX;
    542     while (ctx->stack.top != base) {
    543         scanObject(*ctx->stack.top++, ctx);
    544     }
    545 }
    546 
    547 static size_t objectSize(const Object *obj)
    548 {
    549     assert(dvmIsValidObject(obj));
    550     assert(dvmIsValidObject((Object *)obj->clazz));
    551     if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
    552         return dvmArrayObjectSize((ArrayObject *)obj);
    553     } else if (obj->clazz == gDvm.classJavaLangClass) {
    554         return dvmClassObjectSize((ClassObject *)obj);
    555     } else {
    556         return obj->clazz->objectSize;
    557     }
    558 }
    559 
    560 /*
    561  * Scans forward to the header of the next marked object between start
    562  * and limit.  Returns NULL if no marked objects are in that region.
    563  */
    564 static Object *nextGrayObject(u1 *base, u1 *limit, HeapBitmap *markBits)
    565 {
    566     u1 *ptr;
    567 
    568     assert(base < limit);
    569     assert(limit - base <= GC_CARD_SIZE);
    570     for (ptr = base; ptr < limit; ptr += HB_OBJECT_ALIGNMENT) {
    571         if (dvmHeapBitmapIsObjectBitSet(markBits, ptr))
    572             return (Object *)ptr;
    573     }
    574     return NULL;
    575 }
    576 
    577 /*
    578  * Scan the card table looking for objects that have been grayed by
    579  * the mutator.
    580  */
    581 static void scanGrayObjects(GcMarkContext *ctx)
    582 {
    583     GcHeap *h = gDvm.gcHeap;
    584     HeapBitmap *markBits, *liveBits;
    585     u1 *card, *baseCard, *limitCard;
    586     size_t footprint;
    587 
    588     markBits = ctx->bitmap;
    589     liveBits = dvmHeapSourceGetLiveBits();
    590     footprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
    591     baseCard = &h->cardTableBase[0];
    592     limitCard = dvmCardFromAddr((u1 *)dvmHeapSourceGetBase() + footprint);
    593     assert(limitCard <= &h->cardTableBase[h->cardTableLength]);
    594     for (card = baseCard; card != limitCard; ++card) {
    595         if (*card == GC_CARD_DIRTY) {
    596             /*
    597              * The card is dirty.  Scan all of the objects that
    598              * intersect with the card address.
    599              */
    600             u1 *addr = dvmAddrFromCard(card);
    601             /*
    602              * Scan through all black objects that start on the
    603              * current card.
    604              */
    605             u1 *limit = addr + GC_CARD_SIZE;
    606             u1 *next = addr;
    607             while (next < limit) {
    608                 Object *obj = nextGrayObject(next, limit, markBits);
    609                 if (obj == NULL)
    610                     break;
    611                 scanObject(obj, ctx);
    612                 next = (u1*)obj + ALIGN_UP(objectSize(obj), HB_OBJECT_ALIGNMENT);
    613             }
    614         }
    615     }
    616 }
    617 
    618 /*
    619  * Callback for scanning each object in the bitmap.  The finger is set
    620  * to the address corresponding to the lowest address in the next word
    621  * of bits in the bitmap.
    622  */
    623 static void scanBitmapCallback(void *addr, void *finger, void *arg)
    624 {
    625     GcMarkContext *ctx = arg;
    626     ctx->finger = (void *)finger;
    627     scanObject(addr, ctx);
    628 }
    629 
    630 /* Given bitmaps with the root set marked, find and mark all
    631  * reachable objects.  When this returns, the entire set of
    632  * live objects will be marked and the mark stack will be empty.
    633  */
    634 void dvmHeapScanMarkedObjects(void)
    635 {
    636     GcMarkContext *ctx = &gDvm.gcHeap->markContext;
    637 
    638     assert(ctx->finger == NULL);
    639 
    640     /* The bitmaps currently have bits set for the root set.
    641      * Walk across the bitmaps and scan each object.
    642      */
    643     dvmHeapBitmapScanWalk(ctx->bitmap, scanBitmapCallback, ctx);
    644 
    645     /* We've walked the mark bitmaps.  Scan anything that's
    646      * left on the mark stack.
    647      */
    648     processMarkStack(ctx);
    649 
    650     LOG_SCAN("done with marked objects\n");
    651 }
    652 
    653 void dvmHeapReScanMarkedObjects(void)
    654 {
    655     GcMarkContext *ctx = &gDvm.gcHeap->markContext;
    656 
    657     /*
    658      * The finger must have been set to the maximum value to ensure
    659      * that gray objects will be pushed onto the mark stack.
    660      */
    661     assert(ctx->finger == (void *)ULONG_MAX);
    662     scanGrayObjects(ctx);
    663     processMarkStack(ctx);
    664 }
    665 
    666 /*
    667  * Clear the referent field.
    668  */
    669 static void clearReference(Object *reference)
    670 {
    671     size_t offset = gDvm.offJavaLangRefReference_referent;
    672     dvmSetFieldObject(reference, offset, NULL);
    673 }
    674 
    675 /*
    676  * Returns true if the reference was registered with a reference queue
    677  * and has not yet been enqueued.
    678  */
    679 static bool isEnqueuable(const Object *reference)
    680 {
    681     Object *queue = dvmGetFieldObject(reference,
    682             gDvm.offJavaLangRefReference_queue);
    683     Object *queueNext = dvmGetFieldObject(reference,
    684             gDvm.offJavaLangRefReference_queueNext);
    685     return queue != NULL && queueNext == NULL;
    686 }
    687 
    688 /*
    689  * Schedules a reference to be appended to its reference queue.
    690  */
    691 static void enqueueReference(Object *ref)
    692 {
    693     assert(ref != NULL);
    694     assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
    695     assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
    696     if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
    697         LOGE_HEAP("enqueueReference(): no room for any more "
    698                   "reference operations\n");
    699         dvmAbort();
    700     }
    701 }
    702 
    703 /*
    704  * Walks the reference list marking any references subject to the
    705  * reference clearing policy.  References with a black referent are
    706  * removed from the list.  References with white referents biased
    707  * toward saving are blackened and also removed from the list.
    708  */
    709 void dvmHandleSoftRefs(Object **list)
    710 {
    711     GcMarkContext *ctx;
    712     Object *ref, *referent;
    713     Object *clear;
    714     size_t referentOffset;
    715     size_t counter;
    716     bool marked;
    717 
    718     ctx = &gDvm.gcHeap->markContext;
    719     referentOffset = gDvm.offJavaLangRefReference_referent;
    720     clear = NULL;
    721     counter = 0;
    722     while (*list != NULL) {
    723         ref = dequeuePendingReference(list);
    724         referent = dvmGetFieldObject(ref, referentOffset);
    725         if (referent == NULL) {
    726             /* Referent was cleared by the user during marking. */
    727             continue;
    728         }
    729         marked = isMarked(referent, ctx);
    730         if (!marked && ((++counter) & 1)) {
    731             /* Referent is white and biased toward saving, mark it. */
    732             markObject(referent, ctx);
    733             marked = true;
    734         }
    735         if (!marked) {
    736             /* Referent is white, queue it for clearing. */
    737             enqueuePendingReference(ref, &clear);
    738         }
    739     }
    740     *list = clear;
    741     /*
    742      * Restart the mark with the newly black references added to the
    743      * root set.
    744      */
    745     processMarkStack(ctx);
    746 }
    747 
    748 /*
    749  * Unlink the reference list clearing references objects with white
    750  * referents.  Cleared references registered to a reference queue are
    751  * scheduled for appending by the heap worker thread.
    752  */
    753 void dvmClearWhiteRefs(Object **list)
    754 {
    755     GcMarkContext *ctx;
    756     Object *ref, *referent;
    757     size_t referentOffset;
    758     bool doSignal;
    759 
    760     ctx = &gDvm.gcHeap->markContext;
    761     referentOffset = gDvm.offJavaLangRefReference_referent;
    762     doSignal = false;
    763     while (*list != NULL) {
    764         ref = dequeuePendingReference(list);
    765         referent = dvmGetFieldObject(ref, referentOffset);
    766         if (referent != NULL && !isMarked(referent, ctx)) {
    767             /* Referent is white, clear it. */
    768             clearReference(ref);
    769             if (isEnqueuable(ref)) {
    770                 enqueueReference(ref);
    771                 doSignal = true;
    772             }
    773         }
    774     }
    775     /*
    776      * If we cleared a reference with a reference queue we must notify
    777      * the heap worker to append the reference.
    778      */
    779     if (doSignal) {
    780         dvmSignalHeapWorker(false);
    781     }
    782     assert(*list == NULL);
    783 }
    784 
    785 /* Find unreachable objects that need to be finalized,
    786  * and schedule them for finalization.
    787  */
    788 void dvmHeapScheduleFinalizations()
    789 {
    790     HeapRefTable newPendingRefs;
    791     LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
    792     Object **ref;
    793     Object **lastRef;
    794     size_t totalPendCount;
    795     GcMarkContext *ctx = &gDvm.gcHeap->markContext;
    796 
    797     /*
    798      * All reachable objects have been marked.
    799      * Any unmarked finalizable objects need to be finalized.
    800      */
    801 
    802     /* Create a table that the new pending refs will
    803      * be added to.
    804      */
    805     if (!dvmHeapInitHeapRefTable(&newPendingRefs)) {
    806         //TODO: mark all finalizable refs and hope that
    807         //      we can schedule them next time.  Watch out,
    808         //      because we may be expecting to free up space
    809         //      by calling finalizers.
    810         LOGE_GC("dvmHeapScheduleFinalizations(): no room for "
    811                 "pending finalizations\n");
    812         dvmAbort();
    813     }
    814 
    815     /* Walk through finalizableRefs and move any unmarked references
    816      * to the list of new pending refs.
    817      */
    818     totalPendCount = 0;
    819     while (finRefs != NULL) {
    820         Object **gapRef;
    821         size_t newPendCount = 0;
    822 
    823         gapRef = ref = finRefs->refs.table;
    824         lastRef = finRefs->refs.nextEntry;
    825         while (ref < lastRef) {
    826             if (!isMarked(*ref, ctx)) {
    827                 if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
    828                     //TODO: add the current table and allocate
    829                     //      a new, smaller one.
    830                     LOGE_GC("dvmHeapScheduleFinalizations(): "
    831                             "no room for any more pending finalizations: %zd\n",
    832                             dvmHeapNumHeapRefTableEntries(&newPendingRefs));
    833                     dvmAbort();
    834                 }
    835                 newPendCount++;
    836             } else {
    837                 /* This ref is marked, so will remain on finalizableRefs.
    838                  */
    839                 if (newPendCount > 0) {
    840                     /* Copy it up to fill the holes.
    841                      */
    842                     *gapRef++ = *ref;
    843                 } else {
    844                     /* No holes yet; don't bother copying.
    845                      */
    846                     gapRef++;
    847                 }
    848             }
    849             ref++;
    850         }
    851         finRefs->refs.nextEntry = gapRef;
    852         //TODO: if the table is empty when we're done, free it.
    853         totalPendCount += newPendCount;
    854         finRefs = finRefs->next;
    855     }
    856     LOGD_GC("dvmHeapScheduleFinalizations(): %zd finalizers triggered.\n",
    857             totalPendCount);
    858     if (totalPendCount == 0) {
    859         /* No objects required finalization.
    860          * Free the empty temporary table.
    861          */
    862         dvmClearReferenceTable(&newPendingRefs);
    863         return;
    864     }
    865 
    866     /* Add the new pending refs to the main list.
    867      */
    868     if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
    869                 &newPendingRefs))
    870     {
    871         LOGE_GC("dvmHeapScheduleFinalizations(): can't insert new "
    872                 "pending finalizations\n");
    873         dvmAbort();
    874     }
    875 
    876     //TODO: try compacting the main list with a memcpy loop
    877 
    878     /* Mark the refs we just moved;  we don't want them or their
    879      * children to get swept yet.
    880      */
    881     ref = newPendingRefs.table;
    882     lastRef = newPendingRefs.nextEntry;
    883     assert(ref < lastRef);
    884     HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
    885     while (ref < lastRef) {
    886         assert(*ref != NULL);
    887         markObject(*ref, ctx);
    888         ref++;
    889     }
    890     HPROF_CLEAR_GC_SCAN_STATE();
    891     processMarkStack(ctx);
    892     dvmSignalHeapWorker(false);
    893 }
    894 
    895 void dvmHeapFinishMarkStep()
    896 {
    897     GcMarkContext *ctx;
    898 
    899     ctx = &gDvm.gcHeap->markContext;
    900 
    901     /* The mark bits are now not needed.
    902      */
    903     dvmHeapSourceZeroMarkBitmap();
    904 
    905     /* Clean up everything else associated with the marking process.
    906      */
    907     destroyMarkStack(&ctx->stack);
    908 
    909     ctx->finger = NULL;
    910 }
    911 
    912 typedef struct {
    913     size_t numObjects;
    914     size_t numBytes;
    915     bool isConcurrent;
    916 } SweepContext;
    917 
    918 static void sweepBitmapCallback(size_t numPtrs, void **ptrs, void *arg)
    919 {
    920     SweepContext *ctx = arg;
    921 
    922     if (ctx->isConcurrent) {
    923         dvmLockHeap();
    924     }
    925     ctx->numBytes += dvmHeapSourceFreeList(numPtrs, ptrs);
    926     ctx->numObjects += numPtrs;
    927     if (ctx->isConcurrent) {
    928         dvmUnlockHeap();
    929     }
    930 }
    931 
    932 /*
    933  * Returns true if the given object is unmarked.  This assumes that
    934  * the bitmaps have not yet been swapped.
    935  */
    936 static int isUnmarkedObject(void *object)
    937 {
    938     return !isMarked((void *)((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
    939             &gDvm.gcHeap->markContext);
    940 }
    941 
    942 /*
    943  * Process all the internal system structures that behave like
    944  * weakly-held objects.
    945  */
    946 void dvmHeapSweepSystemWeaks(void)
    947 {
    948     dvmGcDetachDeadInternedStrings(isUnmarkedObject);
    949     dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
    950 }
    951 
    952 /*
    953  * Walk through the list of objects that haven't been marked and free
    954  * them.  Assumes the bitmaps have been swapped.
    955  */
    956 void dvmHeapSweepUnmarkedObjects(GcMode mode, bool isConcurrent,
    957                                  size_t *numObjects, size_t *numBytes)
    958 {
    959     HeapBitmap currMark[HEAP_SOURCE_MAX_HEAP_COUNT];
    960     HeapBitmap currLive[HEAP_SOURCE_MAX_HEAP_COUNT];
    961     SweepContext ctx;
    962     size_t numBitmaps, numSweepBitmaps;
    963     size_t i;
    964 
    965     numBitmaps = dvmHeapSourceGetNumHeaps();
    966     dvmHeapSourceGetObjectBitmaps(currLive, currMark, numBitmaps);
    967     if (mode == GC_PARTIAL) {
    968         numSweepBitmaps = 1;
    969         assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == currLive[0].base);
    970     } else {
    971         numSweepBitmaps = numBitmaps;
    972     }
    973     ctx.numObjects = ctx.numBytes = 0;
    974     ctx.isConcurrent = isConcurrent;
    975     for (i = 0; i < numSweepBitmaps; i++) {
    976         HeapBitmap* prevLive = &currMark[i];
    977         HeapBitmap* prevMark = &currLive[i];
    978         dvmHeapBitmapSweepWalk(prevLive, prevMark, sweepBitmapCallback, &ctx);
    979     }
    980     *numObjects = ctx.numObjects;
    981     *numBytes = ctx.numBytes;
    982     if (gDvm.allocProf.enabled) {
    983         gDvm.allocProf.freeCount += ctx.numObjects;
    984         gDvm.allocProf.freeSize += ctx.numBytes;
    985     }
    986 }
    987