blob: e50f048661944038eb3600fe64dfcd89b9fbf53a [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Dalvik.h"
Barry Hayeseac47ed2009-06-22 11:45:20 -070018#include "alloc/clz.h"
Carl Shapiro7ec91442010-10-21 15:35:19 -070019#include "alloc/CardTable.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080020#include "alloc/HeapBitmap.h"
21#include "alloc/HeapInternal.h"
22#include "alloc/HeapSource.h"
23#include "alloc/MarkSweep.h"
Carl Shapiroec805ea2010-06-28 16:28:26 -070024#include "alloc/Visit.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080025#include <limits.h> // for ULONG_MAX
26#include <sys/mman.h> // for madvise(), mmap()
The Android Open Source Project99409882009-03-18 22:20:24 -070027#include <errno.h>
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080028
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080029#define GC_LOG_TAG LOG_TAG "-gc"
30
31#if LOG_NDEBUG
32#define LOGV_GC(...) ((void)0)
33#define LOGD_GC(...) ((void)0)
34#else
35#define LOGV_GC(...) LOG(LOG_VERBOSE, GC_LOG_TAG, __VA_ARGS__)
36#define LOGD_GC(...) LOG(LOG_DEBUG, GC_LOG_TAG, __VA_ARGS__)
37#endif
38
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080039#define LOGI_GC(...) LOG(LOG_INFO, GC_LOG_TAG, __VA_ARGS__)
40#define LOGW_GC(...) LOG(LOG_WARN, GC_LOG_TAG, __VA_ARGS__)
41#define LOGE_GC(...) LOG(LOG_ERROR, GC_LOG_TAG, __VA_ARGS__)
42
43#define LOG_SCAN(...) LOGV_GC("SCAN: " __VA_ARGS__)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080044
Carl Shapiro7ec91442010-10-21 15:35:19 -070045#define ALIGN_DOWN(x, n) ((size_t)(x) & -(n))
Carl Shapiro57ee2702010-08-27 13:06:48 -070046#define ALIGN_UP(x, n) (((size_t)(x) + (n) - 1) & ~((n) - 1))
47#define ALIGN_UP_TO_PAGE_SIZE(p) ALIGN_UP(p, SYSTEM_PAGE_SIZE)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080048
Carl Shapiro7ec91442010-10-21 15:35:19 -070049typedef unsigned long Word;
50const size_t kWordSize = sizeof(Word);
51
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080052/* Do not cast the result of this to a boolean; the only set bit
53 * may be > 1<<8.
54 */
Carl Shapiro6343bd02010-02-16 17:40:19 -080055static inline long isMarked(const void *obj, const GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080056{
Carl Shapirof373efd2010-02-19 00:46:33 -080057 return dvmHeapBitmapIsObjectBitSet(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080058}
59
Carl Shapirofdf80522010-11-09 14:27:02 -080060/*
61 * Initializes the stack top and advises the mark stack pages as needed.
62 */
Carl Shapirod7400e02010-09-02 18:24:29 -070063static bool createMarkStack(GcMarkStack *stack)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080064{
Carl Shapirofdf80522010-11-09 14:27:02 -080065 assert(stack != NULL);
66 size_t length = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
67 (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
68 madvise(stack->base, length, MADV_NORMAL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080069 stack->top = stack->base;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080070 return true;
71}
72
Carl Shapirofdf80522010-11-09 14:27:02 -080073/*
74 * Assigns NULL to the stack top and advises the mark stack pages as
75 * not needed.
76 */
Carl Shapirod7400e02010-09-02 18:24:29 -070077static void destroyMarkStack(GcMarkStack *stack)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080078{
Carl Shapirofdf80522010-11-09 14:27:02 -080079 assert(stack != NULL);
80 madvise(stack->base, stack->length, MADV_DONTNEED);
81 stack->top = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080082}
83
Carl Shapirofdf80522010-11-09 14:27:02 -080084/*
85 * Pops an object from the mark stack.
86 */
87static void markStackPush(GcMarkStack *stack, const Object *obj)
88{
89 assert(stack != NULL);
90 assert(stack->base <= stack->top);
91 assert(stack->limit > stack->top);
92 assert(obj != NULL);
93 *stack->top = obj;
94 ++stack->top;
95}
96
97/*
98 * Pushes an object on the mark stack.
99 */
100static const Object *markStackPop(GcMarkStack *stack)
101{
102 const Object *obj;
103
104 assert(stack != NULL);
105 assert(stack->base < stack->top);
106 assert(stack->limit > stack->top);
107 --stack->top;
108 obj = *stack->top;
109 return obj;
110}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800111
Carl Shapirod7400e02010-09-02 18:24:29 -0700112bool dvmHeapBeginMarkStep(GcMode mode)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800113{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700114 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800115
Carl Shapirob2e78d32010-08-20 11:34:18 -0700116 if (!createMarkStack(&ctx->stack)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800117 return false;
118 }
Carl Shapirob2e78d32010-08-20 11:34:18 -0700119 ctx->finger = NULL;
120 ctx->immuneLimit = dvmHeapSourceGetImmuneLimit(mode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800121 return true;
122}
123
Carl Shapirod7400e02010-09-02 18:24:29 -0700124static long setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800125{
Carl Shapirof373efd2010-02-19 00:46:33 -0800126 return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800127}
128
Carl Shapirod7400e02010-09-02 18:24:29 -0700129static void markObjectNonNull(const Object *obj, GcMarkContext *ctx,
130 bool checkFinger)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800131{
Barry Hayese1bccb92010-05-18 09:48:37 -0700132 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800133 assert(obj != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800134 assert(dvmIsValidObject(obj));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800135
Carl Shapirob31b3012010-05-25 18:35:37 -0700136 if (obj < (Object *)ctx->immuneLimit) {
Carl Shapirod25566d2010-03-11 20:39:47 -0800137 assert(isMarked(obj, ctx));
138 return;
139 }
Carl Shapiro6343bd02010-02-16 17:40:19 -0800140 if (!setAndReturnMarkBit(ctx, obj)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800141 /* This object was not previously marked.
142 */
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700143 if (checkFinger && (void *)obj < ctx->finger) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800144 /* This object will need to go on the mark stack.
145 */
Carl Shapirofdf80522010-11-09 14:27:02 -0800146 markStackPush(&ctx->stack, obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800147 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800148 }
149}
150
151/* Used to mark objects when recursing. Recursion is done by moving
152 * the finger across the bitmaps in address order and marking child
153 * objects. Any newly-marked objects whose addresses are lower than
154 * the finger won't be visited by the bitmap scan, so those objects
155 * need to be added to the mark stack.
156 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700157static void markObject(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800158{
Barry Hayese1bccb92010-05-18 09:48:37 -0700159 if (obj != NULL) {
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700160 markObjectNonNull(obj, ctx, true);
Barry Hayese1bccb92010-05-18 09:48:37 -0700161 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800162}
163
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800164/* If the object hasn't already been marked, mark it and
165 * schedule it to be scanned for references.
166 *
167 * obj may not be NULL. The macro dvmMarkObject() should
168 * be used in situations where a reference may be NULL.
169 *
170 * This function may only be called when marking the root
Barry Hayese1bccb92010-05-18 09:48:37 -0700171 * set. When recursing, use the internal markObject().
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800172 */
Carl Shapirod7400e02010-09-02 18:24:29 -0700173void dvmMarkObjectNonNull(const Object *obj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800174{
Barry Hayese1bccb92010-05-18 09:48:37 -0700175 assert(obj != NULL);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700176 markObjectNonNull(obj, &gDvm.gcHeap->markContext, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800177}
178
179/* Mark the set of root objects.
180 *
181 * Things we need to scan:
182 * - System classes defined by root classloader
183 * - For each thread:
184 * - Interpreted stack, from top to "curFrame"
185 * - Dalvik registers (args + local vars)
186 * - JNI local references
187 * - Automatic VM local references (TrackedAlloc)
188 * - Associated Thread/VMThread object
189 * - ThreadGroups (could track & start with these instead of working
190 * upward from Threads)
191 * - Exception currently being thrown, if present
192 * - JNI global references
193 * - Interned string table
194 * - Primitive classes
195 * - Special objects
196 * - gDvm.outOfMemoryObj
197 * - Objects allocated with ALLOC_NO_GC
198 * - Objects pending finalization (but not yet finalized)
199 * - Objects in debugger object registry
200 *
201 * Don't need:
202 * - Native stack (for in-progress stuff in the VM)
203 * - The TrackedAlloc stuff watches all native VM references.
204 */
205void dvmHeapMarkRootSet()
206{
Barry Hayesd4f78d32010-06-08 09:34:42 -0700207 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800208
Carl Shapirod25566d2010-03-11 20:39:47 -0800209 LOG_SCAN("immune objects");
Barry Hayes425848f2010-05-04 13:32:12 -0700210 dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
Carl Shapirod25566d2010-03-11 20:39:47 -0800211
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800212 LOG_SCAN("root class loader\n");
213 dvmGcScanRootClassLoader();
214 LOG_SCAN("primitive classes\n");
215 dvmGcScanPrimitiveClasses();
216
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800217 LOG_SCAN("root thread groups\n");
218 dvmGcScanRootThreadGroups();
219
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800220 LOG_SCAN("interned strings\n");
221 dvmGcScanInternedStrings();
222
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800223 LOG_SCAN("JNI global refs\n");
224 dvmGcMarkJniGlobalRefs();
225
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800226 LOG_SCAN("pending reference operations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700227 dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800228
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800229 LOG_SCAN("pending finalizations\n");
Carl Shapiro646ba092010-06-10 15:17:00 -0700230 dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800231
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800232 LOG_SCAN("debugger refs\n");
233 dvmGcMarkDebuggerRefs();
234
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800235 /* Mark any special objects we have sitting around.
236 */
237 LOG_SCAN("special objects\n");
238 dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
239 dvmMarkObjectNonNull(gDvm.internalErrorObj);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700240 dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800241//TODO: scan object references sitting in gDvm; use pointer begin & end
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800242}
243
244/*
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700245 * Callback applied to root references. If the root location contains
246 * a white reference it is pushed on the mark stack and grayed.
247 */
Carl Shapiro07018e22010-10-26 21:07:41 -0700248static void markObjectVisitor(void *addr, RootType type, u4 thread, void *arg)
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700249{
250 Object *obj;
251
252 assert(addr != NULL);
253 assert(arg != NULL);
254 obj = *(Object **)addr;
255 if (obj != NULL) {
256 markObjectNonNull(obj, arg, true);
257 }
258}
259
260/*
261 * Grays all references in the roots.
262 */
263void dvmHeapReMarkRootSet(void)
264{
265 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
266 assert(ctx->finger == (void *)ULONG_MAX);
267 dvmVisitRoots(markObjectVisitor, ctx);
268}
269
270/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700271 * Nothing past this point is allowed to use dvmMarkObject() or
272 * dvmMarkObjectNonNull(), which are for root-marking only.
273 * Scanning/recursion must use markObject(), which takes the finger
274 * into account.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800275 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700276#undef dvmMarkObject
277#define dvmMarkObject __dont_use_dvmMarkObject__
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800278#define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
279
Barry Hayese1bccb92010-05-18 09:48:37 -0700280/*
281 * Scans instance fields.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800282 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700283static void scanInstanceFields(const Object *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800284{
Barry Hayese1bccb92010-05-18 09:48:37 -0700285 assert(obj != NULL);
286 assert(obj->clazz != NULL);
287 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800288
Barry Hayese1bccb92010-05-18 09:48:37 -0700289 if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
290 unsigned int refOffsets = obj->clazz->refOffsets;
Barry Hayeseac47ed2009-06-22 11:45:20 -0700291 while (refOffsets != 0) {
292 const int rshift = CLZ(refOffsets);
293 refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
294 markObject(dvmGetFieldObject((Object*)obj,
Barry Hayese1bccb92010-05-18 09:48:37 -0700295 CLASS_OFFSET_FROM_CLZ(rshift)), ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800296 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700297 } else {
Barry Hayese1bccb92010-05-18 09:48:37 -0700298 ClassObject *clazz;
299 int i;
300 for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
301 InstField *field = clazz->ifields;
302 for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
303 void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
304 markObject(((JValue *)addr)->l, ctx);
Barry Hayeseac47ed2009-06-22 11:45:20 -0700305 }
Barry Hayeseac47ed2009-06-22 11:45:20 -0700306 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800307 }
308}
309
Barry Hayese1bccb92010-05-18 09:48:37 -0700310/*
311 * Scans the header, static field references, and interface
312 * pointers of a class object.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800313 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700314static void scanClassObject(const ClassObject *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800315{
Barry Hayese1bccb92010-05-18 09:48:37 -0700316 int i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800317
Barry Hayese1bccb92010-05-18 09:48:37 -0700318 assert(obj != NULL);
319 assert(obj->obj.clazz == gDvm.classJavaLangClass);
320 assert(ctx != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800321
Barry Hayese1bccb92010-05-18 09:48:37 -0700322 markObject((Object *)obj->obj.clazz, ctx);
323 if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
324 markObject((Object *)obj->elementClass, ctx);
325 }
Barry Hayesc49db852010-05-14 13:43:34 -0700326 /* Do super and the interfaces contain Objects and not dex idx values? */
327 if (obj->status > CLASS_IDX) {
328 markObject((Object *)obj->super, ctx);
329 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700330 markObject(obj->classLoader, ctx);
331 /* Scan static field references. */
332 for (i = 0; i < obj->sfieldCount; ++i) {
333 char ch = obj->sfields[i].field.signature[0];
334 if (ch == '[' || ch == 'L') {
335 markObject(obj->sfields[i].value.l, ctx);
336 }
337 }
338 /* Scan the instance fields. */
339 scanInstanceFields((const Object *)obj, ctx);
340 /* Scan interface references. */
Barry Hayesc49db852010-05-14 13:43:34 -0700341 if (obj->status > CLASS_IDX) {
342 for (i = 0; i < obj->interfaceCount; ++i) {
343 markObject((Object *)obj->interfaces[i], ctx);
344 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800345 }
346}
347
Barry Hayese1bccb92010-05-18 09:48:37 -0700348/*
349 * Scans the header of all array objects. If the array object is
350 * specialized to a reference type, scans the array data as well.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800351 */
Barry Hayese1bccb92010-05-18 09:48:37 -0700352static void scanArrayObject(const ArrayObject *obj, GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800353{
Barry Hayese1bccb92010-05-18 09:48:37 -0700354 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800355
Barry Hayese1bccb92010-05-18 09:48:37 -0700356 assert(obj != NULL);
357 assert(obj->obj.clazz != NULL);
358 assert(ctx != NULL);
359 /* Scan the class object reference. */
360 markObject((Object *)obj->obj.clazz, ctx);
361 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISOBJECTARRAY)) {
362 /* Scan the array contents. */
363 Object **contents = (Object **)obj->contents;
364 for (i = 0; i < obj->length; ++i) {
365 markObject(contents[i], ctx);
366 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800367 }
Barry Hayese1bccb92010-05-18 09:48:37 -0700368}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800369
Barry Hayese1bccb92010-05-18 09:48:37 -0700370/*
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700371 * Returns class flags relating to Reference subclasses.
372 */
373static int referenceClassFlags(const Object *obj)
374{
375 int flags = CLASS_ISREFERENCE |
376 CLASS_ISWEAKREFERENCE |
377 CLASS_ISPHANTOMREFERENCE;
378 return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
379}
380
381/*
382 * Returns true if the object derives from SoftReference.
383 */
384static bool isSoftReference(const Object *obj)
385{
386 return referenceClassFlags(obj) == CLASS_ISREFERENCE;
387}
388
389/*
390 * Returns true if the object derives from WeakReference.
391 */
392static bool isWeakReference(const Object *obj)
393{
394 return referenceClassFlags(obj) & CLASS_ISWEAKREFERENCE;
395}
396
397/*
398 * Returns true if the object derives from PhantomReference.
399 */
400static bool isPhantomReference(const Object *obj)
401{
402 return referenceClassFlags(obj) & CLASS_ISPHANTOMREFERENCE;
403}
404
405/*
406 * Adds a reference to the tail of a circular queue of references.
407 */
408static void enqueuePendingReference(Object *ref, Object **list)
409{
410 size_t offset;
411
412 assert(ref != NULL);
413 assert(list != NULL);
414 offset = gDvm.offJavaLangRefReference_pendingNext;
415 if (*list == NULL) {
416 dvmSetFieldObject(ref, offset, ref);
417 *list = ref;
418 } else {
419 Object *head = dvmGetFieldObject(*list, offset);
420 dvmSetFieldObject(ref, offset, head);
421 dvmSetFieldObject(*list, offset, ref);
422 }
423}
424
425/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700426 * Removes the reference at the head of a circular queue of
427 * references.
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700428 */
429static Object *dequeuePendingReference(Object **list)
430{
431 Object *ref, *head;
432 size_t offset;
433
434 assert(list != NULL);
435 assert(*list != NULL);
436 offset = gDvm.offJavaLangRefReference_pendingNext;
437 head = dvmGetFieldObject(*list, offset);
438 if (*list == head) {
439 ref = *list;
440 *list = NULL;
441 } else {
442 Object *next = dvmGetFieldObject(head, offset);
443 dvmSetFieldObject(*list, offset, next);
444 ref = head;
445 }
446 dvmSetFieldObject(ref, offset, NULL);
447 return ref;
448}
449
450/*
Barry Hayese1bccb92010-05-18 09:48:37 -0700451 * Process the "referent" field in a java.lang.ref.Reference. If the
452 * referent has not yet been marked, put it on the appropriate list in
453 * the gcHeap for later processing.
454 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700455static void delayReferenceReferent(Object *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700456{
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700457 GcHeap *gcHeap = gDvm.gcHeap;
458 Object *pending, *referent;
459 size_t pendingNextOffset, referentOffset;
460
Barry Hayese1bccb92010-05-18 09:48:37 -0700461 assert(obj != NULL);
Barry Hayes697b5a92010-06-23 11:38:52 -0700462 assert(obj->clazz != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700463 assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
Barry Hayese1bccb92010-05-18 09:48:37 -0700464 assert(ctx != NULL);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700465 pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
466 referentOffset = gDvm.offJavaLangRefReference_referent;
467 pending = dvmGetFieldObject(obj, pendingNextOffset);
468 referent = dvmGetFieldObject(obj, referentOffset);
469 if (pending == NULL && referent != NULL && !isMarked(referent, ctx)) {
470 Object **list = NULL;
471 if (isSoftReference(obj)) {
472 list = &gcHeap->softReferences;
473 } else if (isWeakReference(obj)) {
474 list = &gcHeap->weakReferences;
475 } else if (isPhantomReference(obj)) {
476 list = &gcHeap->phantomReferences;
Barry Hayese1bccb92010-05-18 09:48:37 -0700477 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700478 assert(list != NULL);
479 enqueuePendingReference(obj, list);
Barry Hayese1bccb92010-05-18 09:48:37 -0700480 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800481}
482
Barry Hayese1bccb92010-05-18 09:48:37 -0700483/*
484 * Scans the header and field references of a data object.
485 */
Barry Hayes697b5a92010-06-23 11:38:52 -0700486static void scanDataObject(DataObject *obj, GcMarkContext *ctx)
Barry Hayese1bccb92010-05-18 09:48:37 -0700487{
488 assert(obj != NULL);
489 assert(obj->obj.clazz != NULL);
490 assert(ctx != NULL);
491 /* Scan the class object. */
492 markObject((Object *)obj->obj.clazz, ctx);
493 /* Scan the instance fields. */
494 scanInstanceFields((const Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700495 if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISREFERENCE)) {
Barry Hayes697b5a92010-06-23 11:38:52 -0700496 delayReferenceReferent((Object *)obj, ctx);
Barry Hayese1bccb92010-05-18 09:48:37 -0700497 }
498}
499
500/*
501 * Scans an object reference. Determines the type of the reference
502 * and dispatches to a specialized scanning routine.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800503 */
504static void scanObject(const Object *obj, GcMarkContext *ctx)
505{
Barry Hayese1bccb92010-05-18 09:48:37 -0700506 assert(obj != NULL);
507 assert(ctx != NULL);
Barry Hayes899cdb72010-06-08 09:59:12 -0700508 assert(obj->clazz != NULL);
Barry Hayese1bccb92010-05-18 09:48:37 -0700509 /* Dispatch a type-specific scan routine. */
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700510 if (obj->clazz == gDvm.classJavaLangClass) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700511 scanClassObject((ClassObject *)obj, ctx);
Carl Shapiro1a8e21a2010-06-08 13:19:57 -0700512 } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
Barry Hayes899cdb72010-06-08 09:59:12 -0700513 scanArrayObject((ArrayObject *)obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800514 } else {
Barry Hayes899cdb72010-06-08 09:59:12 -0700515 scanDataObject((DataObject *)obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800516 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800517}
518
Carl Shapirofdf80522010-11-09 14:27:02 -0800519/*
520 * Scan anything that's on the mark stack. We can't use the bitmaps
521 * anymore, so use a finger that points past the end of them.
522 */
523static void processMarkStack(GcMarkContext *ctx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800524{
Carl Shapirofdf80522010-11-09 14:27:02 -0800525 GcMarkStack *stack;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800526
Carl Shapirofdf80522010-11-09 14:27:02 -0800527 assert(ctx != NULL);
Carl Shapiro034fba52010-11-11 16:39:58 -0800528 assert(ctx->finger == (void *)ULONG_MAX);
Carl Shapirofdf80522010-11-09 14:27:02 -0800529 stack = &ctx->stack;
530 assert(stack->top >= stack->base);
531 while (stack->top > stack->base) {
532 const Object *obj = markStackPop(stack);
533 scanObject(obj, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800534 }
535}
536
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700537static size_t objectSize(const Object *obj)
538{
539 assert(dvmIsValidObject(obj));
540 assert(dvmIsValidObject((Object *)obj->clazz));
541 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
542 return dvmArrayObjectSize((ArrayObject *)obj);
543 } else if (obj->clazz == gDvm.classJavaLangClass) {
544 return dvmClassObjectSize((ClassObject *)obj);
545 } else {
546 return obj->clazz->objectSize;
547 }
548}
549
550/*
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700551 * Scans forward to the header of the next marked object between start
552 * and limit. Returns NULL if no marked objects are in that region.
553 */
Carl Shapiro7ec91442010-10-21 15:35:19 -0700554static Object *nextGrayObject(const u1 *base, const u1 *limit,
555 const HeapBitmap *markBits)
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700556{
Carl Shapiro7ec91442010-10-21 15:35:19 -0700557 const u1 *ptr;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700558
559 assert(base < limit);
560 assert(limit - base <= GC_CARD_SIZE);
561 for (ptr = base; ptr < limit; ptr += HB_OBJECT_ALIGNMENT) {
Carl Shapiroea10c552010-09-02 23:32:25 -0700562 if (dvmHeapBitmapIsObjectBitSet(markBits, ptr))
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700563 return (Object *)ptr;
564 }
565 return NULL;
566}
567
568/*
Carl Shapiro7ec91442010-10-21 15:35:19 -0700569 * Scans each byte from start below end returning the address of the
570 * first dirty card. Returns NULL if no dirty card is found.
571 */
572static const u1 *scanBytesForDirtyCard(const u1 *start, const u1 *end)
573{
574 const u1 *ptr;
575
576 assert(start <= end);
577 for (ptr = start; ptr < end; ++ptr) {
578 if (*ptr == GC_CARD_DIRTY) {
579 return ptr;
580 }
581 }
582 return NULL;
583}
584
585/*
586 * Like scanBytesForDirtyCard but scans the range from start below end
587 * by words. Assumes start and end are word aligned.
588 */
589static const u1 *scanWordsForDirtyCard(const u1 *start, const u1 *end)
590{
591 const u1 *ptr;
592
593 assert((uintptr_t)start % kWordSize == 0);
594 assert((uintptr_t)end % kWordSize == 0);
595 assert(start <= end);
596 for (ptr = start; ptr < end; ptr += kWordSize) {
597 if (*(const Word *)ptr != 0) {
598 const u1 *dirty = scanBytesForDirtyCard(ptr, ptr + kWordSize);
599 if (dirty != NULL) {
600 return dirty;
601 }
602 }
603 }
604 return NULL;
605}
606
607/*
608 * Scans the card table as quickly as possible looking for a dirty
609 * card. Returns the address of the first dirty card found or NULL if
610 * no dirty cards were found.
611 */
612static const u1 *nextDirtyCard(const u1 *start, const u1 *end)
613{
614 const u1 *wstart = (u1 *)ALIGN_UP(start, kWordSize);
615 const u1 *wend = (u1 *)ALIGN_DOWN(end, kWordSize);
616 const u1 *ptr, *dirty;
617
618 assert(start <= end);
619 assert(start <= wstart);
620 assert(end >= wend);
621 ptr = start;
622 if (wstart < end) {
623 /* Scan the leading unaligned bytes. */
624 dirty = scanBytesForDirtyCard(ptr, wstart);
625 if (dirty != NULL) {
626 return dirty;
627 }
628 /* Scan the range of aligned words. */
629 dirty = scanWordsForDirtyCard(wstart, wend);
630 if (dirty != NULL) {
631 return dirty;
632 }
633 ptr = wend;
634 }
635 /* Scan trailing unaligned bytes. */
636 dirty = scanBytesForDirtyCard(ptr, end);
637 if (dirty != NULL) {
638 return dirty;
639 }
640 return NULL;
641}
642
643/*
644 * Scans range of dirty cards between start and end. A range of dirty
645 * cards is composed consecutively dirty cards or dirty cards spanned
646 * by a gray object. Returns the address of a clean card if the scan
647 * reached a clean card or NULL if the scan reached the end.
648 */
649const u1 *scanDirtyCards(const u1 *start, const u1 *end,
650 GcMarkContext *ctx)
651{
652 const HeapBitmap *markBits = ctx->bitmap;
653 const u1 *card = start, *prevAddr = NULL;
654 while (card < end) {
655 if (*card != GC_CARD_DIRTY) {
656 return card;
657 }
658 const u1 *ptr = prevAddr ? prevAddr : dvmAddrFromCard(card);
659 const u1 *limit = ptr + GC_CARD_SIZE;
660 while (ptr < limit) {
661 Object *obj = nextGrayObject(ptr, limit, markBits);
662 if (obj == NULL) {
663 break;
664 }
665 scanObject(obj, ctx);
666 ptr = (u1*)obj + ALIGN_UP(objectSize(obj), HB_OBJECT_ALIGNMENT);
667 }
668 if (ptr < limit) {
669 /* Ended within the current card, advance to the next card. */
670 ++card;
671 prevAddr = NULL;
672 } else {
673 /* Ended past the current card, skip ahead. */
674 card = dvmCardFromAddr(ptr);
675 prevAddr = ptr;
676 }
677 }
678 return NULL;
679}
680
681/*
682 * Blackens gray objects found on dirty cards.
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700683 */
684static void scanGrayObjects(GcMarkContext *ctx)
685{
686 GcHeap *h = gDvm.gcHeap;
Carl Shapiro7ec91442010-10-21 15:35:19 -0700687 const u1 *base, *limit, *ptr, *dirty;
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700688 size_t footprint;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700689
Carl Shapirob8c48ae2010-08-12 11:24:44 -0700690 footprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
Carl Shapiro7ec91442010-10-21 15:35:19 -0700691 base = &h->cardTableBase[0];
692 limit = dvmCardFromAddr((u1 *)dvmHeapSourceGetBase() + footprint);
693 assert(limit <= &h->cardTableBase[h->cardTableLength]);
694
695 ptr = base;
696 for (;;) {
697 dirty = nextDirtyCard(ptr, limit);
698 if (dirty == NULL) {
699 break;
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700700 }
Carl Shapiro7ec91442010-10-21 15:35:19 -0700701 assert((dirty > ptr) && (dirty < limit));
702 ptr = scanDirtyCards(dirty, limit, ctx);
703 if (ptr == NULL) {
704 break;
705 }
706 assert((ptr > dirty) && (ptr < limit));
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700707 }
708}
709
Carl Shapiro57ee2702010-08-27 13:06:48 -0700710/*
711 * Callback for scanning each object in the bitmap. The finger is set
712 * to the address corresponding to the lowest address in the next word
713 * of bits in the bitmap.
714 */
Carl Shapiro38d710b2010-08-31 16:48:31 -0700715static void scanBitmapCallback(void *addr, void *finger, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800716{
Carl Shapiro006346e2010-07-29 20:39:50 -0700717 GcMarkContext *ctx = arg;
Carl Shapiro57ee2702010-08-27 13:06:48 -0700718 ctx->finger = (void *)finger;
719 scanObject(addr, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800720}
721
722/* Given bitmaps with the root set marked, find and mark all
723 * reachable objects. When this returns, the entire set of
724 * live objects will be marked and the mark stack will be empty.
725 */
Carl Shapiro29540742010-03-26 15:34:39 -0700726void dvmHeapScanMarkedObjects(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800727{
728 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
729
730 assert(ctx->finger == NULL);
731
732 /* The bitmaps currently have bits set for the root set.
733 * Walk across the bitmaps and scan each object.
734 */
Carl Shapiro38d710b2010-08-31 16:48:31 -0700735 dvmHeapBitmapScanWalk(ctx->bitmap, scanBitmapCallback, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800736
Carl Shapiro034fba52010-11-11 16:39:58 -0800737 ctx->finger = (void *)ULONG_MAX;
738
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800739 /* We've walked the mark bitmaps. Scan anything that's
740 * left on the mark stack.
741 */
742 processMarkStack(ctx);
743
744 LOG_SCAN("done with marked objects\n");
745}
746
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700747void dvmHeapReScanMarkedObjects(void)
Carl Shapiroec805ea2010-06-28 16:28:26 -0700748{
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700749 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700750
Carl Shapiroec805ea2010-06-28 16:28:26 -0700751 /*
Carl Shapirof5860332010-06-28 23:02:08 -0700752 * The finger must have been set to the maximum value to ensure
753 * that gray objects will be pushed onto the mark stack.
Carl Shapiroec805ea2010-06-28 16:28:26 -0700754 */
755 assert(ctx->finger == (void *)ULONG_MAX);
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700756 scanGrayObjects(ctx);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700757 processMarkStack(ctx);
758}
759
Carl Shapiro34f51992010-07-09 17:55:41 -0700760/*
761 * Clear the referent field.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800762 */
Barry Hayes6930a112009-12-22 11:01:38 -0800763static void clearReference(Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800764{
Carl Shapiro34f51992010-07-09 17:55:41 -0700765 size_t offset = gDvm.offJavaLangRefReference_referent;
766 dvmSetFieldObject(reference, offset, NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800767}
768
Carl Shapiro29540742010-03-26 15:34:39 -0700769/*
770 * Returns true if the reference was registered with a reference queue
771 * and has not yet been enqueued.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800772 */
Carl Shapiro29540742010-03-26 15:34:39 -0700773static bool isEnqueuable(const Object *reference)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800774{
Barry Hayes6930a112009-12-22 11:01:38 -0800775 Object *queue = dvmGetFieldObject(reference,
776 gDvm.offJavaLangRefReference_queue);
777 Object *queueNext = dvmGetFieldObject(reference,
778 gDvm.offJavaLangRefReference_queueNext);
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700779 return queue != NULL && queueNext == NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800780}
781
Carl Shapiro29540742010-03-26 15:34:39 -0700782/*
783 * Schedules a reference to be appended to its reference queue.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800784 */
Carl Shapiro29540742010-03-26 15:34:39 -0700785static void enqueueReference(Object *ref)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800786{
Carl Shapiro646ba092010-06-10 15:17:00 -0700787 assert(ref != NULL);
Carl Shapiro29540742010-03-26 15:34:39 -0700788 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
789 assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
Carl Shapiro646ba092010-06-10 15:17:00 -0700790 if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
Carl Shapiro29540742010-03-26 15:34:39 -0700791 LOGE_HEAP("enqueueReference(): no room for any more "
792 "reference operations\n");
793 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800794 }
795}
796
Carl Shapiro29540742010-03-26 15:34:39 -0700797/*
798 * Walks the reference list marking any references subject to the
799 * reference clearing policy. References with a black referent are
800 * removed from the list. References with white referents biased
801 * toward saving are blackened and also removed from the list.
802 */
803void dvmHandleSoftRefs(Object **list)
804{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700805 GcMarkContext *ctx;
Carl Shapiro29540742010-03-26 15:34:39 -0700806 Object *ref, *referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700807 Object *clear;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700808 size_t referentOffset;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700809 size_t counter;
Carl Shapiro29540742010-03-26 15:34:39 -0700810 bool marked;
811
Carl Shapirob2e78d32010-08-20 11:34:18 -0700812 ctx = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700813 referentOffset = gDvm.offJavaLangRefReference_referent;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700814 clear = NULL;
Carl Shapiro29540742010-03-26 15:34:39 -0700815 counter = 0;
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700816 while (*list != NULL) {
817 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700818 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700819 assert(referent != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700820 marked = isMarked(referent, ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700821 if (!marked && ((++counter) & 1)) {
822 /* Referent is white and biased toward saving, mark it. */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700823 markObject(referent, ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700824 marked = true;
825 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700826 if (!marked) {
827 /* Referent is white, queue it for clearing. */
828 enqueuePendingReference(ref, &clear);
Carl Shapiro29540742010-03-26 15:34:39 -0700829 }
Carl Shapiro29540742010-03-26 15:34:39 -0700830 }
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700831 *list = clear;
Carl Shapiro29540742010-03-26 15:34:39 -0700832 /*
833 * Restart the mark with the newly black references added to the
834 * root set.
835 */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700836 processMarkStack(ctx);
Carl Shapiro29540742010-03-26 15:34:39 -0700837}
838
839/*
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700840 * Unlink the reference list clearing references objects with white
841 * referents. Cleared references registered to a reference queue are
842 * scheduled for appending by the heap worker thread.
Carl Shapiro29540742010-03-26 15:34:39 -0700843 */
844void dvmClearWhiteRefs(Object **list)
845{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700846 GcMarkContext *ctx;
Carl Shapiro29540742010-03-26 15:34:39 -0700847 Object *ref, *referent;
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700848 size_t referentOffset;
Carl Shapiro29540742010-03-26 15:34:39 -0700849 bool doSignal;
850
Carl Shapirob2e78d32010-08-20 11:34:18 -0700851 ctx = &gDvm.gcHeap->markContext;
Carl Shapiro29540742010-03-26 15:34:39 -0700852 referentOffset = gDvm.offJavaLangRefReference_referent;
853 doSignal = false;
854 while (*list != NULL) {
Carl Shapiro2a6f4842010-07-09 16:50:54 -0700855 ref = dequeuePendingReference(list);
Carl Shapiro29540742010-03-26 15:34:39 -0700856 referent = dvmGetFieldObject(ref, referentOffset);
Carl Shapiro29540742010-03-26 15:34:39 -0700857 assert(referent != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700858 if (!isMarked(referent, ctx)) {
Carl Shapiroa1b03a92010-07-12 14:02:28 -0700859 /* Referent is white, clear it. */
Carl Shapiro29540742010-03-26 15:34:39 -0700860 clearReference(ref);
861 if (isEnqueuable(ref)) {
862 enqueueReference(ref);
863 doSignal = true;
864 }
865 }
866 }
867 /*
868 * If we cleared a reference with a reference queue we must notify
869 * the heap worker to append the reference.
870 */
871 if (doSignal) {
872 dvmSignalHeapWorker(false);
873 }
874 assert(*list == NULL);
875}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800876
877/* Find unreachable objects that need to be finalized,
878 * and schedule them for finalization.
879 */
880void dvmHeapScheduleFinalizations()
881{
882 HeapRefTable newPendingRefs;
883 LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
884 Object **ref;
885 Object **lastRef;
886 size_t totalPendCount;
Carl Shapirob2e78d32010-08-20 11:34:18 -0700887 GcMarkContext *ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800888
889 /*
890 * All reachable objects have been marked.
891 * Any unmarked finalizable objects need to be finalized.
892 */
893
894 /* Create a table that the new pending refs will
895 * be added to.
896 */
Barry Hayesd4f78d32010-06-08 09:34:42 -0700897 if (!dvmHeapInitHeapRefTable(&newPendingRefs)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800898 //TODO: mark all finalizable refs and hope that
899 // we can schedule them next time. Watch out,
900 // because we may be expecting to free up space
901 // by calling finalizers.
902 LOGE_GC("dvmHeapScheduleFinalizations(): no room for "
903 "pending finalizations\n");
904 dvmAbort();
905 }
906
907 /* Walk through finalizableRefs and move any unmarked references
908 * to the list of new pending refs.
909 */
910 totalPendCount = 0;
911 while (finRefs != NULL) {
912 Object **gapRef;
913 size_t newPendCount = 0;
914
915 gapRef = ref = finRefs->refs.table;
916 lastRef = finRefs->refs.nextEntry;
917 while (ref < lastRef) {
Carl Shapirob2e78d32010-08-20 11:34:18 -0700918 if (!isMarked(*ref, ctx)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800919 if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
920 //TODO: add the current table and allocate
921 // a new, smaller one.
922 LOGE_GC("dvmHeapScheduleFinalizations(): "
923 "no room for any more pending finalizations: %zd\n",
924 dvmHeapNumHeapRefTableEntries(&newPendingRefs));
925 dvmAbort();
926 }
927 newPendCount++;
928 } else {
929 /* This ref is marked, so will remain on finalizableRefs.
930 */
931 if (newPendCount > 0) {
932 /* Copy it up to fill the holes.
933 */
934 *gapRef++ = *ref;
935 } else {
936 /* No holes yet; don't bother copying.
937 */
938 gapRef++;
939 }
940 }
941 ref++;
942 }
943 finRefs->refs.nextEntry = gapRef;
944 //TODO: if the table is empty when we're done, free it.
945 totalPendCount += newPendCount;
946 finRefs = finRefs->next;
947 }
948 LOGD_GC("dvmHeapScheduleFinalizations(): %zd finalizers triggered.\n",
949 totalPendCount);
950 if (totalPendCount == 0) {
951 /* No objects required finalization.
952 * Free the empty temporary table.
953 */
954 dvmClearReferenceTable(&newPendingRefs);
955 return;
956 }
957
958 /* Add the new pending refs to the main list.
959 */
960 if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
961 &newPendingRefs))
962 {
963 LOGE_GC("dvmHeapScheduleFinalizations(): can't insert new "
964 "pending finalizations\n");
965 dvmAbort();
966 }
967
968 //TODO: try compacting the main list with a memcpy loop
969
970 /* Mark the refs we just moved; we don't want them or their
971 * children to get swept yet.
972 */
973 ref = newPendingRefs.table;
974 lastRef = newPendingRefs.nextEntry;
975 assert(ref < lastRef);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800976 while (ref < lastRef) {
Barry Hayese1bccb92010-05-18 09:48:37 -0700977 assert(*ref != NULL);
Carl Shapirob2e78d32010-08-20 11:34:18 -0700978 markObject(*ref, ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800979 ref++;
980 }
Carl Shapirob2e78d32010-08-20 11:34:18 -0700981 processMarkStack(ctx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800982 dvmSignalHeapWorker(false);
983}
984
985void dvmHeapFinishMarkStep()
986{
Carl Shapirob2e78d32010-08-20 11:34:18 -0700987 GcMarkContext *ctx;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800988
Carl Shapirob2e78d32010-08-20 11:34:18 -0700989 ctx = &gDvm.gcHeap->markContext;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800990
Barry Hayes81010a42010-07-19 14:07:01 -0700991 /* The mark bits are now not needed.
992 */
993 dvmHeapSourceZeroMarkBitmap();
994
Carl Shapirof373efd2010-02-19 00:46:33 -0800995 /* Clean up everything else associated with the marking process.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800996 */
Carl Shapirob2e78d32010-08-20 11:34:18 -0700997 destroyMarkStack(&ctx->stack);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800998
Carl Shapirob2e78d32010-08-20 11:34:18 -0700999 ctx->finger = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001000}
1001
Carl Shapiro8881a802010-08-10 15:55:45 -07001002typedef struct {
1003 size_t numObjects;
1004 size_t numBytes;
1005 bool isConcurrent;
1006} SweepContext;
1007
Carl Shapiro57ee2702010-08-27 13:06:48 -07001008static void sweepBitmapCallback(size_t numPtrs, void **ptrs, void *arg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001009{
Carl Shapirob9b23952010-08-10 17:20:15 -07001010 SweepContext *ctx = arg;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001011
Carl Shapiro8881a802010-08-10 15:55:45 -07001012 if (ctx->isConcurrent) {
1013 dvmLockHeap();
1014 }
1015 ctx->numBytes += dvmHeapSourceFreeList(numPtrs, ptrs);
1016 ctx->numObjects += numPtrs;
1017 if (ctx->isConcurrent) {
1018 dvmUnlockHeap();
1019 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001020}
1021
Carl Shapiro8881a802010-08-10 15:55:45 -07001022/*
1023 * Returns true if the given object is unmarked. This assumes that
1024 * the bitmaps have not yet been swapped.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001025 */
1026static int isUnmarkedObject(void *object)
1027{
Carl Shapiro6343bd02010-02-16 17:40:19 -08001028 return !isMarked((void *)((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001029 &gDvm.gcHeap->markContext);
1030}
1031
Carl Shapiro8881a802010-08-10 15:55:45 -07001032/*
1033 * Process all the internal system structures that behave like
1034 * weakly-held objects.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001035 */
Carl Shapiro8881a802010-08-10 15:55:45 -07001036void dvmHeapSweepSystemWeaks(void)
1037{
1038 dvmGcDetachDeadInternedStrings(isUnmarkedObject);
1039 dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
1040}
1041
1042/*
1043 * Walk through the list of objects that haven't been marked and free
1044 * them. Assumes the bitmaps have been swapped.
1045 */
1046void dvmHeapSweepUnmarkedObjects(GcMode mode, bool isConcurrent,
1047 size_t *numObjects, size_t *numBytes)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001048{
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001049 HeapBitmap currMark[HEAP_SOURCE_MAX_HEAP_COUNT];
1050 HeapBitmap currLive[HEAP_SOURCE_MAX_HEAP_COUNT];
Carl Shapiro8881a802010-08-10 15:55:45 -07001051 SweepContext ctx;
Carl Shapirod25566d2010-03-11 20:39:47 -08001052 size_t numBitmaps, numSweepBitmaps;
Barry Hayese168ebd2010-05-07 09:19:46 -07001053 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001054
Carl Shapirof373efd2010-02-19 00:46:33 -08001055 numBitmaps = dvmHeapSourceGetNumHeaps();
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001056 dvmHeapSourceGetObjectBitmaps(currLive, currMark, numBitmaps);
Carl Shapirod25566d2010-03-11 20:39:47 -08001057 if (mode == GC_PARTIAL) {
1058 numSweepBitmaps = 1;
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001059 assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == currLive[0].base);
Carl Shapirod25566d2010-03-11 20:39:47 -08001060 } else {
1061 numSweepBitmaps = numBitmaps;
1062 }
Carl Shapiro8881a802010-08-10 15:55:45 -07001063 ctx.numObjects = ctx.numBytes = 0;
1064 ctx.isConcurrent = isConcurrent;
Barry Hayese168ebd2010-05-07 09:19:46 -07001065 for (i = 0; i < numSweepBitmaps; i++) {
Carl Shapiro5fdab4a2010-08-18 21:04:31 -07001066 HeapBitmap* prevLive = &currMark[i];
1067 HeapBitmap* prevMark = &currLive[i];
1068 dvmHeapBitmapSweepWalk(prevLive, prevMark, sweepBitmapCallback, &ctx);
Barry Hayese168ebd2010-05-07 09:19:46 -07001069 }
Carl Shapiro8881a802010-08-10 15:55:45 -07001070 *numObjects = ctx.numObjects;
1071 *numBytes = ctx.numBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001072 if (gDvm.allocProf.enabled) {
Carl Shapiro8881a802010-08-10 15:55:45 -07001073 gDvm.allocProf.freeCount += ctx.numObjects;
1074 gDvm.allocProf.freeSize += ctx.numBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001075 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001076}