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