blob: 979209b48440fe288d55ac0bf3f85de8bdd6d9bd [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
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"
Barry Hayeseac47ed2009-06-22 11:45:20 -070018#include "alloc/clz.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080019#include "alloc/HeapBitmap.h"
20#include "alloc/HeapInternal.h"
21#include "alloc/HeapSource.h"
22#include "alloc/MarkSweep.h"
23#include <limits.h> // for ULONG_MAX
24#include <sys/mman.h> // for madvise(), mmap()
25#include <cutils/ashmem.h>
The Android Open Source Project99409882009-03-18 22:20:24 -070026#include <errno.h>
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080027
28#define GC_DEBUG_PARANOID 2
29#define GC_DEBUG_BASIC 1
30#define GC_DEBUG_OFF 0
31#define GC_DEBUG(l) (GC_DEBUG_LEVEL >= (l))
32
33#if 1
34#define GC_DEBUG_LEVEL GC_DEBUG_PARANOID
35#else
36#define GC_DEBUG_LEVEL GC_DEBUG_OFF
37#endif
38
39#define VERBOSE_GC 0
40
41#define GC_LOG_TAG LOG_TAG "-gc"
42
43#if LOG_NDEBUG
44#define LOGV_GC(...) ((void)0)
45#define LOGD_GC(...) ((void)0)
46#else
47#define LOGV_GC(...) LOG(LOG_VERBOSE, GC_LOG_TAG, __VA_ARGS__)
48#define LOGD_GC(...) LOG(LOG_DEBUG, GC_LOG_TAG, __VA_ARGS__)
49#endif
50
51#if VERBOSE_GC
52#define LOGVV_GC(...) LOGV_GC(__VA_ARGS__)
53#else
54#define LOGVV_GC(...) ((void)0)
55#endif
56
57#define LOGI_GC(...) LOG(LOG_INFO, GC_LOG_TAG, __VA_ARGS__)
58#define LOGW_GC(...) LOG(LOG_WARN, GC_LOG_TAG, __VA_ARGS__)
59#define LOGE_GC(...) LOG(LOG_ERROR, GC_LOG_TAG, __VA_ARGS__)
60
61#define LOG_SCAN(...) LOGV_GC("SCAN: " __VA_ARGS__)
62#define LOG_MARK(...) LOGV_GC("MARK: " __VA_ARGS__)
63#define LOG_SWEEP(...) LOGV_GC("SWEEP: " __VA_ARGS__)
64#define LOG_REF(...) LOGV_GC("REF: " __VA_ARGS__)
65
66#define LOGV_SCAN(...) LOGVV_GC("SCAN: " __VA_ARGS__)
67#define LOGV_MARK(...) LOGVV_GC("MARK: " __VA_ARGS__)
68#define LOGV_SWEEP(...) LOGVV_GC("SWEEP: " __VA_ARGS__)
69#define LOGV_REF(...) LOGVV_GC("REF: " __VA_ARGS__)
70
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080071#define ALIGN_UP_TO_PAGE_SIZE(p) \
Andy McFadden96516932009-10-28 17:39:02 -070072 (((size_t)(p) + (SYSTEM_PAGE_SIZE - 1)) & ~(SYSTEM_PAGE_SIZE - 1))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080073
74/* Do not cast the result of this to a boolean; the only set bit
75 * may be > 1<<8.
76 */
77static inline long isMarked(const DvmHeapChunk *hc, const GcMarkContext *ctx)
78 __attribute__((always_inline));
79static inline long isMarked(const DvmHeapChunk *hc, const GcMarkContext *ctx)
80{
81 return dvmHeapBitmapIsObjectBitSetInList(ctx->bitmaps, ctx->numBitmaps, hc);
82}
83
84static bool
85createMarkStack(GcMarkStack *stack)
86{
87 const Object **limit;
88 size_t size;
The Android Open Source Project99409882009-03-18 22:20:24 -070089 int fd, err;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080090
91 /* Create a stack big enough for the worst possible case,
92 * where the heap is perfectly full of the smallest object.
93 * TODO: be better about memory usage; use a smaller stack with
94 * overflow detection and recovery.
95 */
96 size = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
97 (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
98 size = ALIGN_UP_TO_PAGE_SIZE(size);
99 fd = ashmem_create_region("dalvik-heap-markstack", size);
100 if (fd < 0) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700101 LOGE_GC("Could not create %d-byte ashmem mark stack: %s\n",
102 size, strerror(errno));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800103 return false;
104 }
105 limit = (const Object **)mmap(NULL, size, PROT_READ | PROT_WRITE,
106 MAP_PRIVATE, fd, 0);
The Android Open Source Project99409882009-03-18 22:20:24 -0700107 err = errno;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800108 close(fd);
109 if (limit == MAP_FAILED) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700110 LOGE_GC("Could not mmap %d-byte ashmem mark stack: %s\n",
111 size, strerror(err));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800112 return false;
113 }
114
115 memset(stack, 0, sizeof(*stack));
116 stack->limit = limit;
117 stack->base = (const Object **)((uintptr_t)limit + size);
118 stack->top = stack->base;
119
120 return true;
121}
122
123static void
124destroyMarkStack(GcMarkStack *stack)
125{
126 munmap((char *)stack->limit,
127 (uintptr_t)stack->base - (uintptr_t)stack->limit);
128 memset(stack, 0, sizeof(*stack));
129}
130
131#define MARK_STACK_PUSH(stack, obj) \
132 do { \
133 *--(stack).top = (obj); \
134 } while (false)
135
136bool
137dvmHeapBeginMarkStep()
138{
139 GcMarkContext *mc = &gDvm.gcHeap->markContext;
140 HeapBitmap objectBitmaps[HEAP_SOURCE_MAX_HEAP_COUNT];
141 size_t numBitmaps;
142
143 if (!createMarkStack(&mc->stack)) {
144 return false;
145 }
146
147 numBitmaps = dvmHeapSourceGetObjectBitmaps(objectBitmaps,
148 HEAP_SOURCE_MAX_HEAP_COUNT);
149 if (numBitmaps <= 0) {
150 return false;
151 }
152
153 /* Create mark bitmaps that cover the same ranges as the
154 * current object bitmaps.
155 */
156 if (!dvmHeapBitmapInitListFromTemplates(mc->bitmaps, objectBitmaps,
157 numBitmaps, "mark"))
158 {
159 return false;
160 }
161
162 mc->numBitmaps = numBitmaps;
163 mc->finger = NULL;
164
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800165 return true;
166}
167
168static long setAndReturnMarkBit(GcMarkContext *ctx, const DvmHeapChunk *hc)
169 __attribute__((always_inline));
170static long
171setAndReturnMarkBit(GcMarkContext *ctx, const DvmHeapChunk *hc)
172{
173 return dvmHeapBitmapSetAndReturnObjectBitInList(ctx->bitmaps,
174 ctx->numBitmaps, hc);
175}
176
177static void _markObjectNonNullCommon(const Object *obj, GcMarkContext *ctx,
178 bool checkFinger, bool forceStack)
179 __attribute__((always_inline));
180static void
181_markObjectNonNullCommon(const Object *obj, GcMarkContext *ctx,
182 bool checkFinger, bool forceStack)
183{
184 DvmHeapChunk *hc;
185
186 assert(obj != NULL);
187
188#if GC_DEBUG(GC_DEBUG_PARANOID)
189//TODO: make sure we're locked
190 assert(obj != (Object *)gDvm.unlinkedJavaLangClass);
191 assert(dvmIsValidObject(obj));
192#endif
193
194 hc = ptr2chunk(obj);
195 if (!setAndReturnMarkBit(ctx, hc)) {
196 /* This object was not previously marked.
197 */
198 if (forceStack || (checkFinger && (void *)hc < ctx->finger)) {
199 /* This object will need to go on the mark stack.
200 */
201 MARK_STACK_PUSH(ctx->stack, obj);
202 }
203
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800204#if WITH_HPROF
205 if (gDvm.gcHeap->hprofContext != NULL) {
206 hprofMarkRootObject(gDvm.gcHeap->hprofContext, obj, 0);
207 }
208#endif
209#if DVM_TRACK_HEAP_MARKING
210 gDvm.gcHeap->markCount++;
211 gDvm.gcHeap->markSize += dvmHeapSourceChunkSize((void *)hc) +
212 HEAP_SOURCE_CHUNK_OVERHEAD;
213#endif
214
215 /* obj->clazz can be NULL if we catch an object between
216 * dvmMalloc() and DVM_OBJECT_INIT(). This is ok.
217 */
218 LOGV_MARK("0x%08x %s\n", (uint)obj,
219 obj->clazz == NULL ? "<null class>" : obj->clazz->name);
220 }
221}
222
223/* Used to mark objects when recursing. Recursion is done by moving
224 * the finger across the bitmaps in address order and marking child
225 * objects. Any newly-marked objects whose addresses are lower than
226 * the finger won't be visited by the bitmap scan, so those objects
227 * need to be added to the mark stack.
228 */
229static void
230markObjectNonNull(const Object *obj, GcMarkContext *ctx)
231{
232 _markObjectNonNullCommon(obj, ctx, true, false);
233}
234
235#define markObject(obj, ctx) \
236 do { \
237 Object *MO_obj_ = (Object *)(obj); \
238 if (MO_obj_ != NULL) { \
239 markObjectNonNull(MO_obj_, (ctx)); \
240 } \
241 } while (false)
242
243/* If the object hasn't already been marked, mark it and
244 * schedule it to be scanned for references.
245 *
246 * obj may not be NULL. The macro dvmMarkObject() should
247 * be used in situations where a reference may be NULL.
248 *
249 * This function may only be called when marking the root
250 * set. When recursing, use the internal markObject[NonNull]().
251 */
252void
253dvmMarkObjectNonNull(const Object *obj)
254{
255 _markObjectNonNullCommon(obj, &gDvm.gcHeap->markContext, false, false);
256}
257
258/* Mark the set of root objects.
259 *
260 * Things we need to scan:
261 * - System classes defined by root classloader
262 * - For each thread:
263 * - Interpreted stack, from top to "curFrame"
264 * - Dalvik registers (args + local vars)
265 * - JNI local references
266 * - Automatic VM local references (TrackedAlloc)
267 * - Associated Thread/VMThread object
268 * - ThreadGroups (could track & start with these instead of working
269 * upward from Threads)
270 * - Exception currently being thrown, if present
271 * - JNI global references
272 * - Interned string table
273 * - Primitive classes
274 * - Special objects
275 * - gDvm.outOfMemoryObj
276 * - Objects allocated with ALLOC_NO_GC
277 * - Objects pending finalization (but not yet finalized)
278 * - Objects in debugger object registry
279 *
280 * Don't need:
281 * - Native stack (for in-progress stuff in the VM)
282 * - The TrackedAlloc stuff watches all native VM references.
283 */
284void dvmHeapMarkRootSet()
285{
286 HeapRefTable *refs;
287 GcHeap *gcHeap;
288 Object **op;
289
290 gcHeap = gDvm.gcHeap;
291
292 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_STICKY_CLASS, 0);
293
294 LOG_SCAN("root class loader\n");
295 dvmGcScanRootClassLoader();
296 LOG_SCAN("primitive classes\n");
297 dvmGcScanPrimitiveClasses();
298
299 /* dvmGcScanRootThreadGroups() sets a bunch of
300 * different scan states internally.
301 */
302 HPROF_CLEAR_GC_SCAN_STATE();
303
304 LOG_SCAN("root thread groups\n");
305 dvmGcScanRootThreadGroups();
306
307 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_INTERNED_STRING, 0);
308
309 LOG_SCAN("interned strings\n");
310 dvmGcScanInternedStrings();
311
312 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_GLOBAL, 0);
313
314 LOG_SCAN("JNI global refs\n");
315 dvmGcMarkJniGlobalRefs();
316
317 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
318
319 LOG_SCAN("pending reference operations\n");
320 dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations, true);
321
322 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
323
324 LOG_SCAN("pending finalizations\n");
325 dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs, false);
326
327 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_DEBUGGER, 0);
328
329 LOG_SCAN("debugger refs\n");
330 dvmGcMarkDebuggerRefs();
331
332 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_VM_INTERNAL, 0);
333
334 /* Mark all ALLOC_NO_GC objects.
335 */
336 LOG_SCAN("ALLOC_NO_GC objects\n");
337 refs = &gcHeap->nonCollectableRefs;
338 op = refs->table;
339 while ((uintptr_t)op < (uintptr_t)refs->nextEntry) {
340 dvmMarkObjectNonNull(*(op++));
341 }
342
343 /* Mark any special objects we have sitting around.
344 */
345 LOG_SCAN("special objects\n");
346 dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
347 dvmMarkObjectNonNull(gDvm.internalErrorObj);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700348 dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
Andy McFaddenb18992f2009-09-25 10:42:15 -0700349 dvmMarkObject(gDvm.jniWeakGlobalRefQueue);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800350//TODO: scan object references sitting in gDvm; use pointer begin & end
351
352 HPROF_CLEAR_GC_SCAN_STATE();
353}
354
355/*
356 * Nothing past this point is allowed to use dvmMarkObject*().
357 * Scanning/recursion must use markObject*(), which takes the
358 * finger into account.
359 */
360#define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
361
362
363/* Mark all of a ClassObject's interfaces.
364 */
365static void markInterfaces(const ClassObject *clazz, GcMarkContext *ctx)
366{
367 ClassObject **interfaces;
368 int interfaceCount;
369 int i;
370
371 /* Mark all interfaces.
372 */
373 interfaces = clazz->interfaces;
374 interfaceCount = clazz->interfaceCount;
375 for (i = 0; i < interfaceCount; i++) {
376 markObjectNonNull((Object *)*interfaces, ctx);
377 interfaces++;
378 }
379}
380
381/* Mark all objects referred to by a ClassObject's static fields.
382 */
383static void scanStaticFields(const ClassObject *clazz, GcMarkContext *ctx)
384{
385 StaticField *f;
386 int i;
387
388 //TODO: Optimize this with a bit vector or something
389 f = clazz->sfields;
390 for (i = 0; i < clazz->sfieldCount; i++) {
391 char c = f->field.signature[0];
392 if (c == '[' || c == 'L') {
393 /* It's an array or class reference.
394 */
395 markObject((Object *)f->value.l, ctx);
396 }
397 f++;
398 }
399}
400
401/* Mark all objects referred to by a DataObject's instance fields.
402 */
403static void scanInstanceFields(const DataObject *obj, ClassObject *clazz,
404 GcMarkContext *ctx)
405{
Barry Hayesd1497482009-10-28 15:32:19 -0700406 if (clazz->refOffsets != CLASS_WALK_SUPER) {
Barry Hayeseac47ed2009-06-22 11:45:20 -0700407 unsigned int refOffsets = clazz->refOffsets;
408 while (refOffsets != 0) {
409 const int rshift = CLZ(refOffsets);
410 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
411 markObject(dvmGetFieldObject((Object*)obj,
412 CLASS_OFFSET_FROM_CLZ(rshift)), ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800413 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700414 } else {
415 while (clazz != NULL) {
416 InstField *f;
417 int i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800418
Barry Hayeseac47ed2009-06-22 11:45:20 -0700419 /* All of the fields that contain object references
420 * are guaranteed to be at the beginning of the ifields list.
421 */
422 f = clazz->ifields;
423 for (i = 0; i < clazz->ifieldRefCount; i++) {
424 /* Mark the array or object reference.
425 * May be NULL.
426 *
427 * Note that, per the comment on struct InstField,
428 * f->byteOffset is the offset from the beginning of
429 * obj, not the offset into obj->instanceData.
430 */
431 markObject(dvmGetFieldObject((Object*)obj, f->byteOffset), ctx);
432 f++;
433 }
434
435 /* This will be NULL when we hit java.lang.Object
436 */
437 clazz = clazz->super;
438 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800439 }
440}
441
442/* Mark all objects referred to by the array's contents.
443 */
444static void scanObjectArray(const ArrayObject *array, GcMarkContext *ctx)
445{
446 Object **contents;
447 u4 length;
448 u4 i;
449
450 contents = (Object **)array->contents;
451 length = array->length;
452
453 for (i = 0; i < length; i++) {
454 markObject(*contents, ctx); // may be NULL
455 contents++;
456 }
457}
458
459/* Mark all objects referred to by the ClassObject.
460 */
461static void scanClassObject(const ClassObject *clazz, GcMarkContext *ctx)
462{
463 LOGV_SCAN("---------> %s\n", clazz->name);
464
465 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
466 /* We're an array; mark the class object of the contents
467 * of the array.
468 *
469 * Note that we won't necessarily reach the array's element
470 * class by scanning the array contents; the array may be
471 * zero-length, or may only contain null objects.
472 */
473 markObjectNonNull((Object *)clazz->elementClass, ctx);
474 }
475
476 /* We scan these explicitly in case the only remaining
477 * reference to a particular class object is via a data
478 * object; we may not be guaranteed to reach all
479 * live class objects via a classloader.
480 */
481 markObject((Object *)clazz->super, ctx); // may be NULL (java.lang.Object)
482 markObject(clazz->classLoader, ctx); // may be NULL
483
484 scanStaticFields(clazz, ctx);
485 markInterfaces(clazz, ctx);
486}
487
488/* Mark all objects that obj refers to.
489 *
490 * Called on every object in markList.
491 */
492static void scanObject(const Object *obj, GcMarkContext *ctx)
493{
494 ClassObject *clazz;
495
496 assert(dvmIsValidObject(obj));
497 LOGV_SCAN("0x%08x %s\n", (uint)obj, obj->clazz->name);
498
499#if WITH_HPROF
500 if (gDvm.gcHeap->hprofContext != NULL) {
501 hprofDumpHeapObject(gDvm.gcHeap->hprofContext, obj);
502 }
503#endif
504
505 /* Get and mark the class object for this particular instance.
506 */
507 clazz = obj->clazz;
508 if (clazz == NULL) {
509 /* This can happen if we catch an object between
510 * dvmMalloc() and DVM_OBJECT_INIT(). The object
511 * won't contain any references yet, so we can
512 * just skip it.
513 */
514 return;
515 } else if (clazz == gDvm.unlinkedJavaLangClass) {
516 /* This class hasn't been linked yet. We're guaranteed
517 * that the object doesn't contain any references that
518 * aren't already tracked, so we can skip scanning it.
519 *
520 * NOTE: unlinkedJavaLangClass is not on the heap, so
521 * it's very important that we don't try marking it.
522 */
523 return;
524 }
Barry Hayes3592d622009-03-16 16:10:35 -0700525
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800526 assert(dvmIsValidObject((Object *)clazz));
527 markObjectNonNull((Object *)clazz, ctx);
528
529 /* Mark any references in this object.
530 */
531 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
532 /* It's an array object.
533 */
534 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISOBJECTARRAY)) {
535 /* It's an array of object references.
536 */
537 scanObjectArray((ArrayObject *)obj, ctx);
538 }
539 // else there's nothing else to scan
540 } else {
541 /* It's a DataObject-compatible object.
542 */
543 scanInstanceFields((DataObject *)obj, clazz, ctx);
544
545 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISREFERENCE)) {
546 GcHeap *gcHeap = gDvm.gcHeap;
547 Object *referent;
548
549 /* It's a subclass of java/lang/ref/Reference.
550 * The fields in this class have been arranged
551 * such that scanInstanceFields() did not actually
552 * mark the "referent" field; we need to handle
553 * it specially.
554 *
555 * If the referent already has a strong mark (isMarked(referent)),
556 * we don't care about its reference status.
557 */
558 referent = dvmGetFieldObject(obj,
559 gDvm.offJavaLangRefReference_referent);
560 if (referent != NULL &&
561 !isMarked(ptr2chunk(referent), &gcHeap->markContext))
562 {
563 u4 refFlags;
564
565 if (gcHeap->markAllReferents) {
566 LOG_REF("Hard-marking a reference\n");
567
568 /* Don't bother with normal reference-following
569 * behavior, just mark the referent. This should
570 * only be used when following objects that just
571 * became scheduled for finalization.
572 */
573 markObjectNonNull(referent, ctx);
574 goto skip_reference;
575 }
576
577 /* See if this reference was handled by a previous GC.
578 */
579 if (dvmGetFieldObject(obj,
580 gDvm.offJavaLangRefReference_vmData) ==
581 SCHEDULED_REFERENCE_MAGIC)
582 {
583 LOG_REF("Skipping scheduled reference\n");
584
585 /* Don't reschedule it, but make sure that its
586 * referent doesn't get collected (in case it's
587 * a PhantomReference and wasn't cleared automatically).
588 */
589 //TODO: Mark these after handling all new refs of
590 // this strength, in case the new refs refer
591 // to the same referent. Not a very common
592 // case, though.
593 markObjectNonNull(referent, ctx);
594 goto skip_reference;
595 }
596
597 /* Find out what kind of reference is pointing
598 * to referent.
599 */
600 refFlags = GET_CLASS_FLAG_GROUP(clazz,
601 CLASS_ISREFERENCE |
602 CLASS_ISWEAKREFERENCE |
603 CLASS_ISPHANTOMREFERENCE);
604
605 /* We use the vmData field of Reference objects
606 * as a next pointer in a singly-linked list.
607 * That way, we don't need to allocate any memory
608 * while we're doing a GC.
609 */
610#define ADD_REF_TO_LIST(list, ref) \
611 do { \
612 Object *ARTL_ref_ = (/*de-const*/Object *)(ref); \
613 dvmSetFieldObject(ARTL_ref_, \
614 gDvm.offJavaLangRefReference_vmData, list); \
615 list = ARTL_ref_; \
616 } while (false)
617
618 /* At this stage, we just keep track of all of
619 * the live references that we've seen. Later,
620 * we'll walk through each of these lists and
621 * deal with the referents.
622 */
623 if (refFlags == CLASS_ISREFERENCE) {
624 /* It's a soft reference. Depending on the state,
625 * we'll attempt to collect all of them, some of
626 * them, or none of them.
627 */
628 if (gcHeap->softReferenceCollectionState ==
629 SR_COLLECT_NONE)
630 {
631 sr_collect_none:
632 markObjectNonNull(referent, ctx);
633 } else if (gcHeap->softReferenceCollectionState ==
634 SR_COLLECT_ALL)
635 {
636 sr_collect_all:
637 ADD_REF_TO_LIST(gcHeap->softReferences, obj);
638 } else {
639 /* We'll only try to collect half of the
640 * referents.
641 */
642 if (gcHeap->softReferenceColor++ & 1) {
643 goto sr_collect_none;
644 }
645 goto sr_collect_all;
646 }
647 } else {
648 /* It's a weak or phantom reference.
649 * Clearing CLASS_ISREFERENCE will reveal which.
650 */
651 refFlags &= ~CLASS_ISREFERENCE;
652 if (refFlags == CLASS_ISWEAKREFERENCE) {
653 ADD_REF_TO_LIST(gcHeap->weakReferences, obj);
654 } else if (refFlags == CLASS_ISPHANTOMREFERENCE) {
655 ADD_REF_TO_LIST(gcHeap->phantomReferences, obj);
656 } else {
657 assert(!"Unknown reference type");
658 }
659 }
660#undef ADD_REF_TO_LIST
661 }
662 }
663
664 skip_reference:
665 /* If this is a class object, mark various other things that
666 * its internals point to.
667 *
668 * All class objects are instances of java.lang.Class,
669 * including the java.lang.Class class object.
670 */
671 if (clazz == gDvm.classJavaLangClass) {
672 scanClassObject((ClassObject *)obj, ctx);
673 }
674 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800675}
676
677static void
678processMarkStack(GcMarkContext *ctx)
679{
680 const Object **const base = ctx->stack.base;
681
682 /* Scan anything that's on the mark stack.
683 * We can't use the bitmaps anymore, so use
684 * a finger that points past the end of them.
685 */
686 ctx->finger = (void *)ULONG_MAX;
687 while (ctx->stack.top != base) {
688 scanObject(*ctx->stack.top++, ctx);
689 }
690}
691
692#ifndef NDEBUG
693static uintptr_t gLastFinger = 0;
694#endif
695
696static bool
697scanBitmapCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
698{
699 GcMarkContext *ctx = (GcMarkContext *)arg;
700 size_t i;
701
702#ifndef NDEBUG
703 assert((uintptr_t)finger >= gLastFinger);
704 gLastFinger = (uintptr_t)finger;
705#endif
706
707 ctx->finger = finger;
708 for (i = 0; i < numPtrs; i++) {
709 /* The pointers we're getting back are DvmHeapChunks,
710 * not Objects.
711 */
712 scanObject(chunk2ptr(*ptrs++), ctx);
713 }
714
715 return true;
716}
717
718/* Given bitmaps with the root set marked, find and mark all
719 * reachable objects. When this returns, the entire set of
720 * live objects will be marked and the mark stack will be empty.
721 */
722void dvmHeapScanMarkedObjects()
723{
724 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
725
726 assert(ctx->finger == NULL);
727
728 /* The bitmaps currently have bits set for the root set.
729 * Walk across the bitmaps and scan each object.
730 */
731#ifndef NDEBUG
732 gLastFinger = 0;
733#endif
734 dvmHeapBitmapWalkList(ctx->bitmaps, ctx->numBitmaps,
735 scanBitmapCallback, ctx);
736
737 /* We've walked the mark bitmaps. Scan anything that's
738 * left on the mark stack.
739 */
740 processMarkStack(ctx);
741
742 LOG_SCAN("done with marked objects\n");
743}
744
Barry Hayes6930a112009-12-22 11:01:38 -0800745/** Clear the referent field.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800746 */
Barry Hayes6930a112009-12-22 11:01:38 -0800747static void clearReference(Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800748{
749 /* This is what the default implementation of Reference.clear()
750 * does. We're required to clear all references to a given
751 * referent atomically, so we can't pop in and out of interp
752 * code each time.
753 *
Barry Hayes6930a112009-12-22 11:01:38 -0800754 * We don't ever actaully call overriding implementations of
755 * Reference.clear().
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800756 */
757 dvmSetFieldObject(reference,
758 gDvm.offJavaLangRefReference_referent, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800759}
760
761/** @return true if we need to schedule a call to enqueue().
762 */
763static bool enqueueReference(Object *reference)
764{
Barry Hayes6930a112009-12-22 11:01:38 -0800765 Object *queue = dvmGetFieldObject(reference,
766 gDvm.offJavaLangRefReference_queue);
767 Object *queueNext = dvmGetFieldObject(reference,
768 gDvm.offJavaLangRefReference_queueNext);
769 if (queue == NULL || queueNext != NULL) {
770 /* There is no queue, or the reference has already
771 * been enqueued. The Reference.enqueue() method
772 * will do nothing even if we call it.
773 */
774 return false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800775 }
776
777 /* We need to call enqueue(), but if we called it from
778 * here we'd probably deadlock. Schedule a call.
779 */
780 return true;
781}
782
783/* All objects for stronger reference levels have been
784 * marked before this is called.
785 */
786void dvmHeapHandleReferences(Object *refListHead, enum RefType refType)
787{
788 Object *reference;
789 GcMarkContext *markContext = &gDvm.gcHeap->markContext;
790 const int offVmData = gDvm.offJavaLangRefReference_vmData;
791 const int offReferent = gDvm.offJavaLangRefReference_referent;
792 bool workRequired = false;
793
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800794 reference = refListHead;
795 while (reference != NULL) {
796 Object *next;
797 Object *referent;
798
799 /* Pull the interesting fields out of the Reference object.
800 */
801 next = dvmGetFieldObject(reference, offVmData);
802 referent = dvmGetFieldObject(reference, offReferent);
803
804 //TODO: when handling REF_PHANTOM, unlink any references
805 // that fail this initial if(). We need to re-walk
806 // the list, and it would be nice to avoid the extra
807 // work.
808 if (referent != NULL && !isMarked(ptr2chunk(referent), markContext)) {
Barry Hayes6930a112009-12-22 11:01:38 -0800809 bool schedEnqueue;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800810
811 /* This is the strongest reference that refers to referent.
812 * Do the right thing.
813 */
814 switch (refType) {
815 case REF_SOFT:
816 case REF_WEAK:
Barry Hayes6930a112009-12-22 11:01:38 -0800817 clearReference(reference);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800818 schedEnqueue = enqueueReference(reference);
819 break;
820 case REF_PHANTOM:
821 /* PhantomReferences are not cleared automatically.
822 * Until someone clears it (or the reference itself
823 * is collected), the referent must remain alive.
824 *
825 * It's necessary to fully mark the referent because
826 * it will still be present during the next GC, and
827 * all objects that it points to must be valid.
828 * (The referent will be marked outside of this loop,
829 * after handing all references of this strength, in
830 * case multiple references point to the same object.)
Andy McFaddenb18992f2009-09-25 10:42:15 -0700831 *
832 * One exception: JNI "weak global" references are handled
833 * as a special case. They're identified by the queue.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800834 */
Andy McFaddenb18992f2009-09-25 10:42:15 -0700835 if (gDvm.jniWeakGlobalRefQueue != NULL) {
836 Object* queue = dvmGetFieldObject(reference,
837 gDvm.offJavaLangRefReference_queue);
838 if (queue == gDvm.jniWeakGlobalRefQueue) {
839 LOGV("+++ WGR: clearing + not queueing %p:%p\n",
840 reference, referent);
Barry Hayes6930a112009-12-22 11:01:38 -0800841 clearReference(reference);
Andy McFaddenb18992f2009-09-25 10:42:15 -0700842 schedEnqueue = false;
843 break;
844 }
845 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800846
847 /* A PhantomReference is only useful with a
848 * queue, but since it's possible to create one
849 * without a queue, we need to check.
850 */
851 schedEnqueue = enqueueReference(reference);
852 break;
853 default:
854 assert(!"Bad reference type");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800855 schedEnqueue = false;
856 break;
857 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800858
Barry Hayes6930a112009-12-22 11:01:38 -0800859 if (schedEnqueue) {
Barry Hayes6930a112009-12-22 11:01:38 -0800860 /* Stuff the enqueue bit in the bottom of the pointer.
861 * Assumes that objects are 8-byte aligned.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800862 *
863 * Note that we are adding the *Reference* (which
864 * is by definition already marked at this point) to
865 * this list; we're not adding the referent (which
866 * has already been cleared).
867 */
868 assert(((intptr_t)reference & 3) == 0);
Barry Hayes6930a112009-12-22 11:01:38 -0800869 assert((WORKER_ENQUEUE & ~3) == 0);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800870 if (!dvmHeapAddRefToLargeTable(
871 &gDvm.gcHeap->referenceOperations,
Barry Hayes6930a112009-12-22 11:01:38 -0800872 (Object *)((uintptr_t)reference | WORKER_ENQUEUE)))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800873 {
874 LOGE_HEAP("dvmMalloc(): no room for any more "
875 "reference operations\n");
876 dvmAbort();
877 }
878 workRequired = true;
879 }
880
881 if (refType != REF_PHANTOM) {
882 /* Let later GCs know not to reschedule this reference.
883 */
884 dvmSetFieldObject(reference, offVmData,
885 SCHEDULED_REFERENCE_MAGIC);
886 } // else this is handled later for REF_PHANTOM
887
888 } // else there was a stronger reference to the referent.
889
890 reference = next;
891 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800892
893 /* Walk though the reference list again, and mark any non-clear/marked
894 * referents. Only PhantomReferences can have non-clear referents
895 * at this point.
Andy McFaddenb18992f2009-09-25 10:42:15 -0700896 *
897 * (Could skip this for JNI weak globals, since we know they've been
898 * cleared.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800899 */
900 if (refType == REF_PHANTOM) {
901 bool scanRequired = false;
902
903 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
904 reference = refListHead;
905 while (reference != NULL) {
906 Object *next;
907 Object *referent;
908
909 /* Pull the interesting fields out of the Reference object.
910 */
911 next = dvmGetFieldObject(reference, offVmData);
912 referent = dvmGetFieldObject(reference, offReferent);
913
914 if (referent != NULL && !isMarked(ptr2chunk(referent), markContext)) {
915 markObjectNonNull(referent, markContext);
916 scanRequired = true;
917
918 /* Let later GCs know not to reschedule this reference.
919 */
920 dvmSetFieldObject(reference, offVmData,
921 SCHEDULED_REFERENCE_MAGIC);
922 }
923
924 reference = next;
925 }
926 HPROF_CLEAR_GC_SCAN_STATE();
927
928 if (scanRequired) {
929 processMarkStack(markContext);
930 }
931 }
932
933 if (workRequired) {
934 dvmSignalHeapWorker(false);
935 }
936}
937
938
939/* Find unreachable objects that need to be finalized,
940 * and schedule them for finalization.
941 */
942void dvmHeapScheduleFinalizations()
943{
944 HeapRefTable newPendingRefs;
945 LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
946 Object **ref;
947 Object **lastRef;
948 size_t totalPendCount;
949 GcMarkContext *markContext = &gDvm.gcHeap->markContext;
950
951 /*
952 * All reachable objects have been marked.
953 * Any unmarked finalizable objects need to be finalized.
954 */
955
956 /* Create a table that the new pending refs will
957 * be added to.
958 */
959 if (!dvmHeapInitHeapRefTable(&newPendingRefs, 128)) {
960 //TODO: mark all finalizable refs and hope that
961 // we can schedule them next time. Watch out,
962 // because we may be expecting to free up space
963 // by calling finalizers.
964 LOGE_GC("dvmHeapScheduleFinalizations(): no room for "
965 "pending finalizations\n");
966 dvmAbort();
967 }
968
969 /* Walk through finalizableRefs and move any unmarked references
970 * to the list of new pending refs.
971 */
972 totalPendCount = 0;
973 while (finRefs != NULL) {
974 Object **gapRef;
975 size_t newPendCount = 0;
976
977 gapRef = ref = finRefs->refs.table;
978 lastRef = finRefs->refs.nextEntry;
979 while (ref < lastRef) {
980 DvmHeapChunk *hc;
981
982 hc = ptr2chunk(*ref);
983 if (!isMarked(hc, markContext)) {
984 if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
985 //TODO: add the current table and allocate
986 // a new, smaller one.
987 LOGE_GC("dvmHeapScheduleFinalizations(): "
988 "no room for any more pending finalizations: %zd\n",
989 dvmHeapNumHeapRefTableEntries(&newPendingRefs));
990 dvmAbort();
991 }
992 newPendCount++;
993 } else {
994 /* This ref is marked, so will remain on finalizableRefs.
995 */
996 if (newPendCount > 0) {
997 /* Copy it up to fill the holes.
998 */
999 *gapRef++ = *ref;
1000 } else {
1001 /* No holes yet; don't bother copying.
1002 */
1003 gapRef++;
1004 }
1005 }
1006 ref++;
1007 }
1008 finRefs->refs.nextEntry = gapRef;
1009 //TODO: if the table is empty when we're done, free it.
1010 totalPendCount += newPendCount;
1011 finRefs = finRefs->next;
1012 }
1013 LOGD_GC("dvmHeapScheduleFinalizations(): %zd finalizers triggered.\n",
1014 totalPendCount);
1015 if (totalPendCount == 0) {
1016 /* No objects required finalization.
1017 * Free the empty temporary table.
1018 */
1019 dvmClearReferenceTable(&newPendingRefs);
1020 return;
1021 }
1022
1023 /* Add the new pending refs to the main list.
1024 */
1025 if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
1026 &newPendingRefs))
1027 {
1028 LOGE_GC("dvmHeapScheduleFinalizations(): can't insert new "
1029 "pending finalizations\n");
1030 dvmAbort();
1031 }
1032
1033 //TODO: try compacting the main list with a memcpy loop
1034
1035 /* Mark the refs we just moved; we don't want them or their
1036 * children to get swept yet.
1037 */
1038 ref = newPendingRefs.table;
1039 lastRef = newPendingRefs.nextEntry;
1040 assert(ref < lastRef);
1041 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
1042 while (ref < lastRef) {
1043 markObjectNonNull(*ref, markContext);
1044 ref++;
1045 }
1046 HPROF_CLEAR_GC_SCAN_STATE();
1047
1048 /* Set markAllReferents so that we don't collect referents whose
1049 * only references are in final-reachable objects.
1050 * TODO: eventually provide normal reference behavior by properly
1051 * marking these references.
1052 */
1053 gDvm.gcHeap->markAllReferents = true;
1054 processMarkStack(markContext);
1055 gDvm.gcHeap->markAllReferents = false;
1056
1057 dvmSignalHeapWorker(false);
1058}
1059
1060void dvmHeapFinishMarkStep()
1061{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001062 GcMarkContext *markContext;
1063
1064 markContext = &gDvm.gcHeap->markContext;
1065
1066 /* The sweep step freed every object that appeared in the
1067 * HeapSource bitmaps that didn't appear in the mark bitmaps.
1068 * The new state of the HeapSource is exactly the final
1069 * mark bitmaps, so swap them in.
1070 *
1071 * The old bitmaps will be swapped into the context so that
1072 * we can clean them up.
1073 */
1074 dvmHeapSourceReplaceObjectBitmaps(markContext->bitmaps,
1075 markContext->numBitmaps);
1076
1077 /* Clean up the old HeapSource bitmaps and anything else associated
1078 * with the marking process.
1079 */
1080 dvmHeapBitmapDeleteList(markContext->bitmaps, markContext->numBitmaps);
1081 destroyMarkStack(&markContext->stack);
1082
1083 memset(markContext, 0, sizeof(*markContext));
1084}
1085
1086#if WITH_HPROF && WITH_HPROF_UNREACHABLE
1087static bool
1088hprofUnreachableBitmapCallback(size_t numPtrs, void **ptrs,
1089 const void *finger, void *arg)
1090{
1091 hprof_context_t *hctx = (hprof_context_t *)arg;
1092 size_t i;
1093
1094 for (i = 0; i < numPtrs; i++) {
1095 Object *obj;
1096
1097 /* The pointers we're getting back are DvmHeapChunks, not
1098 * Objects.
1099 */
1100 obj = (Object *)chunk2ptr(*ptrs++);
1101
1102 hprofMarkRootObject(hctx, obj, 0);
1103 hprofDumpHeapObject(hctx, obj);
1104 }
1105
1106 return true;
1107}
1108
1109static void
1110hprofDumpUnmarkedObjects(const HeapBitmap markBitmaps[],
1111 const HeapBitmap objectBitmaps[], size_t numBitmaps)
1112{
1113 hprof_context_t *hctx = gDvm.gcHeap->hprofContext;
1114 if (hctx == NULL) {
1115 return;
1116 }
1117
1118 LOGI("hprof: dumping unreachable objects\n");
1119
1120 HPROF_SET_GC_SCAN_STATE(HPROF_UNREACHABLE, 0);
1121
1122 dvmHeapBitmapXorWalkLists(markBitmaps, objectBitmaps, numBitmaps,
1123 hprofUnreachableBitmapCallback, hctx);
1124
1125 HPROF_CLEAR_GC_SCAN_STATE();
1126}
1127#endif
1128
1129static bool
1130sweepBitmapCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
1131{
1132 const ClassObject *const classJavaLangClass = gDvm.classJavaLangClass;
1133 size_t i;
Barry Hayesdde8ab02009-05-20 12:10:36 -07001134 void **origPtrs = ptrs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001135
1136 for (i = 0; i < numPtrs; i++) {
1137 DvmHeapChunk *hc;
1138 Object *obj;
1139
1140 /* The pointers we're getting back are DvmHeapChunks, not
1141 * Objects.
1142 */
1143 hc = (DvmHeapChunk *)*ptrs++;
1144 obj = (Object *)chunk2ptr(hc);
1145
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001146 /* NOTE: Dereferencing clazz is dangerous. If obj was the last
1147 * one to reference its class object, the class object could be
1148 * on the sweep list, and could already have been swept, leaving
1149 * us with a stale pointer.
1150 */
1151 LOGV_SWEEP("FREE: 0x%08x %s\n", (uint)obj, obj->clazz->name);
1152
1153 /* This assumes that java.lang.Class will never go away.
1154 * If it can, and we were the last reference to it, it
1155 * could have already been swept. However, even in that case,
1156 * gDvm.classJavaLangClass should still have a useful
1157 * value.
1158 */
1159 if (obj->clazz == classJavaLangClass) {
1160 LOGV_SWEEP("---------------> %s\n", ((ClassObject *)obj)->name);
1161 /* dvmFreeClassInnards() may have already been called,
1162 * but it's safe to call on the same ClassObject twice.
1163 */
1164 dvmFreeClassInnards((ClassObject *)obj);
1165 }
1166
1167#if 0
1168 /* Overwrite the to-be-freed object to make stale references
1169 * more obvious.
1170 */
1171 {
1172 int chunklen;
1173 ClassObject *clazz = obj->clazz;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001174 chunklen = dvmHeapSourceChunkSize(hc);
1175 memset(hc, 0xa5, chunklen);
1176 obj->clazz = (ClassObject *)((uintptr_t)clazz ^ 0xffffffff);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001177 }
1178#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001179 }
Barry Hayesdde8ab02009-05-20 12:10:36 -07001180 // TODO: dvmHeapSourceFreeList has a loop, just like the above
1181 // does. Consider collapsing the two loops to save overhead.
1182 dvmHeapSourceFreeList(numPtrs, origPtrs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001183
1184 return true;
1185}
1186
Carl Shapiro5a6071b2010-01-07 21:35:50 -08001187/* Returns true if the given object is unmarked. Ignores the low bits
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001188 * of the pointer because the intern table may set them.
1189 */
1190static int isUnmarkedObject(void *object)
1191{
1192 return !isMarked(ptr2chunk((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
1193 &gDvm.gcHeap->markContext);
1194}
1195
1196/* Walk through the list of objects that haven't been
1197 * marked and free them.
1198 */
1199void
1200dvmHeapSweepUnmarkedObjects(int *numFreed, size_t *sizeFreed)
1201{
1202 const HeapBitmap *markBitmaps;
1203 const GcMarkContext *markContext;
1204 HeapBitmap objectBitmaps[HEAP_SOURCE_MAX_HEAP_COUNT];
1205 size_t origObjectsAllocated;
1206 size_t origBytesAllocated;
1207 size_t numBitmaps;
1208
1209 /* All reachable objects have been marked.
1210 * Detach any unreachable interned strings before
1211 * we sweep.
1212 */
1213 dvmGcDetachDeadInternedStrings(isUnmarkedObject);
1214
1215 /* Free any known objects that are not marked.
1216 */
1217 origObjectsAllocated = dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0);
1218 origBytesAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
1219
1220 markContext = &gDvm.gcHeap->markContext;
1221 markBitmaps = markContext->bitmaps;
1222 numBitmaps = dvmHeapSourceGetObjectBitmaps(objectBitmaps,
1223 HEAP_SOURCE_MAX_HEAP_COUNT);
1224#ifndef NDEBUG
1225 if (numBitmaps != markContext->numBitmaps) {
1226 LOGE("heap bitmap count mismatch: %zd != %zd\n",
1227 numBitmaps, markContext->numBitmaps);
1228 dvmAbort();
1229 }
1230#endif
1231
1232#if WITH_HPROF && WITH_HPROF_UNREACHABLE
1233 hprofDumpUnmarkedObjects(markBitmaps, objectBitmaps, numBitmaps);
1234#endif
1235
Carl Shapiro5a6071b2010-01-07 21:35:50 -08001236 dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
1237
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001238 dvmHeapBitmapXorWalkLists(markBitmaps, objectBitmaps, numBitmaps,
1239 sweepBitmapCallback, NULL);
1240
1241 *numFreed = origObjectsAllocated -
1242 dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0);
1243 *sizeFreed = origBytesAllocated -
1244 dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
1245
1246#ifdef WITH_PROFILER
1247 if (gDvm.allocProf.enabled) {
1248 gDvm.allocProf.freeCount += *numFreed;
1249 gDvm.allocProf.freeSize += *sizeFreed;
1250 }
1251#endif
1252}