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