blob: f113322ee096435682282bf9a5003ed051f8cc0f [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Dalvik.h"
Barry Hayeseac47ed2009-06-22 11:45:20 -070018#include "alloc/clz.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080019#include "alloc/HeapBitmap.h"
20#include "alloc/HeapInternal.h"
21#include "alloc/HeapSource.h"
22#include "alloc/MarkSweep.h"
Carl Shapiroec805ea2010-06-28 16:28:26 -070023#include "alloc/Visit.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080024#include <limits.h> // for ULONG_MAX
25#include <sys/mman.h> // for madvise(), mmap()
26#include <cutils/ashmem.h>
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
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080045#define ALIGN_UP_TO_PAGE_SIZE(p) \
Andy McFadden96516932009-10-28 17:39:02 -070046 (((size_t)(p) + (SYSTEM_PAGE_SIZE - 1)) & ~(SYSTEM_PAGE_SIZE - 1))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080047
48/* Do not cast the result of this to a boolean; the only set bit
49 * may be > 1<<8.
50 */
Carl Shapiro6343bd02010-02-16 17:40:19 -080051static inline long isMarked(const void *obj, const GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080052{
Carl Shapirof373efd2010-02-19 00:46:33 -080053 return dvmHeapBitmapIsObjectBitSet(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080054}
55
56static bool
57createMarkStack(GcMarkStack *stack)
58{
59 const Object **limit;
60 size_t size;
The Android Open Source Project99409882009-03-18 22:20:24 -070061 int fd, err;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080062
63 /* Create a stack big enough for the worst possible case,
64 * where the heap is perfectly full of the smallest object.
65 * TODO: be better about memory usage; use a smaller stack with
66 * overflow detection and recovery.
67 */
68 size = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
69 (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
70 size = ALIGN_UP_TO_PAGE_SIZE(size);
71 fd = ashmem_create_region("dalvik-heap-markstack", size);
72 if (fd < 0) {
The Android Open Source Project99409882009-03-18 22:20:24 -070073 LOGE_GC("Could not create %d-byte ashmem mark stack: %s\n",
74 size, strerror(errno));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080075 return false;
76 }
77 limit = (const Object **)mmap(NULL, size, PROT_READ | PROT_WRITE,
78 MAP_PRIVATE, fd, 0);
The Android Open Source Project99409882009-03-18 22:20:24 -070079 err = errno;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080080 close(fd);
81 if (limit == MAP_FAILED) {
The Android Open Source Project99409882009-03-18 22:20:24 -070082 LOGE_GC("Could not mmap %d-byte ashmem mark stack: %s\n",
83 size, strerror(err));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080084 return false;
85 }
86
87 memset(stack, 0, sizeof(*stack));
88 stack->limit = limit;
89 stack->base = (const Object **)((uintptr_t)limit + size);
90 stack->top = stack->base;
91
92 return true;
93}
94
95static void
96destroyMarkStack(GcMarkStack *stack)
97{
98 munmap((char *)stack->limit,
99 (uintptr_t)stack->base - (uintptr_t)stack->limit);
100 memset(stack, 0, sizeof(*stack));
101}
102
103#define MARK_STACK_PUSH(stack, obj) \
104 do { \
105 *--(stack).top = (obj); \
106 } while (false)
107
108bool
Carl Shapirod25566d2010-03-11 20:39:47 -0800109dvmHeapBeginMarkStep(GcMode mode)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800110{
111 GcMarkContext *mc = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800112
113 if (!createMarkStack(&mc->stack)) {
114 return false;
115 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800116 mc->finger = NULL;
Carl Shapirod25566d2010-03-11 20:39:47 -0800117 mc->immuneLimit = dvmHeapSourceGetImmuneLimit(mode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800118 return true;
119}
120
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800121static long
Carl Shapiro6343bd02010-02-16 17:40:19 -0800122setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800123{
Carl Shapirof373efd2010-02-19 00:46:33 -0800124 return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800125}
126
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800127static void
Barry Hayese1bccb92010-05-18 09:48:37 -0700128markObjectNonNull(const Object *obj, GcMarkContext *ctx,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800129 bool checkFinger, bool forceStack)
130{
Barry Hayese1bccb92010-05-18 09:48:37 -0700131 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800132 assert(obj != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800133 assert(dvmIsValidObject(obj));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800134
Carl Shapirob31b3012010-05-25 18:35:37 -0700135 if (obj < (Object *)ctx->immuneLimit) {
Carl Shapirod25566d2010-03-11 20:39:47 -0800136 assert(isMarked(obj, ctx));
137 return;
138 }
Carl Shapiro6343bd02010-02-16 17:40:19 -0800139 if (!setAndReturnMarkBit(ctx, obj)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800140 /* This object was not previously marked.
141 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800142 if (forceStack || (checkFinger && (void *)obj < ctx->finger)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800143 /* This object will need to go on the mark stack.
144 */
145 MARK_STACK_PUSH(ctx->stack, obj);
146 }
147
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800148#if WITH_HPROF
149 if (gDvm.gcHeap->hprofContext != NULL) {
150 hprofMarkRootObject(gDvm.gcHeap->hprofContext, obj, 0);
151 }
152#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800153 }
154}
155
156/* Used to mark objects when recursing. Recursion is done by moving
157 * the finger across the bitmaps in address order and marking child
158 * objects. Any newly-marked objects whose addresses are lower than
159 * the finger won't be visited by the bitmap scan, so those objects
160 * need to be added to the mark stack.
161 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700162static void markObject(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800163{
Barry Hayese1bccb92010-05-18 09:48:37 -0700164 if (obj != NULL) {
165 markObjectNonNull(obj, ctx, true, false);
166 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800167}
168
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800169/* If the object hasn't already been marked, mark it and
170 * schedule it to be scanned for references.
171 *
172 * obj may not be NULL. The macro dvmMarkObject() should
173 * be used in situations where a reference may be NULL.
174 *
175 * This function may only be called when marking the root
Barry Hayese1bccb92010-05-18 09:48:37 -0700176 * set. When recursing, use the internal markObject().
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800177 */
178void
179dvmMarkObjectNonNull(const Object *obj)
180{
Barry Hayese1bccb92010-05-18 09:48:37 -0700181 assert(obj != NULL);
182 markObjectNonNull(obj, &gDvm.gcHeap->markContext, false, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800183}
184
185/* Mark the set of root objects.
186 *
187 * Things we need to scan:
188 * - System classes defined by root classloader
189 * - For each thread:
190 * - Interpreted stack, from top to "curFrame"
191 * - Dalvik registers (args + local vars)
192 * - JNI local references
193 * - Automatic VM local references (TrackedAlloc)
194 * - Associated Thread/VMThread object
195 * - ThreadGroups (could track & start with these instead of working
196 * upward from Threads)
197 * - Exception currently being thrown, if present
198 * - JNI global references
199 * - Interned string table
200 * - Primitive classes
201 * - Special objects
202 * - gDvm.outOfMemoryObj
203 * - Objects allocated with ALLOC_NO_GC
204 * - Objects pending finalization (but not yet finalized)
205 * - Objects in debugger object registry
206 *
207 * Don't need:
208 * - Native stack (for in-progress stuff in the VM)
209 * - The TrackedAlloc stuff watches all native VM references.
210 */
211void dvmHeapMarkRootSet()
212{
Barry Hayesd4f78d32010-06-08 09:34:42 -0700213 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800214
215 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_STICKY_CLASS, 0);
216
Carl Shapirod25566d2010-03-11 20:39:47 -0800217 LOG_SCAN("immune objects");
Barry Hayes425848f2010-05-04 13:32:12 -0700218 dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
Carl Shapirod25566d2010-03-11 20:39:47 -0800219
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800220 LOG_SCAN("root class loader\n");
221 dvmGcScanRootClassLoader();
222 LOG_SCAN("primitive classes\n");
223 dvmGcScanPrimitiveClasses();
224
225 /* dvmGcScanRootThreadGroups() sets a bunch of
226 * different scan states internally.
227 */
228 HPROF_CLEAR_GC_SCAN_STATE();
229
230 LOG_SCAN("root thread groups\n");
231 dvmGcScanRootThreadGroups();
232
233 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_INTERNED_STRING, 0);
234
235 LOG_SCAN("interned strings\n");
236 dvmGcScanInternedStrings();
237
238 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_GLOBAL, 0);
239
240 LOG_SCAN("JNI global refs\n");
241 dvmGcMarkJniGlobalRefs();
242
243 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
244
245 LOG_SCAN("pending reference operations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700246 dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800247
248 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
249
250 LOG_SCAN("pending finalizations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700251 dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800252
253 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_DEBUGGER, 0);
254
255 LOG_SCAN("debugger refs\n");
256 dvmGcMarkDebuggerRefs();
257
258 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_VM_INTERNAL, 0);
259
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800260 /* Mark any special objects we have sitting around.
261 */
262 LOG_SCAN("special objects\n");
263 dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
264 dvmMarkObjectNonNull(gDvm.internalErrorObj);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700265 dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800266//TODO: scan object references sitting in gDvm; use pointer begin & end
267
268 HPROF_CLEAR_GC_SCAN_STATE();
269}
270
271/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700272 * Nothing past this point is allowed to use dvmMarkObject() or
273 * dvmMarkObjectNonNull(), which are for root-marking only.
274 * Scanning/recursion must use markObject(), which takes the finger
275 * into account.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800276 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700277#undef dvmMarkObject
278#define dvmMarkObject __dont_use_dvmMarkObject__
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800279#define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
280
Barry Hayese1bccb92010-05-18 09:48:37 -0700281/*
282 * Scans instance fields.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800283 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700284static void scanInstanceFields(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800285{
Barry Hayese1bccb92010-05-18 09:48:37 -0700286 assert(obj != NULL);
287 assert(obj->clazz != NULL);
288 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800289
Barry Hayese1bccb92010-05-18 09:48:37 -0700290 if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
291 unsigned int refOffsets = obj->clazz->refOffsets;
Barry Hayeseac47ed2009-06-22 11:45:20 -0700292 while (refOffsets != 0) {
293 const int rshift = CLZ(refOffsets);
294 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
295 markObject(dvmGetFieldObject((Object*)obj,
Barry Hayese1bccb92010-05-18 09:48:37 -0700296 CLASS_OFFSET_FROM_CLZ(rshift)), ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800297 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700298 } else {
Barry Hayese1bccb92010-05-18 09:48:37 -0700299 ClassObject *clazz;
300 int i;
301 for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
302 InstField *field = clazz->ifields;
303 for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
304 void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
305 markObject(((JValue *)addr)->l, ctx);
Barry Hayeseac47ed2009-06-22 11:45:20 -0700306 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700307 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800308 }
309}
310
Barry Hayese1bccb92010-05-18 09:48:37 -0700311/*
312 * Scans the header, static field references, and interface
313 * pointers of a class object.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800314 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700315static void scanClassObject(const ClassObject *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800316{
Barry Hayese1bccb92010-05-18 09:48:37 -0700317 int i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800318
Barry Hayese1bccb92010-05-18 09:48:37 -0700319 assert(obj != NULL);
320 assert(obj->obj.clazz == gDvm.classJavaLangClass);
321 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800322
Barry Hayese1bccb92010-05-18 09:48:37 -0700323 markObject((Object *)obj->obj.clazz, ctx);
324 if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
325 markObject((Object *)obj->elementClass, ctx);
326 }
Barry Hayesc49db852010-05-14 13:43:34 -0700327 /* Do super and the interfaces contain Objects and not dex idx values? */
328 if (obj->status > CLASS_IDX) {
329 markObject((Object *)obj->super, ctx);
330 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700331 markObject(obj->classLoader, ctx);
332 /* Scan static field references. */
333 for (i = 0; i < obj->sfieldCount; ++i) {
334 char ch = obj->sfields[i].field.signature[0];
335 if (ch == '[' || ch == 'L') {
336 markObject(obj->sfields[i].value.l, ctx);
337 }
338 }
339 /* Scan the instance fields. */
340 scanInstanceFields((const Object *)obj, ctx);
341 /* Scan interface references. */
Barry Hayesc49db852010-05-14 13:43:34 -0700342 if (obj->status > CLASS_IDX) {
343 for (i = 0; i < obj->interfaceCount; ++i) {
344 markObject((Object *)obj->interfaces[i], ctx);
345 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800346 }
347}
348
Barry Hayese1bccb92010-05-18 09:48:37 -0700349/*
350 * Scans the header of all array objects. If the array object is
351 * specialized to a reference type, scans the array data as well.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800352 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700353static void scanArrayObject(const ArrayObject *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800354{
Barry Hayese1bccb92010-05-18 09:48:37 -0700355 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800356
Barry Hayese1bccb92010-05-18 09:48:37 -0700357 assert(obj != NULL);
358 assert(obj->obj.clazz != NULL);
359 assert(ctx != NULL);
360 /* Scan the class object reference. */
361 markObject((Object *)obj->obj.clazz, ctx);
362 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISOBJECTARRAY)) {
363 /* Scan the array contents. */
364 Object **contents = (Object **)obj->contents;
365 for (i = 0; i < obj->length; ++i) {
366 markObject(contents[i], ctx);
367 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800368 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700369}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800370
Barry Hayese1bccb92010-05-18 09:48:37 -0700371/*
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700372 * Returns class flags relating to Reference subclasses.
373 */
374static int referenceClassFlags(const Object *obj)
375{
376 int flags = CLASS_ISREFERENCE |
377 CLASS_ISWEAKREFERENCE |
378 CLASS_ISPHANTOMREFERENCE;
379 return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
380}
381
382/*
383 * Returns true if the object derives from SoftReference.
384 */
385static bool isSoftReference(const Object *obj)
386{
387 return referenceClassFlags(obj) == CLASS_ISREFERENCE;
388}
389
390/*
391 * Returns true if the object derives from WeakReference.
392 */
393static bool isWeakReference(const Object *obj)
394{
395 return referenceClassFlags(obj) & CLASS_ISWEAKREFERENCE;
396}
397
398/*
399 * Returns true if the object derives from PhantomReference.
400 */
401static bool isPhantomReference(const Object *obj)
402{
403 return referenceClassFlags(obj) & CLASS_ISPHANTOMREFERENCE;
404}
405
406/*
407 * Adds a reference to the tail of a circular queue of references.
408 */
409static void enqueuePendingReference(Object *ref, Object **list)
410{
411 size_t offset;
412
413 assert(ref != NULL);
414 assert(list != NULL);
415 offset = gDvm.offJavaLangRefReference_pendingNext;
416 if (*list == NULL) {
417 dvmSetFieldObject(ref, offset, ref);
418 *list = ref;
419 } else {
420 Object *head = dvmGetFieldObject(*list, offset);
421 dvmSetFieldObject(ref, offset, head);
422 dvmSetFieldObject(*list, offset, ref);
423 }
424}
425
426/*
427 * Removes the reference at the head of circular queue of references.
428 */
429static Object *dequeuePendingReference(Object **list)
430{
431 Object *ref, *head;
432 size_t offset;
433
434 assert(list != NULL);
435 assert(*list != NULL);
436 offset = gDvm.offJavaLangRefReference_pendingNext;
437 head = dvmGetFieldObject(*list, offset);
438 if (*list == head) {
439 ref = *list;
440 *list = NULL;
441 } else {
442 Object *next = dvmGetFieldObject(head, offset);
443 dvmSetFieldObject(*list, offset, next);
444 ref = head;
445 }
446 dvmSetFieldObject(ref, offset, NULL);
447 return ref;
448}
449
450/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700451 * Process the "referent" field in a java.lang.ref.Reference. If the
452 * referent has not yet been marked, put it on the appropriate list in
453 * the gcHeap for later processing.
454 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700455static void delayReferenceReferent(Object *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700456{
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700457 GcHeap *gcHeap = gDvm.gcHeap;
458 Object *pending, *referent;
459 size_t pendingNextOffset, referentOffset;
460
Barry Hayese1bccb92010-05-18 09:48:37 -0700461 assert(obj != NULL);
Barry Hayes697b5a92010-06-23 11:38:52 -0700462 assert(obj->clazz != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700463 assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
Barry Hayese1bccb92010-05-18 09:48:37 -0700464 assert(ctx != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700465 pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
466 referentOffset = gDvm.offJavaLangRefReference_referent;
467 pending = dvmGetFieldObject(obj, pendingNextOffset);
468 referent = dvmGetFieldObject(obj, referentOffset);
469 if (pending == NULL && referent != NULL && !isMarked(referent, ctx)) {
470 Object **list = NULL;
471 if (isSoftReference(obj)) {
472 list = &gcHeap->softReferences;
473 } else if (isWeakReference(obj)) {
474 list = &gcHeap->weakReferences;
475 } else if (isPhantomReference(obj)) {
476 list = &gcHeap->phantomReferences;
Barry Hayese1bccb92010-05-18 09:48:37 -0700477 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700478 assert(list != NULL);
479 enqueuePendingReference(obj, list);
Barry Hayese1bccb92010-05-18 09:48:37 -0700480 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800481}
482
Barry Hayese1bccb92010-05-18 09:48:37 -0700483/*
484 * Scans the header and field references of a data object.
485 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700486static void scanDataObject(DataObject *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700487{
488 assert(obj != NULL);
489 assert(obj->obj.clazz != NULL);
490 assert(ctx != NULL);
491 /* Scan the class object. */
492 markObject((Object *)obj->obj.clazz, ctx);
493 /* Scan the instance fields. */
494 scanInstanceFields((const Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700495 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISREFERENCE)) {
Barry Hayes697b5a92010-06-23 11:38:52 -0700496 delayReferenceReferent((Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700497 }
498}
499
500/*
501 * Scans an object reference. Determines the type of the reference
502 * and dispatches to a specialized scanning routine.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800503 */
504static void scanObject(const Object *obj, GcMarkContext *ctx)
505{
Barry Hayese1bccb92010-05-18 09:48:37 -0700506 assert(obj != NULL);
507 assert(ctx != NULL);
Barry Hayes899cdb72010-06-08 09:59:12 -0700508 assert(obj->clazz != NULL);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700509#if WITH_HPROF
510 if (gDvm.gcHeap->hprofContext != NULL) {
511 hprofDumpHeapObject(gDvm.gcHeap->hprofContext, obj);
512 }
513#endif
Barry Hayese1bccb92010-05-18 09:48:37 -0700514 /* Dispatch a type-specific scan routine. */
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700515 if (obj->clazz == gDvm.classJavaLangClass) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700516 scanClassObject((ClassObject *)obj, ctx);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700517 } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
Barry Hayes899cdb72010-06-08 09:59:12 -0700518 scanArrayObject((ArrayObject *)obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800519 } else {
Barry Hayes899cdb72010-06-08 09:59:12 -0700520 scanDataObject((DataObject *)obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800521 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800522}
523
Barry Hayes6e5cf602010-06-22 12:32:59 -0700524/*
525 * Variants for partial GC. Scan immune objects, and rebuild the card
526 * table.
527 */
528
529/*
530 * Mark an object which was found in an immune object.
531 */
532static void scanImmuneReference(const Object *obj, GcMarkContext *ctx)
533{
534 if (obj != NULL) {
535 if (obj < (Object *)ctx->immuneLimit) {
536 assert(isMarked(obj, ctx));
537 } else {
538 ctx->crossGen = true;
539 markObjectNonNull(obj, ctx, true, false);
540 }
541 }
542}
543
544/*
545 * Scans instance fields.
546 */
547static void scanImmuneInstanceFields(const Object *obj, GcMarkContext *ctx)
548{
549 assert(obj != NULL);
550 assert(obj->clazz != NULL);
551 assert(ctx != NULL);
552
553 if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
554 unsigned int refOffsets = obj->clazz->refOffsets;
555 while (refOffsets != 0) {
556 const int rshift = CLZ(refOffsets);
557 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
558 scanImmuneReference(
559 dvmGetFieldObject((Object*)obj, CLASS_OFFSET_FROM_CLZ(rshift)),
560 ctx);
561 }
562 } else {
563 ClassObject *clazz;
564 int i;
565 for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
566 InstField *field = clazz->ifields;
567 for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
568 void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
569 scanImmuneReference(((JValue *)addr)->l, ctx);
570 }
571 }
572 }
573}
574
575/*
576 * Scans the header, static field references, and interface
577 * pointers of a class object.
578 */
579static void scanImmuneClassObject(const ClassObject *obj, GcMarkContext *ctx)
580{
581 int i;
582
583 assert(obj != NULL);
584 assert(obj->obj.clazz == gDvm.classJavaLangClass);
585 assert(ctx != NULL);
586
587 scanImmuneReference((Object *)obj->obj.clazz, ctx);
588 if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
589 scanImmuneReference((Object *)obj->elementClass, ctx);
590 }
591 /* Do super and the interfaces contain Objects and not dex idx values? */
592 if (obj->status > CLASS_IDX) {
593 scanImmuneReference((Object *)obj->super, ctx);
594 }
595 scanImmuneReference(obj->classLoader, ctx);
596 /* Scan static field references. */
597 for (i = 0; i < obj->sfieldCount; ++i) {
598 char ch = obj->sfields[i].field.signature[0];
599 if (ch == '[' || ch == 'L') {
600 scanImmuneReference(obj->sfields[i].value.l, ctx);
601 }
602 }
603 /* Scan the instance fields. */
604 scanImmuneInstanceFields((const Object *)obj, ctx);
605 /* Scan interface references. */
606 if (obj->status > CLASS_IDX) {
607 for (i = 0; i < obj->interfaceCount; ++i) {
608 scanImmuneReference((Object *)obj->interfaces[i], ctx);
609 }
610 }
611}
612
613/*
614 * Scans the header of all array objects. If the array object is
615 * specialized to a reference type, scans the array data as well.
616 */
617static void scanImmuneArrayObject(const ArrayObject *obj, GcMarkContext *ctx)
618{
619 size_t i;
620
621 assert(obj != NULL);
622 assert(obj->obj.clazz != NULL);
623 assert(ctx != NULL);
624 /* Scan the class object reference. */
625 scanImmuneReference((Object *)obj->obj.clazz, ctx);
626 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISOBJECTARRAY)) {
627 /* Scan the array contents. */
628 Object **contents = (Object **)obj->contents;
629 for (i = 0; i < obj->length; ++i) {
630 scanImmuneReference(contents[i], ctx);
631 }
632 }
633}
634
635/*
636 * Scans the header and field references of a data object.
637 */
638static void scanImmuneDataObject(DataObject *obj, GcMarkContext *ctx)
639{
640 assert(obj != NULL);
641 assert(obj->obj.clazz != NULL);
642 assert(ctx != NULL);
643 /* Scan the class object. */
644 scanImmuneReference((Object *)obj->obj.clazz, ctx);
645 /* Scan the instance fields. */
646 scanImmuneInstanceFields((const Object *)obj, ctx);
647 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISREFERENCE)) {
648 scanImmuneReference((Object *)obj, ctx);
649 }
650}
651
652/*
653 * Scans an object reference. Determines the type of the reference
654 * and dispatches to a specialized scanning routine.
655 */
656static void scanImmuneObject(const Object *obj, GcMarkContext *ctx)
657{
658 assert(obj != NULL);
659 assert(obj->clazz != NULL);
660 assert(ctx != NULL);
661 assert(obj < (Object *)ctx->immuneLimit);
662
663#if WITH_HPROF
664 if (gDvm.gcHeap->hprofContext != NULL) {
665 hprofDumpHeapObject(gDvm.gcHeap->hprofContext, obj);
666 }
667#endif
668 /* Dispatch a type-specific scan routine. */
669 if (obj->clazz == gDvm.classJavaLangClass) {
670 scanImmuneClassObject((ClassObject *)obj, ctx);
671 } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
672 scanImmuneArrayObject((ArrayObject *)obj, ctx);
673 } else {
674 scanImmuneDataObject((DataObject *)obj, ctx);
675 }
676}
677
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800678static void
679processMarkStack(GcMarkContext *ctx)
680{
681 const Object **const base = ctx->stack.base;
682
683 /* Scan anything that's on the mark stack.
684 * We can't use the bitmaps anymore, so use
685 * a finger that points past the end of them.
686 */
687 ctx->finger = (void *)ULONG_MAX;
688 while (ctx->stack.top != base) {
689 scanObject(*ctx->stack.top++, ctx);
690 }
691}
692
693#ifndef NDEBUG
694static uintptr_t gLastFinger = 0;
695#endif
696
697static bool
698scanBitmapCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
699{
700 GcMarkContext *ctx = (GcMarkContext *)arg;
701 size_t i;
702
703#ifndef NDEBUG
704 assert((uintptr_t)finger >= gLastFinger);
705 gLastFinger = (uintptr_t)finger;
706#endif
707
708 ctx->finger = finger;
709 for (i = 0; i < numPtrs; i++) {
Carl Shapiro6343bd02010-02-16 17:40:19 -0800710 scanObject(*ptrs++, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800711 }
712
713 return true;
714}
715
716/* Given bitmaps with the root set marked, find and mark all
717 * reachable objects. When this returns, the entire set of
718 * live objects will be marked and the mark stack will be empty.
719 */
Carl Shapiro29540742010-03-26 15:34:39 -0700720void dvmHeapScanMarkedObjects(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800721{
722 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
723
724 assert(ctx->finger == NULL);
725
726 /* The bitmaps currently have bits set for the root set.
727 * Walk across the bitmaps and scan each object.
728 */
729#ifndef NDEBUG
730 gLastFinger = 0;
731#endif
Barry Hayes6e5cf602010-06-22 12:32:59 -0700732 if (gDvm.executionMode == kExecutionModeInterpPortable) {
733 /* The portable interpreter dirties cards on write; other
734 * modes do not yet do so.
735 * TODO: Bring the fast interpreter and JIT into the fold.
736 */
737 HeapBitmap markBits[HEAP_SOURCE_MAX_HEAP_COUNT];
738 HeapBitmap liveBits[HEAP_SOURCE_MAX_HEAP_COUNT];
739 size_t numBitmaps, i;
740 numBitmaps = dvmHeapSourceGetNumHeaps();
741 dvmHeapSourceGetObjectBitmaps(liveBits, markBits, numBitmaps);
742 for (i = 0; i < numBitmaps; i++) {
743 /* The use of finger to tell visited from unvisited objects
744 * requires we walk the bitmaps from low to high
745 * addresses. This code assumes [and asserts] that the order
746 * of the heaps returned is the reverse of that.
747 */
748 size_t j = numBitmaps-1-i;
749 assert(j == 0 || (markBits[j].base < markBits[j-1].base));
750 if (markBits[j].base < (uintptr_t)ctx->immuneLimit) {
751 if (gDvm.verifyCardTable) {
752 dvmVerifyCardTable(&markBits[j], ctx->immuneLimit);
753 }
754 uintptr_t minAddr = markBits[j].base;
755 uintptr_t maxAddr = markBits[j].base +
756 HB_MAX_OFFSET(&markBits[j]);
757 u1 *minCard = dvmCardFromAddr((void *)minAddr);
758 u1 *maxCard = dvmCardFromAddr((void *)maxAddr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800759
Barry Hayes6e5cf602010-06-22 12:32:59 -0700760 u1 *card;
Barry Hayes8f921a72010-07-09 12:53:49 -0700761 /* TODO: This double-loop should be made faster. In
762 * particular the inner loop could get in bed with the
763 * bitmap scanning routines.
Barry Hayes6e5cf602010-06-22 12:32:59 -0700764 */
765 for (card = minCard; card <= maxCard; card++) {
766 if (*card == GC_CARD_DIRTY) {
767 uintptr_t addr = (uintptr_t)dvmAddrFromCard(card);
768 uintptr_t endAddr = addr + GC_CARD_SIZE;
769 ctx->crossGen = false;
770 for ( ; addr < endAddr; addr += 8) {
771 if (dvmIsValidObject((void *)addr)) {
772 scanImmuneObject((void *)addr, ctx);
773 }
774 }
775 if (! ctx->crossGen) {
776 *card = GC_CARD_CLEAN;
777 }
778 }
779 }
780 if (gDvm.verifyCardTable) {
781 dvmVerifyCardTable(&markBits[j], ctx->immuneLimit);
782 }
783 } else {
784 dvmHeapBitmapWalk(&markBits[j], scanBitmapCallback, ctx);
785 }
786 }
787 } else {
788 dvmHeapBitmapWalk(ctx->bitmap, scanBitmapCallback, ctx);
789 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800790 /* We've walked the mark bitmaps. Scan anything that's
791 * left on the mark stack.
792 */
793 processMarkStack(ctx);
794
795 LOG_SCAN("done with marked objects\n");
796}
797
Carl Shapiroec805ea2010-06-28 16:28:26 -0700798static void dirtyObjectVisitor(void *ptr, void *arg)
799{
800 markObject(*(Object **)ptr, (GcMarkContext *)arg);
801}
802
803/*
804 * Callback applied to each gray object to blacken it.
805 */
806static bool dirtyObjectCallback(size_t numPtrs, void **ptrs,
807 const void *finger, void *arg)
808{
809 GcMarkContext *ctx;
810 size_t i;
811
812 ctx = (GcMarkContext *)arg;
813 for (i = 0; i < numPtrs; ++i) {
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700814 Object *obj = ptrs[i];
815 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE)) {
816 scanDataObject((DataObject *)obj, ctx);
817 } else {
818 dvmVisitObject(dirtyObjectVisitor, obj, ctx);
819 }
Carl Shapiroec805ea2010-06-28 16:28:26 -0700820 }
821 return true;
822}
823
824/*
825 * Re-mark dirtied objects. Iterates through all blackened objects
826 * looking for references to white objects.
827 */
828void dvmMarkDirtyObjects(void)
829{
830 HeapBitmap markBits[HEAP_SOURCE_MAX_HEAP_COUNT];
831 HeapBitmap liveBits[HEAP_SOURCE_MAX_HEAP_COUNT];
832 GcMarkContext *ctx;
833 size_t numBitmaps;
834 size_t i;
835
836 ctx = &gDvm.gcHeap->markContext;
837 /*
Carl Shapirof5860332010-06-28 23:02:08 -0700838 * The finger must have been set to the maximum value to ensure
839 * that gray objects will be pushed onto the mark stack.
Carl Shapiroec805ea2010-06-28 16:28:26 -0700840 */
841 assert(ctx->finger == (void *)ULONG_MAX);
842 numBitmaps = dvmHeapSourceGetNumHeaps();
843 dvmHeapSourceGetObjectBitmaps(liveBits, markBits, numBitmaps);
844 for (i = 0; i < numBitmaps; i++) {
845 dvmHeapBitmapWalk(&markBits[i], dirtyObjectCallback, ctx);
846 }
847 processMarkStack(ctx);
848}
849
Barry Hayes6930a112009-12-22 11:01:38 -0800850/** Clear the referent field.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800851 */
Barry Hayes6930a112009-12-22 11:01:38 -0800852static void clearReference(Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800853{
854 /* This is what the default implementation of Reference.clear()
855 * does. We're required to clear all references to a given
856 * referent atomically, so we can't pop in and out of interp
857 * code each time.
858 *
Barry Hayes6930a112009-12-22 11:01:38 -0800859 * We don't ever actaully call overriding implementations of
860 * Reference.clear().
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800861 */
862 dvmSetFieldObject(reference,
863 gDvm.offJavaLangRefReference_referent, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800864}
865
Carl Shapiro29540742010-03-26 15:34:39 -0700866/*
867 * Returns true if the reference was registered with a reference queue
868 * and has not yet been enqueued.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800869 */
Carl Shapiro29540742010-03-26 15:34:39 -0700870static bool isEnqueuable(const Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800871{
Barry Hayes6930a112009-12-22 11:01:38 -0800872 Object *queue = dvmGetFieldObject(reference,
873 gDvm.offJavaLangRefReference_queue);
874 Object *queueNext = dvmGetFieldObject(reference,
875 gDvm.offJavaLangRefReference_queueNext);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700876 return queue != NULL && queueNext == NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800877}
878
Carl Shapiro29540742010-03-26 15:34:39 -0700879/*
880 * Schedules a reference to be appended to its reference queue.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800881 */
Carl Shapiro29540742010-03-26 15:34:39 -0700882static void enqueueReference(Object *ref)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800883{
Carl Shapiro646ba092010-06-10 15:17:00 -0700884 assert(ref != NULL);
Carl Shapiro29540742010-03-26 15:34:39 -0700885 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
886 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
Carl Shapiro646ba092010-06-10 15:17:00 -0700887 if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
Carl Shapiro29540742010-03-26 15:34:39 -0700888 LOGE_HEAP("enqueueReference(): no room for any more "
889 "reference operations\n");
890 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800891 }
892}
893
Carl Shapiro29540742010-03-26 15:34:39 -0700894/*
895 * Walks the reference list marking any references subject to the
896 * reference clearing policy. References with a black referent are
897 * removed from the list. References with white referents biased
898 * toward saving are blackened and also removed from the list.
899 */
900void dvmHandleSoftRefs(Object **list)
901{
902 GcMarkContext *markContext;
903 Object *ref, *referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700904 Object *clear;
905 size_t pendingNextOffset, referentOffset;
906 size_t counter;
Carl Shapiro29540742010-03-26 15:34:39 -0700907 bool marked;
908
909 markContext = &gDvm.gcHeap->markContext;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700910 pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
Carl Shapiro29540742010-03-26 15:34:39 -0700911 referentOffset = gDvm.offJavaLangRefReference_referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700912 clear = NULL;
Carl Shapiro29540742010-03-26 15:34:39 -0700913 counter = 0;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700914 while (*list != NULL) {
915 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700916 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700917 assert(referent != NULL);
918 marked = isMarked(referent, markContext);
919 if (!marked && ((++counter) & 1)) {
920 /* Referent is white and biased toward saving, mark it. */
Barry Hayese1bccb92010-05-18 09:48:37 -0700921 markObject(referent, markContext);
Carl Shapiro29540742010-03-26 15:34:39 -0700922 marked = true;
923 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700924 if (!marked) {
925 /* Referent is white, queue it for clearing. */
926 enqueuePendingReference(ref, &clear);
Carl Shapiro29540742010-03-26 15:34:39 -0700927 }
Carl Shapiro29540742010-03-26 15:34:39 -0700928 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700929 *list = clear;
Carl Shapiro29540742010-03-26 15:34:39 -0700930 /*
931 * Restart the mark with the newly black references added to the
932 * root set.
933 */
934 processMarkStack(markContext);
935}
936
937/*
938 * Walks the reference list and clears references with an unmarked
939 * (white) referents. Cleared references registered to a reference
940 * queue are scheduled for appending by the heap worker thread.
941 */
942void dvmClearWhiteRefs(Object **list)
943{
944 GcMarkContext *markContext;
945 Object *ref, *referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700946 size_t pendingNextOffset, referentOffset;
Carl Shapiro29540742010-03-26 15:34:39 -0700947 bool doSignal;
948
949 markContext = &gDvm.gcHeap->markContext;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700950 pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
Carl Shapiro29540742010-03-26 15:34:39 -0700951 referentOffset = gDvm.offJavaLangRefReference_referent;
952 doSignal = false;
953 while (*list != NULL) {
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700954 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700955 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700956 assert(referent != NULL);
957 if (!isMarked(referent, markContext)) {
958 /* Referent is "white", clear it. */
959 clearReference(ref);
960 if (isEnqueuable(ref)) {
961 enqueueReference(ref);
962 doSignal = true;
963 }
964 }
965 }
966 /*
967 * If we cleared a reference with a reference queue we must notify
968 * the heap worker to append the reference.
969 */
970 if (doSignal) {
971 dvmSignalHeapWorker(false);
972 }
973 assert(*list == NULL);
974}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800975
976/* Find unreachable objects that need to be finalized,
977 * and schedule them for finalization.
978 */
979void dvmHeapScheduleFinalizations()
980{
981 HeapRefTable newPendingRefs;
982 LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
983 Object **ref;
984 Object **lastRef;
985 size_t totalPendCount;
986 GcMarkContext *markContext = &gDvm.gcHeap->markContext;
987
988 /*
989 * All reachable objects have been marked.
990 * Any unmarked finalizable objects need to be finalized.
991 */
992
993 /* Create a table that the new pending refs will
994 * be added to.
995 */
Barry Hayesd4f78d32010-06-08 09:34:42 -0700996 if (!dvmHeapInitHeapRefTable(&newPendingRefs)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800997 //TODO: mark all finalizable refs and hope that
998 // we can schedule them next time. Watch out,
999 // because we may be expecting to free up space
1000 // by calling finalizers.
1001 LOGE_GC("dvmHeapScheduleFinalizations(): no room for "
1002 "pending finalizations\n");
1003 dvmAbort();
1004 }
1005
1006 /* Walk through finalizableRefs and move any unmarked references
1007 * to the list of new pending refs.
1008 */
1009 totalPendCount = 0;
1010 while (finRefs != NULL) {
1011 Object **gapRef;
1012 size_t newPendCount = 0;
1013
1014 gapRef = ref = finRefs->refs.table;
1015 lastRef = finRefs->refs.nextEntry;
1016 while (ref < lastRef) {
Carl Shapiro6343bd02010-02-16 17:40:19 -08001017 if (!isMarked(*ref, markContext)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001018 if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
1019 //TODO: add the current table and allocate
1020 // a new, smaller one.
1021 LOGE_GC("dvmHeapScheduleFinalizations(): "
1022 "no room for any more pending finalizations: %zd\n",
1023 dvmHeapNumHeapRefTableEntries(&newPendingRefs));
1024 dvmAbort();
1025 }
1026 newPendCount++;
1027 } else {
1028 /* This ref is marked, so will remain on finalizableRefs.
1029 */
1030 if (newPendCount > 0) {
1031 /* Copy it up to fill the holes.
1032 */
1033 *gapRef++ = *ref;
1034 } else {
1035 /* No holes yet; don't bother copying.
1036 */
1037 gapRef++;
1038 }
1039 }
1040 ref++;
1041 }
1042 finRefs->refs.nextEntry = gapRef;
1043 //TODO: if the table is empty when we're done, free it.
1044 totalPendCount += newPendCount;
1045 finRefs = finRefs->next;
1046 }
1047 LOGD_GC("dvmHeapScheduleFinalizations(): %zd finalizers triggered.\n",
1048 totalPendCount);
1049 if (totalPendCount == 0) {
1050 /* No objects required finalization.
1051 * Free the empty temporary table.
1052 */
1053 dvmClearReferenceTable(&newPendingRefs);
1054 return;
1055 }
1056
1057 /* Add the new pending refs to the main list.
1058 */
1059 if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
1060 &newPendingRefs))
1061 {
1062 LOGE_GC("dvmHeapScheduleFinalizations(): can't insert new "
1063 "pending finalizations\n");
1064 dvmAbort();
1065 }
1066
1067 //TODO: try compacting the main list with a memcpy loop
1068
1069 /* Mark the refs we just moved; we don't want them or their
1070 * children to get swept yet.
1071 */
1072 ref = newPendingRefs.table;
1073 lastRef = newPendingRefs.nextEntry;
1074 assert(ref < lastRef);
1075 HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
1076 while (ref < lastRef) {
Barry Hayese1bccb92010-05-18 09:48:37 -07001077 assert(*ref != NULL);
1078 markObject(*ref, markContext);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001079 ref++;
1080 }
1081 HPROF_CLEAR_GC_SCAN_STATE();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001082 processMarkStack(markContext);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001083 dvmSignalHeapWorker(false);
1084}
1085
1086void dvmHeapFinishMarkStep()
1087{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001088 GcMarkContext *markContext;
1089
1090 markContext = &gDvm.gcHeap->markContext;
1091
1092 /* The sweep step freed every object that appeared in the
1093 * HeapSource bitmaps that didn't appear in the mark bitmaps.
1094 * The new state of the HeapSource is exactly the final
1095 * mark bitmaps, so swap them in.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001096 */
Carl Shapirof373efd2010-02-19 00:46:33 -08001097 dvmHeapSourceSwapBitmaps();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001098
Carl Shapirof373efd2010-02-19 00:46:33 -08001099 /* Clean up everything else associated with the marking process.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001100 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001101 destroyMarkStack(&markContext->stack);
1102
Carl Shapirof373efd2010-02-19 00:46:33 -08001103 markContext->finger = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001104}
1105
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001106static bool
1107sweepBitmapCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
1108{
1109 const ClassObject *const classJavaLangClass = gDvm.classJavaLangClass;
Barry Hayes5cbb2302010-02-02 14:07:37 -08001110 const bool overwriteFree = gDvm.overwriteFree;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001111 size_t i;
Barry Hayesdde8ab02009-05-20 12:10:36 -07001112 void **origPtrs = ptrs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001113
1114 for (i = 0; i < numPtrs; i++) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001115 Object *obj;
1116
Carl Shapiro6343bd02010-02-16 17:40:19 -08001117 obj = (Object *)*ptrs++;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001118
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001119 /* This assumes that java.lang.Class will never go away.
1120 * If it can, and we were the last reference to it, it
1121 * could have already been swept. However, even in that case,
1122 * gDvm.classJavaLangClass should still have a useful
1123 * value.
1124 */
1125 if (obj->clazz == classJavaLangClass) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001126 /* dvmFreeClassInnards() may have already been called,
1127 * but it's safe to call on the same ClassObject twice.
1128 */
1129 dvmFreeClassInnards((ClassObject *)obj);
1130 }
1131
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001132 /* Overwrite the to-be-freed object to make stale references
1133 * more obvious.
1134 */
Barry Hayes5cbb2302010-02-02 14:07:37 -08001135 if (overwriteFree) {
Barry Hayes2e3c3e12010-02-22 09:39:10 -08001136 int objlen;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001137 ClassObject *clazz = obj->clazz;
Barry Hayes2e3c3e12010-02-22 09:39:10 -08001138 objlen = dvmHeapSourceChunkSize(obj);
1139 memset(obj, 0xa5, objlen);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001140 obj->clazz = (ClassObject *)((uintptr_t)clazz ^ 0xffffffff);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001141 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001142 }
Barry Hayesdde8ab02009-05-20 12:10:36 -07001143 // TODO: dvmHeapSourceFreeList has a loop, just like the above
1144 // does. Consider collapsing the two loops to save overhead.
1145 dvmHeapSourceFreeList(numPtrs, origPtrs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001146
1147 return true;
1148}
1149
Carl Shapiro5a6071b2010-01-07 21:35:50 -08001150/* Returns true if the given object is unmarked. Ignores the low bits
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001151 * of the pointer because the intern table may set them.
1152 */
1153static int isUnmarkedObject(void *object)
1154{
Carl Shapiro6343bd02010-02-16 17:40:19 -08001155 return !isMarked((void *)((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001156 &gDvm.gcHeap->markContext);
1157}
1158
1159/* Walk through the list of objects that haven't been
1160 * marked and free them.
1161 */
1162void
Carl Shapirod25566d2010-03-11 20:39:47 -08001163dvmHeapSweepUnmarkedObjects(GcMode mode, int *numFreed, size_t *sizeFreed)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001164{
Carl Shapirof373efd2010-02-19 00:46:33 -08001165 HeapBitmap markBits[HEAP_SOURCE_MAX_HEAP_COUNT];
Carl Shapirod77f7fd2010-04-05 19:23:31 -07001166 HeapBitmap liveBits[HEAP_SOURCE_MAX_HEAP_COUNT];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001167 size_t origObjectsAllocated;
1168 size_t origBytesAllocated;
Carl Shapirod25566d2010-03-11 20:39:47 -08001169 size_t numBitmaps, numSweepBitmaps;
Barry Hayese168ebd2010-05-07 09:19:46 -07001170 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001171
1172 /* All reachable objects have been marked.
1173 * Detach any unreachable interned strings before
1174 * we sweep.
1175 */
1176 dvmGcDetachDeadInternedStrings(isUnmarkedObject);
1177
1178 /* Free any known objects that are not marked.
1179 */
1180 origObjectsAllocated = dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0);
1181 origBytesAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
1182
Carl Shapiro5a6071b2010-01-07 21:35:50 -08001183 dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
1184
Carl Shapirof373efd2010-02-19 00:46:33 -08001185 numBitmaps = dvmHeapSourceGetNumHeaps();
Carl Shapirod77f7fd2010-04-05 19:23:31 -07001186 dvmHeapSourceGetObjectBitmaps(liveBits, markBits, numBitmaps);
Carl Shapirod25566d2010-03-11 20:39:47 -08001187 if (mode == GC_PARTIAL) {
1188 numSweepBitmaps = 1;
Carl Shapirod77f7fd2010-04-05 19:23:31 -07001189 assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == liveBits[0].base);
Carl Shapirod25566d2010-03-11 20:39:47 -08001190 } else {
1191 numSweepBitmaps = numBitmaps;
1192 }
Barry Hayese168ebd2010-05-07 09:19:46 -07001193 for (i = 0; i < numSweepBitmaps; i++) {
1194 dvmHeapBitmapXorWalk(&markBits[i], &liveBits[i],
1195 sweepBitmapCallback, NULL);
1196 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001197
1198 *numFreed = origObjectsAllocated -
1199 dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0);
1200 *sizeFreed = origBytesAllocated -
1201 dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
1202
1203#ifdef WITH_PROFILER
1204 if (gDvm.allocProf.enabled) {
1205 gDvm.allocProf.freeCount += *numFreed;
1206 gDvm.allocProf.freeSize += *sizeFreed;
1207 }
1208#endif
1209}