blob: 91365adbe8965536348b6583110f8d5630e9ca2d [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"
Carl Shapiro7ec91442010-10-21 15:35:19 -070019#include "alloc/CardTable.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080020#include "alloc/HeapBitmap.h"
21#include "alloc/HeapInternal.h"
22#include "alloc/HeapSource.h"
23#include "alloc/MarkSweep.h"
Carl Shapiroec805ea2010-06-28 16:28:26 -070024#include "alloc/Visit.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080025#include <limits.h> // for ULONG_MAX
26#include <sys/mman.h> // for madvise(), mmap()
The Android Open Source Project99409882009-03-18 22:20:24 -070027#include <errno.h>
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080028
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080029#define GC_LOG_TAG LOG_TAG "-gc"
30
31#if LOG_NDEBUG
32#define LOGV_GC(...) ((void)0)
33#define LOGD_GC(...) ((void)0)
34#else
35#define LOGV_GC(...) LOG(LOG_VERBOSE, GC_LOG_TAG, __VA_ARGS__)
36#define LOGD_GC(...) LOG(LOG_DEBUG, GC_LOG_TAG, __VA_ARGS__)
37#endif
38
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080039#define LOGI_GC(...) LOG(LOG_INFO, GC_LOG_TAG, __VA_ARGS__)
40#define LOGW_GC(...) LOG(LOG_WARN, GC_LOG_TAG, __VA_ARGS__)
41#define LOGE_GC(...) LOG(LOG_ERROR, GC_LOG_TAG, __VA_ARGS__)
42
43#define LOG_SCAN(...) LOGV_GC("SCAN: " __VA_ARGS__)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080044
Carl Shapiro7ec91442010-10-21 15:35:19 -070045#define ALIGN_DOWN(x, n) ((size_t)(x) & -(n))
Carl Shapiro57ee2702010-08-27 13:06:48 -070046#define ALIGN_UP(x, n) (((size_t)(x) + (n) - 1) & ~((n) - 1))
47#define ALIGN_UP_TO_PAGE_SIZE(p) ALIGN_UP(p, SYSTEM_PAGE_SIZE)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080048
Carl Shapiro7ec91442010-10-21 15:35:19 -070049typedef unsigned long Word;
50const size_t kWordSize = sizeof(Word);
51
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080052/* Do not cast the result of this to a boolean; the only set bit
53 * may be > 1<<8.
54 */
Carl Shapiro6343bd02010-02-16 17:40:19 -080055static inline long isMarked(const void *obj, const GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080056{
Carl Shapirof373efd2010-02-19 00:46:33 -080057 return dvmHeapBitmapIsObjectBitSet(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080058}
59
Carl Shapirod7400e02010-09-02 18:24:29 -070060static bool createMarkStack(GcMarkStack *stack)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080061{
62 const Object **limit;
Carl Shapiro742c4452010-07-13 18:28:13 -070063 const char *name;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080064 size_t size;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080065
66 /* Create a stack big enough for the worst possible case,
67 * where the heap is perfectly full of the smallest object.
68 * TODO: be better about memory usage; use a smaller stack with
69 * overflow detection and recovery.
70 */
71 size = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
72 (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
73 size = ALIGN_UP_TO_PAGE_SIZE(size);
Carl Shapiro742c4452010-07-13 18:28:13 -070074 name = "dalvik-mark-stack";
75 limit = dvmAllocRegion(size, PROT_READ | PROT_WRITE, name);
76 if (limit == NULL) {
77 LOGE_GC("Could not mmap %zd-byte ashmem region '%s'", size, name);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080078 return false;
79 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080080 stack->limit = limit;
81 stack->base = (const Object **)((uintptr_t)limit + size);
82 stack->top = stack->base;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080083 return true;
84}
85
Carl Shapirod7400e02010-09-02 18:24:29 -070086static void destroyMarkStack(GcMarkStack *stack)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080087{
88 munmap((char *)stack->limit,
89 (uintptr_t)stack->base - (uintptr_t)stack->limit);
90 memset(stack, 0, sizeof(*stack));
91}
92
93#define MARK_STACK_PUSH(stack, obj) \
94 do { \
95 *--(stack).top = (obj); \
96 } while (false)
97
Carl Shapirod7400e02010-09-02 18:24:29 -070098bool dvmHeapBeginMarkStep(GcMode mode)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080099{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700100 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800101
Carl Shapirob2e78d32010-08-20 11:34:18 -0700102 if (!createMarkStack(&ctx->stack)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800103 return false;
104 }
Carl Shapirob2e78d32010-08-20 11:34:18 -0700105 ctx->finger = NULL;
106 ctx->immuneLimit = dvmHeapSourceGetImmuneLimit(mode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800107 return true;
108}
109
Carl Shapirod7400e02010-09-02 18:24:29 -0700110static long setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800111{
Carl Shapirof373efd2010-02-19 00:46:33 -0800112 return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800113}
114
Carl Shapirod7400e02010-09-02 18:24:29 -0700115static void markObjectNonNull(const Object *obj, GcMarkContext *ctx,
116 bool checkFinger)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800117{
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 Shapiro106c5fd2010-07-28 14:12:27 -0700129 if (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) {
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700152 markObjectNonNull(obj, ctx, true);
Barry Hayese1bccb92010-05-18 09:48:37 -0700153 }
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 */
Carl Shapirod7400e02010-09-02 18:24:29 -0700165void dvmMarkObjectNonNull(const Object *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800166{
Barry Hayese1bccb92010-05-18 09:48:37 -0700167 assert(obj != NULL);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700168 markObjectNonNull(obj, &gDvm.gcHeap->markContext, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800169}
170
171/* Mark the set of root objects.
172 *
173 * Things we need to scan:
174 * - System classes defined by root classloader
175 * - For each thread:
176 * - Interpreted stack, from top to "curFrame"
177 * - Dalvik registers (args + local vars)
178 * - JNI local references
179 * - Automatic VM local references (TrackedAlloc)
180 * - Associated Thread/VMThread object
181 * - ThreadGroups (could track & start with these instead of working
182 * upward from Threads)
183 * - Exception currently being thrown, if present
184 * - JNI global references
185 * - Interned string table
186 * - Primitive classes
187 * - Special objects
188 * - gDvm.outOfMemoryObj
189 * - Objects allocated with ALLOC_NO_GC
190 * - Objects pending finalization (but not yet finalized)
191 * - Objects in debugger object registry
192 *
193 * Don't need:
194 * - Native stack (for in-progress stuff in the VM)
195 * - The TrackedAlloc stuff watches all native VM references.
196 */
197void dvmHeapMarkRootSet()
198{
Barry Hayesd4f78d32010-06-08 09:34:42 -0700199 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800200
201 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_STICKY_CLASS, 0);
202
Carl Shapirod25566d2010-03-11 20:39:47 -0800203 LOG_SCAN("immune objects");
Barry Hayes425848f2010-05-04 13:32:12 -0700204 dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
Carl Shapirod25566d2010-03-11 20:39:47 -0800205
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800206 LOG_SCAN("root class loader\n");
207 dvmGcScanRootClassLoader();
208 LOG_SCAN("primitive classes\n");
209 dvmGcScanPrimitiveClasses();
210
211 /* dvmGcScanRootThreadGroups() sets a bunch of
212 * different scan states internally.
213 */
214 HPROF_CLEAR_GC_SCAN_STATE();
215
216 LOG_SCAN("root thread groups\n");
217 dvmGcScanRootThreadGroups();
218
219 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_INTERNED_STRING, 0);
220
221 LOG_SCAN("interned strings\n");
222 dvmGcScanInternedStrings();
223
224 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_GLOBAL, 0);
225
226 LOG_SCAN("JNI global refs\n");
227 dvmGcMarkJniGlobalRefs();
228
229 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
230
231 LOG_SCAN("pending reference operations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700232 dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800233
234 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
235
236 LOG_SCAN("pending finalizations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700237 dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800238
239 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_DEBUGGER, 0);
240
241 LOG_SCAN("debugger refs\n");
242 dvmGcMarkDebuggerRefs();
243
244 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_VM_INTERNAL, 0);
245
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800246 /* Mark any special objects we have sitting around.
247 */
248 LOG_SCAN("special objects\n");
249 dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
250 dvmMarkObjectNonNull(gDvm.internalErrorObj);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700251 dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800252//TODO: scan object references sitting in gDvm; use pointer begin & end
253
254 HPROF_CLEAR_GC_SCAN_STATE();
255}
256
257/*
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700258 * Callback applied to root references. If the root location contains
259 * a white reference it is pushed on the mark stack and grayed.
260 */
261static void markObjectVisitor(void *addr, void *arg)
262{
263 Object *obj;
264
265 assert(addr != NULL);
266 assert(arg != NULL);
267 obj = *(Object **)addr;
268 if (obj != NULL) {
269 markObjectNonNull(obj, arg, true);
270 }
271}
272
273/*
274 * Grays all references in the roots.
275 */
276void dvmHeapReMarkRootSet(void)
277{
278 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
279 assert(ctx->finger == (void *)ULONG_MAX);
280 dvmVisitRoots(markObjectVisitor, ctx);
281}
282
283/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700284 * Nothing past this point is allowed to use dvmMarkObject() or
285 * dvmMarkObjectNonNull(), which are for root-marking only.
286 * Scanning/recursion must use markObject(), which takes the finger
287 * into account.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800288 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700289#undef dvmMarkObject
290#define dvmMarkObject __dont_use_dvmMarkObject__
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800291#define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
292
Barry Hayese1bccb92010-05-18 09:48:37 -0700293/*
294 * Scans instance fields.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800295 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700296static void scanInstanceFields(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800297{
Barry Hayese1bccb92010-05-18 09:48:37 -0700298 assert(obj != NULL);
299 assert(obj->clazz != NULL);
300 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800301
Barry Hayese1bccb92010-05-18 09:48:37 -0700302 if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
303 unsigned int refOffsets = obj->clazz->refOffsets;
Barry Hayeseac47ed2009-06-22 11:45:20 -0700304 while (refOffsets != 0) {
305 const int rshift = CLZ(refOffsets);
306 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
307 markObject(dvmGetFieldObject((Object*)obj,
Barry Hayese1bccb92010-05-18 09:48:37 -0700308 CLASS_OFFSET_FROM_CLZ(rshift)), ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800309 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700310 } else {
Barry Hayese1bccb92010-05-18 09:48:37 -0700311 ClassObject *clazz;
312 int i;
313 for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
314 InstField *field = clazz->ifields;
315 for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
316 void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
317 markObject(((JValue *)addr)->l, ctx);
Barry Hayeseac47ed2009-06-22 11:45:20 -0700318 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700319 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800320 }
321}
322
Barry Hayese1bccb92010-05-18 09:48:37 -0700323/*
324 * Scans the header, static field references, and interface
325 * pointers of a class object.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800326 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700327static void scanClassObject(const ClassObject *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800328{
Barry Hayese1bccb92010-05-18 09:48:37 -0700329 int i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800330
Barry Hayese1bccb92010-05-18 09:48:37 -0700331 assert(obj != NULL);
332 assert(obj->obj.clazz == gDvm.classJavaLangClass);
333 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800334
Barry Hayese1bccb92010-05-18 09:48:37 -0700335 markObject((Object *)obj->obj.clazz, ctx);
336 if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
337 markObject((Object *)obj->elementClass, ctx);
338 }
Barry Hayesc49db852010-05-14 13:43:34 -0700339 /* Do super and the interfaces contain Objects and not dex idx values? */
340 if (obj->status > CLASS_IDX) {
341 markObject((Object *)obj->super, ctx);
342 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700343 markObject(obj->classLoader, ctx);
344 /* Scan static field references. */
345 for (i = 0; i < obj->sfieldCount; ++i) {
346 char ch = obj->sfields[i].field.signature[0];
347 if (ch == '[' || ch == 'L') {
348 markObject(obj->sfields[i].value.l, ctx);
349 }
350 }
351 /* Scan the instance fields. */
352 scanInstanceFields((const Object *)obj, ctx);
353 /* Scan interface references. */
Barry Hayesc49db852010-05-14 13:43:34 -0700354 if (obj->status > CLASS_IDX) {
355 for (i = 0; i < obj->interfaceCount; ++i) {
356 markObject((Object *)obj->interfaces[i], ctx);
357 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800358 }
359}
360
Barry Hayese1bccb92010-05-18 09:48:37 -0700361/*
362 * Scans the header of all array objects. If the array object is
363 * specialized to a reference type, scans the array data as well.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800364 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700365static void scanArrayObject(const ArrayObject *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800366{
Barry Hayese1bccb92010-05-18 09:48:37 -0700367 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800368
Barry Hayese1bccb92010-05-18 09:48:37 -0700369 assert(obj != NULL);
370 assert(obj->obj.clazz != NULL);
371 assert(ctx != NULL);
372 /* Scan the class object reference. */
373 markObject((Object *)obj->obj.clazz, ctx);
374 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISOBJECTARRAY)) {
375 /* Scan the array contents. */
376 Object **contents = (Object **)obj->contents;
377 for (i = 0; i < obj->length; ++i) {
378 markObject(contents[i], ctx);
379 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800380 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700381}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800382
Barry Hayese1bccb92010-05-18 09:48:37 -0700383/*
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700384 * Returns class flags relating to Reference subclasses.
385 */
386static int referenceClassFlags(const Object *obj)
387{
388 int flags = CLASS_ISREFERENCE |
389 CLASS_ISWEAKREFERENCE |
390 CLASS_ISPHANTOMREFERENCE;
391 return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
392}
393
394/*
395 * Returns true if the object derives from SoftReference.
396 */
397static bool isSoftReference(const Object *obj)
398{
399 return referenceClassFlags(obj) == CLASS_ISREFERENCE;
400}
401
402/*
403 * Returns true if the object derives from WeakReference.
404 */
405static bool isWeakReference(const Object *obj)
406{
407 return referenceClassFlags(obj) & CLASS_ISWEAKREFERENCE;
408}
409
410/*
411 * Returns true if the object derives from PhantomReference.
412 */
413static bool isPhantomReference(const Object *obj)
414{
415 return referenceClassFlags(obj) & CLASS_ISPHANTOMREFERENCE;
416}
417
418/*
419 * Adds a reference to the tail of a circular queue of references.
420 */
421static void enqueuePendingReference(Object *ref, Object **list)
422{
423 size_t offset;
424
425 assert(ref != NULL);
426 assert(list != NULL);
427 offset = gDvm.offJavaLangRefReference_pendingNext;
428 if (*list == NULL) {
429 dvmSetFieldObject(ref, offset, ref);
430 *list = ref;
431 } else {
432 Object *head = dvmGetFieldObject(*list, offset);
433 dvmSetFieldObject(ref, offset, head);
434 dvmSetFieldObject(*list, offset, ref);
435 }
436}
437
438/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700439 * Removes the reference at the head of a circular queue of
440 * references.
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700441 */
442static Object *dequeuePendingReference(Object **list)
443{
444 Object *ref, *head;
445 size_t offset;
446
447 assert(list != NULL);
448 assert(*list != NULL);
449 offset = gDvm.offJavaLangRefReference_pendingNext;
450 head = dvmGetFieldObject(*list, offset);
451 if (*list == head) {
452 ref = *list;
453 *list = NULL;
454 } else {
455 Object *next = dvmGetFieldObject(head, offset);
456 dvmSetFieldObject(*list, offset, next);
457 ref = head;
458 }
459 dvmSetFieldObject(ref, offset, NULL);
460 return ref;
461}
462
463/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700464 * Process the "referent" field in a java.lang.ref.Reference. If the
465 * referent has not yet been marked, put it on the appropriate list in
466 * the gcHeap for later processing.
467 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700468static void delayReferenceReferent(Object *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700469{
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700470 GcHeap *gcHeap = gDvm.gcHeap;
471 Object *pending, *referent;
472 size_t pendingNextOffset, referentOffset;
473
Barry Hayese1bccb92010-05-18 09:48:37 -0700474 assert(obj != NULL);
Barry Hayes697b5a92010-06-23 11:38:52 -0700475 assert(obj->clazz != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700476 assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
Barry Hayese1bccb92010-05-18 09:48:37 -0700477 assert(ctx != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700478 pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
479 referentOffset = gDvm.offJavaLangRefReference_referent;
480 pending = dvmGetFieldObject(obj, pendingNextOffset);
481 referent = dvmGetFieldObject(obj, referentOffset);
482 if (pending == NULL && referent != NULL && !isMarked(referent, ctx)) {
483 Object **list = NULL;
484 if (isSoftReference(obj)) {
485 list = &gcHeap->softReferences;
486 } else if (isWeakReference(obj)) {
487 list = &gcHeap->weakReferences;
488 } else if (isPhantomReference(obj)) {
489 list = &gcHeap->phantomReferences;
Barry Hayese1bccb92010-05-18 09:48:37 -0700490 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700491 assert(list != NULL);
492 enqueuePendingReference(obj, list);
Barry Hayese1bccb92010-05-18 09:48:37 -0700493 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800494}
495
Barry Hayese1bccb92010-05-18 09:48:37 -0700496/*
497 * Scans the header and field references of a data object.
498 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700499static void scanDataObject(DataObject *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700500{
501 assert(obj != NULL);
502 assert(obj->obj.clazz != NULL);
503 assert(ctx != NULL);
504 /* Scan the class object. */
505 markObject((Object *)obj->obj.clazz, ctx);
506 /* Scan the instance fields. */
507 scanInstanceFields((const Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700508 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISREFERENCE)) {
Barry Hayes697b5a92010-06-23 11:38:52 -0700509 delayReferenceReferent((Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700510 }
511}
512
513/*
514 * Scans an object reference. Determines the type of the reference
515 * and dispatches to a specialized scanning routine.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800516 */
517static void scanObject(const Object *obj, GcMarkContext *ctx)
518{
Barry Hayese1bccb92010-05-18 09:48:37 -0700519 assert(obj != NULL);
520 assert(ctx != NULL);
Barry Hayes899cdb72010-06-08 09:59:12 -0700521 assert(obj->clazz != NULL);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700522#if WITH_HPROF
523 if (gDvm.gcHeap->hprofContext != NULL) {
524 hprofDumpHeapObject(gDvm.gcHeap->hprofContext, obj);
525 }
526#endif
Barry Hayese1bccb92010-05-18 09:48:37 -0700527 /* Dispatch a type-specific scan routine. */
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700528 if (obj->clazz == gDvm.classJavaLangClass) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700529 scanClassObject((ClassObject *)obj, ctx);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700530 } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
Barry Hayes899cdb72010-06-08 09:59:12 -0700531 scanArrayObject((ArrayObject *)obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800532 } else {
Barry Hayes899cdb72010-06-08 09:59:12 -0700533 scanDataObject((DataObject *)obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800534 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800535}
536
537static void
538processMarkStack(GcMarkContext *ctx)
539{
540 const Object **const base = ctx->stack.base;
541
542 /* Scan anything that's on the mark stack.
543 * We can't use the bitmaps anymore, so use
544 * a finger that points past the end of them.
545 */
546 ctx->finger = (void *)ULONG_MAX;
547 while (ctx->stack.top != base) {
548 scanObject(*ctx->stack.top++, ctx);
549 }
550}
551
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700552static size_t objectSize(const Object *obj)
553{
554 assert(dvmIsValidObject(obj));
555 assert(dvmIsValidObject((Object *)obj->clazz));
556 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
557 return dvmArrayObjectSize((ArrayObject *)obj);
558 } else if (obj->clazz == gDvm.classJavaLangClass) {
559 return dvmClassObjectSize((ClassObject *)obj);
560 } else {
561 return obj->clazz->objectSize;
562 }
563}
564
565/*
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700566 * Scans forward to the header of the next marked object between start
567 * and limit. Returns NULL if no marked objects are in that region.
568 */
Carl Shapiro7ec91442010-10-21 15:35:19 -0700569static Object *nextGrayObject(const u1 *base, const u1 *limit,
570 const HeapBitmap *markBits)
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700571{
Carl Shapiro7ec91442010-10-21 15:35:19 -0700572 const u1 *ptr;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700573
574 assert(base < limit);
575 assert(limit - base <= GC_CARD_SIZE);
576 for (ptr = base; ptr < limit; ptr += HB_OBJECT_ALIGNMENT) {
Carl Shapiroea10c552010-09-02 23:32:25 -0700577 if (dvmHeapBitmapIsObjectBitSet(markBits, ptr))
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700578 return (Object *)ptr;
579 }
580 return NULL;
581}
582
583/*
Carl Shapiro7ec91442010-10-21 15:35:19 -0700584 * Scans each byte from start below end returning the address of the
585 * first dirty card. Returns NULL if no dirty card is found.
586 */
587static const u1 *scanBytesForDirtyCard(const u1 *start, const u1 *end)
588{
589 const u1 *ptr;
590
591 assert(start <= end);
592 for (ptr = start; ptr < end; ++ptr) {
593 if (*ptr == GC_CARD_DIRTY) {
594 return ptr;
595 }
596 }
597 return NULL;
598}
599
600/*
601 * Like scanBytesForDirtyCard but scans the range from start below end
602 * by words. Assumes start and end are word aligned.
603 */
604static const u1 *scanWordsForDirtyCard(const u1 *start, const u1 *end)
605{
606 const u1 *ptr;
607
608 assert((uintptr_t)start % kWordSize == 0);
609 assert((uintptr_t)end % kWordSize == 0);
610 assert(start <= end);
611 for (ptr = start; ptr < end; ptr += kWordSize) {
612 if (*(const Word *)ptr != 0) {
613 const u1 *dirty = scanBytesForDirtyCard(ptr, ptr + kWordSize);
614 if (dirty != NULL) {
615 return dirty;
616 }
617 }
618 }
619 return NULL;
620}
621
622/*
623 * Scans the card table as quickly as possible looking for a dirty
624 * card. Returns the address of the first dirty card found or NULL if
625 * no dirty cards were found.
626 */
627static const u1 *nextDirtyCard(const u1 *start, const u1 *end)
628{
629 const u1 *wstart = (u1 *)ALIGN_UP(start, kWordSize);
630 const u1 *wend = (u1 *)ALIGN_DOWN(end, kWordSize);
631 const u1 *ptr, *dirty;
632
633 assert(start <= end);
634 assert(start <= wstart);
635 assert(end >= wend);
636 ptr = start;
637 if (wstart < end) {
638 /* Scan the leading unaligned bytes. */
639 dirty = scanBytesForDirtyCard(ptr, wstart);
640 if (dirty != NULL) {
641 return dirty;
642 }
643 /* Scan the range of aligned words. */
644 dirty = scanWordsForDirtyCard(wstart, wend);
645 if (dirty != NULL) {
646 return dirty;
647 }
648 ptr = wend;
649 }
650 /* Scan trailing unaligned bytes. */
651 dirty = scanBytesForDirtyCard(ptr, end);
652 if (dirty != NULL) {
653 return dirty;
654 }
655 return NULL;
656}
657
658/*
659 * Scans range of dirty cards between start and end. A range of dirty
660 * cards is composed consecutively dirty cards or dirty cards spanned
661 * by a gray object. Returns the address of a clean card if the scan
662 * reached a clean card or NULL if the scan reached the end.
663 */
664const u1 *scanDirtyCards(const u1 *start, const u1 *end,
665 GcMarkContext *ctx)
666{
667 const HeapBitmap *markBits = ctx->bitmap;
668 const u1 *card = start, *prevAddr = NULL;
669 while (card < end) {
670 if (*card != GC_CARD_DIRTY) {
671 return card;
672 }
673 const u1 *ptr = prevAddr ? prevAddr : dvmAddrFromCard(card);
674 const u1 *limit = ptr + GC_CARD_SIZE;
675 while (ptr < limit) {
676 Object *obj = nextGrayObject(ptr, limit, markBits);
677 if (obj == NULL) {
678 break;
679 }
680 scanObject(obj, ctx);
681 ptr = (u1*)obj + ALIGN_UP(objectSize(obj), HB_OBJECT_ALIGNMENT);
682 }
683 if (ptr < limit) {
684 /* Ended within the current card, advance to the next card. */
685 ++card;
686 prevAddr = NULL;
687 } else {
688 /* Ended past the current card, skip ahead. */
689 card = dvmCardFromAddr(ptr);
690 prevAddr = ptr;
691 }
692 }
693 return NULL;
694}
695
696/*
697 * Blackens gray objects found on dirty cards.
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700698 */
699static void scanGrayObjects(GcMarkContext *ctx)
700{
701 GcHeap *h = gDvm.gcHeap;
Carl Shapiro7ec91442010-10-21 15:35:19 -0700702 const u1 *base, *limit, *ptr, *dirty;
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700703 size_t footprint;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700704
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700705 footprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
Carl Shapiro7ec91442010-10-21 15:35:19 -0700706 base = &h->cardTableBase[0];
707 limit = dvmCardFromAddr((u1 *)dvmHeapSourceGetBase() + footprint);
708 assert(limit <= &h->cardTableBase[h->cardTableLength]);
709
710 ptr = base;
711 for (;;) {
712 dirty = nextDirtyCard(ptr, limit);
713 if (dirty == NULL) {
714 break;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700715 }
Carl Shapiro7ec91442010-10-21 15:35:19 -0700716 assert((dirty > ptr) && (dirty < limit));
717 ptr = scanDirtyCards(dirty, limit, ctx);
718 if (ptr == NULL) {
719 break;
720 }
721 assert((ptr > dirty) && (ptr < limit));
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700722 }
723}
724
Carl Shapiro57ee2702010-08-27 13:06:48 -0700725/*
726 * Callback for scanning each object in the bitmap. The finger is set
727 * to the address corresponding to the lowest address in the next word
728 * of bits in the bitmap.
729 */
Carl Shapiro38d710b2010-08-31 16:48:31 -0700730static void scanBitmapCallback(void *addr, void *finger, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800731{
Carl Shapiro006346e2010-07-29 20:39:50 -0700732 GcMarkContext *ctx = arg;
Carl Shapiro57ee2702010-08-27 13:06:48 -0700733 ctx->finger = (void *)finger;
734 scanObject(addr, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800735}
736
737/* Given bitmaps with the root set marked, find and mark all
738 * reachable objects. When this returns, the entire set of
739 * live objects will be marked and the mark stack will be empty.
740 */
Carl Shapiro29540742010-03-26 15:34:39 -0700741void dvmHeapScanMarkedObjects(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800742{
743 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
744
745 assert(ctx->finger == NULL);
746
747 /* The bitmaps currently have bits set for the root set.
748 * Walk across the bitmaps and scan each object.
749 */
Carl Shapiro38d710b2010-08-31 16:48:31 -0700750 dvmHeapBitmapScanWalk(ctx->bitmap, scanBitmapCallback, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800751
752 /* We've walked the mark bitmaps. Scan anything that's
753 * left on the mark stack.
754 */
755 processMarkStack(ctx);
756
757 LOG_SCAN("done with marked objects\n");
758}
759
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700760void dvmHeapReScanMarkedObjects(void)
Carl Shapiroec805ea2010-06-28 16:28:26 -0700761{
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700762 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700763
Carl Shapiroec805ea2010-06-28 16:28:26 -0700764 /*
Carl Shapirof5860332010-06-28 23:02:08 -0700765 * The finger must have been set to the maximum value to ensure
766 * that gray objects will be pushed onto the mark stack.
Carl Shapiroec805ea2010-06-28 16:28:26 -0700767 */
768 assert(ctx->finger == (void *)ULONG_MAX);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700769 scanGrayObjects(ctx);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700770 processMarkStack(ctx);
771}
772
Carl Shapiro34f51992010-07-09 17:55:41 -0700773/*
774 * Clear the referent field.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800775 */
Barry Hayes6930a112009-12-22 11:01:38 -0800776static void clearReference(Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800777{
Carl Shapiro34f51992010-07-09 17:55:41 -0700778 size_t offset = gDvm.offJavaLangRefReference_referent;
779 dvmSetFieldObject(reference, offset, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800780}
781
Carl Shapiro29540742010-03-26 15:34:39 -0700782/*
783 * Returns true if the reference was registered with a reference queue
784 * and has not yet been enqueued.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800785 */
Carl Shapiro29540742010-03-26 15:34:39 -0700786static bool isEnqueuable(const Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800787{
Barry Hayes6930a112009-12-22 11:01:38 -0800788 Object *queue = dvmGetFieldObject(reference,
789 gDvm.offJavaLangRefReference_queue);
790 Object *queueNext = dvmGetFieldObject(reference,
791 gDvm.offJavaLangRefReference_queueNext);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700792 return queue != NULL && queueNext == NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800793}
794
Carl Shapiro29540742010-03-26 15:34:39 -0700795/*
796 * Schedules a reference to be appended to its reference queue.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800797 */
Carl Shapiro29540742010-03-26 15:34:39 -0700798static void enqueueReference(Object *ref)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800799{
Carl Shapiro646ba092010-06-10 15:17:00 -0700800 assert(ref != NULL);
Carl Shapiro29540742010-03-26 15:34:39 -0700801 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
802 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
Carl Shapiro646ba092010-06-10 15:17:00 -0700803 if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
Carl Shapiro29540742010-03-26 15:34:39 -0700804 LOGE_HEAP("enqueueReference(): no room for any more "
805 "reference operations\n");
806 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800807 }
808}
809
Carl Shapiro29540742010-03-26 15:34:39 -0700810/*
811 * Walks the reference list marking any references subject to the
812 * reference clearing policy. References with a black referent are
813 * removed from the list. References with white referents biased
814 * toward saving are blackened and also removed from the list.
815 */
816void dvmHandleSoftRefs(Object **list)
817{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700818 GcMarkContext *ctx;
Carl Shapiro29540742010-03-26 15:34:39 -0700819 Object *ref, *referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700820 Object *clear;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700821 size_t referentOffset;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700822 size_t counter;
Carl Shapiro29540742010-03-26 15:34:39 -0700823 bool marked;
824
Carl Shapirob2e78d32010-08-20 11:34:18 -0700825 ctx = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700826 referentOffset = gDvm.offJavaLangRefReference_referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700827 clear = NULL;
Carl Shapiro29540742010-03-26 15:34:39 -0700828 counter = 0;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700829 while (*list != NULL) {
830 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700831 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700832 assert(referent != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700833 marked = isMarked(referent, ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700834 if (!marked && ((++counter) & 1)) {
835 /* Referent is white and biased toward saving, mark it. */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700836 markObject(referent, ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700837 marked = true;
838 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700839 if (!marked) {
840 /* Referent is white, queue it for clearing. */
841 enqueuePendingReference(ref, &clear);
Carl Shapiro29540742010-03-26 15:34:39 -0700842 }
Carl Shapiro29540742010-03-26 15:34:39 -0700843 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700844 *list = clear;
Carl Shapiro29540742010-03-26 15:34:39 -0700845 /*
846 * Restart the mark with the newly black references added to the
847 * root set.
848 */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700849 processMarkStack(ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700850}
851
852/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700853 * Unlink the reference list clearing references objects with white
854 * referents. Cleared references registered to a reference queue are
855 * scheduled for appending by the heap worker thread.
Carl Shapiro29540742010-03-26 15:34:39 -0700856 */
857void dvmClearWhiteRefs(Object **list)
858{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700859 GcMarkContext *ctx;
Carl Shapiro29540742010-03-26 15:34:39 -0700860 Object *ref, *referent;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700861 size_t referentOffset;
Carl Shapiro29540742010-03-26 15:34:39 -0700862 bool doSignal;
863
Carl Shapirob2e78d32010-08-20 11:34:18 -0700864 ctx = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700865 referentOffset = gDvm.offJavaLangRefReference_referent;
866 doSignal = false;
867 while (*list != NULL) {
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700868 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700869 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700870 assert(referent != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700871 if (!isMarked(referent, ctx)) {
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700872 /* Referent is white, clear it. */
Carl Shapiro29540742010-03-26 15:34:39 -0700873 clearReference(ref);
874 if (isEnqueuable(ref)) {
875 enqueueReference(ref);
876 doSignal = true;
877 }
878 }
879 }
880 /*
881 * If we cleared a reference with a reference queue we must notify
882 * the heap worker to append the reference.
883 */
884 if (doSignal) {
885 dvmSignalHeapWorker(false);
886 }
887 assert(*list == NULL);
888}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800889
890/* Find unreachable objects that need to be finalized,
891 * and schedule them for finalization.
892 */
893void dvmHeapScheduleFinalizations()
894{
895 HeapRefTable newPendingRefs;
896 LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
897 Object **ref;
898 Object **lastRef;
899 size_t totalPendCount;
Carl Shapirob2e78d32010-08-20 11:34:18 -0700900 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800901
902 /*
903 * All reachable objects have been marked.
904 * Any unmarked finalizable objects need to be finalized.
905 */
906
907 /* Create a table that the new pending refs will
908 * be added to.
909 */
Barry Hayesd4f78d32010-06-08 09:34:42 -0700910 if (!dvmHeapInitHeapRefTable(&newPendingRefs)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800911 //TODO: mark all finalizable refs and hope that
912 // we can schedule them next time. Watch out,
913 // because we may be expecting to free up space
914 // by calling finalizers.
915 LOGE_GC("dvmHeapScheduleFinalizations(): no room for "
916 "pending finalizations\n");
917 dvmAbort();
918 }
919
920 /* Walk through finalizableRefs and move any unmarked references
921 * to the list of new pending refs.
922 */
923 totalPendCount = 0;
924 while (finRefs != NULL) {
925 Object **gapRef;
926 size_t newPendCount = 0;
927
928 gapRef = ref = finRefs->refs.table;
929 lastRef = finRefs->refs.nextEntry;
930 while (ref < lastRef) {
Carl Shapirob2e78d32010-08-20 11:34:18 -0700931 if (!isMarked(*ref, ctx)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800932 if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
933 //TODO: add the current table and allocate
934 // a new, smaller one.
935 LOGE_GC("dvmHeapScheduleFinalizations(): "
936 "no room for any more pending finalizations: %zd\n",
937 dvmHeapNumHeapRefTableEntries(&newPendingRefs));
938 dvmAbort();
939 }
940 newPendCount++;
941 } else {
942 /* This ref is marked, so will remain on finalizableRefs.
943 */
944 if (newPendCount > 0) {
945 /* Copy it up to fill the holes.
946 */
947 *gapRef++ = *ref;
948 } else {
949 /* No holes yet; don't bother copying.
950 */
951 gapRef++;
952 }
953 }
954 ref++;
955 }
956 finRefs->refs.nextEntry = gapRef;
957 //TODO: if the table is empty when we're done, free it.
958 totalPendCount += newPendCount;
959 finRefs = finRefs->next;
960 }
961 LOGD_GC("dvmHeapScheduleFinalizations(): %zd finalizers triggered.\n",
962 totalPendCount);
963 if (totalPendCount == 0) {
964 /* No objects required finalization.
965 * Free the empty temporary table.
966 */
967 dvmClearReferenceTable(&newPendingRefs);
968 return;
969 }
970
971 /* Add the new pending refs to the main list.
972 */
973 if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
974 &newPendingRefs))
975 {
976 LOGE_GC("dvmHeapScheduleFinalizations(): can't insert new "
977 "pending finalizations\n");
978 dvmAbort();
979 }
980
981 //TODO: try compacting the main list with a memcpy loop
982
983 /* Mark the refs we just moved; we don't want them or their
984 * children to get swept yet.
985 */
986 ref = newPendingRefs.table;
987 lastRef = newPendingRefs.nextEntry;
988 assert(ref < lastRef);
989 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
990 while (ref < lastRef) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700991 assert(*ref != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700992 markObject(*ref, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800993 ref++;
994 }
995 HPROF_CLEAR_GC_SCAN_STATE();
Carl Shapirob2e78d32010-08-20 11:34:18 -0700996 processMarkStack(ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800997 dvmSignalHeapWorker(false);
998}
999
1000void dvmHeapFinishMarkStep()
1001{
Carl Shapirob2e78d32010-08-20 11:34:18 -07001002 GcMarkContext *ctx;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001003
Carl Shapirob2e78d32010-08-20 11:34:18 -07001004 ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001005
Barry Hayes81010a42010-07-19 14:07:01 -07001006 /* The mark bits are now not needed.
1007 */
1008 dvmHeapSourceZeroMarkBitmap();
1009
Carl Shapirof373efd2010-02-19 00:46:33 -08001010 /* Clean up everything else associated with the marking process.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001011 */
Carl Shapirob2e78d32010-08-20 11:34:18 -07001012 destroyMarkStack(&ctx->stack);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001013
Carl Shapirob2e78d32010-08-20 11:34:18 -07001014 ctx->finger = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001015}
1016
Carl Shapiro8881a802010-08-10 15:55:45 -07001017typedef struct {
1018 size_t numObjects;
1019 size_t numBytes;
1020 bool isConcurrent;
1021} SweepContext;
1022
Carl Shapiro57ee2702010-08-27 13:06:48 -07001023static void sweepBitmapCallback(size_t numPtrs, void **ptrs, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001024{
Carl Shapirob9b23952010-08-10 17:20:15 -07001025 SweepContext *ctx = arg;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001026
Carl Shapiro8881a802010-08-10 15:55:45 -07001027 if (ctx->isConcurrent) {
1028 dvmLockHeap();
1029 }
1030 ctx->numBytes += dvmHeapSourceFreeList(numPtrs, ptrs);
1031 ctx->numObjects += numPtrs;
1032 if (ctx->isConcurrent) {
1033 dvmUnlockHeap();
1034 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001035}
1036
Carl Shapiro8881a802010-08-10 15:55:45 -07001037/*
1038 * Returns true if the given object is unmarked. This assumes that
1039 * the bitmaps have not yet been swapped.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001040 */
1041static int isUnmarkedObject(void *object)
1042{
Carl Shapiro6343bd02010-02-16 17:40:19 -08001043 return !isMarked((void *)((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001044 &gDvm.gcHeap->markContext);
1045}
1046
Carl Shapiro8881a802010-08-10 15:55:45 -07001047/*
1048 * Process all the internal system structures that behave like
1049 * weakly-held objects.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001050 */
Carl Shapiro8881a802010-08-10 15:55:45 -07001051void dvmHeapSweepSystemWeaks(void)
1052{
1053 dvmGcDetachDeadInternedStrings(isUnmarkedObject);
1054 dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
1055}
1056
1057/*
1058 * Walk through the list of objects that haven't been marked and free
1059 * them. Assumes the bitmaps have been swapped.
1060 */
1061void dvmHeapSweepUnmarkedObjects(GcMode mode, bool isConcurrent,
1062 size_t *numObjects, size_t *numBytes)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001063{
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001064 HeapBitmap currMark[HEAP_SOURCE_MAX_HEAP_COUNT];
1065 HeapBitmap currLive[HEAP_SOURCE_MAX_HEAP_COUNT];
Carl Shapiro8881a802010-08-10 15:55:45 -07001066 SweepContext ctx;
Carl Shapirod25566d2010-03-11 20:39:47 -08001067 size_t numBitmaps, numSweepBitmaps;
Barry Hayese168ebd2010-05-07 09:19:46 -07001068 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001069
Carl Shapirof373efd2010-02-19 00:46:33 -08001070 numBitmaps = dvmHeapSourceGetNumHeaps();
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001071 dvmHeapSourceGetObjectBitmaps(currLive, currMark, numBitmaps);
Carl Shapirod25566d2010-03-11 20:39:47 -08001072 if (mode == GC_PARTIAL) {
1073 numSweepBitmaps = 1;
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001074 assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == currLive[0].base);
Carl Shapirod25566d2010-03-11 20:39:47 -08001075 } else {
1076 numSweepBitmaps = numBitmaps;
1077 }
Carl Shapiro8881a802010-08-10 15:55:45 -07001078 ctx.numObjects = ctx.numBytes = 0;
1079 ctx.isConcurrent = isConcurrent;
Barry Hayese168ebd2010-05-07 09:19:46 -07001080 for (i = 0; i < numSweepBitmaps; i++) {
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001081 HeapBitmap* prevLive = &currMark[i];
1082 HeapBitmap* prevMark = &currLive[i];
1083 dvmHeapBitmapSweepWalk(prevLive, prevMark, sweepBitmapCallback, &ctx);
Barry Hayese168ebd2010-05-07 09:19:46 -07001084 }
Carl Shapiro8881a802010-08-10 15:55:45 -07001085 *numObjects = ctx.numObjects;
1086 *numBytes = ctx.numBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001087 if (gDvm.allocProf.enabled) {
Carl Shapiro8881a802010-08-10 15:55:45 -07001088 gDvm.allocProf.freeCount += ctx.numObjects;
1089 gDvm.allocProf.freeSize += ctx.numBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001090 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001091}