blob: 2a20fc81ab13d0f3ca2744e737c4c5483a890ea7 [file] [log] [blame]
Ian Rogers5d76c432011-10-31 21:42:49 -07001/*
Elliott Hughes2faa5f12012-01-30 14:42:07 -08002 * Copyright (C) 2011 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.
Ian Rogers5d76c432011-10-31 21:42:49 -070015 */
16
Mathieu Chartier7469ebf2012-09-24 16:28:36 -070017#ifndef ART_SRC_GC_CARDTABLE_H_
18#define ART_SRC_GC_CARDTABLE_H_
Ian Rogers5d76c432011-10-31 21:42:49 -070019
20#include "globals.h"
21#include "logging.h"
22#include "mem_map.h"
Mathieu Chartiercc236d72012-07-20 10:29:05 -070023#include "space_bitmap.h"
Ian Rogers5d76c432011-10-31 21:42:49 -070024#include "UniquePtr.h"
Mathieu Chartierd22d5482012-11-06 17:14:12 -080025#include "utils.h"
Ian Rogers5d76c432011-10-31 21:42:49 -070026
27namespace art {
28
Mathieu Chartier262e5ff2012-06-01 17:35:38 -070029class Heap;
Mathieu Chartier2fde5332012-09-14 14:51:54 -070030class ContinuousSpace;
Mathieu Chartierb062fdd2012-07-03 09:51:48 -070031class SpaceBitmap;
Ian Rogers5d76c432011-10-31 21:42:49 -070032class Object;
33
Elliott Hughes2faa5f12012-01-30 14:42:07 -080034// Maintain a card table from the the write barrier. All writes of
35// non-NULL values to heap addresses should go through an entry in
36// WriteBarrier, and from there to here.
Ian Rogers5d76c432011-10-31 21:42:49 -070037class CardTable {
38 public:
Mathieu Chartier7469ebf2012-09-24 16:28:36 -070039 static const size_t kCardShift = 7;
40 static const size_t kCardSize = (1 << kCardShift);
41 static const uint8_t kCardClean = 0x0;
42 static const uint8_t kCardDirty = 0x70;
43
Ian Rogers30fab402012-01-23 15:43:46 -080044 static CardTable* Create(const byte* heap_begin, size_t heap_capacity);
Ian Rogers5d76c432011-10-31 21:42:49 -070045
Ian Rogers30fab402012-01-23 15:43:46 -080046 // Set the card associated with the given address to GC_CARD_DIRTY.
Ian Rogers5d76c432011-10-31 21:42:49 -070047 void MarkCard(const void *addr) {
Elliott Hughes24edeb52012-06-18 15:29:46 -070048 byte* card_addr = CardFromAddr(addr);
Mathieu Chartier7469ebf2012-09-24 16:28:36 -070049 *card_addr = kCardDirty;
Ian Rogers5d76c432011-10-31 21:42:49 -070050 }
51
Ian Rogers30fab402012-01-23 15:43:46 -080052 // Is the object on a dirty card?
Ian Rogers5d76c432011-10-31 21:42:49 -070053 bool IsDirty(const Object* obj) const {
Mathieu Chartier7469ebf2012-09-24 16:28:36 -070054 return *CardFromAddr(obj) == kCardDirty;
Ian Rogers5d76c432011-10-31 21:42:49 -070055 }
56
Mathieu Chartier7469ebf2012-09-24 16:28:36 -070057 // Visit and clear cards within memory range, only visits dirty cards.
Mathieu Chartierb43b7d42012-06-19 13:15:09 -070058 template <typename Visitor>
59 void VisitClear(const void* start, const void* end, const Visitor& visitor) {
60 byte* card_start = CardFromAddr(start);
61 byte* card_end = CardFromAddr(end);
Mathieu Chartier7469ebf2012-09-24 16:28:36 -070062 for (byte* it = card_start; it != card_end; ++it) {
63 if (*it == kCardDirty) {
64 *it = kCardClean;
65 visitor(it);
Mathieu Chartierb43b7d42012-06-19 13:15:09 -070066 }
67 }
68 }
69
Ian Rogers30fab402012-01-23 15:43:46 -080070 // Returns a value that when added to a heap address >> GC_CARD_SHIFT will address the appropriate
71 // card table byte. For convenience this value is cached in every Thread
72 byte* GetBiasedBegin() const {
73 return biased_begin_;
jeffhao39da0352011-11-04 14:58:55 -070074 }
75
Mathieu Chartierd22d5482012-11-06 17:14:12 -080076 /*
77 * Visitor is expected to take in a card and return the new value. When a value is modified, the
78 * modify visitor is called.
79 * visitor: The visitor which modifies the cards. Returns the new value for a card given an old
80 * value.
81 * modified: Whenever the visitor modifies a card, this visitor is called on the card. Enables
82 * us to know which cards got cleared.
83 */
84 template <typename Visitor, typename ModifiedVisitor>
85 void ModifyCardsAtomic(byte* scan_begin, byte* scan_end, const Visitor& visitor,
86 const ModifiedVisitor& modified = VoidFunctor()) {
87 byte* card_cur = CardFromAddr(scan_begin);
88 byte* card_end = CardFromAddr(scan_end);
89 CheckCardValid(card_cur);
90 CheckCardValid(card_end);
91
92 // Handle any unaligned cards at the start.
93 while (!IsAligned<sizeof(word)>(card_cur) && card_cur < card_end) {
94 byte expected, new_value;
95 do {
96 expected = *card_cur;
97 new_value = visitor(expected);
98 } while (expected != new_value && UNLIKELY(byte_cas(expected, new_value, card_cur) != 0));
99 if (expected != new_value) {
100 modified(card_cur, expected, new_value);
101 }
102 ++card_cur;
103 }
104
105 // Handle unaligned cards at the end.
106 while (!IsAligned<sizeof(word)>(card_end) && card_end > card_cur) {
107 --card_end;
108 byte expected, new_value;
109 do {
110 expected = *card_end;
111 new_value = visitor(expected);
112 } while (expected != new_value && UNLIKELY(byte_cas(expected, new_value, card_end) != 0));
113 if (expected != new_value) {
114 modified(card_cur, expected, new_value);
115 }
116 }
117
118 // Now we have the words, we can process words in parallel.
119 uintptr_t* word_cur = reinterpret_cast<uintptr_t*>(card_cur);
120 uintptr_t* word_end = reinterpret_cast<uintptr_t*>(card_end);
121 uintptr_t expected_word;
122 uintptr_t new_word;
123
124 // TODO: Parallelize.
125 while (word_cur < word_end) {
126 while ((expected_word = *word_cur) != 0) {
127 new_word =
128 (visitor((expected_word >> 0) & 0xFF) << 0) |
129 (visitor((expected_word >> 8) & 0xFF) << 8) |
130 (visitor((expected_word >> 16) & 0xFF) << 16) |
131 (visitor((expected_word >> 24) & 0xFF) << 24);
132 if (new_word == expected_word) {
133 // No need to do a cas.
134 break;
135 }
136 if (LIKELY(android_atomic_cas(expected_word, new_word,
137 reinterpret_cast<int32_t*>(word_cur)) == 0)) {
138 for (size_t i = 0; i < sizeof(uintptr_t); ++i) {
139 const byte expected_byte = (expected_word >> (8 * i)) & 0xFF;
140 const byte new_byte = (new_word >> (8 * i)) & 0xFF;
141 if (expected_byte != new_byte) {
142 modified(reinterpret_cast<byte*>(word_cur) + i, expected_byte, new_byte);
143 }
144 }
145 break;
146 }
147 }
148 ++word_cur;
149 }
150 }
151
152 // For every dirty at least minumum age between begin and end invoke the visitor with the
153 // specified argument.
Mathieu Chartier357e9be2012-08-01 11:00:14 -0700154 template <typename Visitor, typename FingerVisitor>
155 void Scan(SpaceBitmap* bitmap, byte* scan_begin, byte* scan_end,
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800156 const Visitor& visitor, const FingerVisitor& finger_visitor,
157 const byte minimum_age = kCardDirty) const
Ian Rogersb726dcb2012-09-05 08:57:23 -0700158 EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
159 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Mathieu Chartiercc236d72012-07-20 10:29:05 -0700160 DCHECK(bitmap->HasAddress(scan_begin));
161 DCHECK(bitmap->HasAddress(scan_end - 1)); // scan_end is the byte after the last byte we scan.
162 byte* card_cur = CardFromAddr(scan_begin);
163 byte* card_end = CardFromAddr(scan_end);
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800164 CheckCardValid(card_cur);
165 CheckCardValid(card_end);
166
167 // Handle any unaligned cards at the start.
168 while (!IsAligned<sizeof(word)>(card_cur) && card_cur < card_end) {
169 if (*card_cur >= minimum_age) {
170 uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card_cur));
171 uintptr_t end = start + kCardSize;
172 bitmap->VisitMarkedRange(start, end, visitor, finger_visitor);
173 }
174 ++card_cur;
175 }
176
177 byte* aligned_end = card_end -
178 (reinterpret_cast<uintptr_t>(card_end) & (sizeof(uintptr_t) - 1));
179
180 // Now we have the words, we can send these to be processed in parallel.
181 uintptr_t* word_cur = reinterpret_cast<uintptr_t*>(card_cur);
182 uintptr_t* word_end = reinterpret_cast<uintptr_t*>(aligned_end);
183
184 // TODO: Parallelize
185 while (word_cur < word_end) {
Mathieu Chartier357e9be2012-08-01 11:00:14 -0700186 // Find the first dirty card.
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800187 while (*word_cur == 0 && word_cur < word_end) {
188 word_cur++;
189 }
190 if (word_cur >= word_end) {
Mathieu Chartier357e9be2012-08-01 11:00:14 -0700191 break;
Mathieu Chartiercc236d72012-07-20 10:29:05 -0700192 }
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800193 uintptr_t start_word = *word_cur;
194 for (size_t i = 0; i < sizeof(uintptr_t); ++i) {
195 if ((start_word & 0xFF) == minimum_age) {
196 byte* card = reinterpret_cast<byte*>(word_cur) + i;
197 DCHECK_EQ(*card, start_word & 0xFF);
198 uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card));
199 uintptr_t end = start + kCardSize;
200 bitmap->VisitMarkedRange(start, end, visitor, finger_visitor);
201 }
202 start_word >>= 8;
Mathieu Chartiercc236d72012-07-20 10:29:05 -0700203 }
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800204 ++word_cur;
205 }
Mathieu Chartiercc236d72012-07-20 10:29:05 -0700206
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800207 // Handle any unaligned cards at the end.
208 card_cur = reinterpret_cast<byte*>(word_end);
209 while (card_cur < card_end) {
210 if (*card_cur >= minimum_age) {
211 uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card_cur));
212 uintptr_t end = start + kCardSize;
213 bitmap->VisitMarkedRange(start, end, visitor, finger_visitor);
214 }
215 ++card_cur;
Mathieu Chartiercc236d72012-07-20 10:29:05 -0700216 }
217 }
Ian Rogers30fab402012-01-23 15:43:46 -0800218
Ian Rogers30fab402012-01-23 15:43:46 -0800219 // Assertion used to check the given address is covered by the card table
220 void CheckAddrIsInCardTable(const byte* addr) const;
221
Mathieu Chartier262e5ff2012-06-01 17:35:38 -0700222 // Resets all of the bytes in the card table to clean.
223 void ClearCardTable();
224
Mathieu Chartierb43b7d42012-06-19 13:15:09 -0700225 // Resets all of the bytes in the card table which do not map to the image space.
Mathieu Chartier2fde5332012-09-14 14:51:54 -0700226 void ClearSpaceCards(ContinuousSpace* space);
Ian Rogers5d76c432011-10-31 21:42:49 -0700227
Mathieu Chartierb43b7d42012-06-19 13:15:09 -0700228 // Returns the first address in the heap which maps to this card.
229 void* AddrFromCard(const byte *card_addr) const {
230 DCHECK(IsValidCard(card_addr))
231 << " card_addr: " << reinterpret_cast<const void*>(card_addr)
232 << " begin: " << reinterpret_cast<void*>(mem_map_->Begin() + offset_)
233 << " end: " << reinterpret_cast<void*>(mem_map_->End());
234 uintptr_t offset = card_addr - biased_begin_;
Mathieu Chartier7469ebf2012-09-24 16:28:36 -0700235 return reinterpret_cast<void*>(offset << kCardShift);
Mathieu Chartierb43b7d42012-06-19 13:15:09 -0700236 }
Ian Rogers5d76c432011-10-31 21:42:49 -0700237
Ian Rogers30fab402012-01-23 15:43:46 -0800238 // Returns the address of the relevant byte in the card table, given an address on the heap.
Ian Rogers5d76c432011-10-31 21:42:49 -0700239 byte* CardFromAddr(const void *addr) const {
Mathieu Chartier7469ebf2012-09-24 16:28:36 -0700240 byte *card_addr = biased_begin_ + ((uintptr_t)addr >> kCardShift);
Ian Rogers30fab402012-01-23 15:43:46 -0800241 // Sanity check the caller was asking for address covered by the card table
Elliott Hughes24edeb52012-06-18 15:29:46 -0700242 DCHECK(IsValidCard(card_addr)) << "addr: " << addr
243 << " card_addr: " << reinterpret_cast<void*>(card_addr);
244 return card_addr;
Ian Rogers5d76c432011-10-31 21:42:49 -0700245 }
246
Mathieu Chartier7469ebf2012-09-24 16:28:36 -0700247 bool AddrIsInCardTable(const void* addr) const;
248
Mathieu Chartiercc236d72012-07-20 10:29:05 -0700249 private:
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800250 static int byte_cas(byte old_value, byte new_value, byte* address) {
251 // Little endian means most significant byte is on the left.
252 const size_t shift = reinterpret_cast<uintptr_t>(address) % sizeof(uintptr_t);
253 // Align the address down.
254 address -= shift;
255 int32_t* word_address = reinterpret_cast<int32_t*>(address);
256 // Word with the byte we are trying to cas cleared.
257 const int32_t cur_word = *word_address & ~(0xFF << shift);
258 const int32_t old_word = cur_word | (static_cast<int32_t>(old_value) << shift);
259 const int32_t new_word = cur_word | (static_cast<int32_t>(new_value) << shift);
260 return android_atomic_cas(old_word, new_word, word_address);
261 }
262
Mathieu Chartiercc236d72012-07-20 10:29:05 -0700263 CardTable(MemMap* begin, byte* biased_begin, size_t offset);
264
Ian Rogers30fab402012-01-23 15:43:46 -0800265 // Returns true iff the card table address is within the bounds of the card table.
Elliott Hughes24edeb52012-06-18 15:29:46 -0700266 bool IsValidCard(const byte* card_addr) const {
Ian Rogers30fab402012-01-23 15:43:46 -0800267 byte* begin = mem_map_->Begin() + offset_;
268 byte* end = mem_map_->End();
Elliott Hughes24edeb52012-06-18 15:29:46 -0700269 return card_addr >= begin && card_addr < end;
Ian Rogers5d76c432011-10-31 21:42:49 -0700270 }
271
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800272 void CheckCardValid(byte* card) const {
273 DCHECK(IsValidCard(card))
274 << " card_addr: " << reinterpret_cast<const void*>(card)
275 << " begin: " << reinterpret_cast<void*>(mem_map_->Begin() + offset_)
276 << " end: " << reinterpret_cast<void*>(mem_map_->End());
277 }
278
Ian Rogers30fab402012-01-23 15:43:46 -0800279 // Verifies that all gray objects are on a dirty card.
Ian Rogers5d76c432011-10-31 21:42:49 -0700280 void VerifyCardTable();
281
Ian Rogers30fab402012-01-23 15:43:46 -0800282 // Mmapped pages for the card table
Ian Rogers5d76c432011-10-31 21:42:49 -0700283 UniquePtr<MemMap> mem_map_;
Ian Rogers30fab402012-01-23 15:43:46 -0800284 // Value used to compute card table addresses from object addresses, see GetBiasedBegin
285 byte* const biased_begin_;
286 // Card table doesn't begin at the beginning of the mem_map_, instead it is displaced by offset
287 // to allow the byte value of biased_begin_ to equal GC_CARD_DIRTY
288 const size_t offset_;
Ian Rogers5d76c432011-10-31 21:42:49 -0700289};
290
291} // namespace art
Mathieu Chartier858f1c52012-10-17 17:45:55 -0700292#endif // ART_SRC_GC_CARDTABLE_H_