blob: a745c4383ab2ebd5776bd083d84ac8f107dc584d [file] [log] [blame]
Barry Hayes6e5cf602010-06-22 12:32:59 -07001/*
2 * Copyright (C) 2010 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
Carl Shapiro5ba39372010-08-06 17:07:53 -070017#include <sys/mman.h> /* for PROT_* */
Barry Hayes6e5cf602010-06-22 12:32:59 -070018
19#include "Dalvik.h"
Carl Shapiroc38b7ed2011-02-08 17:43:43 -080020#include "alloc/HeapBitmap.h"
21#include "alloc/HeapBitmapInlines.h"
Barry Hayes6e5cf602010-06-22 12:32:59 -070022#include "alloc/HeapSource.h"
23#include "alloc/Visit.h"
24
25/*
26 * Maintain a card table from the the write barrier. All writes of
27 * non-NULL values to heap addresses should go through an entry in
28 * WriteBarrier, and from there to here.
29 *
Barry Hayes8f921a72010-07-09 12:53:49 -070030 * The heap is divided into "cards" of GC_CARD_SIZE bytes, as
31 * determined by GC_CARD_SHIFT. The card table contains one byte of
32 * data per card, to be used by the GC. The value of the byte will be
33 * one of GC_CARD_CLEAN or GC_CARD_DIRTY.
Barry Hayes6e5cf602010-06-22 12:32:59 -070034 *
35 * After any store of a non-NULL object pointer into a heap object,
36 * code is obliged to mark the card dirty. The setters in
37 * ObjectInlines.h [such as dvmSetFieldObject] do this for you. The
38 * JIT and fast interpreters also contain code to mark cards as dirty.
39 *
Barry Hayes6e5cf602010-06-22 12:32:59 -070040 * The card table's base [the "biased card table"] gets set to a
41 * rather strange value. In order to keep the JIT from having to
42 * fabricate or load GC_DIRTY_CARD to store into the card table,
43 * biased base is within the mmap allocation at a point where it's low
44 * byte is equal to GC_DIRTY_CARD. See dvmCardTableStartup for details.
45 */
46
47/*
48 * Initializes the card table; must be called before any other
49 * dvmCardTable*() functions.
50 */
Carl Shapirodf9f08b2011-01-18 17:59:30 -080051bool dvmCardTableStartup(size_t heapMaximumSize)
Barry Hayes6e5cf602010-06-22 12:32:59 -070052{
53 size_t length;
54 void *allocBase;
55 u1 *biasedBase;
Barry Hayesb874ab92010-07-14 08:13:18 -070056 GcHeap *gcHeap = gDvm.gcHeap;
57 void *heapBase = dvmHeapSourceGetBase();
58 assert(gcHeap != NULL);
59 assert(heapBase != NULL);
Barry Hayes6e5cf602010-06-22 12:32:59 -070060
61 /* Set up the card table */
Carl Shapirodf9f08b2011-01-18 17:59:30 -080062 length = heapMaximumSize / GC_CARD_SIZE;
Barry Hayes6e5cf602010-06-22 12:32:59 -070063 /* Allocate an extra 256 bytes to allow fixed low-byte of base */
64 allocBase = dvmAllocRegion(length + 0x100, PROT_READ | PROT_WRITE,
65 "dalvik-card-table");
66 if (allocBase == NULL) {
67 return false;
68 }
Carl Shapirofc75f3e2010-12-07 11:43:38 -080069 gcHeap->cardTableBase = (u1*)allocBase;
Barry Hayes6e5cf602010-06-22 12:32:59 -070070 gcHeap->cardTableLength = length;
71 /* All zeros is the correct initial value; all clean. */
72 assert(GC_CARD_CLEAN == 0);
73
74 biasedBase = (u1 *)((uintptr_t)allocBase -
75 ((uintptr_t)heapBase >> GC_CARD_SHIFT));
76 if (((uintptr_t)biasedBase & 0xff) != GC_CARD_DIRTY) {
Carl Shapiro5d81aa32010-08-20 11:04:25 -070077 int offset = GC_CARD_DIRTY - ((uintptr_t)biasedBase & 0xff);
Barry Hayes6e5cf602010-06-22 12:32:59 -070078 biasedBase += offset + (offset < 0 ? 0x100 : 0);
79 }
80 assert(((uintptr_t)biasedBase & 0xff) == GC_CARD_DIRTY);
Barry Hayes4496ed92010-07-12 09:52:20 -070081 gDvm.biasedCardTableBase = biasedBase;
Barry Hayes6e5cf602010-06-22 12:32:59 -070082
83 return true;
84}
85
86/*
87 * Tears down the entire CardTable.
88 */
89void dvmCardTableShutdown()
90{
Barry Hayesb874ab92010-07-14 08:13:18 -070091 gDvm.biasedCardTableBase = NULL;
Barry Hayes6e5cf602010-06-22 12:32:59 -070092 munmap(gDvm.gcHeap->cardTableBase, gDvm.gcHeap->cardTableLength);
93}
94
Carl Shapiro106c5fd2010-07-28 14:12:27 -070095void dvmClearCardTable(void)
96{
97 assert(gDvm.gcHeap->cardTableBase != NULL);
98 memset(gDvm.gcHeap->cardTableBase, GC_CARD_CLEAN, gDvm.gcHeap->cardTableLength);
99}
100
Barry Hayes6e5cf602010-06-22 12:32:59 -0700101/*
Barry Hayes4496ed92010-07-12 09:52:20 -0700102 * Returns true iff the address is within the bounds of the card table.
103 */
104bool dvmIsValidCard(const u1 *cardAddr)
105{
106 GcHeap *h = gDvm.gcHeap;
107 return cardAddr >= h->cardTableBase &&
108 cardAddr < &h->cardTableBase[h->cardTableLength];
109}
110
111/*
Barry Hayes8f921a72010-07-09 12:53:49 -0700112 * Returns the address of the relevent byte in the card table, given
Barry Hayes6e5cf602010-06-22 12:32:59 -0700113 * an address on the heap.
114 */
115u1 *dvmCardFromAddr(const void *addr)
116{
Barry Hayes4496ed92010-07-12 09:52:20 -0700117 u1 *biasedBase = gDvm.biasedCardTableBase;
118 u1 *cardAddr = biasedBase + ((uintptr_t)addr >> GC_CARD_SHIFT);
119 assert(dvmIsValidCard(cardAddr));
Barry Hayes6e5cf602010-06-22 12:32:59 -0700120 return cardAddr;
121}
122
Barry Hayes8f921a72010-07-09 12:53:49 -0700123/*
124 * Returns the first address in the heap which maps to this card.
125 */
126void *dvmAddrFromCard(const u1 *cardAddr)
127{
Barry Hayes4496ed92010-07-12 09:52:20 -0700128 assert(dvmIsValidCard(cardAddr));
129 uintptr_t offset = cardAddr - gDvm.biasedCardTableBase;
Barry Hayes8f921a72010-07-09 12:53:49 -0700130 return (void *)(offset << GC_CARD_SHIFT);
Barry Hayes6e5cf602010-06-22 12:32:59 -0700131}
132
133/*
134 * Dirties the card for the given address.
135 */
136void dvmMarkCard(const void *addr)
137{
138 u1 *cardAddr = dvmCardFromAddr(addr);
139 *cardAddr = GC_CARD_DIRTY;
140}
Carl Shapiro5ba39372010-08-06 17:07:53 -0700141
142/*
Carl Shapiro5ba39372010-08-06 17:07:53 -0700143 * Returns true if the object is on a dirty card.
144 */
145static bool isObjectDirty(const Object *obj)
146{
147 assert(obj != NULL);
148 assert(dvmIsValidObject(obj));
Carl Shapiro71ce7a92010-09-29 01:09:11 -0700149 u1 *card = dvmCardFromAddr(obj);
150 return *card == GC_CARD_DIRTY;
Carl Shapiro5ba39372010-08-06 17:07:53 -0700151}
152
153/*
154 * Context structure for verifying the card table.
155 */
156typedef struct {
157 HeapBitmap *markBits;
158 size_t whiteRefs;
159} WhiteReferenceCounter;
160
161/*
162 * Visitor that counts white referents.
163 */
164static void countWhiteReferenceVisitor(void *addr, void *arg)
165{
166 WhiteReferenceCounter *ctx;
167 Object *obj;
168
169 assert(addr != NULL);
170 assert(arg != NULL);
171 obj = *(Object **)addr;
Carl Shapiro8e14bc72010-10-18 16:27:29 -0700172 if (obj == NULL) {
173 return;
174 }
Carl Shapiro5ba39372010-08-06 17:07:53 -0700175 assert(dvmIsValidObject(obj));
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800176 ctx = (WhiteReferenceCounter *)arg;
Carl Shapiro8e14bc72010-10-18 16:27:29 -0700177 if (dvmHeapBitmapIsObjectBitSet(ctx->markBits, obj)) {
Carl Shapiro5ba39372010-08-06 17:07:53 -0700178 return;
179 }
180 ctx->whiteRefs += 1;
181}
182
183/*
Carl Shapiro7f43c032010-10-18 17:26:46 -0700184 * Visitor that logs white references.
185 */
186static void dumpWhiteReferenceVisitor(void *addr, void *arg)
187{
188 WhiteReferenceCounter *ctx;
189 Object *obj;
190
191 assert(addr != NULL);
192 assert(arg != NULL);
193 obj = *(Object **)addr;
194 if (obj == NULL) {
195 return;
196 }
197 assert(dvmIsValidObject(obj));
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800198 ctx = (WhiteReferenceCounter*)arg;
Carl Shapiro7f43c032010-10-18 17:26:46 -0700199 if (dvmHeapBitmapIsObjectBitSet(ctx->markBits, obj)) {
200 return;
201 }
202 LOGE("object %p is white", obj);
203}
204
205/*
206 * Visitor that signals the caller when a matching reference is found.
207 */
208static void dumpReferencesVisitor(void *pObj, void *arg)
209{
210 Object *obj = *(Object **)pObj;
211 Object *lookingFor = *(Object **)arg;
212 if (lookingFor != NULL && lookingFor == obj) {
213 *(Object **)arg = NULL;
214 }
215}
216
217static void dumpReferencesCallback(void *ptr, void *arg)
218{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800219 Object *obj = (Object *)arg;
Carl Shapiro7f43c032010-10-18 17:26:46 -0700220 if (ptr == obj) {
221 return;
222 }
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800223 dvmVisitObject(dumpReferencesVisitor, (Object *)ptr, &obj);
Carl Shapiro7f43c032010-10-18 17:26:46 -0700224 if (obj == NULL) {
225 LOGD("Found %p in the heap @ %p", arg, ptr);
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800226 dvmDumpObject((Object *)ptr);
Carl Shapiro7f43c032010-10-18 17:26:46 -0700227 }
228}
229
230/*
231 * Root visitor that looks for matching references.
232 */
Carl Shapiro07018e22010-10-26 21:07:41 -0700233static void dumpReferencesRootVisitor(void *ptr, u4 threadId,
234 RootType type, void *arg)
Carl Shapiro7f43c032010-10-18 17:26:46 -0700235{
236 Object *obj = *(Object **)ptr;
237 Object *lookingFor = *(Object **)arg;
238 if (obj == lookingFor) {
239 LOGD("Found %p in a root @ %p", arg, ptr);
240 }
241}
242
243/*
244 * Invokes visitors to search for references to an object.
245 */
246static void dumpReferences(const Object *obj)
247{
248 HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
249 void *arg = (void *)obj;
250 dvmVisitRoots(dumpReferencesRootVisitor, arg);
251 dvmHeapBitmapWalk(bitmap, dumpReferencesCallback, arg);
252}
253
254/*
Carl Shapiro5ba39372010-08-06 17:07:53 -0700255 * Returns true if the given object is a reference object and the
256 * just the referent is unmarked.
257 */
258static bool isReferentUnmarked(const Object *obj,
259 const WhiteReferenceCounter* ctx)
260{
261 assert(obj != NULL);
262 assert(obj->clazz != NULL);
263 assert(ctx != NULL);
264 if (ctx->whiteRefs != 1) {
265 return false;
266 } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE)) {
267 size_t offset = gDvm.offJavaLangRefReference_referent;
268 const Object *referent = dvmGetFieldObject(obj, offset);
269 return !dvmHeapBitmapIsObjectBitSet(ctx->markBits, referent);
270 } else {
271 return false;
272 }
273}
274
275/*
276 * Returns true if the given object is a string and has been interned
277 * by the user.
278 */
279static bool isWeakInternedString(const Object *obj)
280{
281 assert(obj != NULL);
282 if (obj->clazz == gDvm.classJavaLangString) {
283 return dvmIsWeakInternedString((StringObject *)obj);
284 } else {
285 return false;
286 }
287}
288
289/*
Carl Shapiro71ce7a92010-09-29 01:09:11 -0700290 * Returns true if the given object has been pushed on the mark stack
291 * by root marking.
292 */
293static bool isPushedOnMarkStack(const Object *obj)
294{
Carl Shapirofdf80522010-11-09 14:27:02 -0800295 GcMarkStack *stack = &gDvm.gcHeap->markContext.stack;
Carl Shapiro71ce7a92010-09-29 01:09:11 -0700296 const Object **ptr;
297
Carl Shapirofdf80522010-11-09 14:27:02 -0800298 for (ptr = stack->base; ptr < stack->top; ++ptr) {
Carl Shapiro71ce7a92010-09-29 01:09:11 -0700299 if (*ptr == obj) {
300 return true;
301 }
302 }
303 return false;
304}
305
306/*
307 * Callback applied to marked objects. If the object is gray and on
308 * an unmarked card an error is logged and the VM is aborted. Card
309 * table verification occurs between root marking and weak reference
310 * processing. We treat objects marked from the roots and weak
311 * references specially as it is permissible for these objects to be
312 * gray and on an unmarked card.
Carl Shapiro5ba39372010-08-06 17:07:53 -0700313 */
Carl Shapiro57ee2702010-08-27 13:06:48 -0700314static void verifyCardTableCallback(void *ptr, void *arg)
Carl Shapiro5ba39372010-08-06 17:07:53 -0700315{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800316 Object *obj = (Object *)ptr;
317 WhiteReferenceCounter ctx = { (HeapBitmap *)arg, 0 };
Carl Shapiro5ba39372010-08-06 17:07:53 -0700318
Carl Shapiro57ee2702010-08-27 13:06:48 -0700319 dvmVisitObject(countWhiteReferenceVisitor, obj, &ctx);
320 if (ctx.whiteRefs == 0) {
321 return;
322 } else if (isObjectDirty(obj)) {
323 return;
324 } else if (isReferentUnmarked(obj, &ctx)) {
325 return;
326 } else if (isWeakInternedString(obj)) {
327 return;
Carl Shapiro71ce7a92010-09-29 01:09:11 -0700328 } else if (isPushedOnMarkStack(obj)) {
329 return;
Carl Shapiro57ee2702010-08-27 13:06:48 -0700330 } else {
Carl Shapiro71ce7a92010-09-29 01:09:11 -0700331 LOGE("Verify failed, object %p is gray and on an unmarked card", obj);
Carl Shapiro5ba39372010-08-06 17:07:53 -0700332 dvmDumpObject(obj);
Carl Shapiro7f43c032010-10-18 17:26:46 -0700333 dvmVisitObject(dumpWhiteReferenceVisitor, obj, &ctx);
334 dumpReferences(obj);
Carl Shapiro5ba39372010-08-06 17:07:53 -0700335 dvmAbort();
336 }
337}
338
339/*
340 * Verifies that gray objects are on a dirty card.
341 */
342void dvmVerifyCardTable(void)
343{
344 HeapBitmap *markBits = gDvm.gcHeap->markContext.bitmap;
345 dvmHeapBitmapWalk(markBits, verifyCardTableCallback, markBits);
346}