blob: 533d5bc8ab7cd019201148574175ab745dd3c410 [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
Carl Shapiro6c355e52011-03-02 15:43:39 -080047static bool allocCardTable(size_t heapMaximumSize)
Barry Hayes6e5cf602010-06-22 12:32:59 -070048{
49 size_t length;
50 void *allocBase;
51 u1 *biasedBase;
Barry Hayesb874ab92010-07-14 08:13:18 -070052 GcHeap *gcHeap = gDvm.gcHeap;
53 void *heapBase = dvmHeapSourceGetBase();
54 assert(gcHeap != NULL);
55 assert(heapBase != NULL);
Barry Hayes6e5cf602010-06-22 12:32:59 -070056
57 /* Set up the card table */
Carl Shapirodf9f08b2011-01-18 17:59:30 -080058 length = heapMaximumSize / GC_CARD_SIZE;
Carl Shapiro6c355e52011-03-02 15:43:39 -080059 assert(length * GC_CARD_SIZE == heapMaximumSize);
Barry Hayes6e5cf602010-06-22 12:32:59 -070060 /* Allocate an extra 256 bytes to allow fixed low-byte of base */
61 allocBase = dvmAllocRegion(length + 0x100, PROT_READ | PROT_WRITE,
62 "dalvik-card-table");
63 if (allocBase == NULL) {
64 return false;
65 }
Carl Shapirofc75f3e2010-12-07 11:43:38 -080066 gcHeap->cardTableBase = (u1*)allocBase;
Barry Hayes6e5cf602010-06-22 12:32:59 -070067 gcHeap->cardTableLength = length;
68 /* All zeros is the correct initial value; all clean. */
69 assert(GC_CARD_CLEAN == 0);
70
71 biasedBase = (u1 *)((uintptr_t)allocBase -
72 ((uintptr_t)heapBase >> GC_CARD_SHIFT));
73 if (((uintptr_t)biasedBase & 0xff) != GC_CARD_DIRTY) {
Carl Shapiro5d81aa32010-08-20 11:04:25 -070074 int offset = GC_CARD_DIRTY - ((uintptr_t)biasedBase & 0xff);
Barry Hayes6e5cf602010-06-22 12:32:59 -070075 biasedBase += offset + (offset < 0 ? 0x100 : 0);
76 }
77 assert(((uintptr_t)biasedBase & 0xff) == GC_CARD_DIRTY);
Barry Hayes4496ed92010-07-12 09:52:20 -070078 gDvm.biasedCardTableBase = biasedBase;
Barry Hayes6e5cf602010-06-22 12:32:59 -070079
80 return true;
81}
82
Brian Carlstrom4a7db9c2011-04-04 12:06:15 -070083static bool allocModUnionTable(size_t heapSize)
Carl Shapiro6c355e52011-03-02 15:43:39 -080084{
Brian Carlstrom4a7db9c2011-04-04 12:06:15 -070085 size_t cardsPerHeap = heapSize / GC_CARD_SIZE;
86 size_t byteLength = cardsPerHeap / CHAR_BIT;
87 assert(byteLength * GC_CARD_SIZE * CHAR_BIT == heapSize);
Carl Shapiro6c355e52011-03-02 15:43:39 -080088 int prot = PROT_READ | PROT_WRITE;
Brian Carlstrom4a7db9c2011-04-04 12:06:15 -070089 void *allocBase = dvmAllocRegion(byteLength, prot, "dalvik-modunion-table");
Carl Shapiro6c355e52011-03-02 15:43:39 -080090 if (allocBase == NULL) {
91 return false;
92 }
93 GcHeap *gcHeap = gDvm.gcHeap;
94 gcHeap->modUnionTableBase = (u1*)allocBase;
Brian Carlstrom4a7db9c2011-04-04 12:06:15 -070095 gcHeap->modUnionTableLength = byteLength;
Carl Shapiro6c355e52011-03-02 15:43:39 -080096 return true;
97}
98
99/*
100 * Initializes the card table; must be called before any other
101 * dvmCardTable*() functions.
102 */
103bool dvmCardTableStartup(size_t heapMaximumSize)
104{
105 return allocCardTable(heapMaximumSize) && allocModUnionTable(heapMaximumSize);
106}
107
108/*
109 * Releases storage for the card table and clears its globals.
110 */
111static void freeCardTable()
112{
113 if (gDvm.biasedCardTableBase == NULL) {
114 return;
115 }
116 gDvm.biasedCardTableBase = NULL;
117 munmap(gDvm.gcHeap->cardTableBase, gDvm.gcHeap->cardTableLength);
118 gDvm.gcHeap->cardTableBase = NULL;
119 gDvm.gcHeap->cardTableLength = 0;
120}
121
122/*
123 * Releases storage for the mod union table and clears its globals.
124 */
125static void freeModUnionTable()
126{
127 if (gDvm.gcHeap->modUnionTableBase == NULL) {
128 return;
129 }
130 munmap(gDvm.gcHeap->modUnionTableBase, gDvm.gcHeap->modUnionTableLength);
131 gDvm.gcHeap->modUnionTableBase = NULL;
132 gDvm.gcHeap->modUnionTableLength = 0;
133}
134
Barry Hayes6e5cf602010-06-22 12:32:59 -0700135/*
136 * Tears down the entire CardTable.
137 */
138void dvmCardTableShutdown()
139{
Carl Shapiro6c355e52011-03-02 15:43:39 -0800140 freeCardTable();
141 freeModUnionTable();
142}
143
144/*
145 * Set a bit in the mod union table for each dirty byte in the card
146 * table. Clears the corresponding byte in the card table.
147 */
148static void moveCardsToModUnion(u1 *base, u1 *limit)
149{
150 GcHeap *h = gDvm.gcHeap;
151 u1 *baseCard = dvmCardFromAddr(base);
152 u1 *limitCard = dvmCardFromAddr(limit);
153 u4 *bits = (u4*)h->modUnionTableBase;
154 u1 *heapBase = (u1*)dvmHeapSourceGetBase();
155 u1 *card;
156 for (card = baseCard; card < limitCard; ++card) {
157 if (*card == GC_CARD_CLEAN) {
158 continue;
159 }
160 u1 *addr = (u1*)dvmAddrFromCard(card);
161 u1 *biased = (u1*)((uintptr_t)addr - (uintptr_t)heapBase);
162 size_t offset = (uintptr_t)biased / GC_CARD_SIZE / HB_BITS_PER_WORD;
163 u4 bit = 1 << (((uintptr_t)biased / GC_CARD_SIZE) % HB_BITS_PER_WORD);
164 assert((u1*)&bits[offset] >= h->modUnionTableBase);
165 assert((u1*)&bits[offset] < h->modUnionTableBase+h->modUnionTableLength);
166 bits[offset] |= bit;
167 *card = GC_CARD_CLEAN;
168 }
Barry Hayes6e5cf602010-06-22 12:32:59 -0700169}
170
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700171void dvmClearCardTable(void)
172{
Carl Shapiro6c355e52011-03-02 15:43:39 -0800173 uintptr_t base[HEAP_SOURCE_MAX_HEAP_COUNT];
174 uintptr_t limit[HEAP_SOURCE_MAX_HEAP_COUNT];
175 size_t numHeaps = dvmHeapSourceGetNumHeaps();
176 dvmHeapSourceGetRegions(base, NULL, limit, numHeaps);
177 size_t i;
178 for (i = 0; i < numHeaps; ++i) {
179 if (i != 0) {
180 moveCardsToModUnion((u1*)base[i], (u1*)limit[i]);
181 } else {
182 u1 *baseCard = dvmCardFromAddr((u1*)base[i]);
Carl Shapiro20d4d042011-03-08 13:46:10 -0800183 size_t length = (limit[i] - base[i]) >> GC_CARD_SHIFT;
184 memset(baseCard, GC_CARD_CLEAN, length);
Carl Shapiro6c355e52011-03-02 15:43:39 -0800185 }
186 }
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700187}
188
Barry Hayes6e5cf602010-06-22 12:32:59 -0700189/*
Barry Hayes4496ed92010-07-12 09:52:20 -0700190 * Returns true iff the address is within the bounds of the card table.
191 */
192bool dvmIsValidCard(const u1 *cardAddr)
193{
194 GcHeap *h = gDvm.gcHeap;
195 return cardAddr >= h->cardTableBase &&
196 cardAddr < &h->cardTableBase[h->cardTableLength];
197}
198
199/*
Barry Hayes8f921a72010-07-09 12:53:49 -0700200 * Returns the address of the relevent byte in the card table, given
Barry Hayes6e5cf602010-06-22 12:32:59 -0700201 * an address on the heap.
202 */
203u1 *dvmCardFromAddr(const void *addr)
204{
Barry Hayes4496ed92010-07-12 09:52:20 -0700205 u1 *biasedBase = gDvm.biasedCardTableBase;
206 u1 *cardAddr = biasedBase + ((uintptr_t)addr >> GC_CARD_SHIFT);
207 assert(dvmIsValidCard(cardAddr));
Barry Hayes6e5cf602010-06-22 12:32:59 -0700208 return cardAddr;
209}
210
Barry Hayes8f921a72010-07-09 12:53:49 -0700211/*
212 * Returns the first address in the heap which maps to this card.
213 */
214void *dvmAddrFromCard(const u1 *cardAddr)
215{
Barry Hayes4496ed92010-07-12 09:52:20 -0700216 assert(dvmIsValidCard(cardAddr));
217 uintptr_t offset = cardAddr - gDvm.biasedCardTableBase;
Barry Hayes8f921a72010-07-09 12:53:49 -0700218 return (void *)(offset << GC_CARD_SHIFT);
Barry Hayes6e5cf602010-06-22 12:32:59 -0700219}
220
221/*
222 * Dirties the card for the given address.
223 */
224void dvmMarkCard(const void *addr)
225{
226 u1 *cardAddr = dvmCardFromAddr(addr);
227 *cardAddr = GC_CARD_DIRTY;
228}
Carl Shapiro5ba39372010-08-06 17:07:53 -0700229
230/*
Carl Shapiro5ba39372010-08-06 17:07:53 -0700231 * Returns true if the object is on a dirty card.
232 */
233static bool isObjectDirty(const Object *obj)
234{
235 assert(obj != NULL);
236 assert(dvmIsValidObject(obj));
Carl Shapiro71ce7a92010-09-29 01:09:11 -0700237 u1 *card = dvmCardFromAddr(obj);
238 return *card == GC_CARD_DIRTY;
Carl Shapiro5ba39372010-08-06 17:07:53 -0700239}
240
241/*
242 * Context structure for verifying the card table.
243 */
244typedef struct {
245 HeapBitmap *markBits;
246 size_t whiteRefs;
247} WhiteReferenceCounter;
248
249/*
250 * Visitor that counts white referents.
251 */
252static void countWhiteReferenceVisitor(void *addr, void *arg)
253{
254 WhiteReferenceCounter *ctx;
255 Object *obj;
256
257 assert(addr != NULL);
258 assert(arg != NULL);
259 obj = *(Object **)addr;
Carl Shapiro8e14bc72010-10-18 16:27:29 -0700260 if (obj == NULL) {
261 return;
262 }
Carl Shapiro5ba39372010-08-06 17:07:53 -0700263 assert(dvmIsValidObject(obj));
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800264 ctx = (WhiteReferenceCounter *)arg;
Carl Shapiro8e14bc72010-10-18 16:27:29 -0700265 if (dvmHeapBitmapIsObjectBitSet(ctx->markBits, obj)) {
Carl Shapiro5ba39372010-08-06 17:07:53 -0700266 return;
267 }
268 ctx->whiteRefs += 1;
269}
270
271/*
Carl Shapiro7f43c032010-10-18 17:26:46 -0700272 * Visitor that logs white references.
273 */
274static void dumpWhiteReferenceVisitor(void *addr, void *arg)
275{
276 WhiteReferenceCounter *ctx;
277 Object *obj;
278
279 assert(addr != NULL);
280 assert(arg != NULL);
281 obj = *(Object **)addr;
282 if (obj == NULL) {
283 return;
284 }
285 assert(dvmIsValidObject(obj));
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800286 ctx = (WhiteReferenceCounter*)arg;
Carl Shapiro7f43c032010-10-18 17:26:46 -0700287 if (dvmHeapBitmapIsObjectBitSet(ctx->markBits, obj)) {
288 return;
289 }
290 LOGE("object %p is white", obj);
291}
292
293/*
294 * Visitor that signals the caller when a matching reference is found.
295 */
296static void dumpReferencesVisitor(void *pObj, void *arg)
297{
298 Object *obj = *(Object **)pObj;
299 Object *lookingFor = *(Object **)arg;
300 if (lookingFor != NULL && lookingFor == obj) {
301 *(Object **)arg = NULL;
302 }
303}
304
305static void dumpReferencesCallback(void *ptr, void *arg)
306{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800307 Object *obj = (Object *)arg;
Carl Shapiro7f43c032010-10-18 17:26:46 -0700308 if (ptr == obj) {
309 return;
310 }
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800311 dvmVisitObject(dumpReferencesVisitor, (Object *)ptr, &obj);
Carl Shapiro7f43c032010-10-18 17:26:46 -0700312 if (obj == NULL) {
313 LOGD("Found %p in the heap @ %p", arg, ptr);
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800314 dvmDumpObject((Object *)ptr);
Carl Shapiro7f43c032010-10-18 17:26:46 -0700315 }
316}
317
318/*
319 * Root visitor that looks for matching references.
320 */
Carl Shapiro07018e22010-10-26 21:07:41 -0700321static void dumpReferencesRootVisitor(void *ptr, u4 threadId,
322 RootType type, void *arg)
Carl Shapiro7f43c032010-10-18 17:26:46 -0700323{
324 Object *obj = *(Object **)ptr;
325 Object *lookingFor = *(Object **)arg;
326 if (obj == lookingFor) {
327 LOGD("Found %p in a root @ %p", arg, ptr);
328 }
329}
330
331/*
332 * Invokes visitors to search for references to an object.
333 */
334static void dumpReferences(const Object *obj)
335{
336 HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
337 void *arg = (void *)obj;
338 dvmVisitRoots(dumpReferencesRootVisitor, arg);
339 dvmHeapBitmapWalk(bitmap, dumpReferencesCallback, arg);
340}
341
342/*
Carl Shapiro5ba39372010-08-06 17:07:53 -0700343 * Returns true if the given object is a reference object and the
344 * just the referent is unmarked.
345 */
346static bool isReferentUnmarked(const Object *obj,
347 const WhiteReferenceCounter* ctx)
348{
349 assert(obj != NULL);
350 assert(obj->clazz != NULL);
351 assert(ctx != NULL);
352 if (ctx->whiteRefs != 1) {
353 return false;
354 } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE)) {
355 size_t offset = gDvm.offJavaLangRefReference_referent;
356 const Object *referent = dvmGetFieldObject(obj, offset);
357 return !dvmHeapBitmapIsObjectBitSet(ctx->markBits, referent);
358 } else {
359 return false;
360 }
361}
362
363/*
364 * Returns true if the given object is a string and has been interned
365 * by the user.
366 */
367static bool isWeakInternedString(const Object *obj)
368{
369 assert(obj != NULL);
370 if (obj->clazz == gDvm.classJavaLangString) {
371 return dvmIsWeakInternedString((StringObject *)obj);
372 } else {
373 return false;
374 }
375}
376
377/*
Carl Shapiro71ce7a92010-09-29 01:09:11 -0700378 * Returns true if the given object has been pushed on the mark stack
379 * by root marking.
380 */
381static bool isPushedOnMarkStack(const Object *obj)
382{
Carl Shapirofdf80522010-11-09 14:27:02 -0800383 GcMarkStack *stack = &gDvm.gcHeap->markContext.stack;
Carl Shapiro71ce7a92010-09-29 01:09:11 -0700384 const Object **ptr;
385
Carl Shapirofdf80522010-11-09 14:27:02 -0800386 for (ptr = stack->base; ptr < stack->top; ++ptr) {
Carl Shapiro71ce7a92010-09-29 01:09:11 -0700387 if (*ptr == obj) {
388 return true;
389 }
390 }
391 return false;
392}
393
394/*
395 * Callback applied to marked objects. If the object is gray and on
396 * an unmarked card an error is logged and the VM is aborted. Card
397 * table verification occurs between root marking and weak reference
398 * processing. We treat objects marked from the roots and weak
399 * references specially as it is permissible for these objects to be
400 * gray and on an unmarked card.
Carl Shapiro5ba39372010-08-06 17:07:53 -0700401 */
Carl Shapiro57ee2702010-08-27 13:06:48 -0700402static void verifyCardTableCallback(void *ptr, void *arg)
Carl Shapiro5ba39372010-08-06 17:07:53 -0700403{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800404 Object *obj = (Object *)ptr;
405 WhiteReferenceCounter ctx = { (HeapBitmap *)arg, 0 };
Carl Shapiro5ba39372010-08-06 17:07:53 -0700406
Carl Shapiro57ee2702010-08-27 13:06:48 -0700407 dvmVisitObject(countWhiteReferenceVisitor, obj, &ctx);
408 if (ctx.whiteRefs == 0) {
409 return;
410 } else if (isObjectDirty(obj)) {
411 return;
412 } else if (isReferentUnmarked(obj, &ctx)) {
413 return;
414 } else if (isWeakInternedString(obj)) {
415 return;
Carl Shapiro71ce7a92010-09-29 01:09:11 -0700416 } else if (isPushedOnMarkStack(obj)) {
417 return;
Carl Shapiro57ee2702010-08-27 13:06:48 -0700418 } else {
Carl Shapiro71ce7a92010-09-29 01:09:11 -0700419 LOGE("Verify failed, object %p is gray and on an unmarked card", obj);
Carl Shapiro5ba39372010-08-06 17:07:53 -0700420 dvmDumpObject(obj);
Carl Shapiro7f43c032010-10-18 17:26:46 -0700421 dvmVisitObject(dumpWhiteReferenceVisitor, obj, &ctx);
422 dumpReferences(obj);
Carl Shapiro5ba39372010-08-06 17:07:53 -0700423 dvmAbort();
424 }
425}
426
427/*
428 * Verifies that gray objects are on a dirty card.
429 */
430void dvmVerifyCardTable(void)
431{
432 HeapBitmap *markBits = gDvm.gcHeap->markContext.bitmap;
433 dvmHeapBitmapWalk(markBits, verifyCardTableCallback, markBits);
434}