blob: fe8550dc280cdd4c6e212e6662974fe180cd1ae7 [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
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080032#define LOGD_GC(...) ((void)0)
33#else
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080034#define LOGD_GC(...) LOG(LOG_DEBUG, GC_LOG_TAG, __VA_ARGS__)
35#endif
36
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080037#define LOGE_GC(...) LOG(LOG_ERROR, GC_LOG_TAG, __VA_ARGS__)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080038
Carl Shapiro7ec91442010-10-21 15:35:19 -070039#define ALIGN_DOWN(x, n) ((size_t)(x) & -(n))
Carl Shapiro57ee2702010-08-27 13:06:48 -070040#define ALIGN_UP(x, n) (((size_t)(x) + (n) - 1) & ~((n) - 1))
41#define ALIGN_UP_TO_PAGE_SIZE(p) ALIGN_UP(p, SYSTEM_PAGE_SIZE)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080042
Carl Shapiro7ec91442010-10-21 15:35:19 -070043typedef unsigned long Word;
44const size_t kWordSize = sizeof(Word);
45
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080046/* Do not cast the result of this to a boolean; the only set bit
47 * may be > 1<<8.
48 */
Carl Shapiro6343bd02010-02-16 17:40:19 -080049static inline long isMarked(const void *obj, const GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080050{
Carl Shapirof373efd2010-02-19 00:46:33 -080051 return dvmHeapBitmapIsObjectBitSet(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080052}
53
Carl Shapirofdf80522010-11-09 14:27:02 -080054/*
55 * Initializes the stack top and advises the mark stack pages as needed.
56 */
Carl Shapirod7400e02010-09-02 18:24:29 -070057static bool createMarkStack(GcMarkStack *stack)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080058{
Carl Shapirofdf80522010-11-09 14:27:02 -080059 assert(stack != NULL);
60 size_t length = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
61 (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
62 madvise(stack->base, length, MADV_NORMAL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080063 stack->top = stack->base;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080064 return true;
65}
66
Carl Shapirofdf80522010-11-09 14:27:02 -080067/*
68 * Assigns NULL to the stack top and advises the mark stack pages as
69 * not needed.
70 */
Carl Shapirod7400e02010-09-02 18:24:29 -070071static void destroyMarkStack(GcMarkStack *stack)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080072{
Carl Shapirofdf80522010-11-09 14:27:02 -080073 assert(stack != NULL);
74 madvise(stack->base, stack->length, MADV_DONTNEED);
75 stack->top = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080076}
77
Carl Shapirofdf80522010-11-09 14:27:02 -080078/*
79 * Pops an object from the mark stack.
80 */
81static void markStackPush(GcMarkStack *stack, const Object *obj)
82{
83 assert(stack != NULL);
84 assert(stack->base <= stack->top);
85 assert(stack->limit > stack->top);
86 assert(obj != NULL);
87 *stack->top = obj;
88 ++stack->top;
89}
90
91/*
92 * Pushes an object on the mark stack.
93 */
94static const Object *markStackPop(GcMarkStack *stack)
95{
Carl Shapirofdf80522010-11-09 14:27:02 -080096 assert(stack != NULL);
97 assert(stack->base < stack->top);
98 assert(stack->limit > stack->top);
99 --stack->top;
Carl Shapiro26a82802010-12-01 18:54:19 -0800100 return *stack->top;
Carl Shapirofdf80522010-11-09 14:27:02 -0800101}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800102
Carl Shapirod7400e02010-09-02 18:24:29 -0700103bool dvmHeapBeginMarkStep(GcMode mode)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800104{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700105 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800106
Carl Shapirob2e78d32010-08-20 11:34:18 -0700107 if (!createMarkStack(&ctx->stack)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800108 return false;
109 }
Carl Shapirob2e78d32010-08-20 11:34:18 -0700110 ctx->finger = NULL;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800111 ctx->immuneLimit = (char*)dvmHeapSourceGetImmuneLimit(mode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800112 return true;
113}
114
Carl Shapirod7400e02010-09-02 18:24:29 -0700115static long setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800116{
Carl Shapirof373efd2010-02-19 00:46:33 -0800117 return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800118}
119
Carl Shapirod7400e02010-09-02 18:24:29 -0700120static void markObjectNonNull(const Object *obj, GcMarkContext *ctx,
121 bool checkFinger)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800122{
Barry Hayese1bccb92010-05-18 09:48:37 -0700123 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800124 assert(obj != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800125 assert(dvmIsValidObject(obj));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800126
Carl Shapirob31b3012010-05-25 18:35:37 -0700127 if (obj < (Object *)ctx->immuneLimit) {
Carl Shapirod25566d2010-03-11 20:39:47 -0800128 assert(isMarked(obj, ctx));
129 return;
130 }
Carl Shapiro6343bd02010-02-16 17:40:19 -0800131 if (!setAndReturnMarkBit(ctx, obj)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800132 /* This object was not previously marked.
133 */
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700134 if (checkFinger && (void *)obj < ctx->finger) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800135 /* This object will need to go on the mark stack.
136 */
Carl Shapirofdf80522010-11-09 14:27:02 -0800137 markStackPush(&ctx->stack, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800138 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800139 }
140}
141
142/* Used to mark objects when recursing. Recursion is done by moving
143 * the finger across the bitmaps in address order and marking child
144 * objects. Any newly-marked objects whose addresses are lower than
145 * the finger won't be visited by the bitmap scan, so those objects
146 * need to be added to the mark stack.
147 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700148static void markObject(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800149{
Barry Hayese1bccb92010-05-18 09:48:37 -0700150 if (obj != NULL) {
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700151 markObjectNonNull(obj, ctx, true);
Barry Hayese1bccb92010-05-18 09:48:37 -0700152 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800153}
154
Carl Shapiro6d4ce5e2010-12-02 16:16:01 -0800155/*
156 * Callback applied to root references during the initial root
157 * marking. Visited roots are always marked but are only pushed on
158 * the mark stack if their address is below the finger.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800159 */
Carl Shapiro6d4ce5e2010-12-02 16:16:01 -0800160static void rootMarkObjectVisitor(void *addr, RootType type, u4 thread, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800161{
Carl Shapiro6d4ce5e2010-12-02 16:16:01 -0800162 Object *obj;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800163 GcMarkContext *ctx;
Carl Shapiro6d4ce5e2010-12-02 16:16:01 -0800164
165 assert(addr != NULL);
166 assert(arg != NULL);
167 obj = *(Object **)addr;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800168 ctx = (GcMarkContext *)arg;
Carl Shapiro6d4ce5e2010-12-02 16:16:01 -0800169 if (obj != NULL) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800170 markObjectNonNull(obj, ctx, false);
Carl Shapiro6d4ce5e2010-12-02 16:16:01 -0800171 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800172}
173
174/* Mark the set of root objects.
175 *
176 * Things we need to scan:
177 * - System classes defined by root classloader
178 * - For each thread:
179 * - Interpreted stack, from top to "curFrame"
180 * - Dalvik registers (args + local vars)
181 * - JNI local references
182 * - Automatic VM local references (TrackedAlloc)
183 * - Associated Thread/VMThread object
184 * - ThreadGroups (could track & start with these instead of working
185 * upward from Threads)
186 * - Exception currently being thrown, if present
187 * - JNI global references
188 * - Interned string table
189 * - Primitive classes
190 * - Special objects
191 * - gDvm.outOfMemoryObj
192 * - Objects allocated with ALLOC_NO_GC
193 * - Objects pending finalization (but not yet finalized)
194 * - Objects in debugger object registry
195 *
196 * Don't need:
197 * - Native stack (for in-progress stuff in the VM)
198 * - The TrackedAlloc stuff watches all native VM references.
199 */
200void dvmHeapMarkRootSet()
201{
Barry Hayesd4f78d32010-06-08 09:34:42 -0700202 GcHeap *gcHeap = gDvm.gcHeap;
Barry Hayes425848f2010-05-04 13:32:12 -0700203 dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
Carl Shapiro6d4ce5e2010-12-02 16:16:01 -0800204 dvmVisitRoots(rootMarkObjectVisitor, &gcHeap->markContext);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800205}
206
207/*
Carl Shapiro6d4ce5e2010-12-02 16:16:01 -0800208 * Callback applied to root references during root remarking. If the
209 * root location contains a white reference it is pushed on the mark
210 * stack and grayed.
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700211 */
Carl Shapiro07018e22010-10-26 21:07:41 -0700212static void markObjectVisitor(void *addr, RootType type, u4 thread, void *arg)
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700213{
214 Object *obj;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800215 GcMarkContext *ctx;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700216
217 assert(addr != NULL);
218 assert(arg != NULL);
219 obj = *(Object **)addr;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800220 ctx = (GcMarkContext *)arg;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700221 if (obj != NULL) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800222 markObjectNonNull(obj, ctx, true);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700223 }
224}
225
226/*
227 * Grays all references in the roots.
228 */
229void dvmHeapReMarkRootSet(void)
230{
231 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
232 assert(ctx->finger == (void *)ULONG_MAX);
233 dvmVisitRoots(markObjectVisitor, ctx);
234}
235
236/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700237 * Scans instance fields.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800238 */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800239static void scanFields(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800240{
Barry Hayese1bccb92010-05-18 09:48:37 -0700241 assert(obj != NULL);
242 assert(obj->clazz != NULL);
243 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800244
Barry Hayese1bccb92010-05-18 09:48:37 -0700245 if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
246 unsigned int refOffsets = obj->clazz->refOffsets;
Barry Hayeseac47ed2009-06-22 11:45:20 -0700247 while (refOffsets != 0) {
Carl Shapiro3e24d332010-11-29 17:24:50 -0800248 size_t rshift = CLZ(refOffsets);
249 size_t offset = CLASS_OFFSET_FROM_CLZ(rshift);
250 Object *ref = dvmGetFieldObject((Object*)obj, offset);
251 markObject(ref, ctx);
Barry Hayeseac47ed2009-06-22 11:45:20 -0700252 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800253 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700254 } else {
Barry Hayese1bccb92010-05-18 09:48:37 -0700255 ClassObject *clazz;
Barry Hayese1bccb92010-05-18 09:48:37 -0700256 for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
257 InstField *field = clazz->ifields;
Carl Shapiro3e24d332010-11-29 17:24:50 -0800258 int i;
Barry Hayese1bccb92010-05-18 09:48:37 -0700259 for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
260 void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800261 Object *ref = (Object *)((JValue *)addr)->l;
262 markObject(ref, ctx);
Barry Hayeseac47ed2009-06-22 11:45:20 -0700263 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700264 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800265 }
266}
267
Barry Hayese1bccb92010-05-18 09:48:37 -0700268/*
Carl Shapiro3e24d332010-11-29 17:24:50 -0800269 * Scans the static fields of a class object.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800270 */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800271static void scanStaticFields(const ClassObject *clazz, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800272{
Barry Hayese1bccb92010-05-18 09:48:37 -0700273 int i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800274
Carl Shapiro3e24d332010-11-29 17:24:50 -0800275 assert(clazz != NULL);
Barry Hayese1bccb92010-05-18 09:48:37 -0700276 assert(ctx != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800277 for (i = 0; i < clazz->sfieldCount; ++i) {
278 char ch = clazz->sfields[i].field.signature[0];
279 if (ch == '[' || ch == 'L') {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800280 Object *obj = (Object *)clazz->sfields[i].value.l;
281 markObject(obj, ctx);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800282 }
283 }
284}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800285
Carl Shapiro3e24d332010-11-29 17:24:50 -0800286/*
287 * Visit the interfaces of a class object.
288 */
289static void scanInterfaces(const ClassObject *clazz, GcMarkContext *ctx)
290{
291 int i;
292
293 assert(clazz != NULL);
294 assert(ctx != NULL);
295 for (i = 0; i < clazz->interfaceCount; ++i) {
296 markObject((const Object *)clazz->interfaces[i], ctx);
297 }
298}
299
300/*
301 * Scans the header, static field references, and interface
302 * pointers of a class object.
303 */
304static void scanClassObject(const Object *obj, GcMarkContext *ctx)
305{
306 const ClassObject *asClass;
307
308 assert(obj != NULL);
309 assert(obj->clazz == gDvm.classJavaLangClass);
310 assert(ctx != NULL);
311 markObject((const Object *)obj->clazz, ctx);
312 asClass = (const ClassObject *)obj;
313 if (IS_CLASS_FLAG_SET(asClass, CLASS_ISARRAY)) {
314 markObject((const Object *)asClass->elementClass, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700315 }
Barry Hayesc49db852010-05-14 13:43:34 -0700316 /* Do super and the interfaces contain Objects and not dex idx values? */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800317 if (asClass->status > CLASS_IDX) {
318 markObject((const Object *)asClass->super, ctx);
Barry Hayesc49db852010-05-14 13:43:34 -0700319 }
Carl Shapiro3e24d332010-11-29 17:24:50 -0800320 markObject((const Object *)asClass->classLoader, ctx);
321 scanFields(obj, ctx);
322 scanStaticFields(asClass, ctx);
323 if (asClass->status > CLASS_IDX) {
324 scanInterfaces(asClass, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800325 }
326}
327
Barry Hayese1bccb92010-05-18 09:48:37 -0700328/*
329 * Scans the header of all array objects. If the array object is
330 * specialized to a reference type, scans the array data as well.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800331 */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800332static void scanArrayObject(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800333{
Barry Hayese1bccb92010-05-18 09:48:37 -0700334 assert(obj != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800335 assert(obj->clazz != NULL);
Barry Hayese1bccb92010-05-18 09:48:37 -0700336 assert(ctx != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800337 markObject((const Object *)obj->clazz, ctx);
338 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISOBJECTARRAY)) {
339 const ArrayObject *array = (const ArrayObject *)obj;
340 const Object **contents = (const Object **)array->contents;
341 size_t i;
342 for (i = 0; i < array->length; ++i) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700343 markObject(contents[i], ctx);
344 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800345 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700346}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800347
Barry Hayese1bccb92010-05-18 09:48:37 -0700348/*
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700349 * Returns class flags relating to Reference subclasses.
350 */
351static int referenceClassFlags(const Object *obj)
352{
353 int flags = CLASS_ISREFERENCE |
354 CLASS_ISWEAKREFERENCE |
355 CLASS_ISPHANTOMREFERENCE;
356 return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
357}
358
359/*
360 * Returns true if the object derives from SoftReference.
361 */
362static bool isSoftReference(const Object *obj)
363{
364 return referenceClassFlags(obj) == CLASS_ISREFERENCE;
365}
366
367/*
368 * Returns true if the object derives from WeakReference.
369 */
370static bool isWeakReference(const Object *obj)
371{
372 return referenceClassFlags(obj) & CLASS_ISWEAKREFERENCE;
373}
374
375/*
376 * Returns true if the object derives from PhantomReference.
377 */
378static bool isPhantomReference(const Object *obj)
379{
380 return referenceClassFlags(obj) & CLASS_ISPHANTOMREFERENCE;
381}
382
383/*
384 * Adds a reference to the tail of a circular queue of references.
385 */
386static void enqueuePendingReference(Object *ref, Object **list)
387{
388 size_t offset;
389
390 assert(ref != NULL);
391 assert(list != NULL);
392 offset = gDvm.offJavaLangRefReference_pendingNext;
393 if (*list == NULL) {
394 dvmSetFieldObject(ref, offset, ref);
395 *list = ref;
396 } else {
397 Object *head = dvmGetFieldObject(*list, offset);
398 dvmSetFieldObject(ref, offset, head);
399 dvmSetFieldObject(*list, offset, ref);
400 }
401}
402
403/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700404 * Removes the reference at the head of a circular queue of
405 * references.
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700406 */
407static Object *dequeuePendingReference(Object **list)
408{
409 Object *ref, *head;
410 size_t offset;
411
412 assert(list != NULL);
413 assert(*list != NULL);
414 offset = gDvm.offJavaLangRefReference_pendingNext;
415 head = dvmGetFieldObject(*list, offset);
416 if (*list == head) {
417 ref = *list;
418 *list = NULL;
419 } else {
420 Object *next = dvmGetFieldObject(head, offset);
421 dvmSetFieldObject(*list, offset, next);
422 ref = head;
423 }
424 dvmSetFieldObject(ref, offset, NULL);
425 return ref;
426}
427
428/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700429 * Process the "referent" field in a java.lang.ref.Reference. If the
430 * referent has not yet been marked, put it on the appropriate list in
431 * the gcHeap for later processing.
432 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700433static void delayReferenceReferent(Object *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700434{
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700435 GcHeap *gcHeap = gDvm.gcHeap;
436 Object *pending, *referent;
437 size_t pendingNextOffset, referentOffset;
438
Barry Hayese1bccb92010-05-18 09:48:37 -0700439 assert(obj != NULL);
Barry Hayes697b5a92010-06-23 11:38:52 -0700440 assert(obj->clazz != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700441 assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
Barry Hayese1bccb92010-05-18 09:48:37 -0700442 assert(ctx != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700443 pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
444 referentOffset = gDvm.offJavaLangRefReference_referent;
445 pending = dvmGetFieldObject(obj, pendingNextOffset);
446 referent = dvmGetFieldObject(obj, referentOffset);
447 if (pending == NULL && referent != NULL && !isMarked(referent, ctx)) {
448 Object **list = NULL;
449 if (isSoftReference(obj)) {
450 list = &gcHeap->softReferences;
451 } else if (isWeakReference(obj)) {
452 list = &gcHeap->weakReferences;
453 } else if (isPhantomReference(obj)) {
454 list = &gcHeap->phantomReferences;
Barry Hayese1bccb92010-05-18 09:48:37 -0700455 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700456 assert(list != NULL);
457 enqueuePendingReference(obj, list);
Barry Hayese1bccb92010-05-18 09:48:37 -0700458 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800459}
460
Barry Hayese1bccb92010-05-18 09:48:37 -0700461/*
462 * Scans the header and field references of a data object.
463 */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800464static void scanDataObject(const Object *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700465{
466 assert(obj != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800467 assert(obj->clazz != NULL);
Barry Hayese1bccb92010-05-18 09:48:37 -0700468 assert(ctx != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800469 markObject((const Object *)obj->clazz, ctx);
470 scanFields(obj, ctx);
471 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE)) {
Barry Hayes697b5a92010-06-23 11:38:52 -0700472 delayReferenceReferent((Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700473 }
474}
475
476/*
477 * Scans an object reference. Determines the type of the reference
478 * and dispatches to a specialized scanning routine.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800479 */
480static void scanObject(const Object *obj, GcMarkContext *ctx)
481{
Barry Hayese1bccb92010-05-18 09:48:37 -0700482 assert(obj != NULL);
483 assert(ctx != NULL);
Barry Hayes899cdb72010-06-08 09:59:12 -0700484 assert(obj->clazz != NULL);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700485 if (obj->clazz == gDvm.classJavaLangClass) {
Carl Shapiro3e24d332010-11-29 17:24:50 -0800486 scanClassObject(obj, ctx);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700487 } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
Carl Shapiro3e24d332010-11-29 17:24:50 -0800488 scanArrayObject(obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800489 } else {
Carl Shapiro3e24d332010-11-29 17:24:50 -0800490 scanDataObject(obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800491 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800492}
493
Carl Shapirofdf80522010-11-09 14:27:02 -0800494/*
495 * Scan anything that's on the mark stack. We can't use the bitmaps
496 * anymore, so use a finger that points past the end of them.
497 */
498static void processMarkStack(GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800499{
Carl Shapirofdf80522010-11-09 14:27:02 -0800500 GcMarkStack *stack;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800501
Carl Shapirofdf80522010-11-09 14:27:02 -0800502 assert(ctx != NULL);
Carl Shapiro034fba52010-11-11 16:39:58 -0800503 assert(ctx->finger == (void *)ULONG_MAX);
Carl Shapirofdf80522010-11-09 14:27:02 -0800504 stack = &ctx->stack;
505 assert(stack->top >= stack->base);
506 while (stack->top > stack->base) {
507 const Object *obj = markStackPop(stack);
508 scanObject(obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800509 }
510}
511
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700512static size_t objectSize(const Object *obj)
513{
514 assert(dvmIsValidObject(obj));
515 assert(dvmIsValidObject((Object *)obj->clazz));
516 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
517 return dvmArrayObjectSize((ArrayObject *)obj);
518 } else if (obj->clazz == gDvm.classJavaLangClass) {
519 return dvmClassObjectSize((ClassObject *)obj);
520 } else {
521 return obj->clazz->objectSize;
522 }
523}
524
525/*
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700526 * Scans forward to the header of the next marked object between start
527 * and limit. Returns NULL if no marked objects are in that region.
528 */
Carl Shapiro7ec91442010-10-21 15:35:19 -0700529static Object *nextGrayObject(const u1 *base, const u1 *limit,
530 const HeapBitmap *markBits)
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700531{
Carl Shapiro7ec91442010-10-21 15:35:19 -0700532 const u1 *ptr;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700533
534 assert(base < limit);
535 assert(limit - base <= GC_CARD_SIZE);
536 for (ptr = base; ptr < limit; ptr += HB_OBJECT_ALIGNMENT) {
Carl Shapiroea10c552010-09-02 23:32:25 -0700537 if (dvmHeapBitmapIsObjectBitSet(markBits, ptr))
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700538 return (Object *)ptr;
539 }
540 return NULL;
541}
542
543/*
Carl Shapiro7ec91442010-10-21 15:35:19 -0700544 * Scans each byte from start below end returning the address of the
545 * first dirty card. Returns NULL if no dirty card is found.
546 */
547static const u1 *scanBytesForDirtyCard(const u1 *start, const u1 *end)
548{
549 const u1 *ptr;
550
551 assert(start <= end);
552 for (ptr = start; ptr < end; ++ptr) {
553 if (*ptr == GC_CARD_DIRTY) {
554 return ptr;
555 }
556 }
557 return NULL;
558}
559
560/*
561 * Like scanBytesForDirtyCard but scans the range from start below end
562 * by words. Assumes start and end are word aligned.
563 */
564static const u1 *scanWordsForDirtyCard(const u1 *start, const u1 *end)
565{
566 const u1 *ptr;
567
568 assert((uintptr_t)start % kWordSize == 0);
569 assert((uintptr_t)end % kWordSize == 0);
570 assert(start <= end);
571 for (ptr = start; ptr < end; ptr += kWordSize) {
572 if (*(const Word *)ptr != 0) {
573 const u1 *dirty = scanBytesForDirtyCard(ptr, ptr + kWordSize);
574 if (dirty != NULL) {
575 return dirty;
576 }
577 }
578 }
579 return NULL;
580}
581
582/*
583 * Scans the card table as quickly as possible looking for a dirty
584 * card. Returns the address of the first dirty card found or NULL if
585 * no dirty cards were found.
586 */
587static const u1 *nextDirtyCard(const u1 *start, const u1 *end)
588{
589 const u1 *wstart = (u1 *)ALIGN_UP(start, kWordSize);
590 const u1 *wend = (u1 *)ALIGN_DOWN(end, kWordSize);
591 const u1 *ptr, *dirty;
592
593 assert(start <= end);
594 assert(start <= wstart);
595 assert(end >= wend);
596 ptr = start;
597 if (wstart < end) {
598 /* Scan the leading unaligned bytes. */
599 dirty = scanBytesForDirtyCard(ptr, wstart);
600 if (dirty != NULL) {
601 return dirty;
602 }
603 /* Scan the range of aligned words. */
604 dirty = scanWordsForDirtyCard(wstart, wend);
605 if (dirty != NULL) {
606 return dirty;
607 }
608 ptr = wend;
609 }
610 /* Scan trailing unaligned bytes. */
611 dirty = scanBytesForDirtyCard(ptr, end);
612 if (dirty != NULL) {
613 return dirty;
614 }
615 return NULL;
616}
617
618/*
619 * Scans range of dirty cards between start and end. A range of dirty
620 * cards is composed consecutively dirty cards or dirty cards spanned
621 * by a gray object. Returns the address of a clean card if the scan
622 * reached a clean card or NULL if the scan reached the end.
623 */
624const u1 *scanDirtyCards(const u1 *start, const u1 *end,
625 GcMarkContext *ctx)
626{
627 const HeapBitmap *markBits = ctx->bitmap;
628 const u1 *card = start, *prevAddr = NULL;
629 while (card < end) {
630 if (*card != GC_CARD_DIRTY) {
631 return card;
632 }
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800633 const u1 *ptr = prevAddr ? prevAddr : (u1*)dvmAddrFromCard(card);
Carl Shapiro7ec91442010-10-21 15:35:19 -0700634 const u1 *limit = ptr + GC_CARD_SIZE;
635 while (ptr < limit) {
636 Object *obj = nextGrayObject(ptr, limit, markBits);
637 if (obj == NULL) {
638 break;
639 }
640 scanObject(obj, ctx);
641 ptr = (u1*)obj + ALIGN_UP(objectSize(obj), HB_OBJECT_ALIGNMENT);
642 }
643 if (ptr < limit) {
644 /* Ended within the current card, advance to the next card. */
645 ++card;
646 prevAddr = NULL;
647 } else {
648 /* Ended past the current card, skip ahead. */
649 card = dvmCardFromAddr(ptr);
650 prevAddr = ptr;
651 }
652 }
653 return NULL;
654}
655
656/*
657 * Blackens gray objects found on dirty cards.
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700658 */
659static void scanGrayObjects(GcMarkContext *ctx)
660{
661 GcHeap *h = gDvm.gcHeap;
Carl Shapiro7ec91442010-10-21 15:35:19 -0700662 const u1 *base, *limit, *ptr, *dirty;
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700663 size_t footprint;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700664
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700665 footprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
Carl Shapiro7ec91442010-10-21 15:35:19 -0700666 base = &h->cardTableBase[0];
667 limit = dvmCardFromAddr((u1 *)dvmHeapSourceGetBase() + footprint);
668 assert(limit <= &h->cardTableBase[h->cardTableLength]);
669
670 ptr = base;
671 for (;;) {
672 dirty = nextDirtyCard(ptr, limit);
673 if (dirty == NULL) {
674 break;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700675 }
Carl Shapiro7ec91442010-10-21 15:35:19 -0700676 assert((dirty > ptr) && (dirty < limit));
677 ptr = scanDirtyCards(dirty, limit, ctx);
678 if (ptr == NULL) {
679 break;
680 }
681 assert((ptr > dirty) && (ptr < limit));
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700682 }
683}
684
Carl Shapiro57ee2702010-08-27 13:06:48 -0700685/*
686 * Callback for scanning each object in the bitmap. The finger is set
687 * to the address corresponding to the lowest address in the next word
688 * of bits in the bitmap.
689 */
Carl Shapiro38d710b2010-08-31 16:48:31 -0700690static void scanBitmapCallback(void *addr, void *finger, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800691{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800692 GcMarkContext *ctx = (GcMarkContext *)arg;
Carl Shapiro57ee2702010-08-27 13:06:48 -0700693 ctx->finger = (void *)finger;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800694 scanObject((Object *)addr, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800695}
696
697/* Given bitmaps with the root set marked, find and mark all
698 * reachable objects. When this returns, the entire set of
699 * live objects will be marked and the mark stack will be empty.
700 */
Carl Shapiro29540742010-03-26 15:34:39 -0700701void dvmHeapScanMarkedObjects(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800702{
703 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
704
705 assert(ctx->finger == NULL);
706
707 /* The bitmaps currently have bits set for the root set.
708 * Walk across the bitmaps and scan each object.
709 */
Carl Shapiro38d710b2010-08-31 16:48:31 -0700710 dvmHeapBitmapScanWalk(ctx->bitmap, scanBitmapCallback, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800711
Carl Shapiro034fba52010-11-11 16:39:58 -0800712 ctx->finger = (void *)ULONG_MAX;
713
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800714 /* We've walked the mark bitmaps. Scan anything that's
715 * left on the mark stack.
716 */
717 processMarkStack(ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800718}
719
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700720void dvmHeapReScanMarkedObjects(void)
Carl Shapiroec805ea2010-06-28 16:28:26 -0700721{
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700722 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700723
Carl Shapiroec805ea2010-06-28 16:28:26 -0700724 /*
Carl Shapirof5860332010-06-28 23:02:08 -0700725 * The finger must have been set to the maximum value to ensure
726 * that gray objects will be pushed onto the mark stack.
Carl Shapiroec805ea2010-06-28 16:28:26 -0700727 */
728 assert(ctx->finger == (void *)ULONG_MAX);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700729 scanGrayObjects(ctx);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700730 processMarkStack(ctx);
731}
732
Carl Shapiro34f51992010-07-09 17:55:41 -0700733/*
734 * Clear the referent field.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800735 */
Barry Hayes6930a112009-12-22 11:01:38 -0800736static void clearReference(Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800737{
Carl Shapiro34f51992010-07-09 17:55:41 -0700738 size_t offset = gDvm.offJavaLangRefReference_referent;
739 dvmSetFieldObject(reference, offset, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800740}
741
Carl Shapiro29540742010-03-26 15:34:39 -0700742/*
743 * Returns true if the reference was registered with a reference queue
744 * and has not yet been enqueued.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800745 */
Carl Shapiro29540742010-03-26 15:34:39 -0700746static bool isEnqueuable(const Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800747{
Barry Hayes6930a112009-12-22 11:01:38 -0800748 Object *queue = dvmGetFieldObject(reference,
749 gDvm.offJavaLangRefReference_queue);
750 Object *queueNext = dvmGetFieldObject(reference,
751 gDvm.offJavaLangRefReference_queueNext);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700752 return queue != NULL && queueNext == NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800753}
754
Carl Shapiro29540742010-03-26 15:34:39 -0700755/*
756 * Schedules a reference to be appended to its reference queue.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800757 */
Carl Shapiro29540742010-03-26 15:34:39 -0700758static void enqueueReference(Object *ref)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800759{
Carl Shapiro646ba092010-06-10 15:17:00 -0700760 assert(ref != NULL);
Carl Shapiro29540742010-03-26 15:34:39 -0700761 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
762 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
Carl Shapiro646ba092010-06-10 15:17:00 -0700763 if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
Carl Shapiro29540742010-03-26 15:34:39 -0700764 LOGE_HEAP("enqueueReference(): no room for any more "
765 "reference operations\n");
766 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800767 }
768}
769
Carl Shapiro29540742010-03-26 15:34:39 -0700770/*
771 * Walks the reference list marking any references subject to the
772 * reference clearing policy. References with a black referent are
773 * removed from the list. References with white referents biased
774 * toward saving are blackened and also removed from the list.
775 */
Carl Shapiroe8ef2b52010-12-01 19:32:05 -0800776static void preserveSomeSoftReferences(Object **list)
Carl Shapiro29540742010-03-26 15:34:39 -0700777{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700778 GcMarkContext *ctx;
Carl Shapiro29540742010-03-26 15:34:39 -0700779 Object *ref, *referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700780 Object *clear;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700781 size_t referentOffset;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700782 size_t counter;
Carl Shapiro29540742010-03-26 15:34:39 -0700783 bool marked;
784
Carl Shapirob2e78d32010-08-20 11:34:18 -0700785 ctx = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700786 referentOffset = gDvm.offJavaLangRefReference_referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700787 clear = NULL;
Carl Shapiro29540742010-03-26 15:34:39 -0700788 counter = 0;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700789 while (*list != NULL) {
790 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700791 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700792 assert(referent != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700793 marked = isMarked(referent, ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700794 if (!marked && ((++counter) & 1)) {
795 /* Referent is white and biased toward saving, mark it. */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700796 markObject(referent, ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700797 marked = true;
798 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700799 if (!marked) {
800 /* Referent is white, queue it for clearing. */
801 enqueuePendingReference(ref, &clear);
Carl Shapiro29540742010-03-26 15:34:39 -0700802 }
Carl Shapiro29540742010-03-26 15:34:39 -0700803 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700804 *list = clear;
Carl Shapiro29540742010-03-26 15:34:39 -0700805 /*
806 * Restart the mark with the newly black references added to the
807 * root set.
808 */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700809 processMarkStack(ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700810}
811
812/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700813 * Unlink the reference list clearing references objects with white
814 * referents. Cleared references registered to a reference queue are
815 * scheduled for appending by the heap worker thread.
Carl Shapiro29540742010-03-26 15:34:39 -0700816 */
Carl Shapiroe8ef2b52010-12-01 19:32:05 -0800817static void clearWhiteReferences(Object **list)
Carl Shapiro29540742010-03-26 15:34:39 -0700818{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700819 GcMarkContext *ctx;
Carl Shapiro29540742010-03-26 15:34:39 -0700820 Object *ref, *referent;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700821 size_t referentOffset;
Carl Shapiro29540742010-03-26 15:34:39 -0700822 bool doSignal;
823
Carl Shapirob2e78d32010-08-20 11:34:18 -0700824 ctx = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700825 referentOffset = gDvm.offJavaLangRefReference_referent;
826 doSignal = false;
827 while (*list != NULL) {
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700828 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700829 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700830 assert(referent != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700831 if (!isMarked(referent, ctx)) {
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700832 /* Referent is white, clear it. */
Carl Shapiro29540742010-03-26 15:34:39 -0700833 clearReference(ref);
834 if (isEnqueuable(ref)) {
835 enqueueReference(ref);
836 doSignal = true;
837 }
838 }
839 }
840 /*
841 * If we cleared a reference with a reference queue we must notify
842 * the heap worker to append the reference.
843 */
844 if (doSignal) {
845 dvmSignalHeapWorker(false);
846 }
847 assert(*list == NULL);
848}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800849
850/* Find unreachable objects that need to be finalized,
851 * and schedule them for finalization.
852 */
Carl Shapiroe8ef2b52010-12-01 19:32:05 -0800853static void scheduleFinalizations(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800854{
855 HeapRefTable newPendingRefs;
856 LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
857 Object **ref;
858 Object **lastRef;
859 size_t totalPendCount;
Carl Shapirob2e78d32010-08-20 11:34:18 -0700860 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800861
862 /*
863 * All reachable objects have been marked.
864 * Any unmarked finalizable objects need to be finalized.
865 */
866
867 /* Create a table that the new pending refs will
868 * be added to.
869 */
Barry Hayesd4f78d32010-06-08 09:34:42 -0700870 if (!dvmHeapInitHeapRefTable(&newPendingRefs)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800871 //TODO: mark all finalizable refs and hope that
872 // we can schedule them next time. Watch out,
873 // because we may be expecting to free up space
874 // by calling finalizers.
Carl Shapiroe8ef2b52010-12-01 19:32:05 -0800875 LOGE_GC("scheduleFinalizations(): no room for "
876 "pending finalizations");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800877 dvmAbort();
878 }
879
880 /* Walk through finalizableRefs and move any unmarked references
881 * to the list of new pending refs.
882 */
883 totalPendCount = 0;
884 while (finRefs != NULL) {
885 Object **gapRef;
886 size_t newPendCount = 0;
887
888 gapRef = ref = finRefs->refs.table;
889 lastRef = finRefs->refs.nextEntry;
890 while (ref < lastRef) {
Carl Shapirob2e78d32010-08-20 11:34:18 -0700891 if (!isMarked(*ref, ctx)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800892 if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
893 //TODO: add the current table and allocate
894 // a new, smaller one.
Carl Shapiroe8ef2b52010-12-01 19:32:05 -0800895 LOGE_GC("scheduleFinalizations(): "
896 "no room for any more pending finalizations: %zd",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800897 dvmHeapNumHeapRefTableEntries(&newPendingRefs));
898 dvmAbort();
899 }
900 newPendCount++;
901 } else {
902 /* This ref is marked, so will remain on finalizableRefs.
903 */
904 if (newPendCount > 0) {
905 /* Copy it up to fill the holes.
906 */
907 *gapRef++ = *ref;
908 } else {
909 /* No holes yet; don't bother copying.
910 */
911 gapRef++;
912 }
913 }
914 ref++;
915 }
916 finRefs->refs.nextEntry = gapRef;
917 //TODO: if the table is empty when we're done, free it.
918 totalPendCount += newPendCount;
919 finRefs = finRefs->next;
920 }
Carl Shapiroe8ef2b52010-12-01 19:32:05 -0800921 LOGD_GC("scheduleFinalizations(): %zd finalizers triggered.",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800922 totalPendCount);
923 if (totalPendCount == 0) {
924 /* No objects required finalization.
925 * Free the empty temporary table.
926 */
927 dvmClearReferenceTable(&newPendingRefs);
928 return;
929 }
930
931 /* Add the new pending refs to the main list.
932 */
933 if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
934 &newPendingRefs))
935 {
Carl Shapiroe8ef2b52010-12-01 19:32:05 -0800936 LOGE_GC("scheduleFinalizations(): can't insert new "
937 "pending finalizations");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800938 dvmAbort();
939 }
940
941 //TODO: try compacting the main list with a memcpy loop
942
943 /* Mark the refs we just moved; we don't want them or their
944 * children to get swept yet.
945 */
946 ref = newPendingRefs.table;
947 lastRef = newPendingRefs.nextEntry;
948 assert(ref < lastRef);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800949 while (ref < lastRef) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700950 assert(*ref != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700951 markObject(*ref, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800952 ref++;
953 }
Carl Shapirob2e78d32010-08-20 11:34:18 -0700954 processMarkStack(ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800955 dvmSignalHeapWorker(false);
956}
957
Carl Shapiroe8ef2b52010-12-01 19:32:05 -0800958/*
959 * Process reference class instances and schedule finalizations.
960 */
961void dvmHeapProcessReferences(Object **softReferences, bool clearSoftRefs,
962 Object **weakReferences,
963 Object **phantomReferences)
964{
965 assert(softReferences != NULL);
966 assert(weakReferences != NULL);
967 assert(phantomReferences != NULL);
968 /*
969 * Unless we are required to clear soft references with white
970 * references, preserve some white referents.
971 */
972 if (!clearSoftRefs) {
973 preserveSomeSoftReferences(softReferences);
974 }
975 /*
976 * Clear all remaining soft and weak references with white
977 * referents.
978 */
979 clearWhiteReferences(softReferences);
980 clearWhiteReferences(weakReferences);
981 /*
982 * Preserve all white objects with finalize methods and schedule
983 * them for finalization.
984 */
985 scheduleFinalizations();
986 /*
987 * Clear all f-reachable soft and weak references with white
988 * referents.
989 */
990 clearWhiteReferences(softReferences);
991 clearWhiteReferences(weakReferences);
992 /*
993 * Clear all phantom references with white referents.
994 */
995 clearWhiteReferences(phantomReferences);
996 /*
997 * At this point all reference lists should be empty.
998 */
999 assert(*softReferences == NULL);
1000 assert(*weakReferences == NULL);
1001 assert(*phantomReferences == NULL);
1002}
1003
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001004void dvmHeapFinishMarkStep()
1005{
Carl Shapirob2e78d32010-08-20 11:34:18 -07001006 GcMarkContext *ctx;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001007
Carl Shapirob2e78d32010-08-20 11:34:18 -07001008 ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001009
Barry Hayes81010a42010-07-19 14:07:01 -07001010 /* The mark bits are now not needed.
1011 */
1012 dvmHeapSourceZeroMarkBitmap();
1013
Carl Shapirof373efd2010-02-19 00:46:33 -08001014 /* Clean up everything else associated with the marking process.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001015 */
Carl Shapirob2e78d32010-08-20 11:34:18 -07001016 destroyMarkStack(&ctx->stack);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001017
Carl Shapirob2e78d32010-08-20 11:34:18 -07001018 ctx->finger = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001019}
1020
Carl Shapiro8881a802010-08-10 15:55:45 -07001021typedef struct {
1022 size_t numObjects;
1023 size_t numBytes;
1024 bool isConcurrent;
1025} SweepContext;
1026
Carl Shapiro57ee2702010-08-27 13:06:48 -07001027static void sweepBitmapCallback(size_t numPtrs, void **ptrs, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001028{
Carl Shapirofc75f3e2010-12-07 11:43:38 -08001029 SweepContext *ctx = (SweepContext *)arg;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001030
Carl Shapiro8881a802010-08-10 15:55:45 -07001031 if (ctx->isConcurrent) {
1032 dvmLockHeap();
1033 }
1034 ctx->numBytes += dvmHeapSourceFreeList(numPtrs, ptrs);
1035 ctx->numObjects += numPtrs;
1036 if (ctx->isConcurrent) {
1037 dvmUnlockHeap();
1038 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001039}
1040
Carl Shapiro8881a802010-08-10 15:55:45 -07001041/*
1042 * Returns true if the given object is unmarked. This assumes that
1043 * the bitmaps have not yet been swapped.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001044 */
1045static int isUnmarkedObject(void *object)
1046{
Carl Shapiro6343bd02010-02-16 17:40:19 -08001047 return !isMarked((void *)((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001048 &gDvm.gcHeap->markContext);
1049}
1050
Carl Shapiro8881a802010-08-10 15:55:45 -07001051/*
1052 * Process all the internal system structures that behave like
1053 * weakly-held objects.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001054 */
Carl Shapiro8881a802010-08-10 15:55:45 -07001055void dvmHeapSweepSystemWeaks(void)
1056{
1057 dvmGcDetachDeadInternedStrings(isUnmarkedObject);
1058 dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
1059}
1060
1061/*
1062 * Walk through the list of objects that haven't been marked and free
1063 * them. Assumes the bitmaps have been swapped.
1064 */
1065void dvmHeapSweepUnmarkedObjects(GcMode mode, bool isConcurrent,
1066 size_t *numObjects, size_t *numBytes)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001067{
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001068 HeapBitmap currMark[HEAP_SOURCE_MAX_HEAP_COUNT];
1069 HeapBitmap currLive[HEAP_SOURCE_MAX_HEAP_COUNT];
Carl Shapiro8881a802010-08-10 15:55:45 -07001070 SweepContext ctx;
Carl Shapirod25566d2010-03-11 20:39:47 -08001071 size_t numBitmaps, numSweepBitmaps;
Barry Hayese168ebd2010-05-07 09:19:46 -07001072 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001073
Carl Shapirof373efd2010-02-19 00:46:33 -08001074 numBitmaps = dvmHeapSourceGetNumHeaps();
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001075 dvmHeapSourceGetObjectBitmaps(currLive, currMark, numBitmaps);
Carl Shapirod25566d2010-03-11 20:39:47 -08001076 if (mode == GC_PARTIAL) {
1077 numSweepBitmaps = 1;
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001078 assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == currLive[0].base);
Carl Shapirod25566d2010-03-11 20:39:47 -08001079 } else {
1080 numSweepBitmaps = numBitmaps;
1081 }
Carl Shapiro8881a802010-08-10 15:55:45 -07001082 ctx.numObjects = ctx.numBytes = 0;
1083 ctx.isConcurrent = isConcurrent;
Barry Hayese168ebd2010-05-07 09:19:46 -07001084 for (i = 0; i < numSweepBitmaps; i++) {
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001085 HeapBitmap* prevLive = &currMark[i];
1086 HeapBitmap* prevMark = &currLive[i];
1087 dvmHeapBitmapSweepWalk(prevLive, prevMark, sweepBitmapCallback, &ctx);
Barry Hayese168ebd2010-05-07 09:19:46 -07001088 }
Carl Shapiro8881a802010-08-10 15:55:45 -07001089 *numObjects = ctx.numObjects;
1090 *numBytes = ctx.numBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001091 if (gDvm.allocProf.enabled) {
Carl Shapiro8881a802010-08-10 15:55:45 -07001092 gDvm.allocProf.freeCount += ctx.numObjects;
1093 gDvm.allocProf.freeSize += ctx.numBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001094 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001095}