blob: eab30ba13138e65f0f3599d5b21edf0ba662ded4 [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 Shapirof373efd2010-02-19 00:46:33 -080081 return dvmHeapBitmapIsObjectBitSet(ctx->bitmap, 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
Carl Shapirod25566d2010-03-11 20:39:47 -0800137dvmHeapBeginMarkStep(GcMode mode)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800138{
139 GcMarkContext *mc = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800140
141 if (!createMarkStack(&mc->stack)) {
142 return false;
143 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800144 mc->finger = NULL;
Carl Shapirod25566d2010-03-11 20:39:47 -0800145 mc->immuneLimit = dvmHeapSourceGetImmuneLimit(mode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800146 return true;
147}
148
Carl Shapiro6343bd02010-02-16 17:40:19 -0800149static long setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800150 __attribute__((always_inline));
151static long
Carl Shapiro6343bd02010-02-16 17:40:19 -0800152setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800153{
Carl Shapirof373efd2010-02-19 00:46:33 -0800154 return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800155}
156
157static void _markObjectNonNullCommon(const Object *obj, GcMarkContext *ctx,
158 bool checkFinger, bool forceStack)
159 __attribute__((always_inline));
160static void
161_markObjectNonNullCommon(const Object *obj, GcMarkContext *ctx,
162 bool checkFinger, bool forceStack)
163{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800164 assert(obj != NULL);
165
166#if GC_DEBUG(GC_DEBUG_PARANOID)
167//TODO: make sure we're locked
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800168 assert(dvmIsValidObject(obj));
169#endif
170
Carl Shapirod25566d2010-03-11 20:39:47 -0800171 if ((char *)obj < ctx->immuneLimit) {
172 assert(isMarked(obj, ctx));
173 return;
174 }
Carl Shapiro6343bd02010-02-16 17:40:19 -0800175 if (!setAndReturnMarkBit(ctx, obj)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800176 /* This object was not previously marked.
177 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800178 if (forceStack || (checkFinger && (void *)obj < ctx->finger)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800179 /* This object will need to go on the mark stack.
180 */
181 MARK_STACK_PUSH(ctx->stack, obj);
182 }
183
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800184#if WITH_HPROF
185 if (gDvm.gcHeap->hprofContext != NULL) {
186 hprofMarkRootObject(gDvm.gcHeap->hprofContext, obj, 0);
187 }
188#endif
189#if DVM_TRACK_HEAP_MARKING
190 gDvm.gcHeap->markCount++;
Carl Shapiro6343bd02010-02-16 17:40:19 -0800191 gDvm.gcHeap->markSize += dvmHeapSourceChunkSize((void *)obj) +
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800192 HEAP_SOURCE_CHUNK_OVERHEAD;
193#endif
194
195 /* obj->clazz can be NULL if we catch an object between
196 * dvmMalloc() and DVM_OBJECT_INIT(). This is ok.
197 */
198 LOGV_MARK("0x%08x %s\n", (uint)obj,
199 obj->clazz == NULL ? "<null class>" : obj->clazz->name);
200 }
201}
202
203/* Used to mark objects when recursing. Recursion is done by moving
204 * the finger across the bitmaps in address order and marking child
205 * objects. Any newly-marked objects whose addresses are lower than
206 * the finger won't be visited by the bitmap scan, so those objects
207 * need to be added to the mark stack.
208 */
209static void
210markObjectNonNull(const Object *obj, GcMarkContext *ctx)
211{
212 _markObjectNonNullCommon(obj, ctx, true, false);
213}
214
215#define markObject(obj, ctx) \
216 do { \
217 Object *MO_obj_ = (Object *)(obj); \
218 if (MO_obj_ != NULL) { \
219 markObjectNonNull(MO_obj_, (ctx)); \
220 } \
221 } while (false)
222
223/* If the object hasn't already been marked, mark it and
224 * schedule it to be scanned for references.
225 *
226 * obj may not be NULL. The macro dvmMarkObject() should
227 * be used in situations where a reference may be NULL.
228 *
229 * This function may only be called when marking the root
230 * set. When recursing, use the internal markObject[NonNull]().
231 */
232void
233dvmMarkObjectNonNull(const Object *obj)
234{
235 _markObjectNonNullCommon(obj, &gDvm.gcHeap->markContext, false, false);
236}
237
238/* Mark the set of root objects.
239 *
240 * Things we need to scan:
241 * - System classes defined by root classloader
242 * - For each thread:
243 * - Interpreted stack, from top to "curFrame"
244 * - Dalvik registers (args + local vars)
245 * - JNI local references
246 * - Automatic VM local references (TrackedAlloc)
247 * - Associated Thread/VMThread object
248 * - ThreadGroups (could track & start with these instead of working
249 * upward from Threads)
250 * - Exception currently being thrown, if present
251 * - JNI global references
252 * - Interned string table
253 * - Primitive classes
254 * - Special objects
255 * - gDvm.outOfMemoryObj
256 * - Objects allocated with ALLOC_NO_GC
257 * - Objects pending finalization (but not yet finalized)
258 * - Objects in debugger object registry
259 *
260 * Don't need:
261 * - Native stack (for in-progress stuff in the VM)
262 * - The TrackedAlloc stuff watches all native VM references.
263 */
264void dvmHeapMarkRootSet()
265{
266 HeapRefTable *refs;
267 GcHeap *gcHeap;
268 Object **op;
269
270 gcHeap = gDvm.gcHeap;
271
272 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_STICKY_CLASS, 0);
273
Carl Shapirod25566d2010-03-11 20:39:47 -0800274 LOG_SCAN("immune objects");
275 dvmMarkImmuneObjects();
276
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800277 LOG_SCAN("root class loader\n");
278 dvmGcScanRootClassLoader();
279 LOG_SCAN("primitive classes\n");
280 dvmGcScanPrimitiveClasses();
281
282 /* dvmGcScanRootThreadGroups() sets a bunch of
283 * different scan states internally.
284 */
285 HPROF_CLEAR_GC_SCAN_STATE();
286
287 LOG_SCAN("root thread groups\n");
288 dvmGcScanRootThreadGroups();
289
290 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_INTERNED_STRING, 0);
291
292 LOG_SCAN("interned strings\n");
293 dvmGcScanInternedStrings();
294
295 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_GLOBAL, 0);
296
297 LOG_SCAN("JNI global refs\n");
298 dvmGcMarkJniGlobalRefs();
299
300 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
301
302 LOG_SCAN("pending reference operations\n");
303 dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations, true);
304
305 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
306
307 LOG_SCAN("pending finalizations\n");
308 dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs, false);
309
310 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_DEBUGGER, 0);
311
312 LOG_SCAN("debugger refs\n");
313 dvmGcMarkDebuggerRefs();
314
315 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_VM_INTERNAL, 0);
316
317 /* Mark all ALLOC_NO_GC objects.
318 */
319 LOG_SCAN("ALLOC_NO_GC objects\n");
320 refs = &gcHeap->nonCollectableRefs;
321 op = refs->table;
322 while ((uintptr_t)op < (uintptr_t)refs->nextEntry) {
323 dvmMarkObjectNonNull(*(op++));
324 }
325
326 /* Mark any special objects we have sitting around.
327 */
328 LOG_SCAN("special objects\n");
329 dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
330 dvmMarkObjectNonNull(gDvm.internalErrorObj);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700331 dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
Andy McFaddenb18992f2009-09-25 10:42:15 -0700332 dvmMarkObject(gDvm.jniWeakGlobalRefQueue);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800333//TODO: scan object references sitting in gDvm; use pointer begin & end
334
335 HPROF_CLEAR_GC_SCAN_STATE();
336}
337
338/*
339 * Nothing past this point is allowed to use dvmMarkObject*().
340 * Scanning/recursion must use markObject*(), which takes the
341 * finger into account.
342 */
343#define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
344
345
346/* Mark all of a ClassObject's interfaces.
347 */
348static void markInterfaces(const ClassObject *clazz, GcMarkContext *ctx)
349{
350 ClassObject **interfaces;
351 int interfaceCount;
352 int i;
353
354 /* Mark all interfaces.
355 */
356 interfaces = clazz->interfaces;
357 interfaceCount = clazz->interfaceCount;
358 for (i = 0; i < interfaceCount; i++) {
359 markObjectNonNull((Object *)*interfaces, ctx);
360 interfaces++;
361 }
362}
363
364/* Mark all objects referred to by a ClassObject's static fields.
365 */
366static void scanStaticFields(const ClassObject *clazz, GcMarkContext *ctx)
367{
Andy McFadden929ebe22010-03-10 15:21:21 -0800368 const StaticField *f;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800369 int i;
370
371 //TODO: Optimize this with a bit vector or something
Barry Hayes03aa70a2010-03-01 15:49:41 -0800372 f = &clazz->sfields[0];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800373 for (i = 0; i < clazz->sfieldCount; i++) {
374 char c = f->field.signature[0];
375 if (c == '[' || c == 'L') {
376 /* It's an array or class reference.
377 */
378 markObject((Object *)f->value.l, ctx);
379 }
380 f++;
381 }
382}
383
384/* Mark all objects referred to by a DataObject's instance fields.
385 */
386static void scanInstanceFields(const DataObject *obj, ClassObject *clazz,
387 GcMarkContext *ctx)
388{
Barry Hayesd1497482009-10-28 15:32:19 -0700389 if (clazz->refOffsets != CLASS_WALK_SUPER) {
Barry Hayeseac47ed2009-06-22 11:45:20 -0700390 unsigned int refOffsets = clazz->refOffsets;
391 while (refOffsets != 0) {
392 const int rshift = CLZ(refOffsets);
393 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
394 markObject(dvmGetFieldObject((Object*)obj,
395 CLASS_OFFSET_FROM_CLZ(rshift)), ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800396 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700397 } else {
398 while (clazz != NULL) {
399 InstField *f;
400 int i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800401
Barry Hayeseac47ed2009-06-22 11:45:20 -0700402 /* All of the fields that contain object references
403 * are guaranteed to be at the beginning of the ifields list.
404 */
405 f = clazz->ifields;
406 for (i = 0; i < clazz->ifieldRefCount; i++) {
407 /* Mark the array or object reference.
408 * May be NULL.
409 *
410 * Note that, per the comment on struct InstField,
411 * f->byteOffset is the offset from the beginning of
412 * obj, not the offset into obj->instanceData.
413 */
414 markObject(dvmGetFieldObject((Object*)obj, f->byteOffset), ctx);
415 f++;
416 }
417
418 /* This will be NULL when we hit java.lang.Object
419 */
420 clazz = clazz->super;
421 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800422 }
423}
424
425/* Mark all objects referred to by the array's contents.
426 */
427static void scanObjectArray(const ArrayObject *array, GcMarkContext *ctx)
428{
429 Object **contents;
430 u4 length;
431 u4 i;
432
433 contents = (Object **)array->contents;
434 length = array->length;
435
436 for (i = 0; i < length; i++) {
437 markObject(*contents, ctx); // may be NULL
438 contents++;
439 }
440}
441
442/* Mark all objects referred to by the ClassObject.
443 */
444static void scanClassObject(const ClassObject *clazz, GcMarkContext *ctx)
445{
446 LOGV_SCAN("---------> %s\n", clazz->name);
447
448 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
449 /* We're an array; mark the class object of the contents
450 * of the array.
451 *
452 * Note that we won't necessarily reach the array's element
453 * class by scanning the array contents; the array may be
454 * zero-length, or may only contain null objects.
455 */
456 markObjectNonNull((Object *)clazz->elementClass, ctx);
457 }
458
459 /* We scan these explicitly in case the only remaining
460 * reference to a particular class object is via a data
461 * object; we may not be guaranteed to reach all
462 * live class objects via a classloader.
463 */
464 markObject((Object *)clazz->super, ctx); // may be NULL (java.lang.Object)
465 markObject(clazz->classLoader, ctx); // may be NULL
466
467 scanStaticFields(clazz, ctx);
468 markInterfaces(clazz, ctx);
469}
470
471/* Mark all objects that obj refers to.
472 *
473 * Called on every object in markList.
474 */
475static void scanObject(const Object *obj, GcMarkContext *ctx)
476{
477 ClassObject *clazz;
478
479 assert(dvmIsValidObject(obj));
Barry Hayes03aa70a2010-03-01 15:49:41 -0800480 LOGV_SCAN("0x%08x %s\n", (uint)obj, obj->clazz->descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800481
482#if WITH_HPROF
483 if (gDvm.gcHeap->hprofContext != NULL) {
484 hprofDumpHeapObject(gDvm.gcHeap->hprofContext, obj);
485 }
486#endif
487
488 /* Get and mark the class object for this particular instance.
489 */
490 clazz = obj->clazz;
491 if (clazz == NULL) {
Barry Hayesb36e6402010-03-05 09:51:12 -0800492 /* This can happen if we catch an object between dvmMalloc()
493 * and DVM_OBJECT_INIT(). The object won't contain any
494 * references yet, so we can just skip it. It can also mean
495 * that this object is unlinkedJavaLangClass, which has its
496 * clazz explicitly set to NULL.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800497 */
498 return;
499 } else if (clazz == gDvm.unlinkedJavaLangClass) {
500 /* This class hasn't been linked yet. We're guaranteed
501 * that the object doesn't contain any references that
502 * aren't already tracked, so we can skip scanning it.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800503 */
504 return;
505 }
Barry Hayes3592d622009-03-16 16:10:35 -0700506
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800507 assert(dvmIsValidObject((Object *)clazz));
508 markObjectNonNull((Object *)clazz, ctx);
509
510 /* Mark any references in this object.
511 */
512 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
513 /* It's an array object.
514 */
515 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISOBJECTARRAY)) {
516 /* It's an array of object references.
517 */
518 scanObjectArray((ArrayObject *)obj, ctx);
519 }
520 // else there's nothing else to scan
521 } else {
522 /* It's a DataObject-compatible object.
523 */
524 scanInstanceFields((DataObject *)obj, clazz, ctx);
525
526 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISREFERENCE)) {
527 GcHeap *gcHeap = gDvm.gcHeap;
528 Object *referent;
529
530 /* It's a subclass of java/lang/ref/Reference.
531 * The fields in this class have been arranged
532 * such that scanInstanceFields() did not actually
533 * mark the "referent" field; we need to handle
534 * it specially.
535 *
536 * If the referent already has a strong mark (isMarked(referent)),
537 * we don't care about its reference status.
538 */
539 referent = dvmGetFieldObject(obj,
540 gDvm.offJavaLangRefReference_referent);
541 if (referent != NULL &&
Carl Shapiro6343bd02010-02-16 17:40:19 -0800542 !isMarked(referent, &gcHeap->markContext))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800543 {
544 u4 refFlags;
545
546 if (gcHeap->markAllReferents) {
547 LOG_REF("Hard-marking a reference\n");
548
549 /* Don't bother with normal reference-following
550 * behavior, just mark the referent. This should
551 * only be used when following objects that just
552 * became scheduled for finalization.
553 */
554 markObjectNonNull(referent, ctx);
555 goto skip_reference;
556 }
557
558 /* See if this reference was handled by a previous GC.
559 */
560 if (dvmGetFieldObject(obj,
561 gDvm.offJavaLangRefReference_vmData) ==
562 SCHEDULED_REFERENCE_MAGIC)
563 {
564 LOG_REF("Skipping scheduled reference\n");
565
566 /* Don't reschedule it, but make sure that its
567 * referent doesn't get collected (in case it's
568 * a PhantomReference and wasn't cleared automatically).
569 */
570 //TODO: Mark these after handling all new refs of
571 // this strength, in case the new refs refer
572 // to the same referent. Not a very common
573 // case, though.
574 markObjectNonNull(referent, ctx);
575 goto skip_reference;
576 }
577
578 /* Find out what kind of reference is pointing
579 * to referent.
580 */
581 refFlags = GET_CLASS_FLAG_GROUP(clazz,
582 CLASS_ISREFERENCE |
583 CLASS_ISWEAKREFERENCE |
584 CLASS_ISPHANTOMREFERENCE);
585
586 /* We use the vmData field of Reference objects
587 * as a next pointer in a singly-linked list.
588 * That way, we don't need to allocate any memory
589 * while we're doing a GC.
590 */
591#define ADD_REF_TO_LIST(list, ref) \
592 do { \
593 Object *ARTL_ref_ = (/*de-const*/Object *)(ref); \
594 dvmSetFieldObject(ARTL_ref_, \
595 gDvm.offJavaLangRefReference_vmData, list); \
596 list = ARTL_ref_; \
597 } while (false)
598
599 /* At this stage, we just keep track of all of
600 * the live references that we've seen. Later,
601 * we'll walk through each of these lists and
602 * deal with the referents.
603 */
604 if (refFlags == CLASS_ISREFERENCE) {
605 /* It's a soft reference. Depending on the state,
606 * we'll attempt to collect all of them, some of
607 * them, or none of them.
608 */
609 if (gcHeap->softReferenceCollectionState ==
610 SR_COLLECT_NONE)
611 {
612 sr_collect_none:
613 markObjectNonNull(referent, ctx);
614 } else if (gcHeap->softReferenceCollectionState ==
615 SR_COLLECT_ALL)
616 {
617 sr_collect_all:
618 ADD_REF_TO_LIST(gcHeap->softReferences, obj);
619 } else {
620 /* We'll only try to collect half of the
621 * referents.
622 */
623 if (gcHeap->softReferenceColor++ & 1) {
624 goto sr_collect_none;
625 }
626 goto sr_collect_all;
627 }
628 } else {
629 /* It's a weak or phantom reference.
630 * Clearing CLASS_ISREFERENCE will reveal which.
631 */
632 refFlags &= ~CLASS_ISREFERENCE;
633 if (refFlags == CLASS_ISWEAKREFERENCE) {
634 ADD_REF_TO_LIST(gcHeap->weakReferences, obj);
635 } else if (refFlags == CLASS_ISPHANTOMREFERENCE) {
636 ADD_REF_TO_LIST(gcHeap->phantomReferences, obj);
637 } else {
638 assert(!"Unknown reference type");
639 }
640 }
641#undef ADD_REF_TO_LIST
642 }
643 }
644
645 skip_reference:
646 /* If this is a class object, mark various other things that
647 * its internals point to.
648 *
649 * All class objects are instances of java.lang.Class,
650 * including the java.lang.Class class object.
651 */
652 if (clazz == gDvm.classJavaLangClass) {
653 scanClassObject((ClassObject *)obj, ctx);
654 }
655 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800656}
657
658static void
659processMarkStack(GcMarkContext *ctx)
660{
661 const Object **const base = ctx->stack.base;
662
663 /* Scan anything that's on the mark stack.
664 * We can't use the bitmaps anymore, so use
665 * a finger that points past the end of them.
666 */
667 ctx->finger = (void *)ULONG_MAX;
668 while (ctx->stack.top != base) {
669 scanObject(*ctx->stack.top++, ctx);
670 }
671}
672
673#ifndef NDEBUG
674static uintptr_t gLastFinger = 0;
675#endif
676
677static bool
678scanBitmapCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
679{
680 GcMarkContext *ctx = (GcMarkContext *)arg;
681 size_t i;
682
683#ifndef NDEBUG
684 assert((uintptr_t)finger >= gLastFinger);
685 gLastFinger = (uintptr_t)finger;
686#endif
687
688 ctx->finger = finger;
689 for (i = 0; i < numPtrs; i++) {
Carl Shapiro6343bd02010-02-16 17:40:19 -0800690 scanObject(*ptrs++, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800691 }
692
693 return true;
694}
695
696/* Given bitmaps with the root set marked, find and mark all
697 * reachable objects. When this returns, the entire set of
698 * live objects will be marked and the mark stack will be empty.
699 */
700void dvmHeapScanMarkedObjects()
701{
702 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
703
704 assert(ctx->finger == NULL);
705
706 /* The bitmaps currently have bits set for the root set.
707 * Walk across the bitmaps and scan each object.
708 */
709#ifndef NDEBUG
710 gLastFinger = 0;
711#endif
Carl Shapirof373efd2010-02-19 00:46:33 -0800712 dvmHeapBitmapWalk(ctx->bitmap, scanBitmapCallback, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800713
714 /* We've walked the mark bitmaps. Scan anything that's
715 * left on the mark stack.
716 */
717 processMarkStack(ctx);
718
719 LOG_SCAN("done with marked objects\n");
720}
721
Barry Hayes6930a112009-12-22 11:01:38 -0800722/** Clear the referent field.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800723 */
Barry Hayes6930a112009-12-22 11:01:38 -0800724static void clearReference(Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800725{
726 /* This is what the default implementation of Reference.clear()
727 * does. We're required to clear all references to a given
728 * referent atomically, so we can't pop in and out of interp
729 * code each time.
730 *
Barry Hayes6930a112009-12-22 11:01:38 -0800731 * We don't ever actaully call overriding implementations of
732 * Reference.clear().
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800733 */
734 dvmSetFieldObject(reference,
735 gDvm.offJavaLangRefReference_referent, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800736}
737
738/** @return true if we need to schedule a call to enqueue().
739 */
740static bool enqueueReference(Object *reference)
741{
Barry Hayes6930a112009-12-22 11:01:38 -0800742 Object *queue = dvmGetFieldObject(reference,
743 gDvm.offJavaLangRefReference_queue);
744 Object *queueNext = dvmGetFieldObject(reference,
745 gDvm.offJavaLangRefReference_queueNext);
746 if (queue == NULL || queueNext != NULL) {
747 /* There is no queue, or the reference has already
748 * been enqueued. The Reference.enqueue() method
749 * will do nothing even if we call it.
750 */
751 return false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800752 }
753
754 /* We need to call enqueue(), but if we called it from
755 * here we'd probably deadlock. Schedule a call.
756 */
757 return true;
758}
759
760/* All objects for stronger reference levels have been
761 * marked before this is called.
762 */
763void dvmHeapHandleReferences(Object *refListHead, enum RefType refType)
764{
765 Object *reference;
766 GcMarkContext *markContext = &gDvm.gcHeap->markContext;
767 const int offVmData = gDvm.offJavaLangRefReference_vmData;
768 const int offReferent = gDvm.offJavaLangRefReference_referent;
769 bool workRequired = false;
770
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800771 reference = refListHead;
772 while (reference != NULL) {
773 Object *next;
774 Object *referent;
775
776 /* Pull the interesting fields out of the Reference object.
777 */
778 next = dvmGetFieldObject(reference, offVmData);
779 referent = dvmGetFieldObject(reference, offReferent);
780
781 //TODO: when handling REF_PHANTOM, unlink any references
782 // that fail this initial if(). We need to re-walk
783 // the list, and it would be nice to avoid the extra
784 // work.
Carl Shapiro6343bd02010-02-16 17:40:19 -0800785 if (referent != NULL && !isMarked(referent, markContext)) {
Barry Hayes6930a112009-12-22 11:01:38 -0800786 bool schedEnqueue;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800787
788 /* This is the strongest reference that refers to referent.
789 * Do the right thing.
790 */
791 switch (refType) {
792 case REF_SOFT:
793 case REF_WEAK:
Barry Hayes6930a112009-12-22 11:01:38 -0800794 clearReference(reference);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800795 schedEnqueue = enqueueReference(reference);
796 break;
797 case REF_PHANTOM:
798 /* PhantomReferences are not cleared automatically.
799 * Until someone clears it (or the reference itself
800 * is collected), the referent must remain alive.
801 *
802 * It's necessary to fully mark the referent because
803 * it will still be present during the next GC, and
804 * all objects that it points to must be valid.
805 * (The referent will be marked outside of this loop,
806 * after handing all references of this strength, in
807 * case multiple references point to the same object.)
Andy McFaddenb18992f2009-09-25 10:42:15 -0700808 *
809 * One exception: JNI "weak global" references are handled
810 * as a special case. They're identified by the queue.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800811 */
Andy McFaddenb18992f2009-09-25 10:42:15 -0700812 if (gDvm.jniWeakGlobalRefQueue != NULL) {
813 Object* queue = dvmGetFieldObject(reference,
814 gDvm.offJavaLangRefReference_queue);
815 if (queue == gDvm.jniWeakGlobalRefQueue) {
816 LOGV("+++ WGR: clearing + not queueing %p:%p\n",
817 reference, referent);
Barry Hayes6930a112009-12-22 11:01:38 -0800818 clearReference(reference);
Andy McFaddenb18992f2009-09-25 10:42:15 -0700819 schedEnqueue = false;
820 break;
821 }
822 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800823
824 /* A PhantomReference is only useful with a
825 * queue, but since it's possible to create one
826 * without a queue, we need to check.
827 */
828 schedEnqueue = enqueueReference(reference);
829 break;
830 default:
831 assert(!"Bad reference type");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800832 schedEnqueue = false;
833 break;
834 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800835
Barry Hayes6930a112009-12-22 11:01:38 -0800836 if (schedEnqueue) {
Barry Hayes6930a112009-12-22 11:01:38 -0800837 /* Stuff the enqueue bit in the bottom of the pointer.
838 * Assumes that objects are 8-byte aligned.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800839 *
840 * Note that we are adding the *Reference* (which
841 * is by definition already marked at this point) to
842 * this list; we're not adding the referent (which
843 * has already been cleared).
844 */
845 assert(((intptr_t)reference & 3) == 0);
Barry Hayes6930a112009-12-22 11:01:38 -0800846 assert((WORKER_ENQUEUE & ~3) == 0);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800847 if (!dvmHeapAddRefToLargeTable(
848 &gDvm.gcHeap->referenceOperations,
Barry Hayes6930a112009-12-22 11:01:38 -0800849 (Object *)((uintptr_t)reference | WORKER_ENQUEUE)))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800850 {
851 LOGE_HEAP("dvmMalloc(): no room for any more "
852 "reference operations\n");
853 dvmAbort();
854 }
855 workRequired = true;
856 }
857
858 if (refType != REF_PHANTOM) {
859 /* Let later GCs know not to reschedule this reference.
860 */
861 dvmSetFieldObject(reference, offVmData,
862 SCHEDULED_REFERENCE_MAGIC);
863 } // else this is handled later for REF_PHANTOM
864
865 } // else there was a stronger reference to the referent.
866
867 reference = next;
868 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800869
870 /* Walk though the reference list again, and mark any non-clear/marked
871 * referents. Only PhantomReferences can have non-clear referents
872 * at this point.
Andy McFaddenb18992f2009-09-25 10:42:15 -0700873 *
874 * (Could skip this for JNI weak globals, since we know they've been
875 * cleared.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800876 */
877 if (refType == REF_PHANTOM) {
878 bool scanRequired = false;
879
880 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
881 reference = refListHead;
882 while (reference != NULL) {
883 Object *next;
884 Object *referent;
885
886 /* Pull the interesting fields out of the Reference object.
887 */
888 next = dvmGetFieldObject(reference, offVmData);
889 referent = dvmGetFieldObject(reference, offReferent);
890
Carl Shapiro6343bd02010-02-16 17:40:19 -0800891 if (referent != NULL && !isMarked(referent, markContext)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800892 markObjectNonNull(referent, markContext);
893 scanRequired = true;
894
895 /* Let later GCs know not to reschedule this reference.
896 */
897 dvmSetFieldObject(reference, offVmData,
898 SCHEDULED_REFERENCE_MAGIC);
899 }
900
901 reference = next;
902 }
903 HPROF_CLEAR_GC_SCAN_STATE();
904
905 if (scanRequired) {
906 processMarkStack(markContext);
907 }
908 }
909
910 if (workRequired) {
911 dvmSignalHeapWorker(false);
912 }
913}
914
915
916/* Find unreachable objects that need to be finalized,
917 * and schedule them for finalization.
918 */
919void dvmHeapScheduleFinalizations()
920{
921 HeapRefTable newPendingRefs;
922 LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
923 Object **ref;
924 Object **lastRef;
925 size_t totalPendCount;
926 GcMarkContext *markContext = &gDvm.gcHeap->markContext;
927
928 /*
929 * All reachable objects have been marked.
930 * Any unmarked finalizable objects need to be finalized.
931 */
932
933 /* Create a table that the new pending refs will
934 * be added to.
935 */
936 if (!dvmHeapInitHeapRefTable(&newPendingRefs, 128)) {
937 //TODO: mark all finalizable refs and hope that
938 // we can schedule them next time. Watch out,
939 // because we may be expecting to free up space
940 // by calling finalizers.
941 LOGE_GC("dvmHeapScheduleFinalizations(): no room for "
942 "pending finalizations\n");
943 dvmAbort();
944 }
945
946 /* Walk through finalizableRefs and move any unmarked references
947 * to the list of new pending refs.
948 */
949 totalPendCount = 0;
950 while (finRefs != NULL) {
951 Object **gapRef;
952 size_t newPendCount = 0;
953
954 gapRef = ref = finRefs->refs.table;
955 lastRef = finRefs->refs.nextEntry;
956 while (ref < lastRef) {
Carl Shapiro6343bd02010-02-16 17:40:19 -0800957 if (!isMarked(*ref, markContext)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800958 if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
959 //TODO: add the current table and allocate
960 // a new, smaller one.
961 LOGE_GC("dvmHeapScheduleFinalizations(): "
962 "no room for any more pending finalizations: %zd\n",
963 dvmHeapNumHeapRefTableEntries(&newPendingRefs));
964 dvmAbort();
965 }
966 newPendCount++;
967 } else {
968 /* This ref is marked, so will remain on finalizableRefs.
969 */
970 if (newPendCount > 0) {
971 /* Copy it up to fill the holes.
972 */
973 *gapRef++ = *ref;
974 } else {
975 /* No holes yet; don't bother copying.
976 */
977 gapRef++;
978 }
979 }
980 ref++;
981 }
982 finRefs->refs.nextEntry = gapRef;
983 //TODO: if the table is empty when we're done, free it.
984 totalPendCount += newPendCount;
985 finRefs = finRefs->next;
986 }
987 LOGD_GC("dvmHeapScheduleFinalizations(): %zd finalizers triggered.\n",
988 totalPendCount);
989 if (totalPendCount == 0) {
990 /* No objects required finalization.
991 * Free the empty temporary table.
992 */
993 dvmClearReferenceTable(&newPendingRefs);
994 return;
995 }
996
997 /* Add the new pending refs to the main list.
998 */
999 if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
1000 &newPendingRefs))
1001 {
1002 LOGE_GC("dvmHeapScheduleFinalizations(): can't insert new "
1003 "pending finalizations\n");
1004 dvmAbort();
1005 }
1006
1007 //TODO: try compacting the main list with a memcpy loop
1008
1009 /* Mark the refs we just moved; we don't want them or their
1010 * children to get swept yet.
1011 */
1012 ref = newPendingRefs.table;
1013 lastRef = newPendingRefs.nextEntry;
1014 assert(ref < lastRef);
1015 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
1016 while (ref < lastRef) {
1017 markObjectNonNull(*ref, markContext);
1018 ref++;
1019 }
1020 HPROF_CLEAR_GC_SCAN_STATE();
1021
1022 /* Set markAllReferents so that we don't collect referents whose
1023 * only references are in final-reachable objects.
1024 * TODO: eventually provide normal reference behavior by properly
1025 * marking these references.
1026 */
1027 gDvm.gcHeap->markAllReferents = true;
1028 processMarkStack(markContext);
1029 gDvm.gcHeap->markAllReferents = false;
1030
1031 dvmSignalHeapWorker(false);
1032}
1033
1034void dvmHeapFinishMarkStep()
1035{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001036 GcMarkContext *markContext;
1037
1038 markContext = &gDvm.gcHeap->markContext;
1039
1040 /* The sweep step freed every object that appeared in the
1041 * HeapSource bitmaps that didn't appear in the mark bitmaps.
1042 * The new state of the HeapSource is exactly the final
1043 * mark bitmaps, so swap them in.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001044 */
Carl Shapirof373efd2010-02-19 00:46:33 -08001045 dvmHeapSourceSwapBitmaps();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001046
Carl Shapirof373efd2010-02-19 00:46:33 -08001047 /* Clean up everything else associated with the marking process.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001048 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001049 destroyMarkStack(&markContext->stack);
1050
Carl Shapirof373efd2010-02-19 00:46:33 -08001051 markContext->finger = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001052}
1053
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001054static bool
1055sweepBitmapCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
1056{
1057 const ClassObject *const classJavaLangClass = gDvm.classJavaLangClass;
Barry Hayes5cbb2302010-02-02 14:07:37 -08001058 const bool overwriteFree = gDvm.overwriteFree;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001059 size_t i;
Barry Hayesdde8ab02009-05-20 12:10:36 -07001060 void **origPtrs = ptrs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001061
1062 for (i = 0; i < numPtrs; i++) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001063 Object *obj;
1064
Carl Shapiro6343bd02010-02-16 17:40:19 -08001065 obj = (Object *)*ptrs++;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001066
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001067 /* NOTE: Dereferencing clazz is dangerous. If obj was the last
1068 * one to reference its class object, the class object could be
1069 * on the sweep list, and could already have been swept, leaving
1070 * us with a stale pointer.
1071 */
1072 LOGV_SWEEP("FREE: 0x%08x %s\n", (uint)obj, obj->clazz->name);
1073
1074 /* This assumes that java.lang.Class will never go away.
1075 * If it can, and we were the last reference to it, it
1076 * could have already been swept. However, even in that case,
1077 * gDvm.classJavaLangClass should still have a useful
1078 * value.
1079 */
1080 if (obj->clazz == classJavaLangClass) {
1081 LOGV_SWEEP("---------------> %s\n", ((ClassObject *)obj)->name);
1082 /* dvmFreeClassInnards() may have already been called,
1083 * but it's safe to call on the same ClassObject twice.
1084 */
1085 dvmFreeClassInnards((ClassObject *)obj);
1086 }
1087
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001088 /* Overwrite the to-be-freed object to make stale references
1089 * more obvious.
1090 */
Barry Hayes5cbb2302010-02-02 14:07:37 -08001091 if (overwriteFree) {
Barry Hayes2e3c3e12010-02-22 09:39:10 -08001092 int objlen;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001093 ClassObject *clazz = obj->clazz;
Barry Hayes2e3c3e12010-02-22 09:39:10 -08001094 objlen = dvmHeapSourceChunkSize(obj);
1095 memset(obj, 0xa5, objlen);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001096 obj->clazz = (ClassObject *)((uintptr_t)clazz ^ 0xffffffff);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001097 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001098 }
Barry Hayesdde8ab02009-05-20 12:10:36 -07001099 // TODO: dvmHeapSourceFreeList has a loop, just like the above
1100 // does. Consider collapsing the two loops to save overhead.
1101 dvmHeapSourceFreeList(numPtrs, origPtrs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001102
1103 return true;
1104}
1105
Carl Shapiro5a6071b2010-01-07 21:35:50 -08001106/* Returns true if the given object is unmarked. Ignores the low bits
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001107 * of the pointer because the intern table may set them.
1108 */
1109static int isUnmarkedObject(void *object)
1110{
Carl Shapiro6343bd02010-02-16 17:40:19 -08001111 return !isMarked((void *)((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001112 &gDvm.gcHeap->markContext);
1113}
1114
1115/* Walk through the list of objects that haven't been
1116 * marked and free them.
1117 */
1118void
Carl Shapirod25566d2010-03-11 20:39:47 -08001119dvmHeapSweepUnmarkedObjects(GcMode mode, int *numFreed, size_t *sizeFreed)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001120{
Carl Shapirof373efd2010-02-19 00:46:33 -08001121 HeapBitmap markBits[HEAP_SOURCE_MAX_HEAP_COUNT];
1122 HeapBitmap objBits[HEAP_SOURCE_MAX_HEAP_COUNT];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001123 size_t origObjectsAllocated;
1124 size_t origBytesAllocated;
Carl Shapirod25566d2010-03-11 20:39:47 -08001125 size_t numBitmaps, numSweepBitmaps;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001126
1127 /* All reachable objects have been marked.
1128 * Detach any unreachable interned strings before
1129 * we sweep.
1130 */
1131 dvmGcDetachDeadInternedStrings(isUnmarkedObject);
1132
1133 /* Free any known objects that are not marked.
1134 */
1135 origObjectsAllocated = dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0);
1136 origBytesAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
1137
Carl Shapiro5a6071b2010-01-07 21:35:50 -08001138 dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
1139
Carl Shapirof373efd2010-02-19 00:46:33 -08001140 numBitmaps = dvmHeapSourceGetNumHeaps();
1141 dvmHeapSourceGetObjectBitmaps(objBits, markBits, numBitmaps);
Carl Shapirod25566d2010-03-11 20:39:47 -08001142 if (mode == GC_PARTIAL) {
1143 numSweepBitmaps = 1;
1144 assert(gDvm.gcHeap->markContext.immuneLimit == objBits[0].base);
1145 } else {
1146 numSweepBitmaps = numBitmaps;
1147 }
1148 dvmHeapBitmapXorWalkLists(markBits, objBits, numSweepBitmaps,
Carl Shapirof373efd2010-02-19 00:46:33 -08001149 sweepBitmapCallback, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001150
1151 *numFreed = origObjectsAllocated -
1152 dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0);
1153 *sizeFreed = origBytesAllocated -
1154 dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
1155
1156#ifdef WITH_PROFILER
1157 if (gDvm.allocProf.enabled) {
1158 gDvm.allocProf.freeCount += *numFreed;
1159 gDvm.allocProf.freeSize += *sizeFreed;
1160 }
1161#endif
1162}