blob: e5cbf816856cd4f41e3a39403848cb1923a523b2 [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
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080044#define ALIGN_UP_TO_PAGE_SIZE(p) \
Andy McFadden96516932009-10-28 17:39:02 -070045 (((size_t)(p) + (SYSTEM_PAGE_SIZE - 1)) & ~(SYSTEM_PAGE_SIZE - 1))
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
55static bool
56createMarkStack(GcMarkStack *stack)
57{
58 const Object **limit;
Carl Shapiro742c4452010-07-13 18:28:13 -070059 const char *name;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080060 size_t size;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080061
62 /* Create a stack big enough for the worst possible case,
63 * where the heap is perfectly full of the smallest object.
64 * TODO: be better about memory usage; use a smaller stack with
65 * overflow detection and recovery.
66 */
67 size = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
68 (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
69 size = ALIGN_UP_TO_PAGE_SIZE(size);
Carl Shapiro742c4452010-07-13 18:28:13 -070070 name = "dalvik-mark-stack";
71 limit = dvmAllocRegion(size, PROT_READ | PROT_WRITE, name);
72 if (limit == NULL) {
73 LOGE_GC("Could not mmap %zd-byte ashmem region '%s'", size, name);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080074 return false;
75 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080076 stack->limit = limit;
77 stack->base = (const Object **)((uintptr_t)limit + size);
78 stack->top = stack->base;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080079 return true;
80}
81
82static void
83destroyMarkStack(GcMarkStack *stack)
84{
85 munmap((char *)stack->limit,
86 (uintptr_t)stack->base - (uintptr_t)stack->limit);
87 memset(stack, 0, sizeof(*stack));
88}
89
90#define MARK_STACK_PUSH(stack, obj) \
91 do { \
92 *--(stack).top = (obj); \
93 } while (false)
94
95bool
Carl Shapirod25566d2010-03-11 20:39:47 -080096dvmHeapBeginMarkStep(GcMode mode)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080097{
98 GcMarkContext *mc = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080099
100 if (!createMarkStack(&mc->stack)) {
101 return false;
102 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800103 mc->finger = NULL;
Carl Shapirod25566d2010-03-11 20:39:47 -0800104 mc->immuneLimit = dvmHeapSourceGetImmuneLimit(mode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800105 return true;
106}
107
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800108static long
Carl Shapiro6343bd02010-02-16 17:40:19 -0800109setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800110{
Carl Shapirof373efd2010-02-19 00:46:33 -0800111 return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800112}
113
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800114static void
Barry Hayese1bccb92010-05-18 09:48:37 -0700115markObjectNonNull(const Object *obj, GcMarkContext *ctx,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800116 bool checkFinger, bool forceStack)
117{
Barry Hayese1bccb92010-05-18 09:48:37 -0700118 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800119 assert(obj != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800120 assert(dvmIsValidObject(obj));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800121
Carl Shapirob31b3012010-05-25 18:35:37 -0700122 if (obj < (Object *)ctx->immuneLimit) {
Carl Shapirod25566d2010-03-11 20:39:47 -0800123 assert(isMarked(obj, ctx));
124 return;
125 }
Carl Shapiro6343bd02010-02-16 17:40:19 -0800126 if (!setAndReturnMarkBit(ctx, obj)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800127 /* This object was not previously marked.
128 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800129 if (forceStack || (checkFinger && (void *)obj < ctx->finger)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800130 /* This object will need to go on the mark stack.
131 */
132 MARK_STACK_PUSH(ctx->stack, obj);
133 }
134
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800135#if WITH_HPROF
136 if (gDvm.gcHeap->hprofContext != NULL) {
137 hprofMarkRootObject(gDvm.gcHeap->hprofContext, obj, 0);
138 }
139#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800140 }
141}
142
143/* Used to mark objects when recursing. Recursion is done by moving
144 * the finger across the bitmaps in address order and marking child
145 * objects. Any newly-marked objects whose addresses are lower than
146 * the finger won't be visited by the bitmap scan, so those objects
147 * need to be added to the mark stack.
148 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700149static void markObject(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800150{
Barry Hayese1bccb92010-05-18 09:48:37 -0700151 if (obj != NULL) {
152 markObjectNonNull(obj, ctx, true, false);
153 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800154}
155
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800156/* If the object hasn't already been marked, mark it and
157 * schedule it to be scanned for references.
158 *
159 * obj may not be NULL. The macro dvmMarkObject() should
160 * be used in situations where a reference may be NULL.
161 *
162 * This function may only be called when marking the root
Barry Hayese1bccb92010-05-18 09:48:37 -0700163 * set. When recursing, use the internal markObject().
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800164 */
165void
166dvmMarkObjectNonNull(const Object *obj)
167{
Barry Hayese1bccb92010-05-18 09:48:37 -0700168 assert(obj != NULL);
169 markObjectNonNull(obj, &gDvm.gcHeap->markContext, false, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800170}
171
172/* Mark the set of root objects.
173 *
174 * Things we need to scan:
175 * - System classes defined by root classloader
176 * - For each thread:
177 * - Interpreted stack, from top to "curFrame"
178 * - Dalvik registers (args + local vars)
179 * - JNI local references
180 * - Automatic VM local references (TrackedAlloc)
181 * - Associated Thread/VMThread object
182 * - ThreadGroups (could track & start with these instead of working
183 * upward from Threads)
184 * - Exception currently being thrown, if present
185 * - JNI global references
186 * - Interned string table
187 * - Primitive classes
188 * - Special objects
189 * - gDvm.outOfMemoryObj
190 * - Objects allocated with ALLOC_NO_GC
191 * - Objects pending finalization (but not yet finalized)
192 * - Objects in debugger object registry
193 *
194 * Don't need:
195 * - Native stack (for in-progress stuff in the VM)
196 * - The TrackedAlloc stuff watches all native VM references.
197 */
198void dvmHeapMarkRootSet()
199{
Barry Hayesd4f78d32010-06-08 09:34:42 -0700200 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800201
202 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_STICKY_CLASS, 0);
203
Carl Shapirod25566d2010-03-11 20:39:47 -0800204 LOG_SCAN("immune objects");
Barry Hayes425848f2010-05-04 13:32:12 -0700205 dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
Carl Shapirod25566d2010-03-11 20:39:47 -0800206
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800207 LOG_SCAN("root class loader\n");
208 dvmGcScanRootClassLoader();
209 LOG_SCAN("primitive classes\n");
210 dvmGcScanPrimitiveClasses();
211
212 /* dvmGcScanRootThreadGroups() sets a bunch of
213 * different scan states internally.
214 */
215 HPROF_CLEAR_GC_SCAN_STATE();
216
217 LOG_SCAN("root thread groups\n");
218 dvmGcScanRootThreadGroups();
219
220 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_INTERNED_STRING, 0);
221
222 LOG_SCAN("interned strings\n");
223 dvmGcScanInternedStrings();
224
225 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_GLOBAL, 0);
226
227 LOG_SCAN("JNI global refs\n");
228 dvmGcMarkJniGlobalRefs();
229
230 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
231
232 LOG_SCAN("pending reference operations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700233 dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800234
235 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
236
237 LOG_SCAN("pending finalizations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700238 dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800239
240 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_DEBUGGER, 0);
241
242 LOG_SCAN("debugger refs\n");
243 dvmGcMarkDebuggerRefs();
244
245 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_VM_INTERNAL, 0);
246
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800247 /* Mark any special objects we have sitting around.
248 */
249 LOG_SCAN("special objects\n");
250 dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
251 dvmMarkObjectNonNull(gDvm.internalErrorObj);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700252 dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800253//TODO: scan object references sitting in gDvm; use pointer begin & end
254
255 HPROF_CLEAR_GC_SCAN_STATE();
256}
257
258/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700259 * Nothing past this point is allowed to use dvmMarkObject() or
260 * dvmMarkObjectNonNull(), which are for root-marking only.
261 * Scanning/recursion must use markObject(), which takes the finger
262 * into account.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800263 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700264#undef dvmMarkObject
265#define dvmMarkObject __dont_use_dvmMarkObject__
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800266#define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
267
Barry Hayese1bccb92010-05-18 09:48:37 -0700268/*
269 * Scans instance fields.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800270 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700271static void scanInstanceFields(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800272{
Barry Hayese1bccb92010-05-18 09:48:37 -0700273 assert(obj != NULL);
274 assert(obj->clazz != NULL);
275 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800276
Barry Hayese1bccb92010-05-18 09:48:37 -0700277 if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
278 unsigned int refOffsets = obj->clazz->refOffsets;
Barry Hayeseac47ed2009-06-22 11:45:20 -0700279 while (refOffsets != 0) {
280 const int rshift = CLZ(refOffsets);
281 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
282 markObject(dvmGetFieldObject((Object*)obj,
Barry Hayese1bccb92010-05-18 09:48:37 -0700283 CLASS_OFFSET_FROM_CLZ(rshift)), ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800284 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700285 } else {
Barry Hayese1bccb92010-05-18 09:48:37 -0700286 ClassObject *clazz;
287 int i;
288 for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
289 InstField *field = clazz->ifields;
290 for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
291 void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
292 markObject(((JValue *)addr)->l, ctx);
Barry Hayeseac47ed2009-06-22 11:45:20 -0700293 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700294 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800295 }
296}
297
Barry Hayese1bccb92010-05-18 09:48:37 -0700298/*
299 * Scans the header, static field references, and interface
300 * pointers of a class object.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800301 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700302static void scanClassObject(const ClassObject *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800303{
Barry Hayese1bccb92010-05-18 09:48:37 -0700304 int i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800305
Barry Hayese1bccb92010-05-18 09:48:37 -0700306 assert(obj != NULL);
307 assert(obj->obj.clazz == gDvm.classJavaLangClass);
308 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800309
Barry Hayese1bccb92010-05-18 09:48:37 -0700310 markObject((Object *)obj->obj.clazz, ctx);
311 if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
312 markObject((Object *)obj->elementClass, ctx);
313 }
Barry Hayesc49db852010-05-14 13:43:34 -0700314 /* Do super and the interfaces contain Objects and not dex idx values? */
315 if (obj->status > CLASS_IDX) {
316 markObject((Object *)obj->super, ctx);
317 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700318 markObject(obj->classLoader, ctx);
319 /* Scan static field references. */
320 for (i = 0; i < obj->sfieldCount; ++i) {
321 char ch = obj->sfields[i].field.signature[0];
322 if (ch == '[' || ch == 'L') {
323 markObject(obj->sfields[i].value.l, ctx);
324 }
325 }
326 /* Scan the instance fields. */
327 scanInstanceFields((const Object *)obj, ctx);
328 /* Scan interface references. */
Barry Hayesc49db852010-05-14 13:43:34 -0700329 if (obj->status > CLASS_IDX) {
330 for (i = 0; i < obj->interfaceCount; ++i) {
331 markObject((Object *)obj->interfaces[i], ctx);
332 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800333 }
334}
335
Barry Hayese1bccb92010-05-18 09:48:37 -0700336/*
337 * Scans the header of all array objects. If the array object is
338 * specialized to a reference type, scans the array data as well.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800339 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700340static void scanArrayObject(const ArrayObject *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800341{
Barry Hayese1bccb92010-05-18 09:48:37 -0700342 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800343
Barry Hayese1bccb92010-05-18 09:48:37 -0700344 assert(obj != NULL);
345 assert(obj->obj.clazz != NULL);
346 assert(ctx != NULL);
347 /* Scan the class object reference. */
348 markObject((Object *)obj->obj.clazz, ctx);
349 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISOBJECTARRAY)) {
350 /* Scan the array contents. */
351 Object **contents = (Object **)obj->contents;
352 for (i = 0; i < obj->length; ++i) {
353 markObject(contents[i], ctx);
354 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800355 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700356}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800357
Barry Hayese1bccb92010-05-18 09:48:37 -0700358/*
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700359 * Returns class flags relating to Reference subclasses.
360 */
361static int referenceClassFlags(const Object *obj)
362{
363 int flags = CLASS_ISREFERENCE |
364 CLASS_ISWEAKREFERENCE |
365 CLASS_ISPHANTOMREFERENCE;
366 return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
367}
368
369/*
370 * Returns true if the object derives from SoftReference.
371 */
372static bool isSoftReference(const Object *obj)
373{
374 return referenceClassFlags(obj) == CLASS_ISREFERENCE;
375}
376
377/*
378 * Returns true if the object derives from WeakReference.
379 */
380static bool isWeakReference(const Object *obj)
381{
382 return referenceClassFlags(obj) & CLASS_ISWEAKREFERENCE;
383}
384
385/*
386 * Returns true if the object derives from PhantomReference.
387 */
388static bool isPhantomReference(const Object *obj)
389{
390 return referenceClassFlags(obj) & CLASS_ISPHANTOMREFERENCE;
391}
392
393/*
394 * Adds a reference to the tail of a circular queue of references.
395 */
396static void enqueuePendingReference(Object *ref, Object **list)
397{
398 size_t offset;
399
400 assert(ref != NULL);
401 assert(list != NULL);
402 offset = gDvm.offJavaLangRefReference_pendingNext;
403 if (*list == NULL) {
404 dvmSetFieldObject(ref, offset, ref);
405 *list = ref;
406 } else {
407 Object *head = dvmGetFieldObject(*list, offset);
408 dvmSetFieldObject(ref, offset, head);
409 dvmSetFieldObject(*list, offset, ref);
410 }
411}
412
413/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700414 * Removes the reference at the head of a circular queue of
415 * references.
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700416 */
417static Object *dequeuePendingReference(Object **list)
418{
419 Object *ref, *head;
420 size_t offset;
421
422 assert(list != NULL);
423 assert(*list != NULL);
424 offset = gDvm.offJavaLangRefReference_pendingNext;
425 head = dvmGetFieldObject(*list, offset);
426 if (*list == head) {
427 ref = *list;
428 *list = NULL;
429 } else {
430 Object *next = dvmGetFieldObject(head, offset);
431 dvmSetFieldObject(*list, offset, next);
432 ref = head;
433 }
434 dvmSetFieldObject(ref, offset, NULL);
435 return ref;
436}
437
438/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700439 * Process the "referent" field in a java.lang.ref.Reference. If the
440 * referent has not yet been marked, put it on the appropriate list in
441 * the gcHeap for later processing.
442 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700443static void delayReferenceReferent(Object *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700444{
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700445 GcHeap *gcHeap = gDvm.gcHeap;
446 Object *pending, *referent;
447 size_t pendingNextOffset, referentOffset;
448
Barry Hayese1bccb92010-05-18 09:48:37 -0700449 assert(obj != NULL);
Barry Hayes697b5a92010-06-23 11:38:52 -0700450 assert(obj->clazz != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700451 assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
Barry Hayese1bccb92010-05-18 09:48:37 -0700452 assert(ctx != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700453 pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
454 referentOffset = gDvm.offJavaLangRefReference_referent;
455 pending = dvmGetFieldObject(obj, pendingNextOffset);
456 referent = dvmGetFieldObject(obj, referentOffset);
457 if (pending == NULL && referent != NULL && !isMarked(referent, ctx)) {
458 Object **list = NULL;
459 if (isSoftReference(obj)) {
460 list = &gcHeap->softReferences;
461 } else if (isWeakReference(obj)) {
462 list = &gcHeap->weakReferences;
463 } else if (isPhantomReference(obj)) {
464 list = &gcHeap->phantomReferences;
Barry Hayese1bccb92010-05-18 09:48:37 -0700465 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700466 assert(list != NULL);
467 enqueuePendingReference(obj, list);
Barry Hayese1bccb92010-05-18 09:48:37 -0700468 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800469}
470
Barry Hayese1bccb92010-05-18 09:48:37 -0700471/*
472 * Scans the header and field references of a data object.
473 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700474static void scanDataObject(DataObject *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700475{
476 assert(obj != NULL);
477 assert(obj->obj.clazz != NULL);
478 assert(ctx != NULL);
479 /* Scan the class object. */
480 markObject((Object *)obj->obj.clazz, ctx);
481 /* Scan the instance fields. */
482 scanInstanceFields((const Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700483 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISREFERENCE)) {
Barry Hayes697b5a92010-06-23 11:38:52 -0700484 delayReferenceReferent((Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700485 }
486}
487
488/*
489 * Scans an object reference. Determines the type of the reference
490 * and dispatches to a specialized scanning routine.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800491 */
492static void scanObject(const Object *obj, GcMarkContext *ctx)
493{
Barry Hayese1bccb92010-05-18 09:48:37 -0700494 assert(obj != NULL);
495 assert(ctx != NULL);
Barry Hayes899cdb72010-06-08 09:59:12 -0700496 assert(obj->clazz != NULL);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700497#if WITH_HPROF
498 if (gDvm.gcHeap->hprofContext != NULL) {
499 hprofDumpHeapObject(gDvm.gcHeap->hprofContext, obj);
500 }
501#endif
Barry Hayese1bccb92010-05-18 09:48:37 -0700502 /* Dispatch a type-specific scan routine. */
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700503 if (obj->clazz == gDvm.classJavaLangClass) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700504 scanClassObject((ClassObject *)obj, ctx);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700505 } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
Barry Hayes899cdb72010-06-08 09:59:12 -0700506 scanArrayObject((ArrayObject *)obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800507 } else {
Barry Hayes899cdb72010-06-08 09:59:12 -0700508 scanDataObject((DataObject *)obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800509 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800510}
511
Barry Hayes6e5cf602010-06-22 12:32:59 -0700512/*
513 * Variants for partial GC. Scan immune objects, and rebuild the card
514 * table.
515 */
516
517/*
518 * Mark an object which was found in an immune object.
519 */
520static void scanImmuneReference(const Object *obj, GcMarkContext *ctx)
521{
522 if (obj != NULL) {
523 if (obj < (Object *)ctx->immuneLimit) {
524 assert(isMarked(obj, ctx));
525 } else {
526 ctx->crossGen = true;
527 markObjectNonNull(obj, ctx, true, false);
528 }
529 }
530}
531
532/*
533 * Scans instance fields.
534 */
535static void scanImmuneInstanceFields(const Object *obj, GcMarkContext *ctx)
536{
537 assert(obj != NULL);
538 assert(obj->clazz != NULL);
539 assert(ctx != NULL);
540
541 if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
542 unsigned int refOffsets = obj->clazz->refOffsets;
543 while (refOffsets != 0) {
544 const int rshift = CLZ(refOffsets);
545 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
546 scanImmuneReference(
547 dvmGetFieldObject((Object*)obj, CLASS_OFFSET_FROM_CLZ(rshift)),
548 ctx);
549 }
550 } else {
551 ClassObject *clazz;
552 int i;
553 for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
554 InstField *field = clazz->ifields;
555 for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
556 void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
557 scanImmuneReference(((JValue *)addr)->l, ctx);
558 }
559 }
560 }
561}
562
563/*
564 * Scans the header, static field references, and interface
565 * pointers of a class object.
566 */
567static void scanImmuneClassObject(const ClassObject *obj, GcMarkContext *ctx)
568{
569 int i;
570
571 assert(obj != NULL);
572 assert(obj->obj.clazz == gDvm.classJavaLangClass);
573 assert(ctx != NULL);
574
575 scanImmuneReference((Object *)obj->obj.clazz, ctx);
576 if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
577 scanImmuneReference((Object *)obj->elementClass, ctx);
578 }
579 /* Do super and the interfaces contain Objects and not dex idx values? */
580 if (obj->status > CLASS_IDX) {
581 scanImmuneReference((Object *)obj->super, ctx);
582 }
583 scanImmuneReference(obj->classLoader, ctx);
584 /* Scan static field references. */
585 for (i = 0; i < obj->sfieldCount; ++i) {
586 char ch = obj->sfields[i].field.signature[0];
587 if (ch == '[' || ch == 'L') {
588 scanImmuneReference(obj->sfields[i].value.l, ctx);
589 }
590 }
591 /* Scan the instance fields. */
592 scanImmuneInstanceFields((const Object *)obj, ctx);
593 /* Scan interface references. */
594 if (obj->status > CLASS_IDX) {
595 for (i = 0; i < obj->interfaceCount; ++i) {
596 scanImmuneReference((Object *)obj->interfaces[i], ctx);
597 }
598 }
599}
600
601/*
602 * Scans the header of all array objects. If the array object is
603 * specialized to a reference type, scans the array data as well.
604 */
605static void scanImmuneArrayObject(const ArrayObject *obj, GcMarkContext *ctx)
606{
607 size_t i;
608
609 assert(obj != NULL);
610 assert(obj->obj.clazz != NULL);
611 assert(ctx != NULL);
612 /* Scan the class object reference. */
613 scanImmuneReference((Object *)obj->obj.clazz, ctx);
614 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISOBJECTARRAY)) {
615 /* Scan the array contents. */
616 Object **contents = (Object **)obj->contents;
617 for (i = 0; i < obj->length; ++i) {
618 scanImmuneReference(contents[i], ctx);
619 }
620 }
621}
622
623/*
624 * Scans the header and field references of a data object.
625 */
626static void scanImmuneDataObject(DataObject *obj, GcMarkContext *ctx)
627{
628 assert(obj != NULL);
629 assert(obj->obj.clazz != NULL);
630 assert(ctx != NULL);
631 /* Scan the class object. */
632 scanImmuneReference((Object *)obj->obj.clazz, ctx);
633 /* Scan the instance fields. */
634 scanImmuneInstanceFields((const Object *)obj, ctx);
635 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISREFERENCE)) {
636 scanImmuneReference((Object *)obj, ctx);
637 }
638}
639
640/*
641 * Scans an object reference. Determines the type of the reference
642 * and dispatches to a specialized scanning routine.
643 */
644static void scanImmuneObject(const Object *obj, GcMarkContext *ctx)
645{
646 assert(obj != NULL);
647 assert(obj->clazz != NULL);
648 assert(ctx != NULL);
649 assert(obj < (Object *)ctx->immuneLimit);
650
651#if WITH_HPROF
652 if (gDvm.gcHeap->hprofContext != NULL) {
653 hprofDumpHeapObject(gDvm.gcHeap->hprofContext, obj);
654 }
655#endif
656 /* Dispatch a type-specific scan routine. */
657 if (obj->clazz == gDvm.classJavaLangClass) {
658 scanImmuneClassObject((ClassObject *)obj, ctx);
659 } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
660 scanImmuneArrayObject((ArrayObject *)obj, ctx);
661 } else {
662 scanImmuneDataObject((DataObject *)obj, ctx);
663 }
664}
665
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800666static void
667processMarkStack(GcMarkContext *ctx)
668{
669 const Object **const base = ctx->stack.base;
670
671 /* Scan anything that's on the mark stack.
672 * We can't use the bitmaps anymore, so use
673 * a finger that points past the end of them.
674 */
675 ctx->finger = (void *)ULONG_MAX;
676 while (ctx->stack.top != base) {
677 scanObject(*ctx->stack.top++, ctx);
678 }
679}
680
681#ifndef NDEBUG
682static uintptr_t gLastFinger = 0;
683#endif
684
685static bool
686scanBitmapCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
687{
688 GcMarkContext *ctx = (GcMarkContext *)arg;
689 size_t i;
690
691#ifndef NDEBUG
692 assert((uintptr_t)finger >= gLastFinger);
693 gLastFinger = (uintptr_t)finger;
694#endif
695
696 ctx->finger = finger;
697 for (i = 0; i < numPtrs; i++) {
Carl Shapiro6343bd02010-02-16 17:40:19 -0800698 scanObject(*ptrs++, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800699 }
700
701 return true;
702}
703
704/* Given bitmaps with the root set marked, find and mark all
705 * reachable objects. When this returns, the entire set of
706 * live objects will be marked and the mark stack will be empty.
707 */
Carl Shapiro29540742010-03-26 15:34:39 -0700708void dvmHeapScanMarkedObjects(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800709{
710 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
711
712 assert(ctx->finger == NULL);
713
714 /* The bitmaps currently have bits set for the root set.
715 * Walk across the bitmaps and scan each object.
716 */
717#ifndef NDEBUG
718 gLastFinger = 0;
719#endif
Barry Hayes6e5cf602010-06-22 12:32:59 -0700720 if (gDvm.executionMode == kExecutionModeInterpPortable) {
721 /* The portable interpreter dirties cards on write; other
722 * modes do not yet do so.
723 * TODO: Bring the fast interpreter and JIT into the fold.
724 */
725 HeapBitmap markBits[HEAP_SOURCE_MAX_HEAP_COUNT];
726 HeapBitmap liveBits[HEAP_SOURCE_MAX_HEAP_COUNT];
727 size_t numBitmaps, i;
728 numBitmaps = dvmHeapSourceGetNumHeaps();
729 dvmHeapSourceGetObjectBitmaps(liveBits, markBits, numBitmaps);
730 for (i = 0; i < numBitmaps; i++) {
731 /* The use of finger to tell visited from unvisited objects
732 * requires we walk the bitmaps from low to high
733 * addresses. This code assumes [and asserts] that the order
734 * of the heaps returned is the reverse of that.
735 */
736 size_t j = numBitmaps-1-i;
737 assert(j == 0 || (markBits[j].base < markBits[j-1].base));
738 if (markBits[j].base < (uintptr_t)ctx->immuneLimit) {
Barry Hayes6e5cf602010-06-22 12:32:59 -0700739 uintptr_t minAddr = markBits[j].base;
740 uintptr_t maxAddr = markBits[j].base +
741 HB_MAX_OFFSET(&markBits[j]);
742 u1 *minCard = dvmCardFromAddr((void *)minAddr);
743 u1 *maxCard = dvmCardFromAddr((void *)maxAddr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800744
Barry Hayes6e5cf602010-06-22 12:32:59 -0700745 u1 *card;
Barry Hayes8f921a72010-07-09 12:53:49 -0700746 /* TODO: This double-loop should be made faster. In
747 * particular the inner loop could get in bed with the
748 * bitmap scanning routines.
Barry Hayes6e5cf602010-06-22 12:32:59 -0700749 */
750 for (card = minCard; card <= maxCard; card++) {
751 if (*card == GC_CARD_DIRTY) {
752 uintptr_t addr = (uintptr_t)dvmAddrFromCard(card);
753 uintptr_t endAddr = addr + GC_CARD_SIZE;
754 ctx->crossGen = false;
755 for ( ; addr < endAddr; addr += 8) {
756 if (dvmIsValidObject((void *)addr)) {
757 scanImmuneObject((void *)addr, ctx);
758 }
759 }
760 if (! ctx->crossGen) {
761 *card = GC_CARD_CLEAN;
762 }
763 }
764 }
Barry Hayes6e5cf602010-06-22 12:32:59 -0700765 } else {
766 dvmHeapBitmapWalk(&markBits[j], scanBitmapCallback, ctx);
767 }
768 }
769 } else {
770 dvmHeapBitmapWalk(ctx->bitmap, scanBitmapCallback, ctx);
771 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800772 /* We've walked the mark bitmaps. Scan anything that's
773 * left on the mark stack.
774 */
775 processMarkStack(ctx);
776
777 LOG_SCAN("done with marked objects\n");
778}
779
Carl Shapiroec805ea2010-06-28 16:28:26 -0700780/*
781 * Callback applied to each gray object to blacken it.
782 */
783static bool dirtyObjectCallback(size_t numPtrs, void **ptrs,
784 const void *finger, void *arg)
785{
Carl Shapiroec805ea2010-06-28 16:28:26 -0700786 size_t i;
787
Carl Shapiroec805ea2010-06-28 16:28:26 -0700788 for (i = 0; i < numPtrs; ++i) {
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700789 scanObject(ptrs[i], arg);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700790 }
791 return true;
792}
793
794/*
795 * Re-mark dirtied objects. Iterates through all blackened objects
796 * looking for references to white objects.
797 */
798void dvmMarkDirtyObjects(void)
799{
800 HeapBitmap markBits[HEAP_SOURCE_MAX_HEAP_COUNT];
801 HeapBitmap liveBits[HEAP_SOURCE_MAX_HEAP_COUNT];
802 GcMarkContext *ctx;
803 size_t numBitmaps;
804 size_t i;
805
806 ctx = &gDvm.gcHeap->markContext;
807 /*
Carl Shapirof5860332010-06-28 23:02:08 -0700808 * The finger must have been set to the maximum value to ensure
809 * that gray objects will be pushed onto the mark stack.
Carl Shapiroec805ea2010-06-28 16:28:26 -0700810 */
811 assert(ctx->finger == (void *)ULONG_MAX);
812 numBitmaps = dvmHeapSourceGetNumHeaps();
813 dvmHeapSourceGetObjectBitmaps(liveBits, markBits, numBitmaps);
814 for (i = 0; i < numBitmaps; i++) {
815 dvmHeapBitmapWalk(&markBits[i], dirtyObjectCallback, ctx);
816 }
817 processMarkStack(ctx);
818}
819
Carl Shapiro34f51992010-07-09 17:55:41 -0700820/*
821 * Clear the referent field.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800822 */
Barry Hayes6930a112009-12-22 11:01:38 -0800823static void clearReference(Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800824{
Carl Shapiro34f51992010-07-09 17:55:41 -0700825 size_t offset = gDvm.offJavaLangRefReference_referent;
826 dvmSetFieldObject(reference, offset, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800827}
828
Carl Shapiro29540742010-03-26 15:34:39 -0700829/*
830 * Returns true if the reference was registered with a reference queue
831 * and has not yet been enqueued.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800832 */
Carl Shapiro29540742010-03-26 15:34:39 -0700833static bool isEnqueuable(const Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800834{
Barry Hayes6930a112009-12-22 11:01:38 -0800835 Object *queue = dvmGetFieldObject(reference,
836 gDvm.offJavaLangRefReference_queue);
837 Object *queueNext = dvmGetFieldObject(reference,
838 gDvm.offJavaLangRefReference_queueNext);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700839 return queue != NULL && queueNext == NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800840}
841
Carl Shapiro29540742010-03-26 15:34:39 -0700842/*
843 * Schedules a reference to be appended to its reference queue.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800844 */
Carl Shapiro29540742010-03-26 15:34:39 -0700845static void enqueueReference(Object *ref)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800846{
Carl Shapiro646ba092010-06-10 15:17:00 -0700847 assert(ref != NULL);
Carl Shapiro29540742010-03-26 15:34:39 -0700848 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
849 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
Carl Shapiro646ba092010-06-10 15:17:00 -0700850 if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
Carl Shapiro29540742010-03-26 15:34:39 -0700851 LOGE_HEAP("enqueueReference(): no room for any more "
852 "reference operations\n");
853 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800854 }
855}
856
Carl Shapiro29540742010-03-26 15:34:39 -0700857/*
858 * Walks the reference list marking any references subject to the
859 * reference clearing policy. References with a black referent are
860 * removed from the list. References with white referents biased
861 * toward saving are blackened and also removed from the list.
862 */
863void dvmHandleSoftRefs(Object **list)
864{
865 GcMarkContext *markContext;
866 Object *ref, *referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700867 Object *clear;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700868 size_t referentOffset;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700869 size_t counter;
Carl Shapiro29540742010-03-26 15:34:39 -0700870 bool marked;
871
872 markContext = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700873 referentOffset = gDvm.offJavaLangRefReference_referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700874 clear = NULL;
Carl Shapiro29540742010-03-26 15:34:39 -0700875 counter = 0;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700876 while (*list != NULL) {
877 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700878 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700879 assert(referent != NULL);
880 marked = isMarked(referent, markContext);
881 if (!marked && ((++counter) & 1)) {
882 /* Referent is white and biased toward saving, mark it. */
Barry Hayese1bccb92010-05-18 09:48:37 -0700883 markObject(referent, markContext);
Carl Shapiro29540742010-03-26 15:34:39 -0700884 marked = true;
885 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700886 if (!marked) {
887 /* Referent is white, queue it for clearing. */
888 enqueuePendingReference(ref, &clear);
Carl Shapiro29540742010-03-26 15:34:39 -0700889 }
Carl Shapiro29540742010-03-26 15:34:39 -0700890 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700891 *list = clear;
Carl Shapiro29540742010-03-26 15:34:39 -0700892 /*
893 * Restart the mark with the newly black references added to the
894 * root set.
895 */
896 processMarkStack(markContext);
897}
898
899/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700900 * Unlink the reference list clearing references objects with white
901 * referents. Cleared references registered to a reference queue are
902 * scheduled for appending by the heap worker thread.
Carl Shapiro29540742010-03-26 15:34:39 -0700903 */
904void dvmClearWhiteRefs(Object **list)
905{
906 GcMarkContext *markContext;
907 Object *ref, *referent;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700908 size_t referentOffset;
Carl Shapiro29540742010-03-26 15:34:39 -0700909 bool doSignal;
910
911 markContext = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700912 referentOffset = gDvm.offJavaLangRefReference_referent;
913 doSignal = false;
914 while (*list != NULL) {
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700915 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700916 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700917 assert(referent != NULL);
918 if (!isMarked(referent, markContext)) {
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700919 /* Referent is white, clear it. */
Carl Shapiro29540742010-03-26 15:34:39 -0700920 clearReference(ref);
921 if (isEnqueuable(ref)) {
922 enqueueReference(ref);
923 doSignal = true;
924 }
925 }
926 }
927 /*
928 * If we cleared a reference with a reference queue we must notify
929 * the heap worker to append the reference.
930 */
931 if (doSignal) {
932 dvmSignalHeapWorker(false);
933 }
934 assert(*list == NULL);
935}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800936
937/* Find unreachable objects that need to be finalized,
938 * and schedule them for finalization.
939 */
940void dvmHeapScheduleFinalizations()
941{
942 HeapRefTable newPendingRefs;
943 LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
944 Object **ref;
945 Object **lastRef;
946 size_t totalPendCount;
947 GcMarkContext *markContext = &gDvm.gcHeap->markContext;
948
949 /*
950 * All reachable objects have been marked.
951 * Any unmarked finalizable objects need to be finalized.
952 */
953
954 /* Create a table that the new pending refs will
955 * be added to.
956 */
Barry Hayesd4f78d32010-06-08 09:34:42 -0700957 if (!dvmHeapInitHeapRefTable(&newPendingRefs)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800958 //TODO: mark all finalizable refs and hope that
959 // we can schedule them next time. Watch out,
960 // because we may be expecting to free up space
961 // by calling finalizers.
962 LOGE_GC("dvmHeapScheduleFinalizations(): no room for "
963 "pending finalizations\n");
964 dvmAbort();
965 }
966
967 /* Walk through finalizableRefs and move any unmarked references
968 * to the list of new pending refs.
969 */
970 totalPendCount = 0;
971 while (finRefs != NULL) {
972 Object **gapRef;
973 size_t newPendCount = 0;
974
975 gapRef = ref = finRefs->refs.table;
976 lastRef = finRefs->refs.nextEntry;
977 while (ref < lastRef) {
Carl Shapiro6343bd02010-02-16 17:40:19 -0800978 if (!isMarked(*ref, markContext)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800979 if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
980 //TODO: add the current table and allocate
981 // a new, smaller one.
982 LOGE_GC("dvmHeapScheduleFinalizations(): "
983 "no room for any more pending finalizations: %zd\n",
984 dvmHeapNumHeapRefTableEntries(&newPendingRefs));
985 dvmAbort();
986 }
987 newPendCount++;
988 } else {
989 /* This ref is marked, so will remain on finalizableRefs.
990 */
991 if (newPendCount > 0) {
992 /* Copy it up to fill the holes.
993 */
994 *gapRef++ = *ref;
995 } else {
996 /* No holes yet; don't bother copying.
997 */
998 gapRef++;
999 }
1000 }
1001 ref++;
1002 }
1003 finRefs->refs.nextEntry = gapRef;
1004 //TODO: if the table is empty when we're done, free it.
1005 totalPendCount += newPendCount;
1006 finRefs = finRefs->next;
1007 }
1008 LOGD_GC("dvmHeapScheduleFinalizations(): %zd finalizers triggered.\n",
1009 totalPendCount);
1010 if (totalPendCount == 0) {
1011 /* No objects required finalization.
1012 * Free the empty temporary table.
1013 */
1014 dvmClearReferenceTable(&newPendingRefs);
1015 return;
1016 }
1017
1018 /* Add the new pending refs to the main list.
1019 */
1020 if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
1021 &newPendingRefs))
1022 {
1023 LOGE_GC("dvmHeapScheduleFinalizations(): can't insert new "
1024 "pending finalizations\n");
1025 dvmAbort();
1026 }
1027
1028 //TODO: try compacting the main list with a memcpy loop
1029
1030 /* Mark the refs we just moved; we don't want them or their
1031 * children to get swept yet.
1032 */
1033 ref = newPendingRefs.table;
1034 lastRef = newPendingRefs.nextEntry;
1035 assert(ref < lastRef);
1036 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
1037 while (ref < lastRef) {
Barry Hayese1bccb92010-05-18 09:48:37 -07001038 assert(*ref != NULL);
1039 markObject(*ref, markContext);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001040 ref++;
1041 }
1042 HPROF_CLEAR_GC_SCAN_STATE();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001043 processMarkStack(markContext);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001044 dvmSignalHeapWorker(false);
1045}
1046
1047void dvmHeapFinishMarkStep()
1048{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001049 GcMarkContext *markContext;
1050
1051 markContext = &gDvm.gcHeap->markContext;
1052
1053 /* The sweep step freed every object that appeared in the
1054 * HeapSource bitmaps that didn't appear in the mark bitmaps.
1055 * The new state of the HeapSource is exactly the final
1056 * mark bitmaps, so swap them in.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001057 */
Carl Shapirof373efd2010-02-19 00:46:33 -08001058 dvmHeapSourceSwapBitmaps();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001059
Carl Shapirof373efd2010-02-19 00:46:33 -08001060 /* Clean up everything else associated with the marking process.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001061 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001062 destroyMarkStack(&markContext->stack);
1063
Carl Shapirof373efd2010-02-19 00:46:33 -08001064 markContext->finger = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001065}
1066
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001067static bool
1068sweepBitmapCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
1069{
1070 const ClassObject *const classJavaLangClass = gDvm.classJavaLangClass;
Barry Hayes5cbb2302010-02-02 14:07:37 -08001071 const bool overwriteFree = gDvm.overwriteFree;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001072 size_t i;
1073
1074 for (i = 0; i < numPtrs; i++) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001075 Object *obj;
1076
Barry Hayes04174be2010-07-21 11:51:37 -07001077 obj = (Object *)ptrs[i];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001078
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001079 /* This assumes that java.lang.Class will never go away.
1080 * If it can, and we were the last reference to it, it
1081 * could have already been swept. However, even in that case,
1082 * gDvm.classJavaLangClass should still have a useful
1083 * value.
1084 */
1085 if (obj->clazz == classJavaLangClass) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001086 /* dvmFreeClassInnards() may have already been called,
1087 * but it's safe to call on the same ClassObject twice.
1088 */
1089 dvmFreeClassInnards((ClassObject *)obj);
1090 }
1091
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001092 /* Overwrite the to-be-freed object to make stale references
1093 * more obvious.
1094 */
Barry Hayes5cbb2302010-02-02 14:07:37 -08001095 if (overwriteFree) {
Barry Hayes2e3c3e12010-02-22 09:39:10 -08001096 int objlen;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001097 ClassObject *clazz = obj->clazz;
Barry Hayes2e3c3e12010-02-22 09:39:10 -08001098 objlen = dvmHeapSourceChunkSize(obj);
1099 memset(obj, 0xa5, objlen);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001100 obj->clazz = (ClassObject *)((uintptr_t)clazz ^ 0xffffffff);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001101 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001102 }
Barry Hayesdde8ab02009-05-20 12:10:36 -07001103 // TODO: dvmHeapSourceFreeList has a loop, just like the above
1104 // does. Consider collapsing the two loops to save overhead.
Barry Hayes04174be2010-07-21 11:51:37 -07001105 dvmHeapSourceFreeList(numPtrs, ptrs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001106
1107 return true;
1108}
1109
Carl Shapiro5a6071b2010-01-07 21:35:50 -08001110/* Returns true if the given object is unmarked. Ignores the low bits
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001111 * of the pointer because the intern table may set them.
1112 */
1113static int isUnmarkedObject(void *object)
1114{
Carl Shapiro6343bd02010-02-16 17:40:19 -08001115 return !isMarked((void *)((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001116 &gDvm.gcHeap->markContext);
1117}
1118
1119/* Walk through the list of objects that haven't been
1120 * marked and free them.
1121 */
1122void
Carl Shapirod25566d2010-03-11 20:39:47 -08001123dvmHeapSweepUnmarkedObjects(GcMode mode, int *numFreed, size_t *sizeFreed)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001124{
Carl Shapirof373efd2010-02-19 00:46:33 -08001125 HeapBitmap markBits[HEAP_SOURCE_MAX_HEAP_COUNT];
Carl Shapirod77f7fd2010-04-05 19:23:31 -07001126 HeapBitmap liveBits[HEAP_SOURCE_MAX_HEAP_COUNT];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001127 size_t origObjectsAllocated;
1128 size_t origBytesAllocated;
Carl Shapirod25566d2010-03-11 20:39:47 -08001129 size_t numBitmaps, numSweepBitmaps;
Barry Hayese168ebd2010-05-07 09:19:46 -07001130 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001131
1132 /* All reachable objects have been marked.
1133 * Detach any unreachable interned strings before
1134 * we sweep.
1135 */
1136 dvmGcDetachDeadInternedStrings(isUnmarkedObject);
1137
1138 /* Free any known objects that are not marked.
1139 */
1140 origObjectsAllocated = dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0);
1141 origBytesAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
1142
Carl Shapiro5a6071b2010-01-07 21:35:50 -08001143 dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
1144
Carl Shapirof373efd2010-02-19 00:46:33 -08001145 numBitmaps = dvmHeapSourceGetNumHeaps();
Carl Shapirod77f7fd2010-04-05 19:23:31 -07001146 dvmHeapSourceGetObjectBitmaps(liveBits, markBits, numBitmaps);
Carl Shapirod25566d2010-03-11 20:39:47 -08001147 if (mode == GC_PARTIAL) {
1148 numSweepBitmaps = 1;
Carl Shapirod77f7fd2010-04-05 19:23:31 -07001149 assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == liveBits[0].base);
Carl Shapirod25566d2010-03-11 20:39:47 -08001150 } else {
1151 numSweepBitmaps = numBitmaps;
1152 }
Barry Hayese168ebd2010-05-07 09:19:46 -07001153 for (i = 0; i < numSweepBitmaps; i++) {
1154 dvmHeapBitmapXorWalk(&markBits[i], &liveBits[i],
1155 sweepBitmapCallback, NULL);
1156 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001157
1158 *numFreed = origObjectsAllocated -
1159 dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0);
1160 *sizeFreed = origBytesAllocated -
1161 dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
1162
1163#ifdef WITH_PROFILER
1164 if (gDvm.allocProf.enabled) {
1165 gDvm.allocProf.freeCount += *numFreed;
1166 gDvm.allocProf.freeSize += *sizeFreed;
1167 }
1168#endif
1169}