blob: 84c111a132ee8ffa6e863e5cdaa7b1a1a60c05ae [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 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800134 }
135}
136
137/* Used to mark objects when recursing. Recursion is done by moving
138 * the finger across the bitmaps in address order and marking child
139 * objects. Any newly-marked objects whose addresses are lower than
140 * the finger won't be visited by the bitmap scan, so those objects
141 * need to be added to the mark stack.
142 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700143static void markObject(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800144{
Barry Hayese1bccb92010-05-18 09:48:37 -0700145 if (obj != NULL) {
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700146 markObjectNonNull(obj, ctx, true);
Barry Hayese1bccb92010-05-18 09:48:37 -0700147 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800148}
149
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800150/* If the object hasn't already been marked, mark it and
151 * schedule it to be scanned for references.
152 *
153 * obj may not be NULL. The macro dvmMarkObject() should
154 * be used in situations where a reference may be NULL.
155 *
156 * This function may only be called when marking the root
Barry Hayese1bccb92010-05-18 09:48:37 -0700157 * set. When recursing, use the internal markObject().
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800158 */
Carl Shapirod7400e02010-09-02 18:24:29 -0700159void dvmMarkObjectNonNull(const Object *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800160{
Barry Hayese1bccb92010-05-18 09:48:37 -0700161 assert(obj != NULL);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700162 markObjectNonNull(obj, &gDvm.gcHeap->markContext, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800163}
164
165/* Mark the set of root objects.
166 *
167 * Things we need to scan:
168 * - System classes defined by root classloader
169 * - For each thread:
170 * - Interpreted stack, from top to "curFrame"
171 * - Dalvik registers (args + local vars)
172 * - JNI local references
173 * - Automatic VM local references (TrackedAlloc)
174 * - Associated Thread/VMThread object
175 * - ThreadGroups (could track & start with these instead of working
176 * upward from Threads)
177 * - Exception currently being thrown, if present
178 * - JNI global references
179 * - Interned string table
180 * - Primitive classes
181 * - Special objects
182 * - gDvm.outOfMemoryObj
183 * - Objects allocated with ALLOC_NO_GC
184 * - Objects pending finalization (but not yet finalized)
185 * - Objects in debugger object registry
186 *
187 * Don't need:
188 * - Native stack (for in-progress stuff in the VM)
189 * - The TrackedAlloc stuff watches all native VM references.
190 */
191void dvmHeapMarkRootSet()
192{
Barry Hayesd4f78d32010-06-08 09:34:42 -0700193 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800194
Carl Shapirod25566d2010-03-11 20:39:47 -0800195 LOG_SCAN("immune objects");
Barry Hayes425848f2010-05-04 13:32:12 -0700196 dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
Carl Shapirod25566d2010-03-11 20:39:47 -0800197
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800198 LOG_SCAN("root class loader\n");
199 dvmGcScanRootClassLoader();
200 LOG_SCAN("primitive classes\n");
201 dvmGcScanPrimitiveClasses();
202
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800203 LOG_SCAN("root thread groups\n");
204 dvmGcScanRootThreadGroups();
205
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800206 LOG_SCAN("interned strings\n");
207 dvmGcScanInternedStrings();
208
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800209 LOG_SCAN("JNI global refs\n");
210 dvmGcMarkJniGlobalRefs();
211
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800212 LOG_SCAN("pending reference operations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700213 dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800214
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800215 LOG_SCAN("pending finalizations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700216 dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800217
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800218 LOG_SCAN("debugger refs\n");
219 dvmGcMarkDebuggerRefs();
220
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800221 /* Mark any special objects we have sitting around.
222 */
223 LOG_SCAN("special objects\n");
224 dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
225 dvmMarkObjectNonNull(gDvm.internalErrorObj);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700226 dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800227//TODO: scan object references sitting in gDvm; use pointer begin & end
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800228}
229
230/*
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700231 * Callback applied to root references. If the root location contains
232 * a white reference it is pushed on the mark stack and grayed.
233 */
Carl Shapiro07018e22010-10-26 21:07:41 -0700234static void markObjectVisitor(void *addr, RootType type, u4 thread, void *arg)
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700235{
236 Object *obj;
237
238 assert(addr != NULL);
239 assert(arg != NULL);
240 obj = *(Object **)addr;
241 if (obj != NULL) {
242 markObjectNonNull(obj, arg, true);
243 }
244}
245
246/*
247 * Grays all references in the roots.
248 */
249void dvmHeapReMarkRootSet(void)
250{
251 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
252 assert(ctx->finger == (void *)ULONG_MAX);
253 dvmVisitRoots(markObjectVisitor, ctx);
254}
255
256/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700257 * Nothing past this point is allowed to use dvmMarkObject() or
258 * dvmMarkObjectNonNull(), which are for root-marking only.
259 * Scanning/recursion must use markObject(), which takes the finger
260 * into account.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800261 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700262#undef dvmMarkObject
263#define dvmMarkObject __dont_use_dvmMarkObject__
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800264#define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
265
Barry Hayese1bccb92010-05-18 09:48:37 -0700266/*
267 * Scans instance fields.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800268 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700269static void scanInstanceFields(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800270{
Barry Hayese1bccb92010-05-18 09:48:37 -0700271 assert(obj != NULL);
272 assert(obj->clazz != NULL);
273 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800274
Barry Hayese1bccb92010-05-18 09:48:37 -0700275 if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
276 unsigned int refOffsets = obj->clazz->refOffsets;
Barry Hayeseac47ed2009-06-22 11:45:20 -0700277 while (refOffsets != 0) {
278 const int rshift = CLZ(refOffsets);
279 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
280 markObject(dvmGetFieldObject((Object*)obj,
Barry Hayese1bccb92010-05-18 09:48:37 -0700281 CLASS_OFFSET_FROM_CLZ(rshift)), ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800282 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700283 } else {
Barry Hayese1bccb92010-05-18 09:48:37 -0700284 ClassObject *clazz;
285 int i;
286 for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
287 InstField *field = clazz->ifields;
288 for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
289 void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
290 markObject(((JValue *)addr)->l, ctx);
Barry Hayeseac47ed2009-06-22 11:45:20 -0700291 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700292 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800293 }
294}
295
Barry Hayese1bccb92010-05-18 09:48:37 -0700296/*
297 * Scans the header, static field references, and interface
298 * pointers of a class object.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800299 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700300static void scanClassObject(const ClassObject *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800301{
Barry Hayese1bccb92010-05-18 09:48:37 -0700302 int i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800303
Barry Hayese1bccb92010-05-18 09:48:37 -0700304 assert(obj != NULL);
305 assert(obj->obj.clazz == gDvm.classJavaLangClass);
306 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800307
Barry Hayese1bccb92010-05-18 09:48:37 -0700308 markObject((Object *)obj->obj.clazz, ctx);
309 if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
310 markObject((Object *)obj->elementClass, ctx);
311 }
Barry Hayesc49db852010-05-14 13:43:34 -0700312 /* Do super and the interfaces contain Objects and not dex idx values? */
313 if (obj->status > CLASS_IDX) {
314 markObject((Object *)obj->super, ctx);
315 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700316 markObject(obj->classLoader, ctx);
317 /* Scan static field references. */
318 for (i = 0; i < obj->sfieldCount; ++i) {
319 char ch = obj->sfields[i].field.signature[0];
320 if (ch == '[' || ch == 'L') {
321 markObject(obj->sfields[i].value.l, ctx);
322 }
323 }
324 /* Scan the instance fields. */
325 scanInstanceFields((const Object *)obj, ctx);
326 /* Scan interface references. */
Barry Hayesc49db852010-05-14 13:43:34 -0700327 if (obj->status > CLASS_IDX) {
328 for (i = 0; i < obj->interfaceCount; ++i) {
329 markObject((Object *)obj->interfaces[i], ctx);
330 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800331 }
332}
333
Barry Hayese1bccb92010-05-18 09:48:37 -0700334/*
335 * Scans the header of all array objects. If the array object is
336 * specialized to a reference type, scans the array data as well.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800337 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700338static void scanArrayObject(const ArrayObject *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800339{
Barry Hayese1bccb92010-05-18 09:48:37 -0700340 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800341
Barry Hayese1bccb92010-05-18 09:48:37 -0700342 assert(obj != NULL);
343 assert(obj->obj.clazz != NULL);
344 assert(ctx != NULL);
345 /* Scan the class object reference. */
346 markObject((Object *)obj->obj.clazz, ctx);
347 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISOBJECTARRAY)) {
348 /* Scan the array contents. */
349 Object **contents = (Object **)obj->contents;
350 for (i = 0; i < obj->length; ++i) {
351 markObject(contents[i], ctx);
352 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800353 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700354}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800355
Barry Hayese1bccb92010-05-18 09:48:37 -0700356/*
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700357 * Returns class flags relating to Reference subclasses.
358 */
359static int referenceClassFlags(const Object *obj)
360{
361 int flags = CLASS_ISREFERENCE |
362 CLASS_ISWEAKREFERENCE |
363 CLASS_ISPHANTOMREFERENCE;
364 return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
365}
366
367/*
368 * Returns true if the object derives from SoftReference.
369 */
370static bool isSoftReference(const Object *obj)
371{
372 return referenceClassFlags(obj) == CLASS_ISREFERENCE;
373}
374
375/*
376 * Returns true if the object derives from WeakReference.
377 */
378static bool isWeakReference(const Object *obj)
379{
380 return referenceClassFlags(obj) & CLASS_ISWEAKREFERENCE;
381}
382
383/*
384 * Returns true if the object derives from PhantomReference.
385 */
386static bool isPhantomReference(const Object *obj)
387{
388 return referenceClassFlags(obj) & CLASS_ISPHANTOMREFERENCE;
389}
390
391/*
392 * Adds a reference to the tail of a circular queue of references.
393 */
394static void enqueuePendingReference(Object *ref, Object **list)
395{
396 size_t offset;
397
398 assert(ref != NULL);
399 assert(list != NULL);
400 offset = gDvm.offJavaLangRefReference_pendingNext;
401 if (*list == NULL) {
402 dvmSetFieldObject(ref, offset, ref);
403 *list = ref;
404 } else {
405 Object *head = dvmGetFieldObject(*list, offset);
406 dvmSetFieldObject(ref, offset, head);
407 dvmSetFieldObject(*list, offset, ref);
408 }
409}
410
411/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700412 * Removes the reference at the head of a circular queue of
413 * references.
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700414 */
415static Object *dequeuePendingReference(Object **list)
416{
417 Object *ref, *head;
418 size_t offset;
419
420 assert(list != NULL);
421 assert(*list != NULL);
422 offset = gDvm.offJavaLangRefReference_pendingNext;
423 head = dvmGetFieldObject(*list, offset);
424 if (*list == head) {
425 ref = *list;
426 *list = NULL;
427 } else {
428 Object *next = dvmGetFieldObject(head, offset);
429 dvmSetFieldObject(*list, offset, next);
430 ref = head;
431 }
432 dvmSetFieldObject(ref, offset, NULL);
433 return ref;
434}
435
436/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700437 * Process the "referent" field in a java.lang.ref.Reference. If the
438 * referent has not yet been marked, put it on the appropriate list in
439 * the gcHeap for later processing.
440 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700441static void delayReferenceReferent(Object *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700442{
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700443 GcHeap *gcHeap = gDvm.gcHeap;
444 Object *pending, *referent;
445 size_t pendingNextOffset, referentOffset;
446
Barry Hayese1bccb92010-05-18 09:48:37 -0700447 assert(obj != NULL);
Barry Hayes697b5a92010-06-23 11:38:52 -0700448 assert(obj->clazz != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700449 assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
Barry Hayese1bccb92010-05-18 09:48:37 -0700450 assert(ctx != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700451 pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
452 referentOffset = gDvm.offJavaLangRefReference_referent;
453 pending = dvmGetFieldObject(obj, pendingNextOffset);
454 referent = dvmGetFieldObject(obj, referentOffset);
455 if (pending == NULL && referent != NULL && !isMarked(referent, ctx)) {
456 Object **list = NULL;
457 if (isSoftReference(obj)) {
458 list = &gcHeap->softReferences;
459 } else if (isWeakReference(obj)) {
460 list = &gcHeap->weakReferences;
461 } else if (isPhantomReference(obj)) {
462 list = &gcHeap->phantomReferences;
Barry Hayese1bccb92010-05-18 09:48:37 -0700463 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700464 assert(list != NULL);
465 enqueuePendingReference(obj, list);
Barry Hayese1bccb92010-05-18 09:48:37 -0700466 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800467}
468
Barry Hayese1bccb92010-05-18 09:48:37 -0700469/*
470 * Scans the header and field references of a data object.
471 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700472static void scanDataObject(DataObject *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700473{
474 assert(obj != NULL);
475 assert(obj->obj.clazz != NULL);
476 assert(ctx != NULL);
477 /* Scan the class object. */
478 markObject((Object *)obj->obj.clazz, ctx);
479 /* Scan the instance fields. */
480 scanInstanceFields((const Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700481 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISREFERENCE)) {
Barry Hayes697b5a92010-06-23 11:38:52 -0700482 delayReferenceReferent((Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700483 }
484}
485
486/*
487 * Scans an object reference. Determines the type of the reference
488 * and dispatches to a specialized scanning routine.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800489 */
490static void scanObject(const Object *obj, GcMarkContext *ctx)
491{
Barry Hayese1bccb92010-05-18 09:48:37 -0700492 assert(obj != NULL);
493 assert(ctx != NULL);
Barry Hayes899cdb72010-06-08 09:59:12 -0700494 assert(obj->clazz != NULL);
Barry Hayese1bccb92010-05-18 09:48:37 -0700495 /* Dispatch a type-specific scan routine. */
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700496 if (obj->clazz == gDvm.classJavaLangClass) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700497 scanClassObject((ClassObject *)obj, ctx);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700498 } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
Barry Hayes899cdb72010-06-08 09:59:12 -0700499 scanArrayObject((ArrayObject *)obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800500 } else {
Barry Hayes899cdb72010-06-08 09:59:12 -0700501 scanDataObject((DataObject *)obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800502 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800503}
504
505static void
506processMarkStack(GcMarkContext *ctx)
507{
508 const Object **const base = ctx->stack.base;
509
510 /* Scan anything that's on the mark stack.
511 * We can't use the bitmaps anymore, so use
512 * a finger that points past the end of them.
513 */
514 ctx->finger = (void *)ULONG_MAX;
515 while (ctx->stack.top != base) {
516 scanObject(*ctx->stack.top++, ctx);
517 }
518}
519
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700520static size_t objectSize(const Object *obj)
521{
522 assert(dvmIsValidObject(obj));
523 assert(dvmIsValidObject((Object *)obj->clazz));
524 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
525 return dvmArrayObjectSize((ArrayObject *)obj);
526 } else if (obj->clazz == gDvm.classJavaLangClass) {
527 return dvmClassObjectSize((ClassObject *)obj);
528 } else {
529 return obj->clazz->objectSize;
530 }
531}
532
533/*
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700534 * Scans forward to the header of the next marked object between start
535 * and limit. Returns NULL if no marked objects are in that region.
536 */
Carl Shapiro7ec91442010-10-21 15:35:19 -0700537static Object *nextGrayObject(const u1 *base, const u1 *limit,
538 const HeapBitmap *markBits)
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700539{
Carl Shapiro7ec91442010-10-21 15:35:19 -0700540 const u1 *ptr;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700541
542 assert(base < limit);
543 assert(limit - base <= GC_CARD_SIZE);
544 for (ptr = base; ptr < limit; ptr += HB_OBJECT_ALIGNMENT) {
Carl Shapiroea10c552010-09-02 23:32:25 -0700545 if (dvmHeapBitmapIsObjectBitSet(markBits, ptr))
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700546 return (Object *)ptr;
547 }
548 return NULL;
549}
550
551/*
Carl Shapiro7ec91442010-10-21 15:35:19 -0700552 * Scans each byte from start below end returning the address of the
553 * first dirty card. Returns NULL if no dirty card is found.
554 */
555static const u1 *scanBytesForDirtyCard(const u1 *start, const u1 *end)
556{
557 const u1 *ptr;
558
559 assert(start <= end);
560 for (ptr = start; ptr < end; ++ptr) {
561 if (*ptr == GC_CARD_DIRTY) {
562 return ptr;
563 }
564 }
565 return NULL;
566}
567
568/*
569 * Like scanBytesForDirtyCard but scans the range from start below end
570 * by words. Assumes start and end are word aligned.
571 */
572static const u1 *scanWordsForDirtyCard(const u1 *start, const u1 *end)
573{
574 const u1 *ptr;
575
576 assert((uintptr_t)start % kWordSize == 0);
577 assert((uintptr_t)end % kWordSize == 0);
578 assert(start <= end);
579 for (ptr = start; ptr < end; ptr += kWordSize) {
580 if (*(const Word *)ptr != 0) {
581 const u1 *dirty = scanBytesForDirtyCard(ptr, ptr + kWordSize);
582 if (dirty != NULL) {
583 return dirty;
584 }
585 }
586 }
587 return NULL;
588}
589
590/*
591 * Scans the card table as quickly as possible looking for a dirty
592 * card. Returns the address of the first dirty card found or NULL if
593 * no dirty cards were found.
594 */
595static const u1 *nextDirtyCard(const u1 *start, const u1 *end)
596{
597 const u1 *wstart = (u1 *)ALIGN_UP(start, kWordSize);
598 const u1 *wend = (u1 *)ALIGN_DOWN(end, kWordSize);
599 const u1 *ptr, *dirty;
600
601 assert(start <= end);
602 assert(start <= wstart);
603 assert(end >= wend);
604 ptr = start;
605 if (wstart < end) {
606 /* Scan the leading unaligned bytes. */
607 dirty = scanBytesForDirtyCard(ptr, wstart);
608 if (dirty != NULL) {
609 return dirty;
610 }
611 /* Scan the range of aligned words. */
612 dirty = scanWordsForDirtyCard(wstart, wend);
613 if (dirty != NULL) {
614 return dirty;
615 }
616 ptr = wend;
617 }
618 /* Scan trailing unaligned bytes. */
619 dirty = scanBytesForDirtyCard(ptr, end);
620 if (dirty != NULL) {
621 return dirty;
622 }
623 return NULL;
624}
625
626/*
627 * Scans range of dirty cards between start and end. A range of dirty
628 * cards is composed consecutively dirty cards or dirty cards spanned
629 * by a gray object. Returns the address of a clean card if the scan
630 * reached a clean card or NULL if the scan reached the end.
631 */
632const u1 *scanDirtyCards(const u1 *start, const u1 *end,
633 GcMarkContext *ctx)
634{
635 const HeapBitmap *markBits = ctx->bitmap;
636 const u1 *card = start, *prevAddr = NULL;
637 while (card < end) {
638 if (*card != GC_CARD_DIRTY) {
639 return card;
640 }
641 const u1 *ptr = prevAddr ? prevAddr : dvmAddrFromCard(card);
642 const u1 *limit = ptr + GC_CARD_SIZE;
643 while (ptr < limit) {
644 Object *obj = nextGrayObject(ptr, limit, markBits);
645 if (obj == NULL) {
646 break;
647 }
648 scanObject(obj, ctx);
649 ptr = (u1*)obj + ALIGN_UP(objectSize(obj), HB_OBJECT_ALIGNMENT);
650 }
651 if (ptr < limit) {
652 /* Ended within the current card, advance to the next card. */
653 ++card;
654 prevAddr = NULL;
655 } else {
656 /* Ended past the current card, skip ahead. */
657 card = dvmCardFromAddr(ptr);
658 prevAddr = ptr;
659 }
660 }
661 return NULL;
662}
663
664/*
665 * Blackens gray objects found on dirty cards.
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700666 */
667static void scanGrayObjects(GcMarkContext *ctx)
668{
669 GcHeap *h = gDvm.gcHeap;
Carl Shapiro7ec91442010-10-21 15:35:19 -0700670 const u1 *base, *limit, *ptr, *dirty;
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700671 size_t footprint;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700672
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700673 footprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
Carl Shapiro7ec91442010-10-21 15:35:19 -0700674 base = &h->cardTableBase[0];
675 limit = dvmCardFromAddr((u1 *)dvmHeapSourceGetBase() + footprint);
676 assert(limit <= &h->cardTableBase[h->cardTableLength]);
677
678 ptr = base;
679 for (;;) {
680 dirty = nextDirtyCard(ptr, limit);
681 if (dirty == NULL) {
682 break;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700683 }
Carl Shapiro7ec91442010-10-21 15:35:19 -0700684 assert((dirty > ptr) && (dirty < limit));
685 ptr = scanDirtyCards(dirty, limit, ctx);
686 if (ptr == NULL) {
687 break;
688 }
689 assert((ptr > dirty) && (ptr < limit));
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700690 }
691}
692
Carl Shapiro57ee2702010-08-27 13:06:48 -0700693/*
694 * Callback for scanning each object in the bitmap. The finger is set
695 * to the address corresponding to the lowest address in the next word
696 * of bits in the bitmap.
697 */
Carl Shapiro38d710b2010-08-31 16:48:31 -0700698static void scanBitmapCallback(void *addr, void *finger, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800699{
Carl Shapiro006346e2010-07-29 20:39:50 -0700700 GcMarkContext *ctx = arg;
Carl Shapiro57ee2702010-08-27 13:06:48 -0700701 ctx->finger = (void *)finger;
702 scanObject(addr, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800703}
704
705/* Given bitmaps with the root set marked, find and mark all
706 * reachable objects. When this returns, the entire set of
707 * live objects will be marked and the mark stack will be empty.
708 */
Carl Shapiro29540742010-03-26 15:34:39 -0700709void dvmHeapScanMarkedObjects(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800710{
711 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
712
713 assert(ctx->finger == NULL);
714
715 /* The bitmaps currently have bits set for the root set.
716 * Walk across the bitmaps and scan each object.
717 */
Carl Shapiro38d710b2010-08-31 16:48:31 -0700718 dvmHeapBitmapScanWalk(ctx->bitmap, scanBitmapCallback, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800719
720 /* We've walked the mark bitmaps. Scan anything that's
721 * left on the mark stack.
722 */
723 processMarkStack(ctx);
724
725 LOG_SCAN("done with marked objects\n");
726}
727
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700728void dvmHeapReScanMarkedObjects(void)
Carl Shapiroec805ea2010-06-28 16:28:26 -0700729{
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700730 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700731
Carl Shapiroec805ea2010-06-28 16:28:26 -0700732 /*
Carl Shapirof5860332010-06-28 23:02:08 -0700733 * The finger must have been set to the maximum value to ensure
734 * that gray objects will be pushed onto the mark stack.
Carl Shapiroec805ea2010-06-28 16:28:26 -0700735 */
736 assert(ctx->finger == (void *)ULONG_MAX);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700737 scanGrayObjects(ctx);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700738 processMarkStack(ctx);
739}
740
Carl Shapiro34f51992010-07-09 17:55:41 -0700741/*
742 * Clear the referent field.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800743 */
Barry Hayes6930a112009-12-22 11:01:38 -0800744static void clearReference(Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800745{
Carl Shapiro34f51992010-07-09 17:55:41 -0700746 size_t offset = gDvm.offJavaLangRefReference_referent;
747 dvmSetFieldObject(reference, offset, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800748}
749
Carl Shapiro29540742010-03-26 15:34:39 -0700750/*
751 * Returns true if the reference was registered with a reference queue
752 * and has not yet been enqueued.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800753 */
Carl Shapiro29540742010-03-26 15:34:39 -0700754static bool isEnqueuable(const Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800755{
Barry Hayes6930a112009-12-22 11:01:38 -0800756 Object *queue = dvmGetFieldObject(reference,
757 gDvm.offJavaLangRefReference_queue);
758 Object *queueNext = dvmGetFieldObject(reference,
759 gDvm.offJavaLangRefReference_queueNext);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700760 return queue != NULL && queueNext == NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800761}
762
Carl Shapiro29540742010-03-26 15:34:39 -0700763/*
764 * Schedules a reference to be appended to its reference queue.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800765 */
Carl Shapiro29540742010-03-26 15:34:39 -0700766static void enqueueReference(Object *ref)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800767{
Carl Shapiro646ba092010-06-10 15:17:00 -0700768 assert(ref != NULL);
Carl Shapiro29540742010-03-26 15:34:39 -0700769 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
770 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
Carl Shapiro646ba092010-06-10 15:17:00 -0700771 if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
Carl Shapiro29540742010-03-26 15:34:39 -0700772 LOGE_HEAP("enqueueReference(): no room for any more "
773 "reference operations\n");
774 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800775 }
776}
777
Carl Shapiro29540742010-03-26 15:34:39 -0700778/*
779 * Walks the reference list marking any references subject to the
780 * reference clearing policy. References with a black referent are
781 * removed from the list. References with white referents biased
782 * toward saving are blackened and also removed from the list.
783 */
784void dvmHandleSoftRefs(Object **list)
785{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700786 GcMarkContext *ctx;
Carl Shapiro29540742010-03-26 15:34:39 -0700787 Object *ref, *referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700788 Object *clear;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700789 size_t referentOffset;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700790 size_t counter;
Carl Shapiro29540742010-03-26 15:34:39 -0700791 bool marked;
792
Carl Shapirob2e78d32010-08-20 11:34:18 -0700793 ctx = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700794 referentOffset = gDvm.offJavaLangRefReference_referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700795 clear = NULL;
Carl Shapiro29540742010-03-26 15:34:39 -0700796 counter = 0;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700797 while (*list != NULL) {
798 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700799 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700800 assert(referent != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700801 marked = isMarked(referent, ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700802 if (!marked && ((++counter) & 1)) {
803 /* Referent is white and biased toward saving, mark it. */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700804 markObject(referent, ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700805 marked = true;
806 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700807 if (!marked) {
808 /* Referent is white, queue it for clearing. */
809 enqueuePendingReference(ref, &clear);
Carl Shapiro29540742010-03-26 15:34:39 -0700810 }
Carl Shapiro29540742010-03-26 15:34:39 -0700811 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700812 *list = clear;
Carl Shapiro29540742010-03-26 15:34:39 -0700813 /*
814 * Restart the mark with the newly black references added to the
815 * root set.
816 */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700817 processMarkStack(ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700818}
819
820/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700821 * Unlink the reference list clearing references objects with white
822 * referents. Cleared references registered to a reference queue are
823 * scheduled for appending by the heap worker thread.
Carl Shapiro29540742010-03-26 15:34:39 -0700824 */
825void dvmClearWhiteRefs(Object **list)
826{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700827 GcMarkContext *ctx;
Carl Shapiro29540742010-03-26 15:34:39 -0700828 Object *ref, *referent;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700829 size_t referentOffset;
Carl Shapiro29540742010-03-26 15:34:39 -0700830 bool doSignal;
831
Carl Shapirob2e78d32010-08-20 11:34:18 -0700832 ctx = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700833 referentOffset = gDvm.offJavaLangRefReference_referent;
834 doSignal = false;
835 while (*list != NULL) {
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700836 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700837 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700838 assert(referent != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700839 if (!isMarked(referent, ctx)) {
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700840 /* Referent is white, clear it. */
Carl Shapiro29540742010-03-26 15:34:39 -0700841 clearReference(ref);
842 if (isEnqueuable(ref)) {
843 enqueueReference(ref);
844 doSignal = true;
845 }
846 }
847 }
848 /*
849 * If we cleared a reference with a reference queue we must notify
850 * the heap worker to append the reference.
851 */
852 if (doSignal) {
853 dvmSignalHeapWorker(false);
854 }
855 assert(*list == NULL);
856}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800857
858/* Find unreachable objects that need to be finalized,
859 * and schedule them for finalization.
860 */
861void dvmHeapScheduleFinalizations()
862{
863 HeapRefTable newPendingRefs;
864 LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
865 Object **ref;
866 Object **lastRef;
867 size_t totalPendCount;
Carl Shapirob2e78d32010-08-20 11:34:18 -0700868 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800869
870 /*
871 * All reachable objects have been marked.
872 * Any unmarked finalizable objects need to be finalized.
873 */
874
875 /* Create a table that the new pending refs will
876 * be added to.
877 */
Barry Hayesd4f78d32010-06-08 09:34:42 -0700878 if (!dvmHeapInitHeapRefTable(&newPendingRefs)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800879 //TODO: mark all finalizable refs and hope that
880 // we can schedule them next time. Watch out,
881 // because we may be expecting to free up space
882 // by calling finalizers.
883 LOGE_GC("dvmHeapScheduleFinalizations(): no room for "
884 "pending finalizations\n");
885 dvmAbort();
886 }
887
888 /* Walk through finalizableRefs and move any unmarked references
889 * to the list of new pending refs.
890 */
891 totalPendCount = 0;
892 while (finRefs != NULL) {
893 Object **gapRef;
894 size_t newPendCount = 0;
895
896 gapRef = ref = finRefs->refs.table;
897 lastRef = finRefs->refs.nextEntry;
898 while (ref < lastRef) {
Carl Shapirob2e78d32010-08-20 11:34:18 -0700899 if (!isMarked(*ref, ctx)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800900 if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
901 //TODO: add the current table and allocate
902 // a new, smaller one.
903 LOGE_GC("dvmHeapScheduleFinalizations(): "
904 "no room for any more pending finalizations: %zd\n",
905 dvmHeapNumHeapRefTableEntries(&newPendingRefs));
906 dvmAbort();
907 }
908 newPendCount++;
909 } else {
910 /* This ref is marked, so will remain on finalizableRefs.
911 */
912 if (newPendCount > 0) {
913 /* Copy it up to fill the holes.
914 */
915 *gapRef++ = *ref;
916 } else {
917 /* No holes yet; don't bother copying.
918 */
919 gapRef++;
920 }
921 }
922 ref++;
923 }
924 finRefs->refs.nextEntry = gapRef;
925 //TODO: if the table is empty when we're done, free it.
926 totalPendCount += newPendCount;
927 finRefs = finRefs->next;
928 }
929 LOGD_GC("dvmHeapScheduleFinalizations(): %zd finalizers triggered.\n",
930 totalPendCount);
931 if (totalPendCount == 0) {
932 /* No objects required finalization.
933 * Free the empty temporary table.
934 */
935 dvmClearReferenceTable(&newPendingRefs);
936 return;
937 }
938
939 /* Add the new pending refs to the main list.
940 */
941 if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
942 &newPendingRefs))
943 {
944 LOGE_GC("dvmHeapScheduleFinalizations(): can't insert new "
945 "pending finalizations\n");
946 dvmAbort();
947 }
948
949 //TODO: try compacting the main list with a memcpy loop
950
951 /* Mark the refs we just moved; we don't want them or their
952 * children to get swept yet.
953 */
954 ref = newPendingRefs.table;
955 lastRef = newPendingRefs.nextEntry;
956 assert(ref < lastRef);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800957 while (ref < lastRef) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700958 assert(*ref != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700959 markObject(*ref, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800960 ref++;
961 }
Carl Shapirob2e78d32010-08-20 11:34:18 -0700962 processMarkStack(ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800963 dvmSignalHeapWorker(false);
964}
965
966void dvmHeapFinishMarkStep()
967{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700968 GcMarkContext *ctx;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800969
Carl Shapirob2e78d32010-08-20 11:34:18 -0700970 ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800971
Barry Hayes81010a42010-07-19 14:07:01 -0700972 /* The mark bits are now not needed.
973 */
974 dvmHeapSourceZeroMarkBitmap();
975
Carl Shapirof373efd2010-02-19 00:46:33 -0800976 /* Clean up everything else associated with the marking process.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800977 */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700978 destroyMarkStack(&ctx->stack);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800979
Carl Shapirob2e78d32010-08-20 11:34:18 -0700980 ctx->finger = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800981}
982
Carl Shapiro8881a802010-08-10 15:55:45 -0700983typedef struct {
984 size_t numObjects;
985 size_t numBytes;
986 bool isConcurrent;
987} SweepContext;
988
Carl Shapiro57ee2702010-08-27 13:06:48 -0700989static void sweepBitmapCallback(size_t numPtrs, void **ptrs, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800990{
Carl Shapirob9b23952010-08-10 17:20:15 -0700991 SweepContext *ctx = arg;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800992
Carl Shapiro8881a802010-08-10 15:55:45 -0700993 if (ctx->isConcurrent) {
994 dvmLockHeap();
995 }
996 ctx->numBytes += dvmHeapSourceFreeList(numPtrs, ptrs);
997 ctx->numObjects += numPtrs;
998 if (ctx->isConcurrent) {
999 dvmUnlockHeap();
1000 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001001}
1002
Carl Shapiro8881a802010-08-10 15:55:45 -07001003/*
1004 * Returns true if the given object is unmarked. This assumes that
1005 * the bitmaps have not yet been swapped.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001006 */
1007static int isUnmarkedObject(void *object)
1008{
Carl Shapiro6343bd02010-02-16 17:40:19 -08001009 return !isMarked((void *)((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001010 &gDvm.gcHeap->markContext);
1011}
1012
Carl Shapiro8881a802010-08-10 15:55:45 -07001013/*
1014 * Process all the internal system structures that behave like
1015 * weakly-held objects.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001016 */
Carl Shapiro8881a802010-08-10 15:55:45 -07001017void dvmHeapSweepSystemWeaks(void)
1018{
1019 dvmGcDetachDeadInternedStrings(isUnmarkedObject);
1020 dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
1021}
1022
1023/*
1024 * Walk through the list of objects that haven't been marked and free
1025 * them. Assumes the bitmaps have been swapped.
1026 */
1027void dvmHeapSweepUnmarkedObjects(GcMode mode, bool isConcurrent,
1028 size_t *numObjects, size_t *numBytes)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001029{
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001030 HeapBitmap currMark[HEAP_SOURCE_MAX_HEAP_COUNT];
1031 HeapBitmap currLive[HEAP_SOURCE_MAX_HEAP_COUNT];
Carl Shapiro8881a802010-08-10 15:55:45 -07001032 SweepContext ctx;
Carl Shapirod25566d2010-03-11 20:39:47 -08001033 size_t numBitmaps, numSweepBitmaps;
Barry Hayese168ebd2010-05-07 09:19:46 -07001034 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001035
Carl Shapirof373efd2010-02-19 00:46:33 -08001036 numBitmaps = dvmHeapSourceGetNumHeaps();
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001037 dvmHeapSourceGetObjectBitmaps(currLive, currMark, numBitmaps);
Carl Shapirod25566d2010-03-11 20:39:47 -08001038 if (mode == GC_PARTIAL) {
1039 numSweepBitmaps = 1;
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001040 assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == currLive[0].base);
Carl Shapirod25566d2010-03-11 20:39:47 -08001041 } else {
1042 numSweepBitmaps = numBitmaps;
1043 }
Carl Shapiro8881a802010-08-10 15:55:45 -07001044 ctx.numObjects = ctx.numBytes = 0;
1045 ctx.isConcurrent = isConcurrent;
Barry Hayese168ebd2010-05-07 09:19:46 -07001046 for (i = 0; i < numSweepBitmaps; i++) {
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001047 HeapBitmap* prevLive = &currMark[i];
1048 HeapBitmap* prevMark = &currLive[i];
1049 dvmHeapBitmapSweepWalk(prevLive, prevMark, sweepBitmapCallback, &ctx);
Barry Hayese168ebd2010-05-07 09:19:46 -07001050 }
Carl Shapiro8881a802010-08-10 15:55:45 -07001051 *numObjects = ctx.numObjects;
1052 *numBytes = ctx.numBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001053 if (gDvm.allocProf.enabled) {
Carl Shapiro8881a802010-08-10 15:55:45 -07001054 gDvm.allocProf.freeCount += ctx.numObjects;
1055 gDvm.allocProf.freeSize += ctx.numBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001056 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001057}