• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
isMarked(const Object * obj,const GcMarkContext * ctx)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  */
createMarkStack(GcMarkStack * stack)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  */
destroyMarkStack(GcMarkStack * stack)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  */
markStackPush(GcMarkStack * stack,const Object * obj)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  */
markStackPop(GcMarkStack * stack)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 
dvmHeapBeginMarkStep(bool isPartial)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 
setAndReturnMarkBit(GcMarkContext * ctx,const void * obj)101 static long setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
102 {
103     return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
104 }
105 
markObjectNonNull(const Object * obj,GcMarkContext * ctx,bool checkFinger)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  */
markObject(const Object * obj,GcMarkContext * ctx)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  */
rootMarkObjectVisitor(void * addr,u4 thread,RootType type,void * arg)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  */
dvmHeapMarkRootSet()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  */
rootReMarkObjectVisitor(void * addr,u4 thread,RootType type,void * arg)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  */
dvmHeapReMarkRootSet()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  */
scanFields(const Object * obj,GcMarkContext * ctx)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  */
scanStaticFields(const ClassObject * clazz,GcMarkContext * ctx)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  */
scanInterfaces(const ClassObject * clazz,GcMarkContext * ctx)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  */
scanClassObject(const Object * obj,GcMarkContext * ctx)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  */
scanArrayObject(const Object * obj,GcMarkContext * ctx)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  */
referenceClassFlags(const Object * obj)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  */
isSoftReference(const Object * obj)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  */
isWeakReference(const Object * obj)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  */
isFinalizerReference(const Object * obj)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  */
isPhantomReference(const Object * obj)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  */
enqueuePendingReference(Object * ref,Object ** list)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  */
dequeuePendingReference(Object ** list)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  */
delayReferenceReferent(Object * obj,GcMarkContext * ctx)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  */
scanDataObject(const Object * obj,GcMarkContext * ctx)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  */
scanObject(const Object * obj,GcMarkContext * ctx)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  */
processMarkStack(GcMarkContext * ctx)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 
objectSize(const Object * obj)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  */
nextGrayObject(const u1 * base,const u1 * limit,const HeapBitmap * markBits)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  */
scanDirtyCards(const u1 * start,const u1 * end,GcMarkContext * ctx)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  */
scanGrayObjects(GcMarkContext * ctx)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  */
scanBitmapCallback(Object * obj,void * finger,void * arg)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  */
dvmHeapScanMarkedObjects(void)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 
dvmHeapReScanMarkedObjects()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  */
clearReference(Object * reference)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  */
isEnqueuable(const Object * reference)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  */
enqueueReference(Object * ref)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  */
preserveSomeSoftReferences(Object ** list)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  */
clearWhiteReferences(Object ** list)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  */
enqueueFinalizerReferences(Object ** list)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  */
dvmSetFinalizable(Object * obj)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  */
dvmHeapProcessReferences(Object ** softReferences,bool clearSoftRefs,Object ** weakReferences,Object ** finalizerReferences,Object ** phantomReferences)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  */
dvmEnqueueClearedReferences(Object ** cleared)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 
dvmHeapFinishMarkStep()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 
sweepBitmapCallback(size_t numPtrs,void ** ptrs,void * arg)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  */
isUnmarkedObject(void * obj)882 static int isUnmarkedObject(void *obj)
883 {
884     return !isMarked((Object *)obj, &gDvm.gcHeap->markContext);
885 }
886 
sweepWeakJniGlobals()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  */
dvmHeapSweepSystemWeaks()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  */
dvmHeapSweepUnmarkedObjects(bool isPartial,bool isConcurrent,size_t * numObjects,size_t * numBytes)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