blob: bde1b49e8821941d6f41206f702e518584926845 [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"
Carl Shapiroec805ea2010-06-28 16:28:26 -070023#include "alloc/Visit.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080024#include <limits.h> // for ULONG_MAX
25#include <sys/mman.h> // for madvise(), mmap()
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 GC_LOG_TAG LOG_TAG "-gc"
29
30#if LOG_NDEBUG
31#define LOGV_GC(...) ((void)0)
32#define LOGD_GC(...) ((void)0)
33#else
34#define LOGV_GC(...) LOG(LOG_VERBOSE, GC_LOG_TAG, __VA_ARGS__)
35#define LOGD_GC(...) LOG(LOG_DEBUG, GC_LOG_TAG, __VA_ARGS__)
36#endif
37
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080038#define LOGI_GC(...) LOG(LOG_INFO, GC_LOG_TAG, __VA_ARGS__)
39#define LOGW_GC(...) LOG(LOG_WARN, GC_LOG_TAG, __VA_ARGS__)
40#define LOGE_GC(...) LOG(LOG_ERROR, GC_LOG_TAG, __VA_ARGS__)
41
42#define LOG_SCAN(...) LOGV_GC("SCAN: " __VA_ARGS__)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080043
Carl Shapiro57ee2702010-08-27 13:06:48 -070044#define ALIGN_UP(x, n) (((size_t)(x) + (n) - 1) & ~((n) - 1))
45#define ALIGN_UP_TO_PAGE_SIZE(p) ALIGN_UP(p, SYSTEM_PAGE_SIZE)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080046
47/* Do not cast the result of this to a boolean; the only set bit
48 * may be > 1<<8.
49 */
Carl Shapiro6343bd02010-02-16 17:40:19 -080050static inline long isMarked(const void *obj, const GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080051{
Carl Shapirof373efd2010-02-19 00:46:33 -080052 return dvmHeapBitmapIsObjectBitSet(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080053}
54
Carl Shapirod7400e02010-09-02 18:24:29 -070055static bool createMarkStack(GcMarkStack *stack)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080056{
57 const Object **limit;
Carl Shapiro742c4452010-07-13 18:28:13 -070058 const char *name;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080059 size_t size;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080060
61 /* Create a stack big enough for the worst possible case,
62 * where the heap is perfectly full of the smallest object.
63 * TODO: be better about memory usage; use a smaller stack with
64 * overflow detection and recovery.
65 */
66 size = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
67 (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
68 size = ALIGN_UP_TO_PAGE_SIZE(size);
Carl Shapiro742c4452010-07-13 18:28:13 -070069 name = "dalvik-mark-stack";
70 limit = dvmAllocRegion(size, PROT_READ | PROT_WRITE, name);
71 if (limit == NULL) {
72 LOGE_GC("Could not mmap %zd-byte ashmem region '%s'", size, name);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080073 return false;
74 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080075 stack->limit = limit;
76 stack->base = (const Object **)((uintptr_t)limit + size);
77 stack->top = stack->base;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080078 return true;
79}
80
Carl Shapirod7400e02010-09-02 18:24:29 -070081static void destroyMarkStack(GcMarkStack *stack)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080082{
83 munmap((char *)stack->limit,
84 (uintptr_t)stack->base - (uintptr_t)stack->limit);
85 memset(stack, 0, sizeof(*stack));
86}
87
88#define MARK_STACK_PUSH(stack, obj) \
89 do { \
90 *--(stack).top = (obj); \
91 } while (false)
92
Carl Shapirod7400e02010-09-02 18:24:29 -070093bool dvmHeapBeginMarkStep(GcMode mode)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080094{
Carl Shapirob2e78d32010-08-20 11:34:18 -070095 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080096
Carl Shapirob2e78d32010-08-20 11:34:18 -070097 if (!createMarkStack(&ctx->stack)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080098 return false;
99 }
Carl Shapirob2e78d32010-08-20 11:34:18 -0700100 ctx->finger = NULL;
101 ctx->immuneLimit = dvmHeapSourceGetImmuneLimit(mode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800102 return true;
103}
104
Carl Shapirod7400e02010-09-02 18:24:29 -0700105static long setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800106{
Carl Shapirof373efd2010-02-19 00:46:33 -0800107 return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800108}
109
Carl Shapirod7400e02010-09-02 18:24:29 -0700110static void markObjectNonNull(const Object *obj, GcMarkContext *ctx,
111 bool checkFinger)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800112{
Barry Hayese1bccb92010-05-18 09:48:37 -0700113 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800114 assert(obj != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800115 assert(dvmIsValidObject(obj));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800116
Carl Shapirob31b3012010-05-25 18:35:37 -0700117 if (obj < (Object *)ctx->immuneLimit) {
Carl Shapirod25566d2010-03-11 20:39:47 -0800118 assert(isMarked(obj, ctx));
119 return;
120 }
Carl Shapiro6343bd02010-02-16 17:40:19 -0800121 if (!setAndReturnMarkBit(ctx, obj)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800122 /* This object was not previously marked.
123 */
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700124 if (checkFinger && (void *)obj < ctx->finger) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800125 /* This object will need to go on the mark stack.
126 */
127 MARK_STACK_PUSH(ctx->stack, obj);
128 }
129
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800130#if WITH_HPROF
131 if (gDvm.gcHeap->hprofContext != NULL) {
132 hprofMarkRootObject(gDvm.gcHeap->hprofContext, obj, 0);
133 }
134#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800135 }
136}
137
138/* Used to mark objects when recursing. Recursion is done by moving
139 * the finger across the bitmaps in address order and marking child
140 * objects. Any newly-marked objects whose addresses are lower than
141 * the finger won't be visited by the bitmap scan, so those objects
142 * need to be added to the mark stack.
143 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700144static void markObject(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800145{
Barry Hayese1bccb92010-05-18 09:48:37 -0700146 if (obj != NULL) {
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700147 markObjectNonNull(obj, ctx, true);
Barry Hayese1bccb92010-05-18 09:48:37 -0700148 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800149}
150
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800151/* If the object hasn't already been marked, mark it and
152 * schedule it to be scanned for references.
153 *
154 * obj may not be NULL. The macro dvmMarkObject() should
155 * be used in situations where a reference may be NULL.
156 *
157 * This function may only be called when marking the root
Barry Hayese1bccb92010-05-18 09:48:37 -0700158 * set. When recursing, use the internal markObject().
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800159 */
Carl Shapirod7400e02010-09-02 18:24:29 -0700160void dvmMarkObjectNonNull(const Object *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800161{
Barry Hayese1bccb92010-05-18 09:48:37 -0700162 assert(obj != NULL);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700163 markObjectNonNull(obj, &gDvm.gcHeap->markContext, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800164}
165
166/* Mark the set of root objects.
167 *
168 * Things we need to scan:
169 * - System classes defined by root classloader
170 * - For each thread:
171 * - Interpreted stack, from top to "curFrame"
172 * - Dalvik registers (args + local vars)
173 * - JNI local references
174 * - Automatic VM local references (TrackedAlloc)
175 * - Associated Thread/VMThread object
176 * - ThreadGroups (could track & start with these instead of working
177 * upward from Threads)
178 * - Exception currently being thrown, if present
179 * - JNI global references
180 * - Interned string table
181 * - Primitive classes
182 * - Special objects
183 * - gDvm.outOfMemoryObj
184 * - Objects allocated with ALLOC_NO_GC
185 * - Objects pending finalization (but not yet finalized)
186 * - Objects in debugger object registry
187 *
188 * Don't need:
189 * - Native stack (for in-progress stuff in the VM)
190 * - The TrackedAlloc stuff watches all native VM references.
191 */
192void dvmHeapMarkRootSet()
193{
Barry Hayesd4f78d32010-06-08 09:34:42 -0700194 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800195
196 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_STICKY_CLASS, 0);
197
Carl Shapirod25566d2010-03-11 20:39:47 -0800198 LOG_SCAN("immune objects");
Barry Hayes425848f2010-05-04 13:32:12 -0700199 dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
Carl Shapirod25566d2010-03-11 20:39:47 -0800200
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800201 LOG_SCAN("root class loader\n");
202 dvmGcScanRootClassLoader();
203 LOG_SCAN("primitive classes\n");
204 dvmGcScanPrimitiveClasses();
205
206 /* dvmGcScanRootThreadGroups() sets a bunch of
207 * different scan states internally.
208 */
209 HPROF_CLEAR_GC_SCAN_STATE();
210
211 LOG_SCAN("root thread groups\n");
212 dvmGcScanRootThreadGroups();
213
214 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_INTERNED_STRING, 0);
215
216 LOG_SCAN("interned strings\n");
217 dvmGcScanInternedStrings();
218
219 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_GLOBAL, 0);
220
221 LOG_SCAN("JNI global refs\n");
222 dvmGcMarkJniGlobalRefs();
223
224 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
225
226 LOG_SCAN("pending reference operations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700227 dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800228
229 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
230
231 LOG_SCAN("pending finalizations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700232 dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800233
234 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_DEBUGGER, 0);
235
236 LOG_SCAN("debugger refs\n");
237 dvmGcMarkDebuggerRefs();
238
239 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_VM_INTERNAL, 0);
240
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800241 /* Mark any special objects we have sitting around.
242 */
243 LOG_SCAN("special objects\n");
244 dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
245 dvmMarkObjectNonNull(gDvm.internalErrorObj);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700246 dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800247//TODO: scan object references sitting in gDvm; use pointer begin & end
248
249 HPROF_CLEAR_GC_SCAN_STATE();
250}
251
252/*
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700253 * Callback applied to root references. If the root location contains
254 * a white reference it is pushed on the mark stack and grayed.
255 */
256static void markObjectVisitor(void *addr, void *arg)
257{
258 Object *obj;
259
260 assert(addr != NULL);
261 assert(arg != NULL);
262 obj = *(Object **)addr;
263 if (obj != NULL) {
264 markObjectNonNull(obj, arg, true);
265 }
266}
267
268/*
269 * Grays all references in the roots.
270 */
271void dvmHeapReMarkRootSet(void)
272{
273 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
274 assert(ctx->finger == (void *)ULONG_MAX);
275 dvmVisitRoots(markObjectVisitor, ctx);
276}
277
278/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700279 * Nothing past this point is allowed to use dvmMarkObject() or
280 * dvmMarkObjectNonNull(), which are for root-marking only.
281 * Scanning/recursion must use markObject(), which takes the finger
282 * into account.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800283 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700284#undef dvmMarkObject
285#define dvmMarkObject __dont_use_dvmMarkObject__
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800286#define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
287
Barry Hayese1bccb92010-05-18 09:48:37 -0700288/*
289 * Scans instance fields.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800290 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700291static void scanInstanceFields(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800292{
Barry Hayese1bccb92010-05-18 09:48:37 -0700293 assert(obj != NULL);
294 assert(obj->clazz != NULL);
295 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800296
Barry Hayese1bccb92010-05-18 09:48:37 -0700297 if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
298 unsigned int refOffsets = obj->clazz->refOffsets;
Barry Hayeseac47ed2009-06-22 11:45:20 -0700299 while (refOffsets != 0) {
300 const int rshift = CLZ(refOffsets);
301 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
302 markObject(dvmGetFieldObject((Object*)obj,
Barry Hayese1bccb92010-05-18 09:48:37 -0700303 CLASS_OFFSET_FROM_CLZ(rshift)), ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800304 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700305 } else {
Barry Hayese1bccb92010-05-18 09:48:37 -0700306 ClassObject *clazz;
307 int i;
308 for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
309 InstField *field = clazz->ifields;
310 for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
311 void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
312 markObject(((JValue *)addr)->l, ctx);
Barry Hayeseac47ed2009-06-22 11:45:20 -0700313 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700314 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800315 }
316}
317
Barry Hayese1bccb92010-05-18 09:48:37 -0700318/*
319 * Scans the header, static field references, and interface
320 * pointers of a class object.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800321 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700322static void scanClassObject(const ClassObject *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800323{
Barry Hayese1bccb92010-05-18 09:48:37 -0700324 int i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800325
Barry Hayese1bccb92010-05-18 09:48:37 -0700326 assert(obj != NULL);
327 assert(obj->obj.clazz == gDvm.classJavaLangClass);
328 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800329
Barry Hayese1bccb92010-05-18 09:48:37 -0700330 markObject((Object *)obj->obj.clazz, ctx);
331 if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
332 markObject((Object *)obj->elementClass, ctx);
333 }
Barry Hayesc49db852010-05-14 13:43:34 -0700334 /* Do super and the interfaces contain Objects and not dex idx values? */
335 if (obj->status > CLASS_IDX) {
336 markObject((Object *)obj->super, ctx);
337 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700338 markObject(obj->classLoader, ctx);
339 /* Scan static field references. */
340 for (i = 0; i < obj->sfieldCount; ++i) {
341 char ch = obj->sfields[i].field.signature[0];
342 if (ch == '[' || ch == 'L') {
343 markObject(obj->sfields[i].value.l, ctx);
344 }
345 }
346 /* Scan the instance fields. */
347 scanInstanceFields((const Object *)obj, ctx);
348 /* Scan interface references. */
Barry Hayesc49db852010-05-14 13:43:34 -0700349 if (obj->status > CLASS_IDX) {
350 for (i = 0; i < obj->interfaceCount; ++i) {
351 markObject((Object *)obj->interfaces[i], ctx);
352 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800353 }
354}
355
Barry Hayese1bccb92010-05-18 09:48:37 -0700356/*
357 * Scans the header of all array objects. If the array object is
358 * specialized to a reference type, scans the array data as well.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800359 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700360static void scanArrayObject(const ArrayObject *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800361{
Barry Hayese1bccb92010-05-18 09:48:37 -0700362 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800363
Barry Hayese1bccb92010-05-18 09:48:37 -0700364 assert(obj != NULL);
365 assert(obj->obj.clazz != NULL);
366 assert(ctx != NULL);
367 /* Scan the class object reference. */
368 markObject((Object *)obj->obj.clazz, ctx);
369 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISOBJECTARRAY)) {
370 /* Scan the array contents. */
371 Object **contents = (Object **)obj->contents;
372 for (i = 0; i < obj->length; ++i) {
373 markObject(contents[i], ctx);
374 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800375 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700376}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800377
Barry Hayese1bccb92010-05-18 09:48:37 -0700378/*
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700379 * Returns class flags relating to Reference subclasses.
380 */
381static int referenceClassFlags(const Object *obj)
382{
383 int flags = CLASS_ISREFERENCE |
384 CLASS_ISWEAKREFERENCE |
385 CLASS_ISPHANTOMREFERENCE;
386 return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
387}
388
389/*
390 * Returns true if the object derives from SoftReference.
391 */
392static bool isSoftReference(const Object *obj)
393{
394 return referenceClassFlags(obj) == CLASS_ISREFERENCE;
395}
396
397/*
398 * Returns true if the object derives from WeakReference.
399 */
400static bool isWeakReference(const Object *obj)
401{
402 return referenceClassFlags(obj) & CLASS_ISWEAKREFERENCE;
403}
404
405/*
406 * Returns true if the object derives from PhantomReference.
407 */
408static bool isPhantomReference(const Object *obj)
409{
410 return referenceClassFlags(obj) & CLASS_ISPHANTOMREFERENCE;
411}
412
413/*
414 * Adds a reference to the tail of a circular queue of references.
415 */
416static void enqueuePendingReference(Object *ref, Object **list)
417{
418 size_t offset;
419
420 assert(ref != NULL);
421 assert(list != NULL);
422 offset = gDvm.offJavaLangRefReference_pendingNext;
423 if (*list == NULL) {
424 dvmSetFieldObject(ref, offset, ref);
425 *list = ref;
426 } else {
427 Object *head = dvmGetFieldObject(*list, offset);
428 dvmSetFieldObject(ref, offset, head);
429 dvmSetFieldObject(*list, offset, ref);
430 }
431}
432
433/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700434 * Removes the reference at the head of a circular queue of
435 * references.
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700436 */
437static Object *dequeuePendingReference(Object **list)
438{
439 Object *ref, *head;
440 size_t offset;
441
442 assert(list != NULL);
443 assert(*list != NULL);
444 offset = gDvm.offJavaLangRefReference_pendingNext;
445 head = dvmGetFieldObject(*list, offset);
446 if (*list == head) {
447 ref = *list;
448 *list = NULL;
449 } else {
450 Object *next = dvmGetFieldObject(head, offset);
451 dvmSetFieldObject(*list, offset, next);
452 ref = head;
453 }
454 dvmSetFieldObject(ref, offset, NULL);
455 return ref;
456}
457
458/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700459 * Process the "referent" field in a java.lang.ref.Reference. If the
460 * referent has not yet been marked, put it on the appropriate list in
461 * the gcHeap for later processing.
462 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700463static void delayReferenceReferent(Object *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700464{
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700465 GcHeap *gcHeap = gDvm.gcHeap;
466 Object *pending, *referent;
467 size_t pendingNextOffset, referentOffset;
468
Barry Hayese1bccb92010-05-18 09:48:37 -0700469 assert(obj != NULL);
Barry Hayes697b5a92010-06-23 11:38:52 -0700470 assert(obj->clazz != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700471 assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
Barry Hayese1bccb92010-05-18 09:48:37 -0700472 assert(ctx != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700473 pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
474 referentOffset = gDvm.offJavaLangRefReference_referent;
475 pending = dvmGetFieldObject(obj, pendingNextOffset);
476 referent = dvmGetFieldObject(obj, referentOffset);
477 if (pending == NULL && referent != NULL && !isMarked(referent, ctx)) {
478 Object **list = NULL;
479 if (isSoftReference(obj)) {
480 list = &gcHeap->softReferences;
481 } else if (isWeakReference(obj)) {
482 list = &gcHeap->weakReferences;
483 } else if (isPhantomReference(obj)) {
484 list = &gcHeap->phantomReferences;
Barry Hayese1bccb92010-05-18 09:48:37 -0700485 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700486 assert(list != NULL);
487 enqueuePendingReference(obj, list);
Barry Hayese1bccb92010-05-18 09:48:37 -0700488 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800489}
490
Barry Hayese1bccb92010-05-18 09:48:37 -0700491/*
492 * Scans the header and field references of a data object.
493 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700494static void scanDataObject(DataObject *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700495{
496 assert(obj != NULL);
497 assert(obj->obj.clazz != NULL);
498 assert(ctx != NULL);
499 /* Scan the class object. */
500 markObject((Object *)obj->obj.clazz, ctx);
501 /* Scan the instance fields. */
502 scanInstanceFields((const Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700503 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISREFERENCE)) {
Barry Hayes697b5a92010-06-23 11:38:52 -0700504 delayReferenceReferent((Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700505 }
506}
507
508/*
509 * Scans an object reference. Determines the type of the reference
510 * and dispatches to a specialized scanning routine.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800511 */
512static void scanObject(const Object *obj, GcMarkContext *ctx)
513{
Barry Hayese1bccb92010-05-18 09:48:37 -0700514 assert(obj != NULL);
515 assert(ctx != NULL);
Barry Hayes899cdb72010-06-08 09:59:12 -0700516 assert(obj->clazz != NULL);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700517#if WITH_HPROF
518 if (gDvm.gcHeap->hprofContext != NULL) {
519 hprofDumpHeapObject(gDvm.gcHeap->hprofContext, obj);
520 }
521#endif
Barry Hayese1bccb92010-05-18 09:48:37 -0700522 /* Dispatch a type-specific scan routine. */
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700523 if (obj->clazz == gDvm.classJavaLangClass) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700524 scanClassObject((ClassObject *)obj, ctx);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700525 } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
Barry Hayes899cdb72010-06-08 09:59:12 -0700526 scanArrayObject((ArrayObject *)obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800527 } else {
Barry Hayes899cdb72010-06-08 09:59:12 -0700528 scanDataObject((DataObject *)obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800529 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800530}
531
532static void
533processMarkStack(GcMarkContext *ctx)
534{
535 const Object **const base = ctx->stack.base;
536
537 /* Scan anything that's on the mark stack.
538 * We can't use the bitmaps anymore, so use
539 * a finger that points past the end of them.
540 */
541 ctx->finger = (void *)ULONG_MAX;
542 while (ctx->stack.top != base) {
543 scanObject(*ctx->stack.top++, ctx);
544 }
545}
546
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700547static size_t objectSize(const Object *obj)
548{
549 assert(dvmIsValidObject(obj));
550 assert(dvmIsValidObject((Object *)obj->clazz));
551 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
552 return dvmArrayObjectSize((ArrayObject *)obj);
553 } else if (obj->clazz == gDvm.classJavaLangClass) {
554 return dvmClassObjectSize((ClassObject *)obj);
555 } else {
556 return obj->clazz->objectSize;
557 }
558}
559
560/*
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700561 * Scans forward to the header of the next marked object between start
562 * and limit. Returns NULL if no marked objects are in that region.
563 */
Carl Shapiroea10c552010-09-02 23:32:25 -0700564static Object *nextGrayObject(u1 *base, u1 *limit, HeapBitmap *markBits)
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700565{
566 u1 *ptr;
567
568 assert(base < limit);
569 assert(limit - base <= GC_CARD_SIZE);
570 for (ptr = base; ptr < limit; ptr += HB_OBJECT_ALIGNMENT) {
Carl Shapiroea10c552010-09-02 23:32:25 -0700571 if (dvmHeapBitmapIsObjectBitSet(markBits, ptr))
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700572 return (Object *)ptr;
573 }
574 return NULL;
575}
576
577/*
578 * Scan the card table looking for objects that have been grayed by
579 * the mutator.
580 */
581static void scanGrayObjects(GcMarkContext *ctx)
582{
583 GcHeap *h = gDvm.gcHeap;
Carl Shapiroea10c552010-09-02 23:32:25 -0700584 HeapBitmap *markBits, *liveBits;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700585 u1 *card, *baseCard, *limitCard;
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700586 size_t footprint;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700587
Carl Shapiroea10c552010-09-02 23:32:25 -0700588 markBits = ctx->bitmap;
589 liveBits = dvmHeapSourceGetLiveBits();
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700590 footprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700591 baseCard = &h->cardTableBase[0];
Carl Shapiro3031fc32010-08-12 13:55:06 -0700592 limitCard = dvmCardFromAddr((u1 *)dvmHeapSourceGetBase() + footprint);
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700593 assert(limitCard <= &h->cardTableBase[h->cardTableLength]);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700594 for (card = baseCard; card != limitCard; ++card) {
595 if (*card == GC_CARD_DIRTY) {
596 /*
597 * The card is dirty. Scan all of the objects that
598 * intersect with the card address.
599 */
600 u1 *addr = dvmAddrFromCard(card);
601 /*
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700602 * Scan through all black objects that start on the
603 * current card.
604 */
605 u1 *limit = addr + GC_CARD_SIZE;
606 u1 *next = addr;
607 while (next < limit) {
Carl Shapiroea10c552010-09-02 23:32:25 -0700608 Object *obj = nextGrayObject(next, limit, markBits);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700609 if (obj == NULL)
610 break;
611 scanObject(obj, ctx);
Carl Shapiro71ce7a92010-09-29 01:09:11 -0700612 next = (u1*)obj + ALIGN_UP(objectSize(obj), HB_OBJECT_ALIGNMENT);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700613 }
614 }
615 }
616}
617
Carl Shapiro57ee2702010-08-27 13:06:48 -0700618/*
619 * Callback for scanning each object in the bitmap. The finger is set
620 * to the address corresponding to the lowest address in the next word
621 * of bits in the bitmap.
622 */
Carl Shapiro38d710b2010-08-31 16:48:31 -0700623static void scanBitmapCallback(void *addr, void *finger, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800624{
Carl Shapiro006346e2010-07-29 20:39:50 -0700625 GcMarkContext *ctx = arg;
Carl Shapiro57ee2702010-08-27 13:06:48 -0700626 ctx->finger = (void *)finger;
627 scanObject(addr, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800628}
629
630/* Given bitmaps with the root set marked, find and mark all
631 * reachable objects. When this returns, the entire set of
632 * live objects will be marked and the mark stack will be empty.
633 */
Carl Shapiro29540742010-03-26 15:34:39 -0700634void dvmHeapScanMarkedObjects(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800635{
636 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
637
638 assert(ctx->finger == NULL);
639
640 /* The bitmaps currently have bits set for the root set.
641 * Walk across the bitmaps and scan each object.
642 */
Carl Shapiro38d710b2010-08-31 16:48:31 -0700643 dvmHeapBitmapScanWalk(ctx->bitmap, scanBitmapCallback, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800644
645 /* We've walked the mark bitmaps. Scan anything that's
646 * left on the mark stack.
647 */
648 processMarkStack(ctx);
649
650 LOG_SCAN("done with marked objects\n");
651}
652
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700653void dvmHeapReScanMarkedObjects(void)
Carl Shapiroec805ea2010-06-28 16:28:26 -0700654{
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700655 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700656
Carl Shapiroec805ea2010-06-28 16:28:26 -0700657 /*
Carl Shapirof5860332010-06-28 23:02:08 -0700658 * The finger must have been set to the maximum value to ensure
659 * that gray objects will be pushed onto the mark stack.
Carl Shapiroec805ea2010-06-28 16:28:26 -0700660 */
661 assert(ctx->finger == (void *)ULONG_MAX);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700662 scanGrayObjects(ctx);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700663 processMarkStack(ctx);
664}
665
Carl Shapiro34f51992010-07-09 17:55:41 -0700666/*
667 * Clear the referent field.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800668 */
Barry Hayes6930a112009-12-22 11:01:38 -0800669static void clearReference(Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800670{
Carl Shapiro34f51992010-07-09 17:55:41 -0700671 size_t offset = gDvm.offJavaLangRefReference_referent;
672 dvmSetFieldObject(reference, offset, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800673}
674
Carl Shapiro29540742010-03-26 15:34:39 -0700675/*
676 * Returns true if the reference was registered with a reference queue
677 * and has not yet been enqueued.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800678 */
Carl Shapiro29540742010-03-26 15:34:39 -0700679static bool isEnqueuable(const Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800680{
Barry Hayes6930a112009-12-22 11:01:38 -0800681 Object *queue = dvmGetFieldObject(reference,
682 gDvm.offJavaLangRefReference_queue);
683 Object *queueNext = dvmGetFieldObject(reference,
684 gDvm.offJavaLangRefReference_queueNext);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700685 return queue != NULL && queueNext == NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800686}
687
Carl Shapiro29540742010-03-26 15:34:39 -0700688/*
689 * Schedules a reference to be appended to its reference queue.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800690 */
Carl Shapiro29540742010-03-26 15:34:39 -0700691static void enqueueReference(Object *ref)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800692{
Carl Shapiro646ba092010-06-10 15:17:00 -0700693 assert(ref != NULL);
Carl Shapiro29540742010-03-26 15:34:39 -0700694 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
695 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
Carl Shapiro646ba092010-06-10 15:17:00 -0700696 if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
Carl Shapiro29540742010-03-26 15:34:39 -0700697 LOGE_HEAP("enqueueReference(): no room for any more "
698 "reference operations\n");
699 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800700 }
701}
702
Carl Shapiro29540742010-03-26 15:34:39 -0700703/*
704 * Walks the reference list marking any references subject to the
705 * reference clearing policy. References with a black referent are
706 * removed from the list. References with white referents biased
707 * toward saving are blackened and also removed from the list.
708 */
709void dvmHandleSoftRefs(Object **list)
710{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700711 GcMarkContext *ctx;
Carl Shapiro29540742010-03-26 15:34:39 -0700712 Object *ref, *referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700713 Object *clear;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700714 size_t referentOffset;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700715 size_t counter;
Carl Shapiro29540742010-03-26 15:34:39 -0700716 bool marked;
717
Carl Shapirob2e78d32010-08-20 11:34:18 -0700718 ctx = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700719 referentOffset = gDvm.offJavaLangRefReference_referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700720 clear = NULL;
Carl Shapiro29540742010-03-26 15:34:39 -0700721 counter = 0;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700722 while (*list != NULL) {
723 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700724 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700725 assert(referent != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700726 marked = isMarked(referent, ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700727 if (!marked && ((++counter) & 1)) {
728 /* Referent is white and biased toward saving, mark it. */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700729 markObject(referent, ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700730 marked = true;
731 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700732 if (!marked) {
733 /* Referent is white, queue it for clearing. */
734 enqueuePendingReference(ref, &clear);
Carl Shapiro29540742010-03-26 15:34:39 -0700735 }
Carl Shapiro29540742010-03-26 15:34:39 -0700736 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700737 *list = clear;
Carl Shapiro29540742010-03-26 15:34:39 -0700738 /*
739 * Restart the mark with the newly black references added to the
740 * root set.
741 */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700742 processMarkStack(ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700743}
744
745/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700746 * Unlink the reference list clearing references objects with white
747 * referents. Cleared references registered to a reference queue are
748 * scheduled for appending by the heap worker thread.
Carl Shapiro29540742010-03-26 15:34:39 -0700749 */
750void dvmClearWhiteRefs(Object **list)
751{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700752 GcMarkContext *ctx;
Carl Shapiro29540742010-03-26 15:34:39 -0700753 Object *ref, *referent;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700754 size_t referentOffset;
Carl Shapiro29540742010-03-26 15:34:39 -0700755 bool doSignal;
756
Carl Shapirob2e78d32010-08-20 11:34:18 -0700757 ctx = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700758 referentOffset = gDvm.offJavaLangRefReference_referent;
759 doSignal = false;
760 while (*list != NULL) {
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700761 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700762 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700763 assert(referent != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700764 if (!isMarked(referent, ctx)) {
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700765 /* Referent is white, clear it. */
Carl Shapiro29540742010-03-26 15:34:39 -0700766 clearReference(ref);
767 if (isEnqueuable(ref)) {
768 enqueueReference(ref);
769 doSignal = true;
770 }
771 }
772 }
773 /*
774 * If we cleared a reference with a reference queue we must notify
775 * the heap worker to append the reference.
776 */
777 if (doSignal) {
778 dvmSignalHeapWorker(false);
779 }
780 assert(*list == NULL);
781}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800782
783/* Find unreachable objects that need to be finalized,
784 * and schedule them for finalization.
785 */
786void dvmHeapScheduleFinalizations()
787{
788 HeapRefTable newPendingRefs;
789 LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
790 Object **ref;
791 Object **lastRef;
792 size_t totalPendCount;
Carl Shapirob2e78d32010-08-20 11:34:18 -0700793 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800794
795 /*
796 * All reachable objects have been marked.
797 * Any unmarked finalizable objects need to be finalized.
798 */
799
800 /* Create a table that the new pending refs will
801 * be added to.
802 */
Barry Hayesd4f78d32010-06-08 09:34:42 -0700803 if (!dvmHeapInitHeapRefTable(&newPendingRefs)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800804 //TODO: mark all finalizable refs and hope that
805 // we can schedule them next time. Watch out,
806 // because we may be expecting to free up space
807 // by calling finalizers.
808 LOGE_GC("dvmHeapScheduleFinalizations(): no room for "
809 "pending finalizations\n");
810 dvmAbort();
811 }
812
813 /* Walk through finalizableRefs and move any unmarked references
814 * to the list of new pending refs.
815 */
816 totalPendCount = 0;
817 while (finRefs != NULL) {
818 Object **gapRef;
819 size_t newPendCount = 0;
820
821 gapRef = ref = finRefs->refs.table;
822 lastRef = finRefs->refs.nextEntry;
823 while (ref < lastRef) {
Carl Shapirob2e78d32010-08-20 11:34:18 -0700824 if (!isMarked(*ref, ctx)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800825 if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
826 //TODO: add the current table and allocate
827 // a new, smaller one.
828 LOGE_GC("dvmHeapScheduleFinalizations(): "
829 "no room for any more pending finalizations: %zd\n",
830 dvmHeapNumHeapRefTableEntries(&newPendingRefs));
831 dvmAbort();
832 }
833 newPendCount++;
834 } else {
835 /* This ref is marked, so will remain on finalizableRefs.
836 */
837 if (newPendCount > 0) {
838 /* Copy it up to fill the holes.
839 */
840 *gapRef++ = *ref;
841 } else {
842 /* No holes yet; don't bother copying.
843 */
844 gapRef++;
845 }
846 }
847 ref++;
848 }
849 finRefs->refs.nextEntry = gapRef;
850 //TODO: if the table is empty when we're done, free it.
851 totalPendCount += newPendCount;
852 finRefs = finRefs->next;
853 }
854 LOGD_GC("dvmHeapScheduleFinalizations(): %zd finalizers triggered.\n",
855 totalPendCount);
856 if (totalPendCount == 0) {
857 /* No objects required finalization.
858 * Free the empty temporary table.
859 */
860 dvmClearReferenceTable(&newPendingRefs);
861 return;
862 }
863
864 /* Add the new pending refs to the main list.
865 */
866 if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
867 &newPendingRefs))
868 {
869 LOGE_GC("dvmHeapScheduleFinalizations(): can't insert new "
870 "pending finalizations\n");
871 dvmAbort();
872 }
873
874 //TODO: try compacting the main list with a memcpy loop
875
876 /* Mark the refs we just moved; we don't want them or their
877 * children to get swept yet.
878 */
879 ref = newPendingRefs.table;
880 lastRef = newPendingRefs.nextEntry;
881 assert(ref < lastRef);
882 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
883 while (ref < lastRef) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700884 assert(*ref != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700885 markObject(*ref, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800886 ref++;
887 }
888 HPROF_CLEAR_GC_SCAN_STATE();
Carl Shapirob2e78d32010-08-20 11:34:18 -0700889 processMarkStack(ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800890 dvmSignalHeapWorker(false);
891}
892
893void dvmHeapFinishMarkStep()
894{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700895 GcMarkContext *ctx;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800896
Carl Shapirob2e78d32010-08-20 11:34:18 -0700897 ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800898
Barry Hayes81010a42010-07-19 14:07:01 -0700899 /* The mark bits are now not needed.
900 */
901 dvmHeapSourceZeroMarkBitmap();
902
Carl Shapirof373efd2010-02-19 00:46:33 -0800903 /* Clean up everything else associated with the marking process.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800904 */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700905 destroyMarkStack(&ctx->stack);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800906
Carl Shapirob2e78d32010-08-20 11:34:18 -0700907 ctx->finger = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800908}
909
Carl Shapiro8881a802010-08-10 15:55:45 -0700910typedef struct {
911 size_t numObjects;
912 size_t numBytes;
913 bool isConcurrent;
914} SweepContext;
915
Carl Shapiro57ee2702010-08-27 13:06:48 -0700916static void sweepBitmapCallback(size_t numPtrs, void **ptrs, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800917{
Carl Shapirob9b23952010-08-10 17:20:15 -0700918 SweepContext *ctx = arg;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800919
Carl Shapiro8881a802010-08-10 15:55:45 -0700920 if (ctx->isConcurrent) {
921 dvmLockHeap();
922 }
923 ctx->numBytes += dvmHeapSourceFreeList(numPtrs, ptrs);
924 ctx->numObjects += numPtrs;
925 if (ctx->isConcurrent) {
926 dvmUnlockHeap();
927 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800928}
929
Carl Shapiro8881a802010-08-10 15:55:45 -0700930/*
931 * Returns true if the given object is unmarked. This assumes that
932 * the bitmaps have not yet been swapped.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800933 */
934static int isUnmarkedObject(void *object)
935{
Carl Shapiro6343bd02010-02-16 17:40:19 -0800936 return !isMarked((void *)((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800937 &gDvm.gcHeap->markContext);
938}
939
Carl Shapiro8881a802010-08-10 15:55:45 -0700940/*
941 * Process all the internal system structures that behave like
942 * weakly-held objects.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800943 */
Carl Shapiro8881a802010-08-10 15:55:45 -0700944void dvmHeapSweepSystemWeaks(void)
945{
946 dvmGcDetachDeadInternedStrings(isUnmarkedObject);
947 dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
948}
949
950/*
951 * Walk through the list of objects that haven't been marked and free
952 * them. Assumes the bitmaps have been swapped.
953 */
954void dvmHeapSweepUnmarkedObjects(GcMode mode, bool isConcurrent,
955 size_t *numObjects, size_t *numBytes)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800956{
Carl Shapiro5fdab4a2010-08-18 21:04:31 -0700957 HeapBitmap currMark[HEAP_SOURCE_MAX_HEAP_COUNT];
958 HeapBitmap currLive[HEAP_SOURCE_MAX_HEAP_COUNT];
Carl Shapiro8881a802010-08-10 15:55:45 -0700959 SweepContext ctx;
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
Carl Shapirof373efd2010-02-19 00:46:33 -0800963 numBitmaps = dvmHeapSourceGetNumHeaps();
Carl Shapiro5fdab4a2010-08-18 21:04:31 -0700964 dvmHeapSourceGetObjectBitmaps(currLive, currMark, numBitmaps);
Carl Shapirod25566d2010-03-11 20:39:47 -0800965 if (mode == GC_PARTIAL) {
966 numSweepBitmaps = 1;
Carl Shapiro5fdab4a2010-08-18 21:04:31 -0700967 assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == currLive[0].base);
Carl Shapirod25566d2010-03-11 20:39:47 -0800968 } else {
969 numSweepBitmaps = numBitmaps;
970 }
Carl Shapiro8881a802010-08-10 15:55:45 -0700971 ctx.numObjects = ctx.numBytes = 0;
972 ctx.isConcurrent = isConcurrent;
Barry Hayese168ebd2010-05-07 09:19:46 -0700973 for (i = 0; i < numSweepBitmaps; i++) {
Carl Shapiro5fdab4a2010-08-18 21:04:31 -0700974 HeapBitmap* prevLive = &currMark[i];
975 HeapBitmap* prevMark = &currLive[i];
976 dvmHeapBitmapSweepWalk(prevLive, prevMark, sweepBitmapCallback, &ctx);
Barry Hayese168ebd2010-05-07 09:19:46 -0700977 }
Carl Shapiro8881a802010-08-10 15:55:45 -0700978 *numObjects = ctx.numObjects;
979 *numBytes = ctx.numBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800980 if (gDvm.allocProf.enabled) {
Carl Shapiro8881a802010-08-10 15:55:45 -0700981 gDvm.allocProf.freeCount += ctx.numObjects;
982 gDvm.allocProf.freeSize += ctx.numBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800983 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800984}