blob: 4070f487344034c10baae9dfdabace951608da75 [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 */
Carl Shapiro6343bd02010-02-16 17:40:19 -080077static inline long isMarked(const void *obj, const GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080078 __attribute__((always_inline));
Carl Shapiro6343bd02010-02-16 17:40:19 -080079static inline long isMarked(const void *obj, const GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080080{
Carl Shapiro6343bd02010-02-16 17:40:19 -080081 return dvmHeapBitmapIsObjectBitSetInList(ctx->bitmaps, ctx->numBitmaps, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080082}
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
Carl Shapiro6343bd02010-02-16 17:40:19 -0800168static long setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800169 __attribute__((always_inline));
170static long
Carl Shapiro6343bd02010-02-16 17:40:19 -0800171setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800172{
173 return dvmHeapBitmapSetAndReturnObjectBitInList(ctx->bitmaps,
Carl Shapiro6343bd02010-02-16 17:40:19 -0800174 ctx->numBitmaps, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800175}
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{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800184 assert(obj != NULL);
185
186#if GC_DEBUG(GC_DEBUG_PARANOID)
187//TODO: make sure we're locked
188 assert(obj != (Object *)gDvm.unlinkedJavaLangClass);
189 assert(dvmIsValidObject(obj));
190#endif
191
Carl Shapiro6343bd02010-02-16 17:40:19 -0800192 if (!setAndReturnMarkBit(ctx, obj)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800193 /* This object was not previously marked.
194 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800195 if (forceStack || (checkFinger && (void *)obj < ctx->finger)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800196 /* This object will need to go on the mark stack.
197 */
198 MARK_STACK_PUSH(ctx->stack, obj);
199 }
200
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800201#if WITH_HPROF
202 if (gDvm.gcHeap->hprofContext != NULL) {
203 hprofMarkRootObject(gDvm.gcHeap->hprofContext, obj, 0);
204 }
205#endif
206#if DVM_TRACK_HEAP_MARKING
207 gDvm.gcHeap->markCount++;
Carl Shapiro6343bd02010-02-16 17:40:19 -0800208 gDvm.gcHeap->markSize += dvmHeapSourceChunkSize((void *)obj) +
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800209 HEAP_SOURCE_CHUNK_OVERHEAD;
210#endif
211
212 /* obj->clazz can be NULL if we catch an object between
213 * dvmMalloc() and DVM_OBJECT_INIT(). This is ok.
214 */
215 LOGV_MARK("0x%08x %s\n", (uint)obj,
216 obj->clazz == NULL ? "<null class>" : obj->clazz->name);
217 }
218}
219
220/* Used to mark objects when recursing. Recursion is done by moving
221 * the finger across the bitmaps in address order and marking child
222 * objects. Any newly-marked objects whose addresses are lower than
223 * the finger won't be visited by the bitmap scan, so those objects
224 * need to be added to the mark stack.
225 */
226static void
227markObjectNonNull(const Object *obj, GcMarkContext *ctx)
228{
229 _markObjectNonNullCommon(obj, ctx, true, false);
230}
231
232#define markObject(obj, ctx) \
233 do { \
234 Object *MO_obj_ = (Object *)(obj); \
235 if (MO_obj_ != NULL) { \
236 markObjectNonNull(MO_obj_, (ctx)); \
237 } \
238 } while (false)
239
240/* If the object hasn't already been marked, mark it and
241 * schedule it to be scanned for references.
242 *
243 * obj may not be NULL. The macro dvmMarkObject() should
244 * be used in situations where a reference may be NULL.
245 *
246 * This function may only be called when marking the root
247 * set. When recursing, use the internal markObject[NonNull]().
248 */
249void
250dvmMarkObjectNonNull(const Object *obj)
251{
252 _markObjectNonNullCommon(obj, &gDvm.gcHeap->markContext, false, false);
253}
254
255/* Mark the set of root objects.
256 *
257 * Things we need to scan:
258 * - System classes defined by root classloader
259 * - For each thread:
260 * - Interpreted stack, from top to "curFrame"
261 * - Dalvik registers (args + local vars)
262 * - JNI local references
263 * - Automatic VM local references (TrackedAlloc)
264 * - Associated Thread/VMThread object
265 * - ThreadGroups (could track & start with these instead of working
266 * upward from Threads)
267 * - Exception currently being thrown, if present
268 * - JNI global references
269 * - Interned string table
270 * - Primitive classes
271 * - Special objects
272 * - gDvm.outOfMemoryObj
273 * - Objects allocated with ALLOC_NO_GC
274 * - Objects pending finalization (but not yet finalized)
275 * - Objects in debugger object registry
276 *
277 * Don't need:
278 * - Native stack (for in-progress stuff in the VM)
279 * - The TrackedAlloc stuff watches all native VM references.
280 */
281void dvmHeapMarkRootSet()
282{
283 HeapRefTable *refs;
284 GcHeap *gcHeap;
285 Object **op;
286
287 gcHeap = gDvm.gcHeap;
288
289 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_STICKY_CLASS, 0);
290
291 LOG_SCAN("root class loader\n");
292 dvmGcScanRootClassLoader();
293 LOG_SCAN("primitive classes\n");
294 dvmGcScanPrimitiveClasses();
295
296 /* dvmGcScanRootThreadGroups() sets a bunch of
297 * different scan states internally.
298 */
299 HPROF_CLEAR_GC_SCAN_STATE();
300
301 LOG_SCAN("root thread groups\n");
302 dvmGcScanRootThreadGroups();
303
304 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_INTERNED_STRING, 0);
305
306 LOG_SCAN("interned strings\n");
307 dvmGcScanInternedStrings();
308
309 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_GLOBAL, 0);
310
311 LOG_SCAN("JNI global refs\n");
312 dvmGcMarkJniGlobalRefs();
313
314 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
315
316 LOG_SCAN("pending reference operations\n");
317 dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations, true);
318
319 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
320
321 LOG_SCAN("pending finalizations\n");
322 dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs, false);
323
324 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_DEBUGGER, 0);
325
326 LOG_SCAN("debugger refs\n");
327 dvmGcMarkDebuggerRefs();
328
329 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_VM_INTERNAL, 0);
330
331 /* Mark all ALLOC_NO_GC objects.
332 */
333 LOG_SCAN("ALLOC_NO_GC objects\n");
334 refs = &gcHeap->nonCollectableRefs;
335 op = refs->table;
336 while ((uintptr_t)op < (uintptr_t)refs->nextEntry) {
337 dvmMarkObjectNonNull(*(op++));
338 }
339
340 /* Mark any special objects we have sitting around.
341 */
342 LOG_SCAN("special objects\n");
343 dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
344 dvmMarkObjectNonNull(gDvm.internalErrorObj);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700345 dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
Andy McFaddenb18992f2009-09-25 10:42:15 -0700346 dvmMarkObject(gDvm.jniWeakGlobalRefQueue);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800347//TODO: scan object references sitting in gDvm; use pointer begin & end
348
349 HPROF_CLEAR_GC_SCAN_STATE();
350}
351
352/*
353 * Nothing past this point is allowed to use dvmMarkObject*().
354 * Scanning/recursion must use markObject*(), which takes the
355 * finger into account.
356 */
357#define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
358
359
360/* Mark all of a ClassObject's interfaces.
361 */
362static void markInterfaces(const ClassObject *clazz, GcMarkContext *ctx)
363{
364 ClassObject **interfaces;
365 int interfaceCount;
366 int i;
367
368 /* Mark all interfaces.
369 */
370 interfaces = clazz->interfaces;
371 interfaceCount = clazz->interfaceCount;
372 for (i = 0; i < interfaceCount; i++) {
373 markObjectNonNull((Object *)*interfaces, ctx);
374 interfaces++;
375 }
376}
377
378/* Mark all objects referred to by a ClassObject's static fields.
379 */
380static void scanStaticFields(const ClassObject *clazz, GcMarkContext *ctx)
381{
382 StaticField *f;
383 int i;
384
385 //TODO: Optimize this with a bit vector or something
386 f = clazz->sfields;
387 for (i = 0; i < clazz->sfieldCount; i++) {
388 char c = f->field.signature[0];
389 if (c == '[' || c == 'L') {
390 /* It's an array or class reference.
391 */
392 markObject((Object *)f->value.l, ctx);
393 }
394 f++;
395 }
396}
397
398/* Mark all objects referred to by a DataObject's instance fields.
399 */
400static void scanInstanceFields(const DataObject *obj, ClassObject *clazz,
401 GcMarkContext *ctx)
402{
Barry Hayesd1497482009-10-28 15:32:19 -0700403 if (clazz->refOffsets != CLASS_WALK_SUPER) {
Barry Hayeseac47ed2009-06-22 11:45:20 -0700404 unsigned int refOffsets = clazz->refOffsets;
405 while (refOffsets != 0) {
406 const int rshift = CLZ(refOffsets);
407 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
408 markObject(dvmGetFieldObject((Object*)obj,
409 CLASS_OFFSET_FROM_CLZ(rshift)), ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800410 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700411 } else {
412 while (clazz != NULL) {
413 InstField *f;
414 int i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800415
Barry Hayeseac47ed2009-06-22 11:45:20 -0700416 /* All of the fields that contain object references
417 * are guaranteed to be at the beginning of the ifields list.
418 */
419 f = clazz->ifields;
420 for (i = 0; i < clazz->ifieldRefCount; i++) {
421 /* Mark the array or object reference.
422 * May be NULL.
423 *
424 * Note that, per the comment on struct InstField,
425 * f->byteOffset is the offset from the beginning of
426 * obj, not the offset into obj->instanceData.
427 */
428 markObject(dvmGetFieldObject((Object*)obj, f->byteOffset), ctx);
429 f++;
430 }
431
432 /* This will be NULL when we hit java.lang.Object
433 */
434 clazz = clazz->super;
435 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800436 }
437}
438
439/* Mark all objects referred to by the array's contents.
440 */
441static void scanObjectArray(const ArrayObject *array, GcMarkContext *ctx)
442{
443 Object **contents;
444 u4 length;
445 u4 i;
446
447 contents = (Object **)array->contents;
448 length = array->length;
449
450 for (i = 0; i < length; i++) {
451 markObject(*contents, ctx); // may be NULL
452 contents++;
453 }
454}
455
456/* Mark all objects referred to by the ClassObject.
457 */
458static void scanClassObject(const ClassObject *clazz, GcMarkContext *ctx)
459{
460 LOGV_SCAN("---------> %s\n", clazz->name);
461
462 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
463 /* We're an array; mark the class object of the contents
464 * of the array.
465 *
466 * Note that we won't necessarily reach the array's element
467 * class by scanning the array contents; the array may be
468 * zero-length, or may only contain null objects.
469 */
470 markObjectNonNull((Object *)clazz->elementClass, ctx);
471 }
472
473 /* We scan these explicitly in case the only remaining
474 * reference to a particular class object is via a data
475 * object; we may not be guaranteed to reach all
476 * live class objects via a classloader.
477 */
478 markObject((Object *)clazz->super, ctx); // may be NULL (java.lang.Object)
479 markObject(clazz->classLoader, ctx); // may be NULL
480
481 scanStaticFields(clazz, ctx);
482 markInterfaces(clazz, ctx);
483}
484
485/* Mark all objects that obj refers to.
486 *
487 * Called on every object in markList.
488 */
489static void scanObject(const Object *obj, GcMarkContext *ctx)
490{
491 ClassObject *clazz;
492
493 assert(dvmIsValidObject(obj));
494 LOGV_SCAN("0x%08x %s\n", (uint)obj, obj->clazz->name);
495
496#if WITH_HPROF
497 if (gDvm.gcHeap->hprofContext != NULL) {
498 hprofDumpHeapObject(gDvm.gcHeap->hprofContext, obj);
499 }
500#endif
501
502 /* Get and mark the class object for this particular instance.
503 */
504 clazz = obj->clazz;
505 if (clazz == NULL) {
506 /* This can happen if we catch an object between
507 * dvmMalloc() and DVM_OBJECT_INIT(). The object
508 * won't contain any references yet, so we can
509 * just skip it.
510 */
511 return;
512 } else if (clazz == gDvm.unlinkedJavaLangClass) {
513 /* This class hasn't been linked yet. We're guaranteed
514 * that the object doesn't contain any references that
515 * aren't already tracked, so we can skip scanning it.
516 *
517 * NOTE: unlinkedJavaLangClass is not on the heap, so
518 * it's very important that we don't try marking it.
519 */
520 return;
521 }
Barry Hayes3592d622009-03-16 16:10:35 -0700522
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800523 assert(dvmIsValidObject((Object *)clazz));
524 markObjectNonNull((Object *)clazz, ctx);
525
526 /* Mark any references in this object.
527 */
528 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
529 /* It's an array object.
530 */
531 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISOBJECTARRAY)) {
532 /* It's an array of object references.
533 */
534 scanObjectArray((ArrayObject *)obj, ctx);
535 }
536 // else there's nothing else to scan
537 } else {
538 /* It's a DataObject-compatible object.
539 */
540 scanInstanceFields((DataObject *)obj, clazz, ctx);
541
542 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISREFERENCE)) {
543 GcHeap *gcHeap = gDvm.gcHeap;
544 Object *referent;
545
546 /* It's a subclass of java/lang/ref/Reference.
547 * The fields in this class have been arranged
548 * such that scanInstanceFields() did not actually
549 * mark the "referent" field; we need to handle
550 * it specially.
551 *
552 * If the referent already has a strong mark (isMarked(referent)),
553 * we don't care about its reference status.
554 */
555 referent = dvmGetFieldObject(obj,
556 gDvm.offJavaLangRefReference_referent);
557 if (referent != NULL &&
Carl Shapiro6343bd02010-02-16 17:40:19 -0800558 !isMarked(referent, &gcHeap->markContext))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800559 {
560 u4 refFlags;
561
562 if (gcHeap->markAllReferents) {
563 LOG_REF("Hard-marking a reference\n");
564
565 /* Don't bother with normal reference-following
566 * behavior, just mark the referent. This should
567 * only be used when following objects that just
568 * became scheduled for finalization.
569 */
570 markObjectNonNull(referent, ctx);
571 goto skip_reference;
572 }
573
574 /* See if this reference was handled by a previous GC.
575 */
576 if (dvmGetFieldObject(obj,
577 gDvm.offJavaLangRefReference_vmData) ==
578 SCHEDULED_REFERENCE_MAGIC)
579 {
580 LOG_REF("Skipping scheduled reference\n");
581
582 /* Don't reschedule it, but make sure that its
583 * referent doesn't get collected (in case it's
584 * a PhantomReference and wasn't cleared automatically).
585 */
586 //TODO: Mark these after handling all new refs of
587 // this strength, in case the new refs refer
588 // to the same referent. Not a very common
589 // case, though.
590 markObjectNonNull(referent, ctx);
591 goto skip_reference;
592 }
593
594 /* Find out what kind of reference is pointing
595 * to referent.
596 */
597 refFlags = GET_CLASS_FLAG_GROUP(clazz,
598 CLASS_ISREFERENCE |
599 CLASS_ISWEAKREFERENCE |
600 CLASS_ISPHANTOMREFERENCE);
601
602 /* We use the vmData field of Reference objects
603 * as a next pointer in a singly-linked list.
604 * That way, we don't need to allocate any memory
605 * while we're doing a GC.
606 */
607#define ADD_REF_TO_LIST(list, ref) \
608 do { \
609 Object *ARTL_ref_ = (/*de-const*/Object *)(ref); \
610 dvmSetFieldObject(ARTL_ref_, \
611 gDvm.offJavaLangRefReference_vmData, list); \
612 list = ARTL_ref_; \
613 } while (false)
614
615 /* At this stage, we just keep track of all of
616 * the live references that we've seen. Later,
617 * we'll walk through each of these lists and
618 * deal with the referents.
619 */
620 if (refFlags == CLASS_ISREFERENCE) {
621 /* It's a soft reference. Depending on the state,
622 * we'll attempt to collect all of them, some of
623 * them, or none of them.
624 */
625 if (gcHeap->softReferenceCollectionState ==
626 SR_COLLECT_NONE)
627 {
628 sr_collect_none:
629 markObjectNonNull(referent, ctx);
630 } else if (gcHeap->softReferenceCollectionState ==
631 SR_COLLECT_ALL)
632 {
633 sr_collect_all:
634 ADD_REF_TO_LIST(gcHeap->softReferences, obj);
635 } else {
636 /* We'll only try to collect half of the
637 * referents.
638 */
639 if (gcHeap->softReferenceColor++ & 1) {
640 goto sr_collect_none;
641 }
642 goto sr_collect_all;
643 }
644 } else {
645 /* It's a weak or phantom reference.
646 * Clearing CLASS_ISREFERENCE will reveal which.
647 */
648 refFlags &= ~CLASS_ISREFERENCE;
649 if (refFlags == CLASS_ISWEAKREFERENCE) {
650 ADD_REF_TO_LIST(gcHeap->weakReferences, obj);
651 } else if (refFlags == CLASS_ISPHANTOMREFERENCE) {
652 ADD_REF_TO_LIST(gcHeap->phantomReferences, obj);
653 } else {
654 assert(!"Unknown reference type");
655 }
656 }
657#undef ADD_REF_TO_LIST
658 }
659 }
660
661 skip_reference:
662 /* If this is a class object, mark various other things that
663 * its internals point to.
664 *
665 * All class objects are instances of java.lang.Class,
666 * including the java.lang.Class class object.
667 */
668 if (clazz == gDvm.classJavaLangClass) {
669 scanClassObject((ClassObject *)obj, ctx);
670 }
671 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800672}
673
674static void
675processMarkStack(GcMarkContext *ctx)
676{
677 const Object **const base = ctx->stack.base;
678
679 /* Scan anything that's on the mark stack.
680 * We can't use the bitmaps anymore, so use
681 * a finger that points past the end of them.
682 */
683 ctx->finger = (void *)ULONG_MAX;
684 while (ctx->stack.top != base) {
685 scanObject(*ctx->stack.top++, ctx);
686 }
687}
688
689#ifndef NDEBUG
690static uintptr_t gLastFinger = 0;
691#endif
692
693static bool
694scanBitmapCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
695{
696 GcMarkContext *ctx = (GcMarkContext *)arg;
697 size_t i;
698
699#ifndef NDEBUG
700 assert((uintptr_t)finger >= gLastFinger);
701 gLastFinger = (uintptr_t)finger;
702#endif
703
704 ctx->finger = finger;
705 for (i = 0; i < numPtrs; i++) {
Carl Shapiro6343bd02010-02-16 17:40:19 -0800706 scanObject(*ptrs++, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800707 }
708
709 return true;
710}
711
712/* Given bitmaps with the root set marked, find and mark all
713 * reachable objects. When this returns, the entire set of
714 * live objects will be marked and the mark stack will be empty.
715 */
716void dvmHeapScanMarkedObjects()
717{
718 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
719
720 assert(ctx->finger == NULL);
721
722 /* The bitmaps currently have bits set for the root set.
723 * Walk across the bitmaps and scan each object.
724 */
725#ifndef NDEBUG
726 gLastFinger = 0;
727#endif
728 dvmHeapBitmapWalkList(ctx->bitmaps, ctx->numBitmaps,
729 scanBitmapCallback, ctx);
730
731 /* We've walked the mark bitmaps. Scan anything that's
732 * left on the mark stack.
733 */
734 processMarkStack(ctx);
735
736 LOG_SCAN("done with marked objects\n");
737}
738
Barry Hayes6930a112009-12-22 11:01:38 -0800739/** Clear the referent field.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800740 */
Barry Hayes6930a112009-12-22 11:01:38 -0800741static void clearReference(Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800742{
743 /* This is what the default implementation of Reference.clear()
744 * does. We're required to clear all references to a given
745 * referent atomically, so we can't pop in and out of interp
746 * code each time.
747 *
Barry Hayes6930a112009-12-22 11:01:38 -0800748 * We don't ever actaully call overriding implementations of
749 * Reference.clear().
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800750 */
751 dvmSetFieldObject(reference,
752 gDvm.offJavaLangRefReference_referent, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800753}
754
755/** @return true if we need to schedule a call to enqueue().
756 */
757static bool enqueueReference(Object *reference)
758{
Barry Hayes6930a112009-12-22 11:01:38 -0800759 Object *queue = dvmGetFieldObject(reference,
760 gDvm.offJavaLangRefReference_queue);
761 Object *queueNext = dvmGetFieldObject(reference,
762 gDvm.offJavaLangRefReference_queueNext);
763 if (queue == NULL || queueNext != NULL) {
764 /* There is no queue, or the reference has already
765 * been enqueued. The Reference.enqueue() method
766 * will do nothing even if we call it.
767 */
768 return false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800769 }
770
771 /* We need to call enqueue(), but if we called it from
772 * here we'd probably deadlock. Schedule a call.
773 */
774 return true;
775}
776
777/* All objects for stronger reference levels have been
778 * marked before this is called.
779 */
780void dvmHeapHandleReferences(Object *refListHead, enum RefType refType)
781{
782 Object *reference;
783 GcMarkContext *markContext = &gDvm.gcHeap->markContext;
784 const int offVmData = gDvm.offJavaLangRefReference_vmData;
785 const int offReferent = gDvm.offJavaLangRefReference_referent;
786 bool workRequired = false;
787
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800788 reference = refListHead;
789 while (reference != NULL) {
790 Object *next;
791 Object *referent;
792
793 /* Pull the interesting fields out of the Reference object.
794 */
795 next = dvmGetFieldObject(reference, offVmData);
796 referent = dvmGetFieldObject(reference, offReferent);
797
798 //TODO: when handling REF_PHANTOM, unlink any references
799 // that fail this initial if(). We need to re-walk
800 // the list, and it would be nice to avoid the extra
801 // work.
Carl Shapiro6343bd02010-02-16 17:40:19 -0800802 if (referent != NULL && !isMarked(referent, markContext)) {
Barry Hayes6930a112009-12-22 11:01:38 -0800803 bool schedEnqueue;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800804
805 /* This is the strongest reference that refers to referent.
806 * Do the right thing.
807 */
808 switch (refType) {
809 case REF_SOFT:
810 case REF_WEAK:
Barry Hayes6930a112009-12-22 11:01:38 -0800811 clearReference(reference);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800812 schedEnqueue = enqueueReference(reference);
813 break;
814 case REF_PHANTOM:
815 /* PhantomReferences are not cleared automatically.
816 * Until someone clears it (or the reference itself
817 * is collected), the referent must remain alive.
818 *
819 * It's necessary to fully mark the referent because
820 * it will still be present during the next GC, and
821 * all objects that it points to must be valid.
822 * (The referent will be marked outside of this loop,
823 * after handing all references of this strength, in
824 * case multiple references point to the same object.)
Andy McFaddenb18992f2009-09-25 10:42:15 -0700825 *
826 * One exception: JNI "weak global" references are handled
827 * as a special case. They're identified by the queue.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800828 */
Andy McFaddenb18992f2009-09-25 10:42:15 -0700829 if (gDvm.jniWeakGlobalRefQueue != NULL) {
830 Object* queue = dvmGetFieldObject(reference,
831 gDvm.offJavaLangRefReference_queue);
832 if (queue == gDvm.jniWeakGlobalRefQueue) {
833 LOGV("+++ WGR: clearing + not queueing %p:%p\n",
834 reference, referent);
Barry Hayes6930a112009-12-22 11:01:38 -0800835 clearReference(reference);
Andy McFaddenb18992f2009-09-25 10:42:15 -0700836 schedEnqueue = false;
837 break;
838 }
839 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800840
841 /* A PhantomReference is only useful with a
842 * queue, but since it's possible to create one
843 * without a queue, we need to check.
844 */
845 schedEnqueue = enqueueReference(reference);
846 break;
847 default:
848 assert(!"Bad reference type");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800849 schedEnqueue = false;
850 break;
851 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800852
Barry Hayes6930a112009-12-22 11:01:38 -0800853 if (schedEnqueue) {
Barry Hayes6930a112009-12-22 11:01:38 -0800854 /* Stuff the enqueue bit in the bottom of the pointer.
855 * Assumes that objects are 8-byte aligned.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800856 *
857 * Note that we are adding the *Reference* (which
858 * is by definition already marked at this point) to
859 * this list; we're not adding the referent (which
860 * has already been cleared).
861 */
862 assert(((intptr_t)reference & 3) == 0);
Barry Hayes6930a112009-12-22 11:01:38 -0800863 assert((WORKER_ENQUEUE & ~3) == 0);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800864 if (!dvmHeapAddRefToLargeTable(
865 &gDvm.gcHeap->referenceOperations,
Barry Hayes6930a112009-12-22 11:01:38 -0800866 (Object *)((uintptr_t)reference | WORKER_ENQUEUE)))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800867 {
868 LOGE_HEAP("dvmMalloc(): no room for any more "
869 "reference operations\n");
870 dvmAbort();
871 }
872 workRequired = true;
873 }
874
875 if (refType != REF_PHANTOM) {
876 /* Let later GCs know not to reschedule this reference.
877 */
878 dvmSetFieldObject(reference, offVmData,
879 SCHEDULED_REFERENCE_MAGIC);
880 } // else this is handled later for REF_PHANTOM
881
882 } // else there was a stronger reference to the referent.
883
884 reference = next;
885 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800886
887 /* Walk though the reference list again, and mark any non-clear/marked
888 * referents. Only PhantomReferences can have non-clear referents
889 * at this point.
Andy McFaddenb18992f2009-09-25 10:42:15 -0700890 *
891 * (Could skip this for JNI weak globals, since we know they've been
892 * cleared.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800893 */
894 if (refType == REF_PHANTOM) {
895 bool scanRequired = false;
896
897 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
898 reference = refListHead;
899 while (reference != NULL) {
900 Object *next;
901 Object *referent;
902
903 /* Pull the interesting fields out of the Reference object.
904 */
905 next = dvmGetFieldObject(reference, offVmData);
906 referent = dvmGetFieldObject(reference, offReferent);
907
Carl Shapiro6343bd02010-02-16 17:40:19 -0800908 if (referent != NULL && !isMarked(referent, markContext)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800909 markObjectNonNull(referent, markContext);
910 scanRequired = true;
911
912 /* Let later GCs know not to reschedule this reference.
913 */
914 dvmSetFieldObject(reference, offVmData,
915 SCHEDULED_REFERENCE_MAGIC);
916 }
917
918 reference = next;
919 }
920 HPROF_CLEAR_GC_SCAN_STATE();
921
922 if (scanRequired) {
923 processMarkStack(markContext);
924 }
925 }
926
927 if (workRequired) {
928 dvmSignalHeapWorker(false);
929 }
930}
931
932
933/* Find unreachable objects that need to be finalized,
934 * and schedule them for finalization.
935 */
936void dvmHeapScheduleFinalizations()
937{
938 HeapRefTable newPendingRefs;
939 LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
940 Object **ref;
941 Object **lastRef;
942 size_t totalPendCount;
943 GcMarkContext *markContext = &gDvm.gcHeap->markContext;
944
945 /*
946 * All reachable objects have been marked.
947 * Any unmarked finalizable objects need to be finalized.
948 */
949
950 /* Create a table that the new pending refs will
951 * be added to.
952 */
953 if (!dvmHeapInitHeapRefTable(&newPendingRefs, 128)) {
954 //TODO: mark all finalizable refs and hope that
955 // we can schedule them next time. Watch out,
956 // because we may be expecting to free up space
957 // by calling finalizers.
958 LOGE_GC("dvmHeapScheduleFinalizations(): no room for "
959 "pending finalizations\n");
960 dvmAbort();
961 }
962
963 /* Walk through finalizableRefs and move any unmarked references
964 * to the list of new pending refs.
965 */
966 totalPendCount = 0;
967 while (finRefs != NULL) {
968 Object **gapRef;
969 size_t newPendCount = 0;
970
971 gapRef = ref = finRefs->refs.table;
972 lastRef = finRefs->refs.nextEntry;
973 while (ref < lastRef) {
Carl Shapiro6343bd02010-02-16 17:40:19 -0800974 if (!isMarked(*ref, markContext)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800975 if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
976 //TODO: add the current table and allocate
977 // a new, smaller one.
978 LOGE_GC("dvmHeapScheduleFinalizations(): "
979 "no room for any more pending finalizations: %zd\n",
980 dvmHeapNumHeapRefTableEntries(&newPendingRefs));
981 dvmAbort();
982 }
983 newPendCount++;
984 } else {
985 /* This ref is marked, so will remain on finalizableRefs.
986 */
987 if (newPendCount > 0) {
988 /* Copy it up to fill the holes.
989 */
990 *gapRef++ = *ref;
991 } else {
992 /* No holes yet; don't bother copying.
993 */
994 gapRef++;
995 }
996 }
997 ref++;
998 }
999 finRefs->refs.nextEntry = gapRef;
1000 //TODO: if the table is empty when we're done, free it.
1001 totalPendCount += newPendCount;
1002 finRefs = finRefs->next;
1003 }
1004 LOGD_GC("dvmHeapScheduleFinalizations(): %zd finalizers triggered.\n",
1005 totalPendCount);
1006 if (totalPendCount == 0) {
1007 /* No objects required finalization.
1008 * Free the empty temporary table.
1009 */
1010 dvmClearReferenceTable(&newPendingRefs);
1011 return;
1012 }
1013
1014 /* Add the new pending refs to the main list.
1015 */
1016 if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
1017 &newPendingRefs))
1018 {
1019 LOGE_GC("dvmHeapScheduleFinalizations(): can't insert new "
1020 "pending finalizations\n");
1021 dvmAbort();
1022 }
1023
1024 //TODO: try compacting the main list with a memcpy loop
1025
1026 /* Mark the refs we just moved; we don't want them or their
1027 * children to get swept yet.
1028 */
1029 ref = newPendingRefs.table;
1030 lastRef = newPendingRefs.nextEntry;
1031 assert(ref < lastRef);
1032 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
1033 while (ref < lastRef) {
1034 markObjectNonNull(*ref, markContext);
1035 ref++;
1036 }
1037 HPROF_CLEAR_GC_SCAN_STATE();
1038
1039 /* Set markAllReferents so that we don't collect referents whose
1040 * only references are in final-reachable objects.
1041 * TODO: eventually provide normal reference behavior by properly
1042 * marking these references.
1043 */
1044 gDvm.gcHeap->markAllReferents = true;
1045 processMarkStack(markContext);
1046 gDvm.gcHeap->markAllReferents = false;
1047
1048 dvmSignalHeapWorker(false);
1049}
1050
1051void dvmHeapFinishMarkStep()
1052{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001053 GcMarkContext *markContext;
1054
1055 markContext = &gDvm.gcHeap->markContext;
1056
1057 /* The sweep step freed every object that appeared in the
1058 * HeapSource bitmaps that didn't appear in the mark bitmaps.
1059 * The new state of the HeapSource is exactly the final
1060 * mark bitmaps, so swap them in.
1061 *
1062 * The old bitmaps will be swapped into the context so that
1063 * we can clean them up.
1064 */
1065 dvmHeapSourceReplaceObjectBitmaps(markContext->bitmaps,
1066 markContext->numBitmaps);
1067
1068 /* Clean up the old HeapSource bitmaps and anything else associated
1069 * with the marking process.
1070 */
1071 dvmHeapBitmapDeleteList(markContext->bitmaps, markContext->numBitmaps);
1072 destroyMarkStack(&markContext->stack);
1073
1074 memset(markContext, 0, sizeof(*markContext));
1075}
1076
1077#if WITH_HPROF && WITH_HPROF_UNREACHABLE
1078static bool
1079hprofUnreachableBitmapCallback(size_t numPtrs, void **ptrs,
1080 const void *finger, void *arg)
1081{
1082 hprof_context_t *hctx = (hprof_context_t *)arg;
1083 size_t i;
1084
1085 for (i = 0; i < numPtrs; i++) {
1086 Object *obj;
1087
Carl Shapiro6343bd02010-02-16 17:40:19 -08001088 obj = (Object *)*ptrs++;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001089
1090 hprofMarkRootObject(hctx, obj, 0);
1091 hprofDumpHeapObject(hctx, obj);
1092 }
1093
1094 return true;
1095}
1096
1097static void
1098hprofDumpUnmarkedObjects(const HeapBitmap markBitmaps[],
1099 const HeapBitmap objectBitmaps[], size_t numBitmaps)
1100{
1101 hprof_context_t *hctx = gDvm.gcHeap->hprofContext;
1102 if (hctx == NULL) {
1103 return;
1104 }
1105
1106 LOGI("hprof: dumping unreachable objects\n");
1107
1108 HPROF_SET_GC_SCAN_STATE(HPROF_UNREACHABLE, 0);
1109
1110 dvmHeapBitmapXorWalkLists(markBitmaps, objectBitmaps, numBitmaps,
1111 hprofUnreachableBitmapCallback, hctx);
1112
1113 HPROF_CLEAR_GC_SCAN_STATE();
1114}
1115#endif
1116
1117static bool
1118sweepBitmapCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
1119{
1120 const ClassObject *const classJavaLangClass = gDvm.classJavaLangClass;
Barry Hayes5cbb2302010-02-02 14:07:37 -08001121 const bool overwriteFree = gDvm.overwriteFree;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001122 size_t i;
Barry Hayesdde8ab02009-05-20 12:10:36 -07001123 void **origPtrs = ptrs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001124
1125 for (i = 0; i < numPtrs; i++) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001126 Object *obj;
1127
Carl Shapiro6343bd02010-02-16 17:40:19 -08001128 obj = (Object *)*ptrs++;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001129
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001130 /* NOTE: Dereferencing clazz is dangerous. If obj was the last
1131 * one to reference its class object, the class object could be
1132 * on the sweep list, and could already have been swept, leaving
1133 * us with a stale pointer.
1134 */
1135 LOGV_SWEEP("FREE: 0x%08x %s\n", (uint)obj, obj->clazz->name);
1136
1137 /* This assumes that java.lang.Class will never go away.
1138 * If it can, and we were the last reference to it, it
1139 * could have already been swept. However, even in that case,
1140 * gDvm.classJavaLangClass should still have a useful
1141 * value.
1142 */
1143 if (obj->clazz == classJavaLangClass) {
1144 LOGV_SWEEP("---------------> %s\n", ((ClassObject *)obj)->name);
1145 /* dvmFreeClassInnards() may have already been called,
1146 * but it's safe to call on the same ClassObject twice.
1147 */
1148 dvmFreeClassInnards((ClassObject *)obj);
1149 }
1150
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001151 /* Overwrite the to-be-freed object to make stale references
1152 * more obvious.
1153 */
Barry Hayes5cbb2302010-02-02 14:07:37 -08001154 if (overwriteFree) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001155 int chunklen;
1156 ClassObject *clazz = obj->clazz;
Carl Shapiro6343bd02010-02-16 17:40:19 -08001157 chunklen = dvmHeapSourceChunkSize(obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001158 memset(hc, 0xa5, chunklen);
1159 obj->clazz = (ClassObject *)((uintptr_t)clazz ^ 0xffffffff);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001160 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001161 }
Barry Hayesdde8ab02009-05-20 12:10:36 -07001162 // TODO: dvmHeapSourceFreeList has a loop, just like the above
1163 // does. Consider collapsing the two loops to save overhead.
1164 dvmHeapSourceFreeList(numPtrs, origPtrs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001165
1166 return true;
1167}
1168
Carl Shapiro5a6071b2010-01-07 21:35:50 -08001169/* Returns true if the given object is unmarked. Ignores the low bits
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001170 * of the pointer because the intern table may set them.
1171 */
1172static int isUnmarkedObject(void *object)
1173{
Carl Shapiro6343bd02010-02-16 17:40:19 -08001174 return !isMarked((void *)((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001175 &gDvm.gcHeap->markContext);
1176}
1177
1178/* Walk through the list of objects that haven't been
1179 * marked and free them.
1180 */
1181void
1182dvmHeapSweepUnmarkedObjects(int *numFreed, size_t *sizeFreed)
1183{
1184 const HeapBitmap *markBitmaps;
1185 const GcMarkContext *markContext;
1186 HeapBitmap objectBitmaps[HEAP_SOURCE_MAX_HEAP_COUNT];
1187 size_t origObjectsAllocated;
1188 size_t origBytesAllocated;
1189 size_t numBitmaps;
1190
1191 /* All reachable objects have been marked.
1192 * Detach any unreachable interned strings before
1193 * we sweep.
1194 */
1195 dvmGcDetachDeadInternedStrings(isUnmarkedObject);
1196
1197 /* Free any known objects that are not marked.
1198 */
1199 origObjectsAllocated = dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0);
1200 origBytesAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
1201
1202 markContext = &gDvm.gcHeap->markContext;
1203 markBitmaps = markContext->bitmaps;
1204 numBitmaps = dvmHeapSourceGetObjectBitmaps(objectBitmaps,
1205 HEAP_SOURCE_MAX_HEAP_COUNT);
1206#ifndef NDEBUG
1207 if (numBitmaps != markContext->numBitmaps) {
1208 LOGE("heap bitmap count mismatch: %zd != %zd\n",
1209 numBitmaps, markContext->numBitmaps);
1210 dvmAbort();
1211 }
1212#endif
1213
1214#if WITH_HPROF && WITH_HPROF_UNREACHABLE
1215 hprofDumpUnmarkedObjects(markBitmaps, objectBitmaps, numBitmaps);
1216#endif
1217
Carl Shapiro5a6071b2010-01-07 21:35:50 -08001218 dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
1219
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001220 dvmHeapBitmapXorWalkLists(markBitmaps, objectBitmaps, numBitmaps,
1221 sweepBitmapCallback, NULL);
1222
1223 *numFreed = origObjectsAllocated -
1224 dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0);
1225 *sizeFreed = origBytesAllocated -
1226 dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
1227
1228#ifdef WITH_PROFILER
1229 if (gDvm.allocProf.enabled) {
1230 gDvm.allocProf.freeCount += *numFreed;
1231 gDvm.allocProf.freeSize += *sizeFreed;
1232 }
1233#endif
1234}