blob: e0ff3a6a441428fc58f19a6659d723a016a05636 [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{
Carl Shapirofdf80522010-11-09 14:27:02 -080099 assert(stack != NULL);
100 assert(stack->base < stack->top);
101 assert(stack->limit > stack->top);
102 --stack->top;
Carl Shapiro26a82802010-12-01 18:54:19 -0800103 return *stack->top;
Carl Shapirofdf80522010-11-09 14:27:02 -0800104}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800105
Carl Shapirod7400e02010-09-02 18:24:29 -0700106bool dvmHeapBeginMarkStep(GcMode mode)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800107{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700108 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800109
Carl Shapirob2e78d32010-08-20 11:34:18 -0700110 if (!createMarkStack(&ctx->stack)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800111 return false;
112 }
Carl Shapirob2e78d32010-08-20 11:34:18 -0700113 ctx->finger = NULL;
114 ctx->immuneLimit = dvmHeapSourceGetImmuneLimit(mode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800115 return true;
116}
117
Carl Shapirod7400e02010-09-02 18:24:29 -0700118static long setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800119{
Carl Shapirof373efd2010-02-19 00:46:33 -0800120 return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800121}
122
Carl Shapirod7400e02010-09-02 18:24:29 -0700123static void markObjectNonNull(const Object *obj, GcMarkContext *ctx,
124 bool checkFinger)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800125{
Barry Hayese1bccb92010-05-18 09:48:37 -0700126 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800127 assert(obj != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800128 assert(dvmIsValidObject(obj));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800129
Carl Shapirob31b3012010-05-25 18:35:37 -0700130 if (obj < (Object *)ctx->immuneLimit) {
Carl Shapirod25566d2010-03-11 20:39:47 -0800131 assert(isMarked(obj, ctx));
132 return;
133 }
Carl Shapiro6343bd02010-02-16 17:40:19 -0800134 if (!setAndReturnMarkBit(ctx, obj)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800135 /* This object was not previously marked.
136 */
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700137 if (checkFinger && (void *)obj < ctx->finger) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800138 /* This object will need to go on the mark stack.
139 */
Carl Shapirofdf80522010-11-09 14:27:02 -0800140 markStackPush(&ctx->stack, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800141 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800142 }
143}
144
145/* Used to mark objects when recursing. Recursion is done by moving
146 * the finger across the bitmaps in address order and marking child
147 * objects. Any newly-marked objects whose addresses are lower than
148 * the finger won't be visited by the bitmap scan, so those objects
149 * need to be added to the mark stack.
150 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700151static void markObject(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800152{
Barry Hayese1bccb92010-05-18 09:48:37 -0700153 if (obj != NULL) {
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700154 markObjectNonNull(obj, ctx, true);
Barry Hayese1bccb92010-05-18 09:48:37 -0700155 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800156}
157
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800158/* If the object hasn't already been marked, mark it and
159 * schedule it to be scanned for references.
160 *
161 * obj may not be NULL. The macro dvmMarkObject() should
162 * be used in situations where a reference may be NULL.
163 *
164 * This function may only be called when marking the root
Barry Hayese1bccb92010-05-18 09:48:37 -0700165 * set. When recursing, use the internal markObject().
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800166 */
Carl Shapirod7400e02010-09-02 18:24:29 -0700167void dvmMarkObjectNonNull(const Object *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800168{
Barry Hayese1bccb92010-05-18 09:48:37 -0700169 assert(obj != NULL);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700170 markObjectNonNull(obj, &gDvm.gcHeap->markContext, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800171}
172
173/* Mark the set of root objects.
174 *
175 * Things we need to scan:
176 * - System classes defined by root classloader
177 * - For each thread:
178 * - Interpreted stack, from top to "curFrame"
179 * - Dalvik registers (args + local vars)
180 * - JNI local references
181 * - Automatic VM local references (TrackedAlloc)
182 * - Associated Thread/VMThread object
183 * - ThreadGroups (could track & start with these instead of working
184 * upward from Threads)
185 * - Exception currently being thrown, if present
186 * - JNI global references
187 * - Interned string table
188 * - Primitive classes
189 * - Special objects
190 * - gDvm.outOfMemoryObj
191 * - Objects allocated with ALLOC_NO_GC
192 * - Objects pending finalization (but not yet finalized)
193 * - Objects in debugger object registry
194 *
195 * Don't need:
196 * - Native stack (for in-progress stuff in the VM)
197 * - The TrackedAlloc stuff watches all native VM references.
198 */
199void dvmHeapMarkRootSet()
200{
Barry Hayesd4f78d32010-06-08 09:34:42 -0700201 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800202
Carl Shapirod25566d2010-03-11 20:39:47 -0800203 LOG_SCAN("immune objects");
Barry Hayes425848f2010-05-04 13:32:12 -0700204 dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
Carl Shapirod25566d2010-03-11 20:39:47 -0800205
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800206 LOG_SCAN("root class loader\n");
207 dvmGcScanRootClassLoader();
208 LOG_SCAN("primitive classes\n");
209 dvmGcScanPrimitiveClasses();
210
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800211 LOG_SCAN("root thread groups\n");
212 dvmGcScanRootThreadGroups();
213
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800214 LOG_SCAN("interned strings\n");
215 dvmGcScanInternedStrings();
216
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800217 LOG_SCAN("JNI global refs\n");
218 dvmGcMarkJniGlobalRefs();
219
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800220 LOG_SCAN("pending reference operations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700221 dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800222
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800223 LOG_SCAN("pending finalizations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700224 dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800225
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800226 LOG_SCAN("debugger refs\n");
227 dvmGcMarkDebuggerRefs();
228
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800229 /* Mark any special objects we have sitting around.
230 */
231 LOG_SCAN("special objects\n");
232 dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
233 dvmMarkObjectNonNull(gDvm.internalErrorObj);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700234 dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800235//TODO: scan object references sitting in gDvm; use pointer begin & end
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800236}
237
238/*
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700239 * Callback applied to root references. If the root location contains
240 * a white reference it is pushed on the mark stack and grayed.
241 */
Carl Shapiro07018e22010-10-26 21:07:41 -0700242static void markObjectVisitor(void *addr, RootType type, u4 thread, void *arg)
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700243{
244 Object *obj;
245
246 assert(addr != NULL);
247 assert(arg != NULL);
248 obj = *(Object **)addr;
249 if (obj != NULL) {
250 markObjectNonNull(obj, arg, true);
251 }
252}
253
254/*
255 * Grays all references in the roots.
256 */
257void dvmHeapReMarkRootSet(void)
258{
259 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
260 assert(ctx->finger == (void *)ULONG_MAX);
261 dvmVisitRoots(markObjectVisitor, ctx);
262}
263
264/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700265 * Nothing past this point is allowed to use dvmMarkObject() or
266 * dvmMarkObjectNonNull(), which are for root-marking only.
267 * Scanning/recursion must use markObject(), which takes the finger
268 * into account.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800269 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700270#undef dvmMarkObject
271#define dvmMarkObject __dont_use_dvmMarkObject__
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800272#define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
273
Barry Hayese1bccb92010-05-18 09:48:37 -0700274/*
275 * Scans instance fields.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800276 */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800277static void scanFields(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800278{
Barry Hayese1bccb92010-05-18 09:48:37 -0700279 assert(obj != NULL);
280 assert(obj->clazz != NULL);
281 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800282
Barry Hayese1bccb92010-05-18 09:48:37 -0700283 if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
284 unsigned int refOffsets = obj->clazz->refOffsets;
Barry Hayeseac47ed2009-06-22 11:45:20 -0700285 while (refOffsets != 0) {
Carl Shapiro3e24d332010-11-29 17:24:50 -0800286 size_t rshift = CLZ(refOffsets);
287 size_t offset = CLASS_OFFSET_FROM_CLZ(rshift);
288 Object *ref = dvmGetFieldObject((Object*)obj, offset);
289 markObject(ref, ctx);
Barry Hayeseac47ed2009-06-22 11:45:20 -0700290 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800291 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700292 } else {
Barry Hayese1bccb92010-05-18 09:48:37 -0700293 ClassObject *clazz;
Barry Hayese1bccb92010-05-18 09:48:37 -0700294 for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
295 InstField *field = clazz->ifields;
Carl Shapiro3e24d332010-11-29 17:24:50 -0800296 int i;
Barry Hayese1bccb92010-05-18 09:48:37 -0700297 for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
298 void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
299 markObject(((JValue *)addr)->l, ctx);
Barry Hayeseac47ed2009-06-22 11:45:20 -0700300 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700301 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800302 }
303}
304
Barry Hayese1bccb92010-05-18 09:48:37 -0700305/*
Carl Shapiro3e24d332010-11-29 17:24:50 -0800306 * Scans the static fields of a class object.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800307 */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800308static void scanStaticFields(const ClassObject *clazz, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800309{
Barry Hayese1bccb92010-05-18 09:48:37 -0700310 int i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800311
Carl Shapiro3e24d332010-11-29 17:24:50 -0800312 assert(clazz != NULL);
Barry Hayese1bccb92010-05-18 09:48:37 -0700313 assert(ctx != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800314 for (i = 0; i < clazz->sfieldCount; ++i) {
315 char ch = clazz->sfields[i].field.signature[0];
316 if (ch == '[' || ch == 'L') {
317 markObject(clazz->sfields[i].value.l, ctx);
318 }
319 }
320}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800321
Carl Shapiro3e24d332010-11-29 17:24:50 -0800322/*
323 * Visit the interfaces of a class object.
324 */
325static void scanInterfaces(const ClassObject *clazz, GcMarkContext *ctx)
326{
327 int i;
328
329 assert(clazz != NULL);
330 assert(ctx != NULL);
331 for (i = 0; i < clazz->interfaceCount; ++i) {
332 markObject((const Object *)clazz->interfaces[i], ctx);
333 }
334}
335
336/*
337 * Scans the header, static field references, and interface
338 * pointers of a class object.
339 */
340static void scanClassObject(const Object *obj, GcMarkContext *ctx)
341{
342 const ClassObject *asClass;
343
344 assert(obj != NULL);
345 assert(obj->clazz == gDvm.classJavaLangClass);
346 assert(ctx != NULL);
347 markObject((const Object *)obj->clazz, ctx);
348 asClass = (const ClassObject *)obj;
349 if (IS_CLASS_FLAG_SET(asClass, CLASS_ISARRAY)) {
350 markObject((const Object *)asClass->elementClass, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700351 }
Barry Hayesc49db852010-05-14 13:43:34 -0700352 /* Do super and the interfaces contain Objects and not dex idx values? */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800353 if (asClass->status > CLASS_IDX) {
354 markObject((const Object *)asClass->super, ctx);
Barry Hayesc49db852010-05-14 13:43:34 -0700355 }
Carl Shapiro3e24d332010-11-29 17:24:50 -0800356 markObject((const Object *)asClass->classLoader, ctx);
357 scanFields(obj, ctx);
358 scanStaticFields(asClass, ctx);
359 if (asClass->status > CLASS_IDX) {
360 scanInterfaces(asClass, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800361 }
362}
363
Barry Hayese1bccb92010-05-18 09:48:37 -0700364/*
365 * Scans the header of all array objects. If the array object is
366 * specialized to a reference type, scans the array data as well.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800367 */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800368static void scanArrayObject(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800369{
Barry Hayese1bccb92010-05-18 09:48:37 -0700370 assert(obj != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800371 assert(obj->clazz != NULL);
Barry Hayese1bccb92010-05-18 09:48:37 -0700372 assert(ctx != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800373 markObject((const Object *)obj->clazz, ctx);
374 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISOBJECTARRAY)) {
375 const ArrayObject *array = (const ArrayObject *)obj;
376 const Object **contents = (const Object **)array->contents;
377 size_t i;
378 for (i = 0; i < array->length; ++i) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700379 markObject(contents[i], ctx);
380 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800381 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700382}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800383
Barry Hayese1bccb92010-05-18 09:48:37 -0700384/*
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700385 * Returns class flags relating to Reference subclasses.
386 */
387static int referenceClassFlags(const Object *obj)
388{
389 int flags = CLASS_ISREFERENCE |
390 CLASS_ISWEAKREFERENCE |
391 CLASS_ISPHANTOMREFERENCE;
392 return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
393}
394
395/*
396 * Returns true if the object derives from SoftReference.
397 */
398static bool isSoftReference(const Object *obj)
399{
400 return referenceClassFlags(obj) == CLASS_ISREFERENCE;
401}
402
403/*
404 * Returns true if the object derives from WeakReference.
405 */
406static bool isWeakReference(const Object *obj)
407{
408 return referenceClassFlags(obj) & CLASS_ISWEAKREFERENCE;
409}
410
411/*
412 * Returns true if the object derives from PhantomReference.
413 */
414static bool isPhantomReference(const Object *obj)
415{
416 return referenceClassFlags(obj) & CLASS_ISPHANTOMREFERENCE;
417}
418
419/*
420 * Adds a reference to the tail of a circular queue of references.
421 */
422static void enqueuePendingReference(Object *ref, Object **list)
423{
424 size_t offset;
425
426 assert(ref != NULL);
427 assert(list != NULL);
428 offset = gDvm.offJavaLangRefReference_pendingNext;
429 if (*list == NULL) {
430 dvmSetFieldObject(ref, offset, ref);
431 *list = ref;
432 } else {
433 Object *head = dvmGetFieldObject(*list, offset);
434 dvmSetFieldObject(ref, offset, head);
435 dvmSetFieldObject(*list, offset, ref);
436 }
437}
438
439/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700440 * Removes the reference at the head of a circular queue of
441 * references.
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700442 */
443static Object *dequeuePendingReference(Object **list)
444{
445 Object *ref, *head;
446 size_t offset;
447
448 assert(list != NULL);
449 assert(*list != NULL);
450 offset = gDvm.offJavaLangRefReference_pendingNext;
451 head = dvmGetFieldObject(*list, offset);
452 if (*list == head) {
453 ref = *list;
454 *list = NULL;
455 } else {
456 Object *next = dvmGetFieldObject(head, offset);
457 dvmSetFieldObject(*list, offset, next);
458 ref = head;
459 }
460 dvmSetFieldObject(ref, offset, NULL);
461 return ref;
462}
463
464/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700465 * Process the "referent" field in a java.lang.ref.Reference. If the
466 * referent has not yet been marked, put it on the appropriate list in
467 * the gcHeap for later processing.
468 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700469static void delayReferenceReferent(Object *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700470{
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700471 GcHeap *gcHeap = gDvm.gcHeap;
472 Object *pending, *referent;
473 size_t pendingNextOffset, referentOffset;
474
Barry Hayese1bccb92010-05-18 09:48:37 -0700475 assert(obj != NULL);
Barry Hayes697b5a92010-06-23 11:38:52 -0700476 assert(obj->clazz != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700477 assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
Barry Hayese1bccb92010-05-18 09:48:37 -0700478 assert(ctx != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700479 pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
480 referentOffset = gDvm.offJavaLangRefReference_referent;
481 pending = dvmGetFieldObject(obj, pendingNextOffset);
482 referent = dvmGetFieldObject(obj, referentOffset);
483 if (pending == NULL && referent != NULL && !isMarked(referent, ctx)) {
484 Object **list = NULL;
485 if (isSoftReference(obj)) {
486 list = &gcHeap->softReferences;
487 } else if (isWeakReference(obj)) {
488 list = &gcHeap->weakReferences;
489 } else if (isPhantomReference(obj)) {
490 list = &gcHeap->phantomReferences;
Barry Hayese1bccb92010-05-18 09:48:37 -0700491 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700492 assert(list != NULL);
493 enqueuePendingReference(obj, list);
Barry Hayese1bccb92010-05-18 09:48:37 -0700494 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800495}
496
Barry Hayese1bccb92010-05-18 09:48:37 -0700497/*
498 * Scans the header and field references of a data object.
499 */
Carl Shapiro3e24d332010-11-29 17:24:50 -0800500static void scanDataObject(const Object *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700501{
502 assert(obj != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800503 assert(obj->clazz != NULL);
Barry Hayese1bccb92010-05-18 09:48:37 -0700504 assert(ctx != NULL);
Carl Shapiro3e24d332010-11-29 17:24:50 -0800505 markObject((const Object *)obj->clazz, ctx);
506 scanFields(obj, ctx);
507 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE)) {
Barry Hayes697b5a92010-06-23 11:38:52 -0700508 delayReferenceReferent((Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700509 }
510}
511
512/*
513 * Scans an object reference. Determines the type of the reference
514 * and dispatches to a specialized scanning routine.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800515 */
516static void scanObject(const Object *obj, GcMarkContext *ctx)
517{
Barry Hayese1bccb92010-05-18 09:48:37 -0700518 assert(obj != NULL);
519 assert(ctx != NULL);
Barry Hayes899cdb72010-06-08 09:59:12 -0700520 assert(obj->clazz != NULL);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700521 if (obj->clazz == gDvm.classJavaLangClass) {
Carl Shapiro3e24d332010-11-29 17:24:50 -0800522 scanClassObject(obj, ctx);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700523 } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
Carl Shapiro3e24d332010-11-29 17:24:50 -0800524 scanArrayObject(obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800525 } else {
Carl Shapiro3e24d332010-11-29 17:24:50 -0800526 scanDataObject(obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800527 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800528}
529
Carl Shapirofdf80522010-11-09 14:27:02 -0800530/*
531 * Scan anything that's on the mark stack. We can't use the bitmaps
532 * anymore, so use a finger that points past the end of them.
533 */
534static void processMarkStack(GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800535{
Carl Shapirofdf80522010-11-09 14:27:02 -0800536 GcMarkStack *stack;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800537
Carl Shapirofdf80522010-11-09 14:27:02 -0800538 assert(ctx != NULL);
Carl Shapiro034fba52010-11-11 16:39:58 -0800539 assert(ctx->finger == (void *)ULONG_MAX);
Carl Shapirofdf80522010-11-09 14:27:02 -0800540 stack = &ctx->stack;
541 assert(stack->top >= stack->base);
542 while (stack->top > stack->base) {
543 const Object *obj = markStackPop(stack);
544 scanObject(obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800545 }
546}
547
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700548static size_t objectSize(const Object *obj)
549{
550 assert(dvmIsValidObject(obj));
551 assert(dvmIsValidObject((Object *)obj->clazz));
552 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
553 return dvmArrayObjectSize((ArrayObject *)obj);
554 } else if (obj->clazz == gDvm.classJavaLangClass) {
555 return dvmClassObjectSize((ClassObject *)obj);
556 } else {
557 return obj->clazz->objectSize;
558 }
559}
560
561/*
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700562 * Scans forward to the header of the next marked object between start
563 * and limit. Returns NULL if no marked objects are in that region.
564 */
Carl Shapiro7ec91442010-10-21 15:35:19 -0700565static Object *nextGrayObject(const u1 *base, const u1 *limit,
566 const HeapBitmap *markBits)
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700567{
Carl Shapiro7ec91442010-10-21 15:35:19 -0700568 const u1 *ptr;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700569
570 assert(base < limit);
571 assert(limit - base <= GC_CARD_SIZE);
572 for (ptr = base; ptr < limit; ptr += HB_OBJECT_ALIGNMENT) {
Carl Shapiroea10c552010-09-02 23:32:25 -0700573 if (dvmHeapBitmapIsObjectBitSet(markBits, ptr))
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700574 return (Object *)ptr;
575 }
576 return NULL;
577}
578
579/*
Carl Shapiro7ec91442010-10-21 15:35:19 -0700580 * Scans each byte from start below end returning the address of the
581 * first dirty card. Returns NULL if no dirty card is found.
582 */
583static const u1 *scanBytesForDirtyCard(const u1 *start, const u1 *end)
584{
585 const u1 *ptr;
586
587 assert(start <= end);
588 for (ptr = start; ptr < end; ++ptr) {
589 if (*ptr == GC_CARD_DIRTY) {
590 return ptr;
591 }
592 }
593 return NULL;
594}
595
596/*
597 * Like scanBytesForDirtyCard but scans the range from start below end
598 * by words. Assumes start and end are word aligned.
599 */
600static const u1 *scanWordsForDirtyCard(const u1 *start, const u1 *end)
601{
602 const u1 *ptr;
603
604 assert((uintptr_t)start % kWordSize == 0);
605 assert((uintptr_t)end % kWordSize == 0);
606 assert(start <= end);
607 for (ptr = start; ptr < end; ptr += kWordSize) {
608 if (*(const Word *)ptr != 0) {
609 const u1 *dirty = scanBytesForDirtyCard(ptr, ptr + kWordSize);
610 if (dirty != NULL) {
611 return dirty;
612 }
613 }
614 }
615 return NULL;
616}
617
618/*
619 * Scans the card table as quickly as possible looking for a dirty
620 * card. Returns the address of the first dirty card found or NULL if
621 * no dirty cards were found.
622 */
623static const u1 *nextDirtyCard(const u1 *start, const u1 *end)
624{
625 const u1 *wstart = (u1 *)ALIGN_UP(start, kWordSize);
626 const u1 *wend = (u1 *)ALIGN_DOWN(end, kWordSize);
627 const u1 *ptr, *dirty;
628
629 assert(start <= end);
630 assert(start <= wstart);
631 assert(end >= wend);
632 ptr = start;
633 if (wstart < end) {
634 /* Scan the leading unaligned bytes. */
635 dirty = scanBytesForDirtyCard(ptr, wstart);
636 if (dirty != NULL) {
637 return dirty;
638 }
639 /* Scan the range of aligned words. */
640 dirty = scanWordsForDirtyCard(wstart, wend);
641 if (dirty != NULL) {
642 return dirty;
643 }
644 ptr = wend;
645 }
646 /* Scan trailing unaligned bytes. */
647 dirty = scanBytesForDirtyCard(ptr, end);
648 if (dirty != NULL) {
649 return dirty;
650 }
651 return NULL;
652}
653
654/*
655 * Scans range of dirty cards between start and end. A range of dirty
656 * cards is composed consecutively dirty cards or dirty cards spanned
657 * by a gray object. Returns the address of a clean card if the scan
658 * reached a clean card or NULL if the scan reached the end.
659 */
660const u1 *scanDirtyCards(const u1 *start, const u1 *end,
661 GcMarkContext *ctx)
662{
663 const HeapBitmap *markBits = ctx->bitmap;
664 const u1 *card = start, *prevAddr = NULL;
665 while (card < end) {
666 if (*card != GC_CARD_DIRTY) {
667 return card;
668 }
669 const u1 *ptr = prevAddr ? prevAddr : dvmAddrFromCard(card);
670 const u1 *limit = ptr + GC_CARD_SIZE;
671 while (ptr < limit) {
672 Object *obj = nextGrayObject(ptr, limit, markBits);
673 if (obj == NULL) {
674 break;
675 }
676 scanObject(obj, ctx);
677 ptr = (u1*)obj + ALIGN_UP(objectSize(obj), HB_OBJECT_ALIGNMENT);
678 }
679 if (ptr < limit) {
680 /* Ended within the current card, advance to the next card. */
681 ++card;
682 prevAddr = NULL;
683 } else {
684 /* Ended past the current card, skip ahead. */
685 card = dvmCardFromAddr(ptr);
686 prevAddr = ptr;
687 }
688 }
689 return NULL;
690}
691
692/*
693 * Blackens gray objects found on dirty cards.
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700694 */
695static void scanGrayObjects(GcMarkContext *ctx)
696{
697 GcHeap *h = gDvm.gcHeap;
Carl Shapiro7ec91442010-10-21 15:35:19 -0700698 const u1 *base, *limit, *ptr, *dirty;
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700699 size_t footprint;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700700
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700701 footprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
Carl Shapiro7ec91442010-10-21 15:35:19 -0700702 base = &h->cardTableBase[0];
703 limit = dvmCardFromAddr((u1 *)dvmHeapSourceGetBase() + footprint);
704 assert(limit <= &h->cardTableBase[h->cardTableLength]);
705
706 ptr = base;
707 for (;;) {
708 dirty = nextDirtyCard(ptr, limit);
709 if (dirty == NULL) {
710 break;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700711 }
Carl Shapiro7ec91442010-10-21 15:35:19 -0700712 assert((dirty > ptr) && (dirty < limit));
713 ptr = scanDirtyCards(dirty, limit, ctx);
714 if (ptr == NULL) {
715 break;
716 }
717 assert((ptr > dirty) && (ptr < limit));
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700718 }
719}
720
Carl Shapiro57ee2702010-08-27 13:06:48 -0700721/*
722 * Callback for scanning each object in the bitmap. The finger is set
723 * to the address corresponding to the lowest address in the next word
724 * of bits in the bitmap.
725 */
Carl Shapiro38d710b2010-08-31 16:48:31 -0700726static void scanBitmapCallback(void *addr, void *finger, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800727{
Carl Shapiro006346e2010-07-29 20:39:50 -0700728 GcMarkContext *ctx = arg;
Carl Shapiro57ee2702010-08-27 13:06:48 -0700729 ctx->finger = (void *)finger;
730 scanObject(addr, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800731}
732
733/* Given bitmaps with the root set marked, find and mark all
734 * reachable objects. When this returns, the entire set of
735 * live objects will be marked and the mark stack will be empty.
736 */
Carl Shapiro29540742010-03-26 15:34:39 -0700737void dvmHeapScanMarkedObjects(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800738{
739 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
740
741 assert(ctx->finger == NULL);
742
743 /* The bitmaps currently have bits set for the root set.
744 * Walk across the bitmaps and scan each object.
745 */
Carl Shapiro38d710b2010-08-31 16:48:31 -0700746 dvmHeapBitmapScanWalk(ctx->bitmap, scanBitmapCallback, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800747
Carl Shapiro034fba52010-11-11 16:39:58 -0800748 ctx->finger = (void *)ULONG_MAX;
749
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800750 /* We've walked the mark bitmaps. Scan anything that's
751 * left on the mark stack.
752 */
753 processMarkStack(ctx);
754
755 LOG_SCAN("done with marked objects\n");
756}
757
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700758void dvmHeapReScanMarkedObjects(void)
Carl Shapiroec805ea2010-06-28 16:28:26 -0700759{
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700760 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700761
Carl Shapiroec805ea2010-06-28 16:28:26 -0700762 /*
Carl Shapirof5860332010-06-28 23:02:08 -0700763 * The finger must have been set to the maximum value to ensure
764 * that gray objects will be pushed onto the mark stack.
Carl Shapiroec805ea2010-06-28 16:28:26 -0700765 */
766 assert(ctx->finger == (void *)ULONG_MAX);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700767 scanGrayObjects(ctx);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700768 processMarkStack(ctx);
769}
770
Carl Shapiro34f51992010-07-09 17:55:41 -0700771/*
772 * Clear the referent field.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800773 */
Barry Hayes6930a112009-12-22 11:01:38 -0800774static void clearReference(Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800775{
Carl Shapiro34f51992010-07-09 17:55:41 -0700776 size_t offset = gDvm.offJavaLangRefReference_referent;
777 dvmSetFieldObject(reference, offset, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800778}
779
Carl Shapiro29540742010-03-26 15:34:39 -0700780/*
781 * Returns true if the reference was registered with a reference queue
782 * and has not yet been enqueued.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800783 */
Carl Shapiro29540742010-03-26 15:34:39 -0700784static bool isEnqueuable(const Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800785{
Barry Hayes6930a112009-12-22 11:01:38 -0800786 Object *queue = dvmGetFieldObject(reference,
787 gDvm.offJavaLangRefReference_queue);
788 Object *queueNext = dvmGetFieldObject(reference,
789 gDvm.offJavaLangRefReference_queueNext);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700790 return queue != NULL && queueNext == NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800791}
792
Carl Shapiro29540742010-03-26 15:34:39 -0700793/*
794 * Schedules a reference to be appended to its reference queue.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800795 */
Carl Shapiro29540742010-03-26 15:34:39 -0700796static void enqueueReference(Object *ref)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800797{
Carl Shapiro646ba092010-06-10 15:17:00 -0700798 assert(ref != NULL);
Carl Shapiro29540742010-03-26 15:34:39 -0700799 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
800 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
Carl Shapiro646ba092010-06-10 15:17:00 -0700801 if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
Carl Shapiro29540742010-03-26 15:34:39 -0700802 LOGE_HEAP("enqueueReference(): no room for any more "
803 "reference operations\n");
804 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800805 }
806}
807
Carl Shapiro29540742010-03-26 15:34:39 -0700808/*
809 * Walks the reference list marking any references subject to the
810 * reference clearing policy. References with a black referent are
811 * removed from the list. References with white referents biased
812 * toward saving are blackened and also removed from the list.
813 */
814void dvmHandleSoftRefs(Object **list)
815{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700816 GcMarkContext *ctx;
Carl Shapiro29540742010-03-26 15:34:39 -0700817 Object *ref, *referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700818 Object *clear;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700819 size_t referentOffset;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700820 size_t counter;
Carl Shapiro29540742010-03-26 15:34:39 -0700821 bool marked;
822
Carl Shapirob2e78d32010-08-20 11:34:18 -0700823 ctx = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700824 referentOffset = gDvm.offJavaLangRefReference_referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700825 clear = NULL;
Carl Shapiro29540742010-03-26 15:34:39 -0700826 counter = 0;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700827 while (*list != NULL) {
828 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 marked = isMarked(referent, ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700832 if (!marked && ((++counter) & 1)) {
833 /* Referent is white and biased toward saving, mark it. */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700834 markObject(referent, ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700835 marked = true;
836 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700837 if (!marked) {
838 /* Referent is white, queue it for clearing. */
839 enqueuePendingReference(ref, &clear);
Carl Shapiro29540742010-03-26 15:34:39 -0700840 }
Carl Shapiro29540742010-03-26 15:34:39 -0700841 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700842 *list = clear;
Carl Shapiro29540742010-03-26 15:34:39 -0700843 /*
844 * Restart the mark with the newly black references added to the
845 * root set.
846 */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700847 processMarkStack(ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700848}
849
850/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700851 * Unlink the reference list clearing references objects with white
852 * referents. Cleared references registered to a reference queue are
853 * scheduled for appending by the heap worker thread.
Carl Shapiro29540742010-03-26 15:34:39 -0700854 */
855void dvmClearWhiteRefs(Object **list)
856{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700857 GcMarkContext *ctx;
Carl Shapiro29540742010-03-26 15:34:39 -0700858 Object *ref, *referent;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700859 size_t referentOffset;
Carl Shapiro29540742010-03-26 15:34:39 -0700860 bool doSignal;
861
Carl Shapirob2e78d32010-08-20 11:34:18 -0700862 ctx = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700863 referentOffset = gDvm.offJavaLangRefReference_referent;
864 doSignal = false;
865 while (*list != NULL) {
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700866 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700867 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700868 assert(referent != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700869 if (!isMarked(referent, ctx)) {
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700870 /* Referent is white, clear it. */
Carl Shapiro29540742010-03-26 15:34:39 -0700871 clearReference(ref);
872 if (isEnqueuable(ref)) {
873 enqueueReference(ref);
874 doSignal = true;
875 }
876 }
877 }
878 /*
879 * If we cleared a reference with a reference queue we must notify
880 * the heap worker to append the reference.
881 */
882 if (doSignal) {
883 dvmSignalHeapWorker(false);
884 }
885 assert(*list == NULL);
886}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800887
888/* Find unreachable objects that need to be finalized,
889 * and schedule them for finalization.
890 */
891void dvmHeapScheduleFinalizations()
892{
893 HeapRefTable newPendingRefs;
894 LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
895 Object **ref;
896 Object **lastRef;
897 size_t totalPendCount;
Carl Shapirob2e78d32010-08-20 11:34:18 -0700898 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800899
900 /*
901 * All reachable objects have been marked.
902 * Any unmarked finalizable objects need to be finalized.
903 */
904
905 /* Create a table that the new pending refs will
906 * be added to.
907 */
Barry Hayesd4f78d32010-06-08 09:34:42 -0700908 if (!dvmHeapInitHeapRefTable(&newPendingRefs)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800909 //TODO: mark all finalizable refs and hope that
910 // we can schedule them next time. Watch out,
911 // because we may be expecting to free up space
912 // by calling finalizers.
913 LOGE_GC("dvmHeapScheduleFinalizations(): no room for "
914 "pending finalizations\n");
915 dvmAbort();
916 }
917
918 /* Walk through finalizableRefs and move any unmarked references
919 * to the list of new pending refs.
920 */
921 totalPendCount = 0;
922 while (finRefs != NULL) {
923 Object **gapRef;
924 size_t newPendCount = 0;
925
926 gapRef = ref = finRefs->refs.table;
927 lastRef = finRefs->refs.nextEntry;
928 while (ref < lastRef) {
Carl Shapirob2e78d32010-08-20 11:34:18 -0700929 if (!isMarked(*ref, ctx)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800930 if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
931 //TODO: add the current table and allocate
932 // a new, smaller one.
933 LOGE_GC("dvmHeapScheduleFinalizations(): "
934 "no room for any more pending finalizations: %zd\n",
935 dvmHeapNumHeapRefTableEntries(&newPendingRefs));
936 dvmAbort();
937 }
938 newPendCount++;
939 } else {
940 /* This ref is marked, so will remain on finalizableRefs.
941 */
942 if (newPendCount > 0) {
943 /* Copy it up to fill the holes.
944 */
945 *gapRef++ = *ref;
946 } else {
947 /* No holes yet; don't bother copying.
948 */
949 gapRef++;
950 }
951 }
952 ref++;
953 }
954 finRefs->refs.nextEntry = gapRef;
955 //TODO: if the table is empty when we're done, free it.
956 totalPendCount += newPendCount;
957 finRefs = finRefs->next;
958 }
959 LOGD_GC("dvmHeapScheduleFinalizations(): %zd finalizers triggered.\n",
960 totalPendCount);
961 if (totalPendCount == 0) {
962 /* No objects required finalization.
963 * Free the empty temporary table.
964 */
965 dvmClearReferenceTable(&newPendingRefs);
966 return;
967 }
968
969 /* Add the new pending refs to the main list.
970 */
971 if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
972 &newPendingRefs))
973 {
974 LOGE_GC("dvmHeapScheduleFinalizations(): can't insert new "
975 "pending finalizations\n");
976 dvmAbort();
977 }
978
979 //TODO: try compacting the main list with a memcpy loop
980
981 /* Mark the refs we just moved; we don't want them or their
982 * children to get swept yet.
983 */
984 ref = newPendingRefs.table;
985 lastRef = newPendingRefs.nextEntry;
986 assert(ref < lastRef);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800987 while (ref < lastRef) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700988 assert(*ref != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700989 markObject(*ref, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800990 ref++;
991 }
Carl Shapirob2e78d32010-08-20 11:34:18 -0700992 processMarkStack(ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800993 dvmSignalHeapWorker(false);
994}
995
996void dvmHeapFinishMarkStep()
997{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700998 GcMarkContext *ctx;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800999
Carl Shapirob2e78d32010-08-20 11:34:18 -07001000 ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001001
Barry Hayes81010a42010-07-19 14:07:01 -07001002 /* The mark bits are now not needed.
1003 */
1004 dvmHeapSourceZeroMarkBitmap();
1005
Carl Shapirof373efd2010-02-19 00:46:33 -08001006 /* Clean up everything else associated with the marking process.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001007 */
Carl Shapirob2e78d32010-08-20 11:34:18 -07001008 destroyMarkStack(&ctx->stack);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001009
Carl Shapirob2e78d32010-08-20 11:34:18 -07001010 ctx->finger = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001011}
1012
Carl Shapiro8881a802010-08-10 15:55:45 -07001013typedef struct {
1014 size_t numObjects;
1015 size_t numBytes;
1016 bool isConcurrent;
1017} SweepContext;
1018
Carl Shapiro57ee2702010-08-27 13:06:48 -07001019static void sweepBitmapCallback(size_t numPtrs, void **ptrs, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001020{
Carl Shapirob9b23952010-08-10 17:20:15 -07001021 SweepContext *ctx = arg;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001022
Carl Shapiro8881a802010-08-10 15:55:45 -07001023 if (ctx->isConcurrent) {
1024 dvmLockHeap();
1025 }
1026 ctx->numBytes += dvmHeapSourceFreeList(numPtrs, ptrs);
1027 ctx->numObjects += numPtrs;
1028 if (ctx->isConcurrent) {
1029 dvmUnlockHeap();
1030 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001031}
1032
Carl Shapiro8881a802010-08-10 15:55:45 -07001033/*
1034 * Returns true if the given object is unmarked. This assumes that
1035 * the bitmaps have not yet been swapped.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001036 */
1037static int isUnmarkedObject(void *object)
1038{
Carl Shapiro6343bd02010-02-16 17:40:19 -08001039 return !isMarked((void *)((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001040 &gDvm.gcHeap->markContext);
1041}
1042
Carl Shapiro8881a802010-08-10 15:55:45 -07001043/*
1044 * Process all the internal system structures that behave like
1045 * weakly-held objects.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001046 */
Carl Shapiro8881a802010-08-10 15:55:45 -07001047void dvmHeapSweepSystemWeaks(void)
1048{
1049 dvmGcDetachDeadInternedStrings(isUnmarkedObject);
1050 dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
1051}
1052
1053/*
1054 * Walk through the list of objects that haven't been marked and free
1055 * them. Assumes the bitmaps have been swapped.
1056 */
1057void dvmHeapSweepUnmarkedObjects(GcMode mode, bool isConcurrent,
1058 size_t *numObjects, size_t *numBytes)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001059{
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001060 HeapBitmap currMark[HEAP_SOURCE_MAX_HEAP_COUNT];
1061 HeapBitmap currLive[HEAP_SOURCE_MAX_HEAP_COUNT];
Carl Shapiro8881a802010-08-10 15:55:45 -07001062 SweepContext ctx;
Carl Shapirod25566d2010-03-11 20:39:47 -08001063 size_t numBitmaps, numSweepBitmaps;
Barry Hayese168ebd2010-05-07 09:19:46 -07001064 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001065
Carl Shapirof373efd2010-02-19 00:46:33 -08001066 numBitmaps = dvmHeapSourceGetNumHeaps();
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001067 dvmHeapSourceGetObjectBitmaps(currLive, currMark, numBitmaps);
Carl Shapirod25566d2010-03-11 20:39:47 -08001068 if (mode == GC_PARTIAL) {
1069 numSweepBitmaps = 1;
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001070 assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == currLive[0].base);
Carl Shapirod25566d2010-03-11 20:39:47 -08001071 } else {
1072 numSweepBitmaps = numBitmaps;
1073 }
Carl Shapiro8881a802010-08-10 15:55:45 -07001074 ctx.numObjects = ctx.numBytes = 0;
1075 ctx.isConcurrent = isConcurrent;
Barry Hayese168ebd2010-05-07 09:19:46 -07001076 for (i = 0; i < numSweepBitmaps; i++) {
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001077 HeapBitmap* prevLive = &currMark[i];
1078 HeapBitmap* prevMark = &currLive[i];
1079 dvmHeapBitmapSweepWalk(prevLive, prevMark, sweepBitmapCallback, &ctx);
Barry Hayese168ebd2010-05-07 09:19:46 -07001080 }
Carl Shapiro8881a802010-08-10 15:55:45 -07001081 *numObjects = ctx.numObjects;
1082 *numBytes = ctx.numBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001083 if (gDvm.allocProf.enabled) {
Carl Shapiro8881a802010-08-10 15:55:45 -07001084 gDvm.allocProf.freeCount += ctx.numObjects;
1085 gDvm.allocProf.freeSize += ctx.numBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001086 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001087}