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