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