blob: 5a012e8761d31eb3fdb634e1ac43e9ff0263149a [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Dalvik.h"
Barry Hayeseac47ed2009-06-22 11:45:20 -070018#include "alloc/clz.h"
Carl Shapiro7ec91442010-10-21 15:35:19 -070019#include "alloc/CardTable.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080020#include "alloc/HeapBitmap.h"
21#include "alloc/HeapInternal.h"
22#include "alloc/HeapSource.h"
23#include "alloc/MarkSweep.h"
Carl Shapiroec805ea2010-06-28 16:28:26 -070024#include "alloc/Visit.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080025#include <limits.h> // for ULONG_MAX
26#include <sys/mman.h> // for madvise(), mmap()
The Android Open Source Project99409882009-03-18 22:20:24 -070027#include <errno.h>
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080028
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080029#define GC_LOG_TAG LOG_TAG "-gc"
30
31#if LOG_NDEBUG
32#define LOGV_GC(...) ((void)0)
33#define LOGD_GC(...) ((void)0)
34#else
35#define LOGV_GC(...) LOG(LOG_VERBOSE, GC_LOG_TAG, __VA_ARGS__)
36#define LOGD_GC(...) LOG(LOG_DEBUG, GC_LOG_TAG, __VA_ARGS__)
37#endif
38
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080039#define LOGE_GC(...) LOG(LOG_ERROR, GC_LOG_TAG, __VA_ARGS__)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080040#define LOG_SCAN(...) LOGV_GC("SCAN: " __VA_ARGS__)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080041
Carl Shapiro7ec91442010-10-21 15:35:19 -070042#define ALIGN_DOWN(x, n) ((size_t)(x) & -(n))
Carl Shapiro57ee2702010-08-27 13:06:48 -070043#define ALIGN_UP(x, n) (((size_t)(x) + (n) - 1) & ~((n) - 1))
44#define ALIGN_UP_TO_PAGE_SIZE(p) ALIGN_UP(p, SYSTEM_PAGE_SIZE)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080045
Carl Shapiro7ec91442010-10-21 15:35:19 -070046typedef unsigned long Word;
47const size_t kWordSize = sizeof(Word);
48
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080049/* Do not cast the result of this to a boolean; the only set bit
50 * may be > 1<<8.
51 */
Carl Shapiro6343bd02010-02-16 17:40:19 -080052static inline long isMarked(const void *obj, const GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080053{
Carl Shapirof373efd2010-02-19 00:46:33 -080054 return dvmHeapBitmapIsObjectBitSet(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080055}
56
Carl Shapirofdf80522010-11-09 14:27:02 -080057/*
58 * Initializes the stack top and advises the mark stack pages as needed.
59 */
Carl Shapirod7400e02010-09-02 18:24:29 -070060static bool createMarkStack(GcMarkStack *stack)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080061{
Carl Shapirofdf80522010-11-09 14:27:02 -080062 assert(stack != NULL);
63 size_t length = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
64 (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
65 madvise(stack->base, length, MADV_NORMAL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080066 stack->top = stack->base;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080067 return true;
68}
69
Carl Shapirofdf80522010-11-09 14:27:02 -080070/*
71 * Assigns NULL to the stack top and advises the mark stack pages as
72 * not needed.
73 */
Carl Shapirod7400e02010-09-02 18:24:29 -070074static void destroyMarkStack(GcMarkStack *stack)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080075{
Carl Shapirofdf80522010-11-09 14:27:02 -080076 assert(stack != NULL);
77 madvise(stack->base, stack->length, MADV_DONTNEED);
78 stack->top = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080079}
80
Carl Shapirofdf80522010-11-09 14:27:02 -080081/*
82 * Pops an object from the mark stack.
83 */
84static void markStackPush(GcMarkStack *stack, const Object *obj)
85{
86 assert(stack != NULL);
87 assert(stack->base <= stack->top);
88 assert(stack->limit > stack->top);
89 assert(obj != NULL);
90 *stack->top = obj;
91 ++stack->top;
92}
93
94/*
95 * Pushes an object on the mark stack.
96 */
97static const Object *markStackPop(GcMarkStack *stack)
98{
99 const Object *obj;
100
101 assert(stack != NULL);
102 assert(stack->base < stack->top);
103 assert(stack->limit > stack->top);
104 --stack->top;
105 obj = *stack->top;
106 return obj;
107}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800108
Carl Shapirod7400e02010-09-02 18:24:29 -0700109bool dvmHeapBeginMarkStep(GcMode mode)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800110{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700111 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800112
Carl Shapirob2e78d32010-08-20 11:34:18 -0700113 if (!createMarkStack(&ctx->stack)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800114 return false;
115 }
Carl Shapirob2e78d32010-08-20 11:34:18 -0700116 ctx->finger = NULL;
117 ctx->immuneLimit = dvmHeapSourceGetImmuneLimit(mode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800118 return true;
119}
120
Carl Shapirod7400e02010-09-02 18:24:29 -0700121static long setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800122{
Carl Shapirof373efd2010-02-19 00:46:33 -0800123 return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800124}
125
Carl Shapirod7400e02010-09-02 18:24:29 -0700126static void markObjectNonNull(const Object *obj, GcMarkContext *ctx,
127 bool checkFinger)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800128{
Barry Hayese1bccb92010-05-18 09:48:37 -0700129 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800130 assert(obj != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800131 assert(dvmIsValidObject(obj));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800132
Carl Shapirob31b3012010-05-25 18:35:37 -0700133 if (obj < (Object *)ctx->immuneLimit) {
Carl Shapirod25566d2010-03-11 20:39:47 -0800134 assert(isMarked(obj, ctx));
135 return;
136 }
Carl Shapiro6343bd02010-02-16 17:40:19 -0800137 if (!setAndReturnMarkBit(ctx, obj)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800138 /* This object was not previously marked.
139 */
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700140 if (checkFinger && (void *)obj < ctx->finger) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800141 /* This object will need to go on the mark stack.
142 */
Carl Shapirofdf80522010-11-09 14:27:02 -0800143 markStackPush(&ctx->stack, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800144 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800145 }
146}
147
148/* Used to mark objects when recursing. Recursion is done by moving
149 * the finger across the bitmaps in address order and marking child
150 * objects. Any newly-marked objects whose addresses are lower than
151 * the finger won't be visited by the bitmap scan, so those objects
152 * need to be added to the mark stack.
153 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700154static void markObject(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800155{
Barry Hayese1bccb92010-05-18 09:48:37 -0700156 if (obj != NULL) {
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700157 markObjectNonNull(obj, ctx, true);
Barry Hayese1bccb92010-05-18 09:48:37 -0700158 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800159}
160
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800161/* If the object hasn't already been marked, mark it and
162 * schedule it to be scanned for references.
163 *
164 * obj may not be NULL. The macro dvmMarkObject() should
165 * be used in situations where a reference may be NULL.
166 *
167 * This function may only be called when marking the root
Barry Hayese1bccb92010-05-18 09:48:37 -0700168 * set. When recursing, use the internal markObject().
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800169 */
Carl Shapirod7400e02010-09-02 18:24:29 -0700170void dvmMarkObjectNonNull(const Object *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800171{
Barry Hayese1bccb92010-05-18 09:48:37 -0700172 assert(obj != NULL);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700173 markObjectNonNull(obj, &gDvm.gcHeap->markContext, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800174}
175
176/* Mark the set of root objects.
177 *
178 * Things we need to scan:
179 * - System classes defined by root classloader
180 * - For each thread:
181 * - Interpreted stack, from top to "curFrame"
182 * - Dalvik registers (args + local vars)
183 * - JNI local references
184 * - Automatic VM local references (TrackedAlloc)
185 * - Associated Thread/VMThread object
186 * - ThreadGroups (could track & start with these instead of working
187 * upward from Threads)
188 * - Exception currently being thrown, if present
189 * - JNI global references
190 * - Interned string table
191 * - Primitive classes
192 * - Special objects
193 * - gDvm.outOfMemoryObj
194 * - Objects allocated with ALLOC_NO_GC
195 * - Objects pending finalization (but not yet finalized)
196 * - Objects in debugger object registry
197 *
198 * Don't need:
199 * - Native stack (for in-progress stuff in the VM)
200 * - The TrackedAlloc stuff watches all native VM references.
201 */
202void dvmHeapMarkRootSet()
203{
Barry Hayesd4f78d32010-06-08 09:34:42 -0700204 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800205
Carl Shapirod25566d2010-03-11 20:39:47 -0800206 LOG_SCAN("immune objects");
Barry Hayes425848f2010-05-04 13:32:12 -0700207 dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
Carl Shapirod25566d2010-03-11 20:39:47 -0800208
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800209 LOG_SCAN("root class loader\n");
210 dvmGcScanRootClassLoader();
211 LOG_SCAN("primitive classes\n");
212 dvmGcScanPrimitiveClasses();
213
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800214 LOG_SCAN("root thread groups\n");
215 dvmGcScanRootThreadGroups();
216
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800217 LOG_SCAN("interned strings\n");
218 dvmGcScanInternedStrings();
219
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800220 LOG_SCAN("JNI global refs\n");
221 dvmGcMarkJniGlobalRefs();
222
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800223 LOG_SCAN("pending reference operations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700224 dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800225
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800226 LOG_SCAN("pending finalizations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700227 dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800228
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800229 LOG_SCAN("debugger refs\n");
230 dvmGcMarkDebuggerRefs();
231
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800232 /* Mark any special objects we have sitting around.
233 */
234 LOG_SCAN("special objects\n");
235 dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
236 dvmMarkObjectNonNull(gDvm.internalErrorObj);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700237 dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800238//TODO: scan object references sitting in gDvm; use pointer begin & end
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800239}
240
241/*
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700242 * Callback applied to root references. If the root location contains
243 * a white reference it is pushed on the mark stack and grayed.
244 */
Carl Shapiro07018e22010-10-26 21:07:41 -0700245static void markObjectVisitor(void *addr, RootType type, u4 thread, void *arg)
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700246{
247 Object *obj;
248
249 assert(addr != NULL);
250 assert(arg != NULL);
251 obj = *(Object **)addr;
252 if (obj != NULL) {
253 markObjectNonNull(obj, arg, true);
254 }
255}
256
257/*
258 * Grays all references in the roots.
259 */
260void dvmHeapReMarkRootSet(void)
261{
262 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
263 assert(ctx->finger == (void *)ULONG_MAX);
264 dvmVisitRoots(markObjectVisitor, ctx);
265}
266
267/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700268 * Nothing past this point is allowed to use dvmMarkObject() or
269 * dvmMarkObjectNonNull(), which are for root-marking only.
270 * Scanning/recursion must use markObject(), which takes the finger
271 * into account.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800272 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700273#undef dvmMarkObject
274#define dvmMarkObject __dont_use_dvmMarkObject__
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800275#define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
276
Barry Hayese1bccb92010-05-18 09:48:37 -0700277/*
278 * Scans instance fields.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800279 */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800280static void scanFields(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800281{
Barry Hayese1bccb92010-05-18 09:48:37 -0700282 assert(obj != NULL);
283 assert(obj->clazz != NULL);
284 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800285
Barry Hayese1bccb92010-05-18 09:48:37 -0700286 if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
287 unsigned int refOffsets = obj->clazz->refOffsets;
Barry Hayeseac47ed2009-06-22 11:45:20 -0700288 while (refOffsets != 0) {
Carl Shapiro3e24d332010-11-29 17:24:50 -0800289 size_t rshift = CLZ(refOffsets);
290 size_t offset = CLASS_OFFSET_FROM_CLZ(rshift);
291 Object *ref = dvmGetFieldObject((Object*)obj, offset);
292 markObject(ref, ctx);
Barry Hayeseac47ed2009-06-22 11:45:20 -0700293 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800294 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700295 } else {
Barry Hayese1bccb92010-05-18 09:48:37 -0700296 ClassObject *clazz;
Barry Hayese1bccb92010-05-18 09:48:37 -0700297 for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
298 InstField *field = clazz->ifields;
Carl Shapiro3e24d332010-11-29 17:24:50 -0800299 int i;
Barry Hayese1bccb92010-05-18 09:48:37 -0700300 for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
301 void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
302 markObject(((JValue *)addr)->l, ctx);
Barry Hayeseac47ed2009-06-22 11:45:20 -0700303 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700304 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800305 }
306}
307
Barry Hayese1bccb92010-05-18 09:48:37 -0700308/*
Carl Shapiro3e24d332010-11-29 17:24:50 -0800309 * Scans the static fields of a class object.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800310 */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800311static void scanStaticFields(const ClassObject *clazz, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800312{
Barry Hayese1bccb92010-05-18 09:48:37 -0700313 int i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800314
Carl Shapiro3e24d332010-11-29 17:24:50 -0800315 assert(clazz != NULL);
Barry Hayese1bccb92010-05-18 09:48:37 -0700316 assert(ctx != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800317 for (i = 0; i < clazz->sfieldCount; ++i) {
318 char ch = clazz->sfields[i].field.signature[0];
319 if (ch == '[' || ch == 'L') {
320 markObject(clazz->sfields[i].value.l, ctx);
321 }
322 }
323}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800324
Carl Shapiro3e24d332010-11-29 17:24:50 -0800325/*
326 * Visit the interfaces of a class object.
327 */
328static void scanInterfaces(const ClassObject *clazz, GcMarkContext *ctx)
329{
330 int i;
331
332 assert(clazz != NULL);
333 assert(ctx != NULL);
334 for (i = 0; i < clazz->interfaceCount; ++i) {
335 markObject((const Object *)clazz->interfaces[i], ctx);
336 }
337}
338
339/*
340 * Scans the header, static field references, and interface
341 * pointers of a class object.
342 */
343static void scanClassObject(const Object *obj, GcMarkContext *ctx)
344{
345 const ClassObject *asClass;
346
347 assert(obj != NULL);
348 assert(obj->clazz == gDvm.classJavaLangClass);
349 assert(ctx != NULL);
350 markObject((const Object *)obj->clazz, ctx);
351 asClass = (const ClassObject *)obj;
352 if (IS_CLASS_FLAG_SET(asClass, CLASS_ISARRAY)) {
353 markObject((const Object *)asClass->elementClass, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700354 }
Barry Hayesc49db852010-05-14 13:43:34 -0700355 /* Do super and the interfaces contain Objects and not dex idx values? */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800356 if (asClass->status > CLASS_IDX) {
357 markObject((const Object *)asClass->super, ctx);
Barry Hayesc49db852010-05-14 13:43:34 -0700358 }
Carl Shapiro3e24d332010-11-29 17:24:50 -0800359 markObject((const Object *)asClass->classLoader, ctx);
360 scanFields(obj, ctx);
361 scanStaticFields(asClass, ctx);
362 if (asClass->status > CLASS_IDX) {
363 scanInterfaces(asClass, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800364 }
365}
366
Barry Hayese1bccb92010-05-18 09:48:37 -0700367/*
368 * Scans the header of all array objects. If the array object is
369 * specialized to a reference type, scans the array data as well.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800370 */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800371static void scanArrayObject(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800372{
Barry Hayese1bccb92010-05-18 09:48:37 -0700373 assert(obj != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800374 assert(obj->clazz != NULL);
Barry Hayese1bccb92010-05-18 09:48:37 -0700375 assert(ctx != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800376 markObject((const Object *)obj->clazz, ctx);
377 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISOBJECTARRAY)) {
378 const ArrayObject *array = (const ArrayObject *)obj;
379 const Object **contents = (const Object **)array->contents;
380 size_t i;
381 for (i = 0; i < array->length; ++i) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700382 markObject(contents[i], ctx);
383 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800384 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700385}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800386
Barry Hayese1bccb92010-05-18 09:48:37 -0700387/*
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700388 * Returns class flags relating to Reference subclasses.
389 */
390static int referenceClassFlags(const Object *obj)
391{
392 int flags = CLASS_ISREFERENCE |
393 CLASS_ISWEAKREFERENCE |
394 CLASS_ISPHANTOMREFERENCE;
395 return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
396}
397
398/*
399 * Returns true if the object derives from SoftReference.
400 */
401static bool isSoftReference(const Object *obj)
402{
403 return referenceClassFlags(obj) == CLASS_ISREFERENCE;
404}
405
406/*
407 * Returns true if the object derives from WeakReference.
408 */
409static bool isWeakReference(const Object *obj)
410{
411 return referenceClassFlags(obj) & CLASS_ISWEAKREFERENCE;
412}
413
414/*
415 * Returns true if the object derives from PhantomReference.
416 */
417static bool isPhantomReference(const Object *obj)
418{
419 return referenceClassFlags(obj) & CLASS_ISPHANTOMREFERENCE;
420}
421
422/*
423 * Adds a reference to the tail of a circular queue of references.
424 */
425static void enqueuePendingReference(Object *ref, Object **list)
426{
427 size_t offset;
428
429 assert(ref != NULL);
430 assert(list != NULL);
431 offset = gDvm.offJavaLangRefReference_pendingNext;
432 if (*list == NULL) {
433 dvmSetFieldObject(ref, offset, ref);
434 *list = ref;
435 } else {
436 Object *head = dvmGetFieldObject(*list, offset);
437 dvmSetFieldObject(ref, offset, head);
438 dvmSetFieldObject(*list, offset, ref);
439 }
440}
441
442/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700443 * Removes the reference at the head of a circular queue of
444 * references.
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700445 */
446static Object *dequeuePendingReference(Object **list)
447{
448 Object *ref, *head;
449 size_t offset;
450
451 assert(list != NULL);
452 assert(*list != NULL);
453 offset = gDvm.offJavaLangRefReference_pendingNext;
454 head = dvmGetFieldObject(*list, offset);
455 if (*list == head) {
456 ref = *list;
457 *list = NULL;
458 } else {
459 Object *next = dvmGetFieldObject(head, offset);
460 dvmSetFieldObject(*list, offset, next);
461 ref = head;
462 }
463 dvmSetFieldObject(ref, offset, NULL);
464 return ref;
465}
466
467/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700468 * Process the "referent" field in a java.lang.ref.Reference. If the
469 * referent has not yet been marked, put it on the appropriate list in
470 * the gcHeap for later processing.
471 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700472static void delayReferenceReferent(Object *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700473{
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700474 GcHeap *gcHeap = gDvm.gcHeap;
475 Object *pending, *referent;
476 size_t pendingNextOffset, referentOffset;
477
Barry Hayese1bccb92010-05-18 09:48:37 -0700478 assert(obj != NULL);
Barry Hayes697b5a92010-06-23 11:38:52 -0700479 assert(obj->clazz != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700480 assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
Barry Hayese1bccb92010-05-18 09:48:37 -0700481 assert(ctx != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700482 pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
483 referentOffset = gDvm.offJavaLangRefReference_referent;
484 pending = dvmGetFieldObject(obj, pendingNextOffset);
485 referent = dvmGetFieldObject(obj, referentOffset);
486 if (pending == NULL && referent != NULL && !isMarked(referent, ctx)) {
487 Object **list = NULL;
488 if (isSoftReference(obj)) {
489 list = &gcHeap->softReferences;
490 } else if (isWeakReference(obj)) {
491 list = &gcHeap->weakReferences;
492 } else if (isPhantomReference(obj)) {
493 list = &gcHeap->phantomReferences;
Barry Hayese1bccb92010-05-18 09:48:37 -0700494 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700495 assert(list != NULL);
496 enqueuePendingReference(obj, list);
Barry Hayese1bccb92010-05-18 09:48:37 -0700497 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800498}
499
Barry Hayese1bccb92010-05-18 09:48:37 -0700500/*
501 * Scans the header and field references of a data object.
502 */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800503static void scanDataObject(const Object *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700504{
505 assert(obj != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800506 assert(obj->clazz != NULL);
Barry Hayese1bccb92010-05-18 09:48:37 -0700507 assert(ctx != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800508 markObject((const Object *)obj->clazz, ctx);
509 scanFields(obj, ctx);
510 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE)) {
Barry Hayes697b5a92010-06-23 11:38:52 -0700511 delayReferenceReferent((Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700512 }
513}
514
515/*
516 * Scans an object reference. Determines the type of the reference
517 * and dispatches to a specialized scanning routine.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800518 */
519static void scanObject(const Object *obj, GcMarkContext *ctx)
520{
Barry Hayese1bccb92010-05-18 09:48:37 -0700521 assert(obj != NULL);
522 assert(ctx != NULL);
Barry Hayes899cdb72010-06-08 09:59:12 -0700523 assert(obj->clazz != NULL);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700524 if (obj->clazz == gDvm.classJavaLangClass) {
Carl Shapiro3e24d332010-11-29 17:24:50 -0800525 scanClassObject(obj, ctx);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700526 } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
Carl Shapiro3e24d332010-11-29 17:24:50 -0800527 scanArrayObject(obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800528 } else {
Carl Shapiro3e24d332010-11-29 17:24:50 -0800529 scanDataObject(obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800530 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800531}
532
Carl Shapirofdf80522010-11-09 14:27:02 -0800533/*
534 * Scan anything that's on the mark stack. We can't use the bitmaps
535 * anymore, so use a finger that points past the end of them.
536 */
537static void processMarkStack(GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800538{
Carl Shapirofdf80522010-11-09 14:27:02 -0800539 GcMarkStack *stack;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800540
Carl Shapirofdf80522010-11-09 14:27:02 -0800541 assert(ctx != NULL);
Carl Shapiro034fba52010-11-11 16:39:58 -0800542 assert(ctx->finger == (void *)ULONG_MAX);
Carl Shapirofdf80522010-11-09 14:27:02 -0800543 stack = &ctx->stack;
544 assert(stack->top >= stack->base);
545 while (stack->top > stack->base) {
546 const Object *obj = markStackPop(stack);
547 scanObject(obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800548 }
549}
550
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700551static size_t objectSize(const Object *obj)
552{
553 assert(dvmIsValidObject(obj));
554 assert(dvmIsValidObject((Object *)obj->clazz));
555 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
556 return dvmArrayObjectSize((ArrayObject *)obj);
557 } else if (obj->clazz == gDvm.classJavaLangClass) {
558 return dvmClassObjectSize((ClassObject *)obj);
559 } else {
560 return obj->clazz->objectSize;
561 }
562}
563
564/*
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700565 * Scans forward to the header of the next marked object between start
566 * and limit. Returns NULL if no marked objects are in that region.
567 */
Carl Shapiro7ec91442010-10-21 15:35:19 -0700568static Object *nextGrayObject(const u1 *base, const u1 *limit,
569 const HeapBitmap *markBits)
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700570{
Carl Shapiro7ec91442010-10-21 15:35:19 -0700571 const u1 *ptr;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700572
573 assert(base < limit);
574 assert(limit - base <= GC_CARD_SIZE);
575 for (ptr = base; ptr < limit; ptr += HB_OBJECT_ALIGNMENT) {
Carl Shapiroea10c552010-09-02 23:32:25 -0700576 if (dvmHeapBitmapIsObjectBitSet(markBits, ptr))
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700577 return (Object *)ptr;
578 }
579 return NULL;
580}
581
582/*
Carl Shapiro7ec91442010-10-21 15:35:19 -0700583 * Scans each byte from start below end returning the address of the
584 * first dirty card. Returns NULL if no dirty card is found.
585 */
586static const u1 *scanBytesForDirtyCard(const u1 *start, const u1 *end)
587{
588 const u1 *ptr;
589
590 assert(start <= end);
591 for (ptr = start; ptr < end; ++ptr) {
592 if (*ptr == GC_CARD_DIRTY) {
593 return ptr;
594 }
595 }
596 return NULL;
597}
598
599/*
600 * Like scanBytesForDirtyCard but scans the range from start below end
601 * by words. Assumes start and end are word aligned.
602 */
603static const u1 *scanWordsForDirtyCard(const u1 *start, const u1 *end)
604{
605 const u1 *ptr;
606
607 assert((uintptr_t)start % kWordSize == 0);
608 assert((uintptr_t)end % kWordSize == 0);
609 assert(start <= end);
610 for (ptr = start; ptr < end; ptr += kWordSize) {
611 if (*(const Word *)ptr != 0) {
612 const u1 *dirty = scanBytesForDirtyCard(ptr, ptr + kWordSize);
613 if (dirty != NULL) {
614 return dirty;
615 }
616 }
617 }
618 return NULL;
619}
620
621/*
622 * Scans the card table as quickly as possible looking for a dirty
623 * card. Returns the address of the first dirty card found or NULL if
624 * no dirty cards were found.
625 */
626static const u1 *nextDirtyCard(const u1 *start, const u1 *end)
627{
628 const u1 *wstart = (u1 *)ALIGN_UP(start, kWordSize);
629 const u1 *wend = (u1 *)ALIGN_DOWN(end, kWordSize);
630 const u1 *ptr, *dirty;
631
632 assert(start <= end);
633 assert(start <= wstart);
634 assert(end >= wend);
635 ptr = start;
636 if (wstart < end) {
637 /* Scan the leading unaligned bytes. */
638 dirty = scanBytesForDirtyCard(ptr, wstart);
639 if (dirty != NULL) {
640 return dirty;
641 }
642 /* Scan the range of aligned words. */
643 dirty = scanWordsForDirtyCard(wstart, wend);
644 if (dirty != NULL) {
645 return dirty;
646 }
647 ptr = wend;
648 }
649 /* Scan trailing unaligned bytes. */
650 dirty = scanBytesForDirtyCard(ptr, end);
651 if (dirty != NULL) {
652 return dirty;
653 }
654 return NULL;
655}
656
657/*
658 * Scans range of dirty cards between start and end. A range of dirty
659 * cards is composed consecutively dirty cards or dirty cards spanned
660 * by a gray object. Returns the address of a clean card if the scan
661 * reached a clean card or NULL if the scan reached the end.
662 */
663const u1 *scanDirtyCards(const u1 *start, const u1 *end,
664 GcMarkContext *ctx)
665{
666 const HeapBitmap *markBits = ctx->bitmap;
667 const u1 *card = start, *prevAddr = NULL;
668 while (card < end) {
669 if (*card != GC_CARD_DIRTY) {
670 return card;
671 }
672 const u1 *ptr = prevAddr ? prevAddr : dvmAddrFromCard(card);
673 const u1 *limit = ptr + GC_CARD_SIZE;
674 while (ptr < limit) {
675 Object *obj = nextGrayObject(ptr, limit, markBits);
676 if (obj == NULL) {
677 break;
678 }
679 scanObject(obj, ctx);
680 ptr = (u1*)obj + ALIGN_UP(objectSize(obj), HB_OBJECT_ALIGNMENT);
681 }
682 if (ptr < limit) {
683 /* Ended within the current card, advance to the next card. */
684 ++card;
685 prevAddr = NULL;
686 } else {
687 /* Ended past the current card, skip ahead. */
688 card = dvmCardFromAddr(ptr);
689 prevAddr = ptr;
690 }
691 }
692 return NULL;
693}
694
695/*
696 * Blackens gray objects found on dirty cards.
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700697 */
698static void scanGrayObjects(GcMarkContext *ctx)
699{
700 GcHeap *h = gDvm.gcHeap;
Carl Shapiro7ec91442010-10-21 15:35:19 -0700701 const u1 *base, *limit, *ptr, *dirty;
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700702 size_t footprint;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700703
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700704 footprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
Carl Shapiro7ec91442010-10-21 15:35:19 -0700705 base = &h->cardTableBase[0];
706 limit = dvmCardFromAddr((u1 *)dvmHeapSourceGetBase() + footprint);
707 assert(limit <= &h->cardTableBase[h->cardTableLength]);
708
709 ptr = base;
710 for (;;) {
711 dirty = nextDirtyCard(ptr, limit);
712 if (dirty == NULL) {
713 break;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700714 }
Carl Shapiro7ec91442010-10-21 15:35:19 -0700715 assert((dirty > ptr) && (dirty < limit));
716 ptr = scanDirtyCards(dirty, limit, ctx);
717 if (ptr == NULL) {
718 break;
719 }
720 assert((ptr > dirty) && (ptr < limit));
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700721 }
722}
723
Carl Shapiro57ee2702010-08-27 13:06:48 -0700724/*
725 * Callback for scanning each object in the bitmap. The finger is set
726 * to the address corresponding to the lowest address in the next word
727 * of bits in the bitmap.
728 */
Carl Shapiro38d710b2010-08-31 16:48:31 -0700729static void scanBitmapCallback(void *addr, void *finger, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800730{
Carl Shapiro006346e2010-07-29 20:39:50 -0700731 GcMarkContext *ctx = arg;
Carl Shapiro57ee2702010-08-27 13:06:48 -0700732 ctx->finger = (void *)finger;
733 scanObject(addr, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800734}
735
736/* Given bitmaps with the root set marked, find and mark all
737 * reachable objects. When this returns, the entire set of
738 * live objects will be marked and the mark stack will be empty.
739 */
Carl Shapiro29540742010-03-26 15:34:39 -0700740void dvmHeapScanMarkedObjects(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800741{
742 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
743
744 assert(ctx->finger == NULL);
745
746 /* The bitmaps currently have bits set for the root set.
747 * Walk across the bitmaps and scan each object.
748 */
Carl Shapiro38d710b2010-08-31 16:48:31 -0700749 dvmHeapBitmapScanWalk(ctx->bitmap, scanBitmapCallback, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800750
Carl Shapiro034fba52010-11-11 16:39:58 -0800751 ctx->finger = (void *)ULONG_MAX;
752
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800753 /* We've walked the mark bitmaps. Scan anything that's
754 * left on the mark stack.
755 */
756 processMarkStack(ctx);
757
758 LOG_SCAN("done with marked objects\n");
759}
760
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700761void dvmHeapReScanMarkedObjects(void)
Carl Shapiroec805ea2010-06-28 16:28:26 -0700762{
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700763 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700764
Carl Shapiroec805ea2010-06-28 16:28:26 -0700765 /*
Carl Shapirof5860332010-06-28 23:02:08 -0700766 * The finger must have been set to the maximum value to ensure
767 * that gray objects will be pushed onto the mark stack.
Carl Shapiroec805ea2010-06-28 16:28:26 -0700768 */
769 assert(ctx->finger == (void *)ULONG_MAX);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700770 scanGrayObjects(ctx);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700771 processMarkStack(ctx);
772}
773
Carl Shapiro34f51992010-07-09 17:55:41 -0700774/*
775 * Clear the referent field.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800776 */
Barry Hayes6930a112009-12-22 11:01:38 -0800777static void clearReference(Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800778{
Carl Shapiro34f51992010-07-09 17:55:41 -0700779 size_t offset = gDvm.offJavaLangRefReference_referent;
780 dvmSetFieldObject(reference, offset, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800781}
782
Carl Shapiro29540742010-03-26 15:34:39 -0700783/*
784 * Returns true if the reference was registered with a reference queue
785 * and has not yet been enqueued.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800786 */
Carl Shapiro29540742010-03-26 15:34:39 -0700787static bool isEnqueuable(const Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800788{
Barry Hayes6930a112009-12-22 11:01:38 -0800789 Object *queue = dvmGetFieldObject(reference,
790 gDvm.offJavaLangRefReference_queue);
791 Object *queueNext = dvmGetFieldObject(reference,
792 gDvm.offJavaLangRefReference_queueNext);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700793 return queue != NULL && queueNext == NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800794}
795
Carl Shapiro29540742010-03-26 15:34:39 -0700796/*
797 * Schedules a reference to be appended to its reference queue.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800798 */
Carl Shapiro29540742010-03-26 15:34:39 -0700799static void enqueueReference(Object *ref)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800800{
Carl Shapiro646ba092010-06-10 15:17:00 -0700801 assert(ref != NULL);
Carl Shapiro29540742010-03-26 15:34:39 -0700802 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
803 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
Carl Shapiro646ba092010-06-10 15:17:00 -0700804 if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
Carl Shapiro29540742010-03-26 15:34:39 -0700805 LOGE_HEAP("enqueueReference(): no room for any more "
806 "reference operations\n");
807 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800808 }
809}
810
Carl Shapiro29540742010-03-26 15:34:39 -0700811/*
812 * Walks the reference list marking any references subject to the
813 * reference clearing policy. References with a black referent are
814 * removed from the list. References with white referents biased
815 * toward saving are blackened and also removed from the list.
816 */
817void dvmHandleSoftRefs(Object **list)
818{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700819 GcMarkContext *ctx;
Carl Shapiro29540742010-03-26 15:34:39 -0700820 Object *ref, *referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700821 Object *clear;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700822 size_t referentOffset;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700823 size_t counter;
Carl Shapiro29540742010-03-26 15:34:39 -0700824 bool marked;
825
Carl Shapirob2e78d32010-08-20 11:34:18 -0700826 ctx = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700827 referentOffset = gDvm.offJavaLangRefReference_referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700828 clear = NULL;
Carl Shapiro29540742010-03-26 15:34:39 -0700829 counter = 0;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700830 while (*list != NULL) {
831 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700832 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700833 assert(referent != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700834 marked = isMarked(referent, ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700835 if (!marked && ((++counter) & 1)) {
836 /* Referent is white and biased toward saving, mark it. */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700837 markObject(referent, ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700838 marked = true;
839 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700840 if (!marked) {
841 /* Referent is white, queue it for clearing. */
842 enqueuePendingReference(ref, &clear);
Carl Shapiro29540742010-03-26 15:34:39 -0700843 }
Carl Shapiro29540742010-03-26 15:34:39 -0700844 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700845 *list = clear;
Carl Shapiro29540742010-03-26 15:34:39 -0700846 /*
847 * Restart the mark with the newly black references added to the
848 * root set.
849 */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700850 processMarkStack(ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700851}
852
853/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700854 * Unlink the reference list clearing references objects with white
855 * referents. Cleared references registered to a reference queue are
856 * scheduled for appending by the heap worker thread.
Carl Shapiro29540742010-03-26 15:34:39 -0700857 */
858void dvmClearWhiteRefs(Object **list)
859{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700860 GcMarkContext *ctx;
Carl Shapiro29540742010-03-26 15:34:39 -0700861 Object *ref, *referent;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700862 size_t referentOffset;
Carl Shapiro29540742010-03-26 15:34:39 -0700863 bool doSignal;
864
Carl Shapirob2e78d32010-08-20 11:34:18 -0700865 ctx = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700866 referentOffset = gDvm.offJavaLangRefReference_referent;
867 doSignal = false;
868 while (*list != NULL) {
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700869 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700870 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700871 assert(referent != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700872 if (!isMarked(referent, ctx)) {
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700873 /* Referent is white, clear it. */
Carl Shapiro29540742010-03-26 15:34:39 -0700874 clearReference(ref);
875 if (isEnqueuable(ref)) {
876 enqueueReference(ref);
877 doSignal = true;
878 }
879 }
880 }
881 /*
882 * If we cleared a reference with a reference queue we must notify
883 * the heap worker to append the reference.
884 */
885 if (doSignal) {
886 dvmSignalHeapWorker(false);
887 }
888 assert(*list == NULL);
889}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800890
891/* Find unreachable objects that need to be finalized,
892 * and schedule them for finalization.
893 */
894void dvmHeapScheduleFinalizations()
895{
896 HeapRefTable newPendingRefs;
897 LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
898 Object **ref;
899 Object **lastRef;
900 size_t totalPendCount;
Carl Shapirob2e78d32010-08-20 11:34:18 -0700901 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800902
903 /*
904 * All reachable objects have been marked.
905 * Any unmarked finalizable objects need to be finalized.
906 */
907
908 /* Create a table that the new pending refs will
909 * be added to.
910 */
Barry Hayesd4f78d32010-06-08 09:34:42 -0700911 if (!dvmHeapInitHeapRefTable(&newPendingRefs)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800912 //TODO: mark all finalizable refs and hope that
913 // we can schedule them next time. Watch out,
914 // because we may be expecting to free up space
915 // by calling finalizers.
916 LOGE_GC("dvmHeapScheduleFinalizations(): no room for "
917 "pending finalizations\n");
918 dvmAbort();
919 }
920
921 /* Walk through finalizableRefs and move any unmarked references
922 * to the list of new pending refs.
923 */
924 totalPendCount = 0;
925 while (finRefs != NULL) {
926 Object **gapRef;
927 size_t newPendCount = 0;
928
929 gapRef = ref = finRefs->refs.table;
930 lastRef = finRefs->refs.nextEntry;
931 while (ref < lastRef) {
Carl Shapirob2e78d32010-08-20 11:34:18 -0700932 if (!isMarked(*ref, ctx)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800933 if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
934 //TODO: add the current table and allocate
935 // a new, smaller one.
936 LOGE_GC("dvmHeapScheduleFinalizations(): "
937 "no room for any more pending finalizations: %zd\n",
938 dvmHeapNumHeapRefTableEntries(&newPendingRefs));
939 dvmAbort();
940 }
941 newPendCount++;
942 } else {
943 /* This ref is marked, so will remain on finalizableRefs.
944 */
945 if (newPendCount > 0) {
946 /* Copy it up to fill the holes.
947 */
948 *gapRef++ = *ref;
949 } else {
950 /* No holes yet; don't bother copying.
951 */
952 gapRef++;
953 }
954 }
955 ref++;
956 }
957 finRefs->refs.nextEntry = gapRef;
958 //TODO: if the table is empty when we're done, free it.
959 totalPendCount += newPendCount;
960 finRefs = finRefs->next;
961 }
962 LOGD_GC("dvmHeapScheduleFinalizations(): %zd finalizers triggered.\n",
963 totalPendCount);
964 if (totalPendCount == 0) {
965 /* No objects required finalization.
966 * Free the empty temporary table.
967 */
968 dvmClearReferenceTable(&newPendingRefs);
969 return;
970 }
971
972 /* Add the new pending refs to the main list.
973 */
974 if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
975 &newPendingRefs))
976 {
977 LOGE_GC("dvmHeapScheduleFinalizations(): can't insert new "
978 "pending finalizations\n");
979 dvmAbort();
980 }
981
982 //TODO: try compacting the main list with a memcpy loop
983
984 /* Mark the refs we just moved; we don't want them or their
985 * children to get swept yet.
986 */
987 ref = newPendingRefs.table;
988 lastRef = newPendingRefs.nextEntry;
989 assert(ref < lastRef);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800990 while (ref < lastRef) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700991 assert(*ref != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700992 markObject(*ref, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800993 ref++;
994 }
Carl Shapirob2e78d32010-08-20 11:34:18 -0700995 processMarkStack(ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800996 dvmSignalHeapWorker(false);
997}
998
999void dvmHeapFinishMarkStep()
1000{
Carl Shapirob2e78d32010-08-20 11:34:18 -07001001 GcMarkContext *ctx;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001002
Carl Shapirob2e78d32010-08-20 11:34:18 -07001003 ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001004
Barry Hayes81010a42010-07-19 14:07:01 -07001005 /* The mark bits are now not needed.
1006 */
1007 dvmHeapSourceZeroMarkBitmap();
1008
Carl Shapirof373efd2010-02-19 00:46:33 -08001009 /* Clean up everything else associated with the marking process.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001010 */
Carl Shapirob2e78d32010-08-20 11:34:18 -07001011 destroyMarkStack(&ctx->stack);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001012
Carl Shapirob2e78d32010-08-20 11:34:18 -07001013 ctx->finger = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001014}
1015
Carl Shapiro8881a802010-08-10 15:55:45 -07001016typedef struct {
1017 size_t numObjects;
1018 size_t numBytes;
1019 bool isConcurrent;
1020} SweepContext;
1021
Carl Shapiro57ee2702010-08-27 13:06:48 -07001022static void sweepBitmapCallback(size_t numPtrs, void **ptrs, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001023{
Carl Shapirob9b23952010-08-10 17:20:15 -07001024 SweepContext *ctx = arg;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001025
Carl Shapiro8881a802010-08-10 15:55:45 -07001026 if (ctx->isConcurrent) {
1027 dvmLockHeap();
1028 }
1029 ctx->numBytes += dvmHeapSourceFreeList(numPtrs, ptrs);
1030 ctx->numObjects += numPtrs;
1031 if (ctx->isConcurrent) {
1032 dvmUnlockHeap();
1033 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001034}
1035
Carl Shapiro8881a802010-08-10 15:55:45 -07001036/*
1037 * Returns true if the given object is unmarked. This assumes that
1038 * the bitmaps have not yet been swapped.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001039 */
1040static int isUnmarkedObject(void *object)
1041{
Carl Shapiro6343bd02010-02-16 17:40:19 -08001042 return !isMarked((void *)((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001043 &gDvm.gcHeap->markContext);
1044}
1045
Carl Shapiro8881a802010-08-10 15:55:45 -07001046/*
1047 * Process all the internal system structures that behave like
1048 * weakly-held objects.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001049 */
Carl Shapiro8881a802010-08-10 15:55:45 -07001050void dvmHeapSweepSystemWeaks(void)
1051{
1052 dvmGcDetachDeadInternedStrings(isUnmarkedObject);
1053 dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
1054}
1055
1056/*
1057 * Walk through the list of objects that haven't been marked and free
1058 * them. Assumes the bitmaps have been swapped.
1059 */
1060void dvmHeapSweepUnmarkedObjects(GcMode mode, bool isConcurrent,
1061 size_t *numObjects, size_t *numBytes)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001062{
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001063 HeapBitmap currMark[HEAP_SOURCE_MAX_HEAP_COUNT];
1064 HeapBitmap currLive[HEAP_SOURCE_MAX_HEAP_COUNT];
Carl Shapiro8881a802010-08-10 15:55:45 -07001065 SweepContext ctx;
Carl Shapirod25566d2010-03-11 20:39:47 -08001066 size_t numBitmaps, numSweepBitmaps;
Barry Hayese168ebd2010-05-07 09:19:46 -07001067 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001068
Carl Shapirof373efd2010-02-19 00:46:33 -08001069 numBitmaps = dvmHeapSourceGetNumHeaps();
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001070 dvmHeapSourceGetObjectBitmaps(currLive, currMark, numBitmaps);
Carl Shapirod25566d2010-03-11 20:39:47 -08001071 if (mode == GC_PARTIAL) {
1072 numSweepBitmaps = 1;
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001073 assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == currLive[0].base);
Carl Shapirod25566d2010-03-11 20:39:47 -08001074 } else {
1075 numSweepBitmaps = numBitmaps;
1076 }
Carl Shapiro8881a802010-08-10 15:55:45 -07001077 ctx.numObjects = ctx.numBytes = 0;
1078 ctx.isConcurrent = isConcurrent;
Barry Hayese168ebd2010-05-07 09:19:46 -07001079 for (i = 0; i < numSweepBitmaps; i++) {
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001080 HeapBitmap* prevLive = &currMark[i];
1081 HeapBitmap* prevMark = &currLive[i];
1082 dvmHeapBitmapSweepWalk(prevLive, prevMark, sweepBitmapCallback, &ctx);
Barry Hayese168ebd2010-05-07 09:19:46 -07001083 }
Carl Shapiro8881a802010-08-10 15:55:45 -07001084 *numObjects = ctx.numObjects;
1085 *numBytes = ctx.numBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001086 if (gDvm.allocProf.enabled) {
Carl Shapiro8881a802010-08-10 15:55:45 -07001087 gDvm.allocProf.freeCount += ctx.numObjects;
1088 gDvm.allocProf.freeSize += ctx.numBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001089 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001090}