blob: fcea5ea0c3b90cdf66fafe9b5126a756d8cea800 [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
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080028#define VERBOSE_GC 0
29
30#define GC_LOG_TAG LOG_TAG "-gc"
31
32#if LOG_NDEBUG
33#define LOGV_GC(...) ((void)0)
34#define LOGD_GC(...) ((void)0)
35#else
36#define LOGV_GC(...) LOG(LOG_VERBOSE, GC_LOG_TAG, __VA_ARGS__)
37#define LOGD_GC(...) LOG(LOG_DEBUG, GC_LOG_TAG, __VA_ARGS__)
38#endif
39
40#if VERBOSE_GC
41#define LOGVV_GC(...) LOGV_GC(__VA_ARGS__)
42#else
43#define LOGVV_GC(...) ((void)0)
44#endif
45
46#define LOGI_GC(...) LOG(LOG_INFO, GC_LOG_TAG, __VA_ARGS__)
47#define LOGW_GC(...) LOG(LOG_WARN, GC_LOG_TAG, __VA_ARGS__)
48#define LOGE_GC(...) LOG(LOG_ERROR, GC_LOG_TAG, __VA_ARGS__)
49
50#define LOG_SCAN(...) LOGV_GC("SCAN: " __VA_ARGS__)
51#define LOG_MARK(...) LOGV_GC("MARK: " __VA_ARGS__)
52#define LOG_SWEEP(...) LOGV_GC("SWEEP: " __VA_ARGS__)
53#define LOG_REF(...) LOGV_GC("REF: " __VA_ARGS__)
54
55#define LOGV_SCAN(...) LOGVV_GC("SCAN: " __VA_ARGS__)
56#define LOGV_MARK(...) LOGVV_GC("MARK: " __VA_ARGS__)
57#define LOGV_SWEEP(...) LOGVV_GC("SWEEP: " __VA_ARGS__)
58#define LOGV_REF(...) LOGVV_GC("REF: " __VA_ARGS__)
59
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080060#define ALIGN_UP_TO_PAGE_SIZE(p) \
Andy McFadden96516932009-10-28 17:39:02 -070061 (((size_t)(p) + (SYSTEM_PAGE_SIZE - 1)) & ~(SYSTEM_PAGE_SIZE - 1))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080062
63/* Do not cast the result of this to a boolean; the only set bit
64 * may be > 1<<8.
65 */
Carl Shapiro6343bd02010-02-16 17:40:19 -080066static inline long isMarked(const void *obj, const GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080067{
Carl Shapirof373efd2010-02-19 00:46:33 -080068 return dvmHeapBitmapIsObjectBitSet(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080069}
70
71static bool
72createMarkStack(GcMarkStack *stack)
73{
74 const Object **limit;
75 size_t size;
The Android Open Source Project99409882009-03-18 22:20:24 -070076 int fd, err;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080077
78 /* Create a stack big enough for the worst possible case,
79 * where the heap is perfectly full of the smallest object.
80 * TODO: be better about memory usage; use a smaller stack with
81 * overflow detection and recovery.
82 */
83 size = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
84 (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
85 size = ALIGN_UP_TO_PAGE_SIZE(size);
86 fd = ashmem_create_region("dalvik-heap-markstack", size);
87 if (fd < 0) {
The Android Open Source Project99409882009-03-18 22:20:24 -070088 LOGE_GC("Could not create %d-byte ashmem mark stack: %s\n",
89 size, strerror(errno));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080090 return false;
91 }
92 limit = (const Object **)mmap(NULL, size, PROT_READ | PROT_WRITE,
93 MAP_PRIVATE, fd, 0);
The Android Open Source Project99409882009-03-18 22:20:24 -070094 err = errno;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080095 close(fd);
96 if (limit == MAP_FAILED) {
The Android Open Source Project99409882009-03-18 22:20:24 -070097 LOGE_GC("Could not mmap %d-byte ashmem mark stack: %s\n",
98 size, strerror(err));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080099 return false;
100 }
101
102 memset(stack, 0, sizeof(*stack));
103 stack->limit = limit;
104 stack->base = (const Object **)((uintptr_t)limit + size);
105 stack->top = stack->base;
106
107 return true;
108}
109
110static void
111destroyMarkStack(GcMarkStack *stack)
112{
113 munmap((char *)stack->limit,
114 (uintptr_t)stack->base - (uintptr_t)stack->limit);
115 memset(stack, 0, sizeof(*stack));
116}
117
118#define MARK_STACK_PUSH(stack, obj) \
119 do { \
120 *--(stack).top = (obj); \
121 } while (false)
122
123bool
Carl Shapirod25566d2010-03-11 20:39:47 -0800124dvmHeapBeginMarkStep(GcMode mode)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800125{
126 GcMarkContext *mc = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800127
128 if (!createMarkStack(&mc->stack)) {
129 return false;
130 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800131 mc->finger = NULL;
Carl Shapirod25566d2010-03-11 20:39:47 -0800132 mc->immuneLimit = dvmHeapSourceGetImmuneLimit(mode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800133 return true;
134}
135
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800136static long
Carl Shapiro6343bd02010-02-16 17:40:19 -0800137setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800138{
Carl Shapirof373efd2010-02-19 00:46:33 -0800139 return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800140}
141
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800142static void
Barry Hayese1bccb92010-05-18 09:48:37 -0700143markObjectNonNull(const Object *obj, GcMarkContext *ctx,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800144 bool checkFinger, bool forceStack)
145{
Barry Hayese1bccb92010-05-18 09:48:37 -0700146 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800147 assert(obj != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800148 assert(dvmIsValidObject(obj));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800149
Carl Shapirob31b3012010-05-25 18:35:37 -0700150 if (obj < (Object *)ctx->immuneLimit) {
Carl Shapirod25566d2010-03-11 20:39:47 -0800151 assert(isMarked(obj, ctx));
152 return;
153 }
Carl Shapiro6343bd02010-02-16 17:40:19 -0800154 if (!setAndReturnMarkBit(ctx, obj)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800155 /* This object was not previously marked.
156 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800157 if (forceStack || (checkFinger && (void *)obj < ctx->finger)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800158 /* This object will need to go on the mark stack.
159 */
160 MARK_STACK_PUSH(ctx->stack, obj);
161 }
162
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800163#if WITH_HPROF
164 if (gDvm.gcHeap->hprofContext != NULL) {
165 hprofMarkRootObject(gDvm.gcHeap->hprofContext, obj, 0);
166 }
167#endif
168#if DVM_TRACK_HEAP_MARKING
169 gDvm.gcHeap->markCount++;
Carl Shapiro6343bd02010-02-16 17:40:19 -0800170 gDvm.gcHeap->markSize += dvmHeapSourceChunkSize((void *)obj) +
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800171 HEAP_SOURCE_CHUNK_OVERHEAD;
172#endif
173
174 /* obj->clazz can be NULL if we catch an object between
175 * dvmMalloc() and DVM_OBJECT_INIT(). This is ok.
176 */
177 LOGV_MARK("0x%08x %s\n", (uint)obj,
178 obj->clazz == NULL ? "<null class>" : obj->clazz->name);
179 }
180}
181
182/* Used to mark objects when recursing. Recursion is done by moving
183 * the finger across the bitmaps in address order and marking child
184 * objects. Any newly-marked objects whose addresses are lower than
185 * the finger won't be visited by the bitmap scan, so those objects
186 * need to be added to the mark stack.
187 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700188static void markObject(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800189{
Barry Hayese1bccb92010-05-18 09:48:37 -0700190 if (obj != NULL) {
191 markObjectNonNull(obj, ctx, true, false);
192 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800193}
194
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800195/* If the object hasn't already been marked, mark it and
196 * schedule it to be scanned for references.
197 *
198 * obj may not be NULL. The macro dvmMarkObject() should
199 * be used in situations where a reference may be NULL.
200 *
201 * This function may only be called when marking the root
Barry Hayese1bccb92010-05-18 09:48:37 -0700202 * set. When recursing, use the internal markObject().
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800203 */
204void
205dvmMarkObjectNonNull(const Object *obj)
206{
Barry Hayese1bccb92010-05-18 09:48:37 -0700207 assert(obj != NULL);
208 markObjectNonNull(obj, &gDvm.gcHeap->markContext, false, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800209}
210
211/* Mark the set of root objects.
212 *
213 * Things we need to scan:
214 * - System classes defined by root classloader
215 * - For each thread:
216 * - Interpreted stack, from top to "curFrame"
217 * - Dalvik registers (args + local vars)
218 * - JNI local references
219 * - Automatic VM local references (TrackedAlloc)
220 * - Associated Thread/VMThread object
221 * - ThreadGroups (could track & start with these instead of working
222 * upward from Threads)
223 * - Exception currently being thrown, if present
224 * - JNI global references
225 * - Interned string table
226 * - Primitive classes
227 * - Special objects
228 * - gDvm.outOfMemoryObj
229 * - Objects allocated with ALLOC_NO_GC
230 * - Objects pending finalization (but not yet finalized)
231 * - Objects in debugger object registry
232 *
233 * Don't need:
234 * - Native stack (for in-progress stuff in the VM)
235 * - The TrackedAlloc stuff watches all native VM references.
236 */
237void dvmHeapMarkRootSet()
238{
239 HeapRefTable *refs;
240 GcHeap *gcHeap;
241 Object **op;
242
243 gcHeap = gDvm.gcHeap;
244
245 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_STICKY_CLASS, 0);
246
Carl Shapirod25566d2010-03-11 20:39:47 -0800247 LOG_SCAN("immune objects");
Barry Hayes425848f2010-05-04 13:32:12 -0700248 dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
Carl Shapirod25566d2010-03-11 20:39:47 -0800249
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800250 LOG_SCAN("root class loader\n");
251 dvmGcScanRootClassLoader();
252 LOG_SCAN("primitive classes\n");
253 dvmGcScanPrimitiveClasses();
254
255 /* dvmGcScanRootThreadGroups() sets a bunch of
256 * different scan states internally.
257 */
258 HPROF_CLEAR_GC_SCAN_STATE();
259
260 LOG_SCAN("root thread groups\n");
261 dvmGcScanRootThreadGroups();
262
263 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_INTERNED_STRING, 0);
264
265 LOG_SCAN("interned strings\n");
266 dvmGcScanInternedStrings();
267
268 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_GLOBAL, 0);
269
270 LOG_SCAN("JNI global refs\n");
271 dvmGcMarkJniGlobalRefs();
272
273 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
274
275 LOG_SCAN("pending reference operations\n");
276 dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations, true);
277
278 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
279
280 LOG_SCAN("pending finalizations\n");
281 dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs, false);
282
283 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_DEBUGGER, 0);
284
285 LOG_SCAN("debugger refs\n");
286 dvmGcMarkDebuggerRefs();
287
288 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_VM_INTERNAL, 0);
289
290 /* Mark all ALLOC_NO_GC objects.
291 */
292 LOG_SCAN("ALLOC_NO_GC objects\n");
293 refs = &gcHeap->nonCollectableRefs;
294 op = refs->table;
295 while ((uintptr_t)op < (uintptr_t)refs->nextEntry) {
296 dvmMarkObjectNonNull(*(op++));
297 }
298
299 /* Mark any special objects we have sitting around.
300 */
301 LOG_SCAN("special objects\n");
302 dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
303 dvmMarkObjectNonNull(gDvm.internalErrorObj);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700304 dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800305//TODO: scan object references sitting in gDvm; use pointer begin & end
306
307 HPROF_CLEAR_GC_SCAN_STATE();
308}
309
310/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700311 * Nothing past this point is allowed to use dvmMarkObject() or
312 * dvmMarkObjectNonNull(), which are for root-marking only.
313 * Scanning/recursion must use markObject(), which takes the finger
314 * into account.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800315 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700316#undef dvmMarkObject
317#define dvmMarkObject __dont_use_dvmMarkObject__
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800318#define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
319
Barry Hayese1bccb92010-05-18 09:48:37 -0700320/*
321 * Scans instance fields.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800322 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700323static void scanInstanceFields(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800324{
Barry Hayese1bccb92010-05-18 09:48:37 -0700325 assert(obj != NULL);
326 assert(obj->clazz != NULL);
327 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800328
Barry Hayese1bccb92010-05-18 09:48:37 -0700329 if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
330 unsigned int refOffsets = obj->clazz->refOffsets;
Barry Hayeseac47ed2009-06-22 11:45:20 -0700331 while (refOffsets != 0) {
332 const int rshift = CLZ(refOffsets);
333 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
334 markObject(dvmGetFieldObject((Object*)obj,
Barry Hayese1bccb92010-05-18 09:48:37 -0700335 CLASS_OFFSET_FROM_CLZ(rshift)), ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800336 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700337 } else {
Barry Hayese1bccb92010-05-18 09:48:37 -0700338 ClassObject *clazz;
339 int i;
340 for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
341 InstField *field = clazz->ifields;
342 for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
343 void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
344 markObject(((JValue *)addr)->l, ctx);
Barry Hayeseac47ed2009-06-22 11:45:20 -0700345 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700346 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800347 }
348}
349
Barry Hayese1bccb92010-05-18 09:48:37 -0700350/*
351 * Scans the header, static field references, and interface
352 * pointers of a class object.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800353 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700354static void scanClassObject(const ClassObject *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800355{
Barry Hayese1bccb92010-05-18 09:48:37 -0700356 ClassObject *clazz;
357 int i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800358
Barry Hayese1bccb92010-05-18 09:48:37 -0700359 assert(obj != NULL);
360 assert(obj->obj.clazz == gDvm.classJavaLangClass);
361 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800362
Barry Hayese1bccb92010-05-18 09:48:37 -0700363 markObject((Object *)obj->obj.clazz, ctx);
364 if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
365 markObject((Object *)obj->elementClass, ctx);
366 }
367 markObject((Object *)obj->super, ctx);
368 markObject(obj->classLoader, ctx);
369 /* Scan static field references. */
370 for (i = 0; i < obj->sfieldCount; ++i) {
371 char ch = obj->sfields[i].field.signature[0];
372 if (ch == '[' || ch == 'L') {
373 markObject(obj->sfields[i].value.l, ctx);
374 }
375 }
376 /* Scan the instance fields. */
377 scanInstanceFields((const Object *)obj, ctx);
378 /* Scan interface references. */
379 for (i = 0; i < obj->interfaceCount; ++i) {
380 markObject((Object *)obj->interfaces[i], ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800381 }
382}
383
Barry Hayese1bccb92010-05-18 09:48:37 -0700384/*
385 * Scans the header of all array objects. If the array object is
386 * specialized to a reference type, scans the array data as well.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800387 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700388static void scanArrayObject(const ArrayObject *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800389{
Barry Hayese1bccb92010-05-18 09:48:37 -0700390 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800391
Barry Hayese1bccb92010-05-18 09:48:37 -0700392 assert(obj != NULL);
393 assert(obj->obj.clazz != NULL);
394 assert(ctx != NULL);
395 /* Scan the class object reference. */
396 markObject((Object *)obj->obj.clazz, ctx);
397 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISOBJECTARRAY)) {
398 /* Scan the array contents. */
399 Object **contents = (Object **)obj->contents;
400 for (i = 0; i < obj->length; ++i) {
401 markObject(contents[i], ctx);
402 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800403 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700404}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800405
Barry Hayese1bccb92010-05-18 09:48:37 -0700406/*
407 * Process the "referent" field in a java.lang.ref.Reference. If the
408 * referent has not yet been marked, put it on the appropriate list in
409 * the gcHeap for later processing.
410 */
411static void delayReferenceReferent(const DataObject *obj,
412 GcMarkContext *ctx)
413{
414 assert(obj != NULL);
415 assert(obj->obj.clazz != NULL);
416 assert(ctx != NULL);
417
418 GcHeap *gcHeap = gDvm.gcHeap;
419 Object *referent;
420
421 /* It's a subclass of java/lang/ref/Reference.
422 * The fields in this class have been arranged
423 * such that scanInstanceFields() did not actually
424 * mark the "referent" field; we need to handle
425 * it specially.
426 *
427 * If the referent already has a strong mark (isMarked(referent)),
428 * we don't care about its reference status.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800429 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700430 referent = dvmGetFieldObject((Object *)obj,
431 gDvm.offJavaLangRefReference_referent);
432 if (referent != NULL && !isMarked(referent, ctx))
433 {
434 u4 refFlags;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800435
Barry Hayese1bccb92010-05-18 09:48:37 -0700436 /* Find out what kind of reference is pointing
437 * to referent.
438 */
439 refFlags = GET_CLASS_FLAG_GROUP(obj->obj.clazz,
440 CLASS_ISREFERENCE |
441 CLASS_ISWEAKREFERENCE |
442 CLASS_ISPHANTOMREFERENCE);
443
444 /* We use the vmData field of Reference objects
445 * as a next pointer in a singly-linked list.
446 * That way, we don't need to allocate any memory
447 * while we're doing a GC.
448 */
449#define ADD_REF_TO_LIST(list, ref) \
450 do { \
451 Object *ARTL_ref_ = (/*de-const*/Object *)(ref); \
452 dvmSetFieldObject(ARTL_ref_, \
453 gDvm.offJavaLangRefReference_vmData, list); \
454 list = ARTL_ref_; \
455 } while (false)
456
457 /* At this stage, we just keep track of all of
458 * the live references that we've seen. Later,
459 * we'll walk through each of these lists and
460 * deal with the referents.
461 */
462 if (refFlags == CLASS_ISREFERENCE) {
463 /* It's a soft reference. Depending on the state,
464 * we'll attempt to collect all of them, some of
465 * them, or none of them.
466 */
467 ADD_REF_TO_LIST(gcHeap->softReferences, obj);
468 } else {
469 /* It's a weak or phantom reference.
470 * Clearing CLASS_ISREFERENCE will reveal which.
471 */
472 refFlags &= ~CLASS_ISREFERENCE;
473 if (refFlags == CLASS_ISWEAKREFERENCE) {
474 ADD_REF_TO_LIST(gcHeap->weakReferences, obj);
475 } else if (refFlags == CLASS_ISPHANTOMREFERENCE) {
476 ADD_REF_TO_LIST(gcHeap->phantomReferences, obj);
477 } else {
478 assert(!"Unknown reference type");
479 }
480 }
481#undef ADD_REF_TO_LIST
482 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800483}
484
Barry Hayese1bccb92010-05-18 09:48:37 -0700485/*
486 * Scans the header and field references of a data object.
487 */
488static void scanDataObject(const DataObject *obj, GcMarkContext *ctx)
489{
490 assert(obj != NULL);
491 assert(obj->obj.clazz != NULL);
492 assert(ctx != NULL);
493 /* Scan the class object. */
494 markObject((Object *)obj->obj.clazz, ctx);
495 /* Scan the instance fields. */
496 scanInstanceFields((const Object *)obj, ctx);
497
498 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISREFERENCE)) {
499 delayReferenceReferent(obj, ctx);
500 }
501}
502
503/*
504 * Scans an object reference. Determines the type of the reference
505 * and dispatches to a specialized scanning routine.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800506 */
507static void scanObject(const Object *obj, GcMarkContext *ctx)
508{
509 ClassObject *clazz;
510
Barry Hayese1bccb92010-05-18 09:48:37 -0700511 assert(obj != NULL);
512 assert(ctx != NULL);
513 /* Check that the object is aligned. */
514 assert(((uintptr_t)obj & 7) == 0);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800515 clazz = obj->clazz;
Barry Hayese1bccb92010-05-18 09:48:37 -0700516 /* Check that the class object is aligned. */
517 assert(((uintptr_t)clazz & 7) == 0);
518 /* Dispatch a type-specific scan routine. */
519 if (clazz == gDvm.classJavaLangClass) {
520 scanClassObject((ClassObject *)obj, ctx);
521 } else if (clazz == NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800522 return;
523 } else if (clazz == gDvm.unlinkedJavaLangClass) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800524 return;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800525 } else {
Barry Hayese1bccb92010-05-18 09:48:37 -0700526 assert(clazz != NULL);
527 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
528 scanArrayObject((ArrayObject *)obj, ctx);
529 } else {
530 scanDataObject((DataObject *)obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800531 }
532 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800533}
534
535static void
536processMarkStack(GcMarkContext *ctx)
537{
538 const Object **const base = ctx->stack.base;
539
540 /* Scan anything that's on the mark stack.
541 * We can't use the bitmaps anymore, so use
542 * a finger that points past the end of them.
543 */
544 ctx->finger = (void *)ULONG_MAX;
545 while (ctx->stack.top != base) {
546 scanObject(*ctx->stack.top++, ctx);
547 }
548}
549
550#ifndef NDEBUG
551static uintptr_t gLastFinger = 0;
552#endif
553
554static bool
555scanBitmapCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
556{
557 GcMarkContext *ctx = (GcMarkContext *)arg;
558 size_t i;
559
560#ifndef NDEBUG
561 assert((uintptr_t)finger >= gLastFinger);
562 gLastFinger = (uintptr_t)finger;
563#endif
564
565 ctx->finger = finger;
566 for (i = 0; i < numPtrs; i++) {
Carl Shapiro6343bd02010-02-16 17:40:19 -0800567 scanObject(*ptrs++, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800568 }
569
570 return true;
571}
572
573/* Given bitmaps with the root set marked, find and mark all
574 * reachable objects. When this returns, the entire set of
575 * live objects will be marked and the mark stack will be empty.
576 */
Carl Shapiro29540742010-03-26 15:34:39 -0700577void dvmHeapScanMarkedObjects(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800578{
579 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
580
581 assert(ctx->finger == NULL);
582
583 /* The bitmaps currently have bits set for the root set.
584 * Walk across the bitmaps and scan each object.
585 */
586#ifndef NDEBUG
587 gLastFinger = 0;
588#endif
Carl Shapirof373efd2010-02-19 00:46:33 -0800589 dvmHeapBitmapWalk(ctx->bitmap, scanBitmapCallback, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800590
591 /* We've walked the mark bitmaps. Scan anything that's
592 * left on the mark stack.
593 */
594 processMarkStack(ctx);
595
596 LOG_SCAN("done with marked objects\n");
597}
598
Barry Hayes6930a112009-12-22 11:01:38 -0800599/** Clear the referent field.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800600 */
Barry Hayes6930a112009-12-22 11:01:38 -0800601static void clearReference(Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800602{
603 /* This is what the default implementation of Reference.clear()
604 * does. We're required to clear all references to a given
605 * referent atomically, so we can't pop in and out of interp
606 * code each time.
607 *
Barry Hayes6930a112009-12-22 11:01:38 -0800608 * We don't ever actaully call overriding implementations of
609 * Reference.clear().
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800610 */
611 dvmSetFieldObject(reference,
612 gDvm.offJavaLangRefReference_referent, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800613}
614
Carl Shapiro29540742010-03-26 15:34:39 -0700615/*
616 * Returns true if the reference was registered with a reference queue
617 * and has not yet been enqueued.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800618 */
Carl Shapiro29540742010-03-26 15:34:39 -0700619static bool isEnqueuable(const Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800620{
Barry Hayes6930a112009-12-22 11:01:38 -0800621 Object *queue = dvmGetFieldObject(reference,
622 gDvm.offJavaLangRefReference_queue);
623 Object *queueNext = dvmGetFieldObject(reference,
624 gDvm.offJavaLangRefReference_queueNext);
625 if (queue == NULL || queueNext != NULL) {
626 /* There is no queue, or the reference has already
627 * been enqueued. The Reference.enqueue() method
628 * will do nothing even if we call it.
629 */
630 return false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800631 }
632
633 /* We need to call enqueue(), but if we called it from
634 * here we'd probably deadlock. Schedule a call.
635 */
636 return true;
637}
638
Carl Shapiro29540742010-03-26 15:34:39 -0700639/*
640 * Schedules a reference to be appended to its reference queue.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800641 */
Carl Shapiro29540742010-03-26 15:34:39 -0700642static void enqueueReference(Object *ref)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800643{
Carl Shapiro29540742010-03-26 15:34:39 -0700644 LargeHeapRefTable **table;
645 Object *op;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800646
Carl Shapiro29540742010-03-26 15:34:39 -0700647 assert(((uintptr_t)ref & 3) == 0);
648 assert((WORKER_ENQUEUE & ~3) == 0);
649 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
650 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
651 /* Stuff the enqueue bit in the bottom of the pointer.
652 * Assumes that objects are 8-byte aligned.
Andy McFaddenb18992f2009-09-25 10:42:15 -0700653 *
Carl Shapiro29540742010-03-26 15:34:39 -0700654 * Note that we are adding the *Reference* (which
655 * is by definition already marked at this point) to
656 * this list; we're not adding the referent (which
657 * has already been cleared).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800658 */
Carl Shapiro29540742010-03-26 15:34:39 -0700659 table = &gDvm.gcHeap->referenceOperations;
660 op = (Object *)((uintptr_t)ref | WORKER_ENQUEUE);
661 if (!dvmHeapAddRefToLargeTable(table, op)) {
662 LOGE_HEAP("enqueueReference(): no room for any more "
663 "reference operations\n");
664 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800665 }
666}
667
Carl Shapiro29540742010-03-26 15:34:39 -0700668/*
669 * Walks the reference list marking any references subject to the
670 * reference clearing policy. References with a black referent are
671 * removed from the list. References with white referents biased
672 * toward saving are blackened and also removed from the list.
673 */
674void dvmHandleSoftRefs(Object **list)
675{
676 GcMarkContext *markContext;
677 Object *ref, *referent;
678 Object *prev, *next;
679 size_t referentOffset, vmDataOffset;
680 unsigned counter;
681 bool marked;
682
683 markContext = &gDvm.gcHeap->markContext;
684 vmDataOffset = gDvm.offJavaLangRefReference_vmData;
685 referentOffset = gDvm.offJavaLangRefReference_referent;
686 counter = 0;
687 prev = next = NULL;
688 ref = *list;
689 while (ref != NULL) {
690 referent = dvmGetFieldObject(ref, referentOffset);
691 next = dvmGetFieldObject(ref, vmDataOffset);
692 assert(referent != NULL);
693 marked = isMarked(referent, markContext);
694 if (!marked && ((++counter) & 1)) {
695 /* Referent is white and biased toward saving, mark it. */
Barry Hayese1bccb92010-05-18 09:48:37 -0700696 assert(referent != NULL);
697 markObject(referent, markContext);
Carl Shapiro29540742010-03-26 15:34:39 -0700698 marked = true;
699 }
700 if (marked) {
701 /* Referent is black, unlink it. */
702 if (prev != NULL) {
703 dvmSetFieldObject(ref, vmDataOffset, NULL);
704 dvmSetFieldObject(prev, vmDataOffset, next);
705 }
706 } else {
707 /* Referent is white, skip over it. */
708 prev = ref;
709 }
710 ref = next;
711 }
712 /*
713 * Restart the mark with the newly black references added to the
714 * root set.
715 */
716 processMarkStack(markContext);
717}
718
719/*
720 * Walks the reference list and clears references with an unmarked
721 * (white) referents. Cleared references registered to a reference
722 * queue are scheduled for appending by the heap worker thread.
723 */
724void dvmClearWhiteRefs(Object **list)
725{
726 GcMarkContext *markContext;
727 Object *ref, *referent;
728 size_t referentOffset, vmDataOffset;
729 bool doSignal;
730
731 markContext = &gDvm.gcHeap->markContext;
732 vmDataOffset = gDvm.offJavaLangRefReference_vmData;
733 referentOffset = gDvm.offJavaLangRefReference_referent;
734 doSignal = false;
735 while (*list != NULL) {
736 ref = *list;
737 referent = dvmGetFieldObject(ref, referentOffset);
738 *list = dvmGetFieldObject(ref, vmDataOffset);
739 assert(referent != NULL);
740 if (!isMarked(referent, markContext)) {
741 /* Referent is "white", clear it. */
742 clearReference(ref);
743 if (isEnqueuable(ref)) {
744 enqueueReference(ref);
745 doSignal = true;
746 }
747 }
748 }
749 /*
750 * If we cleared a reference with a reference queue we must notify
751 * the heap worker to append the reference.
752 */
753 if (doSignal) {
754 dvmSignalHeapWorker(false);
755 }
756 assert(*list == NULL);
757}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800758
759/* Find unreachable objects that need to be finalized,
760 * and schedule them for finalization.
761 */
762void dvmHeapScheduleFinalizations()
763{
764 HeapRefTable newPendingRefs;
765 LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
766 Object **ref;
767 Object **lastRef;
768 size_t totalPendCount;
769 GcMarkContext *markContext = &gDvm.gcHeap->markContext;
770
771 /*
772 * All reachable objects have been marked.
773 * Any unmarked finalizable objects need to be finalized.
774 */
775
776 /* Create a table that the new pending refs will
777 * be added to.
778 */
779 if (!dvmHeapInitHeapRefTable(&newPendingRefs, 128)) {
780 //TODO: mark all finalizable refs and hope that
781 // we can schedule them next time. Watch out,
782 // because we may be expecting to free up space
783 // by calling finalizers.
784 LOGE_GC("dvmHeapScheduleFinalizations(): no room for "
785 "pending finalizations\n");
786 dvmAbort();
787 }
788
789 /* Walk through finalizableRefs and move any unmarked references
790 * to the list of new pending refs.
791 */
792 totalPendCount = 0;
793 while (finRefs != NULL) {
794 Object **gapRef;
795 size_t newPendCount = 0;
796
797 gapRef = ref = finRefs->refs.table;
798 lastRef = finRefs->refs.nextEntry;
799 while (ref < lastRef) {
Carl Shapiro6343bd02010-02-16 17:40:19 -0800800 if (!isMarked(*ref, markContext)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800801 if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
802 //TODO: add the current table and allocate
803 // a new, smaller one.
804 LOGE_GC("dvmHeapScheduleFinalizations(): "
805 "no room for any more pending finalizations: %zd\n",
806 dvmHeapNumHeapRefTableEntries(&newPendingRefs));
807 dvmAbort();
808 }
809 newPendCount++;
810 } else {
811 /* This ref is marked, so will remain on finalizableRefs.
812 */
813 if (newPendCount > 0) {
814 /* Copy it up to fill the holes.
815 */
816 *gapRef++ = *ref;
817 } else {
818 /* No holes yet; don't bother copying.
819 */
820 gapRef++;
821 }
822 }
823 ref++;
824 }
825 finRefs->refs.nextEntry = gapRef;
826 //TODO: if the table is empty when we're done, free it.
827 totalPendCount += newPendCount;
828 finRefs = finRefs->next;
829 }
830 LOGD_GC("dvmHeapScheduleFinalizations(): %zd finalizers triggered.\n",
831 totalPendCount);
832 if (totalPendCount == 0) {
833 /* No objects required finalization.
834 * Free the empty temporary table.
835 */
836 dvmClearReferenceTable(&newPendingRefs);
837 return;
838 }
839
840 /* Add the new pending refs to the main list.
841 */
842 if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
843 &newPendingRefs))
844 {
845 LOGE_GC("dvmHeapScheduleFinalizations(): can't insert new "
846 "pending finalizations\n");
847 dvmAbort();
848 }
849
850 //TODO: try compacting the main list with a memcpy loop
851
852 /* Mark the refs we just moved; we don't want them or their
853 * children to get swept yet.
854 */
855 ref = newPendingRefs.table;
856 lastRef = newPendingRefs.nextEntry;
857 assert(ref < lastRef);
858 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
859 while (ref < lastRef) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700860 assert(*ref != NULL);
861 markObject(*ref, markContext);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800862 ref++;
863 }
864 HPROF_CLEAR_GC_SCAN_STATE();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800865 processMarkStack(markContext);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800866 dvmSignalHeapWorker(false);
867}
868
869void dvmHeapFinishMarkStep()
870{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800871 GcMarkContext *markContext;
872
873 markContext = &gDvm.gcHeap->markContext;
874
875 /* The sweep step freed every object that appeared in the
876 * HeapSource bitmaps that didn't appear in the mark bitmaps.
877 * The new state of the HeapSource is exactly the final
878 * mark bitmaps, so swap them in.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800879 */
Carl Shapirof373efd2010-02-19 00:46:33 -0800880 dvmHeapSourceSwapBitmaps();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800881
Carl Shapirof373efd2010-02-19 00:46:33 -0800882 /* Clean up everything else associated with the marking process.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800883 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800884 destroyMarkStack(&markContext->stack);
885
Carl Shapirof373efd2010-02-19 00:46:33 -0800886 markContext->finger = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800887}
888
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800889static bool
890sweepBitmapCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
891{
892 const ClassObject *const classJavaLangClass = gDvm.classJavaLangClass;
Barry Hayes5cbb2302010-02-02 14:07:37 -0800893 const bool overwriteFree = gDvm.overwriteFree;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800894 size_t i;
Barry Hayesdde8ab02009-05-20 12:10:36 -0700895 void **origPtrs = ptrs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800896
897 for (i = 0; i < numPtrs; i++) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800898 Object *obj;
899
Carl Shapiro6343bd02010-02-16 17:40:19 -0800900 obj = (Object *)*ptrs++;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800901
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800902 /* NOTE: Dereferencing clazz is dangerous. If obj was the last
903 * one to reference its class object, the class object could be
904 * on the sweep list, and could already have been swept, leaving
905 * us with a stale pointer.
906 */
907 LOGV_SWEEP("FREE: 0x%08x %s\n", (uint)obj, obj->clazz->name);
908
909 /* This assumes that java.lang.Class will never go away.
910 * If it can, and we were the last reference to it, it
911 * could have already been swept. However, even in that case,
912 * gDvm.classJavaLangClass should still have a useful
913 * value.
914 */
915 if (obj->clazz == classJavaLangClass) {
916 LOGV_SWEEP("---------------> %s\n", ((ClassObject *)obj)->name);
917 /* dvmFreeClassInnards() may have already been called,
918 * but it's safe to call on the same ClassObject twice.
919 */
920 dvmFreeClassInnards((ClassObject *)obj);
921 }
922
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800923 /* Overwrite the to-be-freed object to make stale references
924 * more obvious.
925 */
Barry Hayes5cbb2302010-02-02 14:07:37 -0800926 if (overwriteFree) {
Barry Hayes2e3c3e12010-02-22 09:39:10 -0800927 int objlen;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800928 ClassObject *clazz = obj->clazz;
Barry Hayes2e3c3e12010-02-22 09:39:10 -0800929 objlen = dvmHeapSourceChunkSize(obj);
930 memset(obj, 0xa5, objlen);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800931 obj->clazz = (ClassObject *)((uintptr_t)clazz ^ 0xffffffff);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800932 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800933 }
Barry Hayesdde8ab02009-05-20 12:10:36 -0700934 // TODO: dvmHeapSourceFreeList has a loop, just like the above
935 // does. Consider collapsing the two loops to save overhead.
936 dvmHeapSourceFreeList(numPtrs, origPtrs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800937
938 return true;
939}
940
Carl Shapiro5a6071b2010-01-07 21:35:50 -0800941/* Returns true if the given object is unmarked. Ignores the low bits
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800942 * of the pointer because the intern table may set them.
943 */
944static int isUnmarkedObject(void *object)
945{
Carl Shapiro6343bd02010-02-16 17:40:19 -0800946 return !isMarked((void *)((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800947 &gDvm.gcHeap->markContext);
948}
949
950/* Walk through the list of objects that haven't been
951 * marked and free them.
952 */
953void
Carl Shapirod25566d2010-03-11 20:39:47 -0800954dvmHeapSweepUnmarkedObjects(GcMode mode, int *numFreed, size_t *sizeFreed)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800955{
Carl Shapirof373efd2010-02-19 00:46:33 -0800956 HeapBitmap markBits[HEAP_SOURCE_MAX_HEAP_COUNT];
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700957 HeapBitmap liveBits[HEAP_SOURCE_MAX_HEAP_COUNT];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800958 size_t origObjectsAllocated;
959 size_t origBytesAllocated;
Carl Shapirod25566d2010-03-11 20:39:47 -0800960 size_t numBitmaps, numSweepBitmaps;
Barry Hayese168ebd2010-05-07 09:19:46 -0700961 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800962
963 /* All reachable objects have been marked.
964 * Detach any unreachable interned strings before
965 * we sweep.
966 */
967 dvmGcDetachDeadInternedStrings(isUnmarkedObject);
968
969 /* Free any known objects that are not marked.
970 */
971 origObjectsAllocated = dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0);
972 origBytesAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
973
Carl Shapiro5a6071b2010-01-07 21:35:50 -0800974 dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
975
Carl Shapirof373efd2010-02-19 00:46:33 -0800976 numBitmaps = dvmHeapSourceGetNumHeaps();
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700977 dvmHeapSourceGetObjectBitmaps(liveBits, markBits, numBitmaps);
Carl Shapirod25566d2010-03-11 20:39:47 -0800978 if (mode == GC_PARTIAL) {
979 numSweepBitmaps = 1;
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700980 assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == liveBits[0].base);
Carl Shapirod25566d2010-03-11 20:39:47 -0800981 } else {
982 numSweepBitmaps = numBitmaps;
983 }
Barry Hayese168ebd2010-05-07 09:19:46 -0700984 for (i = 0; i < numSweepBitmaps; i++) {
985 dvmHeapBitmapXorWalk(&markBits[i], &liveBits[i],
986 sweepBitmapCallback, NULL);
987 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800988
989 *numFreed = origObjectsAllocated -
990 dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0);
991 *sizeFreed = origBytesAllocated -
992 dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
993
994#ifdef WITH_PROFILER
995 if (gDvm.allocProf.enabled) {
996 gDvm.allocProf.freeCount += *numFreed;
997 gDvm.allocProf.freeSize += *sizeFreed;
998 }
999#endif
1000}