blob: d0d25fd375186f1d52bfd2c98c985bceeee8690e [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 Chartier4da7f2f2012-11-13 12:51:01 -080054 return GetCard(obj) == kCardDirty;
55 }
56
57 // Return the state of the card at an address.
58 byte GetCard(const Object* obj) const {
59 return *CardFromAddr(obj);
Ian Rogers5d76c432011-10-31 21:42:49 -070060 }
61
Mathieu Chartier7469ebf2012-09-24 16:28:36 -070062 // Visit and clear cards within memory range, only visits dirty cards.
Mathieu Chartierb43b7d42012-06-19 13:15:09 -070063 template <typename Visitor>
64 void VisitClear(const void* start, const void* end, const Visitor& visitor) {
65 byte* card_start = CardFromAddr(start);
66 byte* card_end = CardFromAddr(end);
Mathieu Chartier7469ebf2012-09-24 16:28:36 -070067 for (byte* it = card_start; it != card_end; ++it) {
68 if (*it == kCardDirty) {
69 *it = kCardClean;
70 visitor(it);
Mathieu Chartierb43b7d42012-06-19 13:15:09 -070071 }
72 }
73 }
74
Ian Rogers30fab402012-01-23 15:43:46 -080075 // Returns a value that when added to a heap address >> GC_CARD_SHIFT will address the appropriate
76 // card table byte. For convenience this value is cached in every Thread
77 byte* GetBiasedBegin() const {
78 return biased_begin_;
jeffhao39da0352011-11-04 14:58:55 -070079 }
80
Mathieu Chartierd22d5482012-11-06 17:14:12 -080081 /*
82 * Visitor is expected to take in a card and return the new value. When a value is modified, the
83 * modify visitor is called.
84 * visitor: The visitor which modifies the cards. Returns the new value for a card given an old
85 * value.
86 * modified: Whenever the visitor modifies a card, this visitor is called on the card. Enables
87 * us to know which cards got cleared.
88 */
89 template <typename Visitor, typename ModifiedVisitor>
90 void ModifyCardsAtomic(byte* scan_begin, byte* scan_end, const Visitor& visitor,
91 const ModifiedVisitor& modified = VoidFunctor()) {
92 byte* card_cur = CardFromAddr(scan_begin);
93 byte* card_end = CardFromAddr(scan_end);
94 CheckCardValid(card_cur);
95 CheckCardValid(card_end);
96
97 // Handle any unaligned cards at the start.
98 while (!IsAligned<sizeof(word)>(card_cur) && card_cur < card_end) {
99 byte expected, new_value;
100 do {
101 expected = *card_cur;
102 new_value = visitor(expected);
103 } while (expected != new_value && UNLIKELY(byte_cas(expected, new_value, card_cur) != 0));
104 if (expected != new_value) {
105 modified(card_cur, expected, new_value);
106 }
107 ++card_cur;
108 }
109
110 // Handle unaligned cards at the end.
111 while (!IsAligned<sizeof(word)>(card_end) && card_end > card_cur) {
112 --card_end;
113 byte expected, new_value;
114 do {
115 expected = *card_end;
116 new_value = visitor(expected);
117 } while (expected != new_value && UNLIKELY(byte_cas(expected, new_value, card_end) != 0));
118 if (expected != new_value) {
119 modified(card_cur, expected, new_value);
120 }
121 }
122
123 // Now we have the words, we can process words in parallel.
124 uintptr_t* word_cur = reinterpret_cast<uintptr_t*>(card_cur);
125 uintptr_t* word_end = reinterpret_cast<uintptr_t*>(card_end);
126 uintptr_t expected_word;
127 uintptr_t new_word;
128
129 // TODO: Parallelize.
130 while (word_cur < word_end) {
131 while ((expected_word = *word_cur) != 0) {
132 new_word =
133 (visitor((expected_word >> 0) & 0xFF) << 0) |
134 (visitor((expected_word >> 8) & 0xFF) << 8) |
135 (visitor((expected_word >> 16) & 0xFF) << 16) |
136 (visitor((expected_word >> 24) & 0xFF) << 24);
137 if (new_word == expected_word) {
138 // No need to do a cas.
139 break;
140 }
141 if (LIKELY(android_atomic_cas(expected_word, new_word,
142 reinterpret_cast<int32_t*>(word_cur)) == 0)) {
143 for (size_t i = 0; i < sizeof(uintptr_t); ++i) {
144 const byte expected_byte = (expected_word >> (8 * i)) & 0xFF;
145 const byte new_byte = (new_word >> (8 * i)) & 0xFF;
146 if (expected_byte != new_byte) {
147 modified(reinterpret_cast<byte*>(word_cur) + i, expected_byte, new_byte);
148 }
149 }
150 break;
151 }
152 }
153 ++word_cur;
154 }
155 }
156
157 // For every dirty at least minumum age between begin and end invoke the visitor with the
158 // specified argument.
Mathieu Chartier357e9be2012-08-01 11:00:14 -0700159 template <typename Visitor, typename FingerVisitor>
160 void Scan(SpaceBitmap* bitmap, byte* scan_begin, byte* scan_end,
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800161 const Visitor& visitor, const FingerVisitor& finger_visitor,
162 const byte minimum_age = kCardDirty) const
Ian Rogersb726dcb2012-09-05 08:57:23 -0700163 EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
164 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Mathieu Chartiercc236d72012-07-20 10:29:05 -0700165 DCHECK(bitmap->HasAddress(scan_begin));
166 DCHECK(bitmap->HasAddress(scan_end - 1)); // scan_end is the byte after the last byte we scan.
167 byte* card_cur = CardFromAddr(scan_begin);
168 byte* card_end = CardFromAddr(scan_end);
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800169 CheckCardValid(card_cur);
170 CheckCardValid(card_end);
171
172 // Handle any unaligned cards at the start.
173 while (!IsAligned<sizeof(word)>(card_cur) && card_cur < card_end) {
174 if (*card_cur >= minimum_age) {
175 uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card_cur));
176 uintptr_t end = start + kCardSize;
177 bitmap->VisitMarkedRange(start, end, visitor, finger_visitor);
178 }
179 ++card_cur;
180 }
181
182 byte* aligned_end = card_end -
183 (reinterpret_cast<uintptr_t>(card_end) & (sizeof(uintptr_t) - 1));
184
185 // Now we have the words, we can send these to be processed in parallel.
186 uintptr_t* word_cur = reinterpret_cast<uintptr_t*>(card_cur);
187 uintptr_t* word_end = reinterpret_cast<uintptr_t*>(aligned_end);
188
189 // TODO: Parallelize
190 while (word_cur < word_end) {
Mathieu Chartier357e9be2012-08-01 11:00:14 -0700191 // Find the first dirty card.
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800192 while (*word_cur == 0 && word_cur < word_end) {
193 word_cur++;
194 }
195 if (word_cur >= word_end) {
Mathieu Chartier357e9be2012-08-01 11:00:14 -0700196 break;
Mathieu Chartiercc236d72012-07-20 10:29:05 -0700197 }
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800198 uintptr_t start_word = *word_cur;
199 for (size_t i = 0; i < sizeof(uintptr_t); ++i) {
Mathieu Chartier4da7f2f2012-11-13 12:51:01 -0800200 if ((start_word & 0xFF) >= minimum_age) {
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800201 byte* card = reinterpret_cast<byte*>(word_cur) + i;
Mathieu Chartier4da7f2f2012-11-13 12:51:01 -0800202 const byte card_byte = *card;
203 DCHECK(card_byte == (start_word & 0xFF) || card_byte == kCardDirty)
204 << "card " << static_cast<size_t>(card_byte) << " word " << (start_word & 0xFF);
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800205 uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card));
206 uintptr_t end = start + kCardSize;
207 bitmap->VisitMarkedRange(start, end, visitor, finger_visitor);
208 }
209 start_word >>= 8;
Mathieu Chartiercc236d72012-07-20 10:29:05 -0700210 }
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800211 ++word_cur;
212 }
Mathieu Chartiercc236d72012-07-20 10:29:05 -0700213
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800214 // Handle any unaligned cards at the end.
215 card_cur = reinterpret_cast<byte*>(word_end);
216 while (card_cur < card_end) {
217 if (*card_cur >= minimum_age) {
218 uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card_cur));
219 uintptr_t end = start + kCardSize;
220 bitmap->VisitMarkedRange(start, end, visitor, finger_visitor);
221 }
222 ++card_cur;
Mathieu Chartiercc236d72012-07-20 10:29:05 -0700223 }
224 }
Ian Rogers30fab402012-01-23 15:43:46 -0800225
Ian Rogers30fab402012-01-23 15:43:46 -0800226 // Assertion used to check the given address is covered by the card table
227 void CheckAddrIsInCardTable(const byte* addr) const;
228
Mathieu Chartier262e5ff2012-06-01 17:35:38 -0700229 // Resets all of the bytes in the card table to clean.
230 void ClearCardTable();
231
Mathieu Chartierb43b7d42012-06-19 13:15:09 -0700232 // Resets all of the bytes in the card table which do not map to the image space.
Mathieu Chartier2fde5332012-09-14 14:51:54 -0700233 void ClearSpaceCards(ContinuousSpace* space);
Ian Rogers5d76c432011-10-31 21:42:49 -0700234
Mathieu Chartierb43b7d42012-06-19 13:15:09 -0700235 // Returns the first address in the heap which maps to this card.
236 void* AddrFromCard(const byte *card_addr) const {
237 DCHECK(IsValidCard(card_addr))
238 << " card_addr: " << reinterpret_cast<const void*>(card_addr)
239 << " begin: " << reinterpret_cast<void*>(mem_map_->Begin() + offset_)
240 << " end: " << reinterpret_cast<void*>(mem_map_->End());
241 uintptr_t offset = card_addr - biased_begin_;
Mathieu Chartier7469ebf2012-09-24 16:28:36 -0700242 return reinterpret_cast<void*>(offset << kCardShift);
Mathieu Chartierb43b7d42012-06-19 13:15:09 -0700243 }
Ian Rogers5d76c432011-10-31 21:42:49 -0700244
Ian Rogers30fab402012-01-23 15:43:46 -0800245 // Returns the address of the relevant byte in the card table, given an address on the heap.
Ian Rogers5d76c432011-10-31 21:42:49 -0700246 byte* CardFromAddr(const void *addr) const {
Mathieu Chartier7469ebf2012-09-24 16:28:36 -0700247 byte *card_addr = biased_begin_ + ((uintptr_t)addr >> kCardShift);
Ian Rogers30fab402012-01-23 15:43:46 -0800248 // Sanity check the caller was asking for address covered by the card table
Elliott Hughes24edeb52012-06-18 15:29:46 -0700249 DCHECK(IsValidCard(card_addr)) << "addr: " << addr
250 << " card_addr: " << reinterpret_cast<void*>(card_addr);
251 return card_addr;
Ian Rogers5d76c432011-10-31 21:42:49 -0700252 }
253
Mathieu Chartier7469ebf2012-09-24 16:28:36 -0700254 bool AddrIsInCardTable(const void* addr) const;
255
Mathieu Chartiercc236d72012-07-20 10:29:05 -0700256 private:
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800257 static int byte_cas(byte old_value, byte new_value, byte* address) {
258 // Little endian means most significant byte is on the left.
259 const size_t shift = reinterpret_cast<uintptr_t>(address) % sizeof(uintptr_t);
260 // Align the address down.
261 address -= shift;
262 int32_t* word_address = reinterpret_cast<int32_t*>(address);
263 // Word with the byte we are trying to cas cleared.
264 const int32_t cur_word = *word_address & ~(0xFF << shift);
265 const int32_t old_word = cur_word | (static_cast<int32_t>(old_value) << shift);
266 const int32_t new_word = cur_word | (static_cast<int32_t>(new_value) << shift);
267 return android_atomic_cas(old_word, new_word, word_address);
268 }
269
Mathieu Chartiercc236d72012-07-20 10:29:05 -0700270 CardTable(MemMap* begin, byte* biased_begin, size_t offset);
271
Ian Rogers30fab402012-01-23 15:43:46 -0800272 // Returns true iff the card table address is within the bounds of the card table.
Elliott Hughes24edeb52012-06-18 15:29:46 -0700273 bool IsValidCard(const byte* card_addr) const {
Ian Rogers30fab402012-01-23 15:43:46 -0800274 byte* begin = mem_map_->Begin() + offset_;
275 byte* end = mem_map_->End();
Elliott Hughes24edeb52012-06-18 15:29:46 -0700276 return card_addr >= begin && card_addr < end;
Ian Rogers5d76c432011-10-31 21:42:49 -0700277 }
278
Mathieu Chartierd22d5482012-11-06 17:14:12 -0800279 void CheckCardValid(byte* card) const {
280 DCHECK(IsValidCard(card))
281 << " card_addr: " << reinterpret_cast<const void*>(card)
282 << " begin: " << reinterpret_cast<void*>(mem_map_->Begin() + offset_)
283 << " end: " << reinterpret_cast<void*>(mem_map_->End());
284 }
285
Ian Rogers30fab402012-01-23 15:43:46 -0800286 // Verifies that all gray objects are on a dirty card.
Ian Rogers5d76c432011-10-31 21:42:49 -0700287 void VerifyCardTable();
288
Ian Rogers30fab402012-01-23 15:43:46 -0800289 // Mmapped pages for the card table
Ian Rogers5d76c432011-10-31 21:42:49 -0700290 UniquePtr<MemMap> mem_map_;
Ian Rogers30fab402012-01-23 15:43:46 -0800291 // Value used to compute card table addresses from object addresses, see GetBiasedBegin
292 byte* const biased_begin_;
293 // Card table doesn't begin at the beginning of the mem_map_, instead it is displaced by offset
294 // to allow the byte value of biased_begin_ to equal GC_CARD_DIRTY
295 const size_t offset_;
Ian Rogers5d76c432011-10-31 21:42:49 -0700296};
297
298} // namespace art
Mathieu Chartier858f1c52012-10-17 17:45:55 -0700299#endif // ART_SRC_GC_CARDTABLE_H_