OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_SLOT_SET_H | 5 #ifndef V8_SLOT_SET_H |
6 #define V8_SLOT_SET_H | 6 #define V8_SLOT_SET_H |
7 | 7 |
8 #include "src/allocation.h" | 8 #include "src/allocation.h" |
9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
10 #include "src/utils.h" | 10 #include "src/utils.h" |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 | 226 |
227 // Data structure for maintaining a multiset of typed slots in a page. | 227 // Data structure for maintaining a multiset of typed slots in a page. |
228 // Typed slots can only appear in Code and JSFunction objects, so | 228 // Typed slots can only appear in Code and JSFunction objects, so |
229 // the maximum possible offset is limited by the LargePage::kMaxCodePageSize. | 229 // the maximum possible offset is limited by the LargePage::kMaxCodePageSize. |
230 // The implementation is a chain of chunks, where each chunks is an array of | 230 // The implementation is a chain of chunks, where each chunks is an array of |
231 // encoded (slot type, slot offset) pairs. | 231 // encoded (slot type, slot offset) pairs. |
232 // There is no duplicate detection and we do not expect many duplicates because | 232 // There is no duplicate detection and we do not expect many duplicates because |
233 // typed slots contain V8 internal pointers that are not directly exposed to JS. | 233 // typed slots contain V8 internal pointers that are not directly exposed to JS. |
234 class TypedSlotSet { | 234 class TypedSlotSet { |
235 public: | 235 public: |
236 typedef uint32_t TypedSlot; | 236 struct TypedSlot { |
| 237 TypedSlot() : type_and_offset_(0), host_offset_(0) {} |
| 238 |
| 239 TypedSlot(SlotType type, uint32_t host_offset, uint32_t offset) |
| 240 : type_and_offset_(TypeField::encode(type) | |
| 241 OffsetField::encode(offset)), |
| 242 host_offset_(host_offset) {} |
| 243 |
| 244 bool operator==(const TypedSlot other) { |
| 245 return type_and_offset_ == other.type_and_offset_ && |
| 246 host_offset_ == other.host_offset_; |
| 247 } |
| 248 |
| 249 bool operator!=(const TypedSlot other) { return !(*this == other); } |
| 250 |
| 251 SlotType type() { return TypeField::decode(type_and_offset_); } |
| 252 |
| 253 uint32_t offset() { return OffsetField::decode(type_and_offset_); } |
| 254 |
| 255 uint32_t host_offset() { return host_offset_; } |
| 256 |
| 257 uint32_t type_and_offset_; |
| 258 uint32_t host_offset_; |
| 259 }; |
237 static const int kMaxOffset = 1 << 29; | 260 static const int kMaxOffset = 1 << 29; |
238 | 261 |
239 explicit TypedSlotSet(Address page_start) : page_start_(page_start) { | 262 explicit TypedSlotSet(Address page_start) : page_start_(page_start) { |
240 chunk_ = new Chunk(nullptr, kInitialBufferSize); | 263 chunk_ = new Chunk(nullptr, kInitialBufferSize); |
241 } | 264 } |
242 | 265 |
243 ~TypedSlotSet() { | 266 ~TypedSlotSet() { |
244 Chunk* chunk = chunk_; | 267 Chunk* chunk = chunk_; |
245 while (chunk != nullptr) { | 268 while (chunk != nullptr) { |
246 Chunk* next = chunk->next; | 269 Chunk* next = chunk->next; |
247 delete chunk; | 270 delete chunk; |
248 chunk = next; | 271 chunk = next; |
249 } | 272 } |
250 } | 273 } |
251 | 274 |
252 // The slot offset specifies a slot at address page_start_ + offset. | 275 // The slot offset specifies a slot at address page_start_ + offset. |
253 void Insert(SlotType type, int offset) { | 276 void Insert(SlotType type, uint32_t host_offset, uint32_t offset) { |
254 TypedSlot slot = ToTypedSlot(type, offset); | 277 TypedSlot slot(type, host_offset, offset); |
255 if (!chunk_->AddSlot(slot)) { | 278 if (!chunk_->AddSlot(slot)) { |
256 chunk_ = new Chunk(chunk_, NextCapacity(chunk_->capacity)); | 279 chunk_ = new Chunk(chunk_, NextCapacity(chunk_->capacity)); |
257 bool added = chunk_->AddSlot(slot); | 280 bool added = chunk_->AddSlot(slot); |
258 DCHECK(added); | 281 DCHECK(added); |
259 USE(added); | 282 USE(added); |
260 } | 283 } |
261 } | 284 } |
262 | 285 |
263 // Iterate over all slots in the set and for each slot invoke the callback. | 286 // Iterate over all slots in the set and for each slot invoke the callback. |
264 // If the callback returns REMOVE_SLOT then the slot is removed from the set. | 287 // If the callback returns REMOVE_SLOT then the slot is removed from the set. |
265 // Returns the new number of slots. | 288 // Returns the new number of slots. |
266 // | 289 // |
267 // Sample usage: | 290 // Sample usage: |
268 // Iterate([](SlotType slot_type, Address slot_address) { | 291 // Iterate([](SlotType slot_type, Address slot_address) { |
269 // if (good(slot_type, slot_address)) return KEEP_SLOT; | 292 // if (good(slot_type, slot_address)) return KEEP_SLOT; |
270 // else return REMOVE_SLOT; | 293 // else return REMOVE_SLOT; |
271 // }); | 294 // }); |
272 template <typename Callback> | 295 template <typename Callback> |
273 int Iterate(Callback callback) { | 296 int Iterate(Callback callback) { |
274 STATIC_ASSERT(NUMBER_OF_SLOT_TYPES < 8); | 297 STATIC_ASSERT(NUMBER_OF_SLOT_TYPES < 8); |
275 const TypedSlot kRemovedSlot = TypeField::encode(NUMBER_OF_SLOT_TYPES); | 298 const TypedSlot kRemovedSlot(NUMBER_OF_SLOT_TYPES, 0, 0); |
276 Chunk* chunk = chunk_; | 299 Chunk* chunk = chunk_; |
277 int new_count = 0; | 300 int new_count = 0; |
278 while (chunk != nullptr) { | 301 while (chunk != nullptr) { |
279 TypedSlot* buffer = chunk->buffer; | 302 TypedSlot* buffer = chunk->buffer; |
280 int count = chunk->count; | 303 int count = chunk->count; |
281 for (int i = 0; i < count; i++) { | 304 for (int i = 0; i < count; i++) { |
282 TypedSlot slot = buffer[i]; | 305 TypedSlot slot = buffer[i]; |
283 if (slot != kRemovedSlot) { | 306 if (slot != kRemovedSlot) { |
284 SlotType type = TypeField::decode(slot); | 307 SlotType type = slot.type(); |
285 Address addr = page_start_ + OffsetField::decode(slot); | 308 Address addr = page_start_ + slot.offset(); |
286 if (callback(type, addr) == KEEP_SLOT) { | 309 Address host_addr = page_start_ + slot.host_offset(); |
| 310 if (callback(type, host_addr, addr) == KEEP_SLOT) { |
287 new_count++; | 311 new_count++; |
288 } else { | 312 } else { |
289 buffer[i] = kRemovedSlot; | 313 buffer[i] = kRemovedSlot; |
290 } | 314 } |
291 } | 315 } |
292 } | 316 } |
293 chunk = chunk->next; | 317 chunk = chunk->next; |
294 } | 318 } |
295 return new_count; | 319 return new_count; |
296 } | 320 } |
297 | 321 |
298 private: | 322 private: |
299 static const int kInitialBufferSize = 100; | 323 static const int kInitialBufferSize = 100; |
300 static const int kMaxBufferSize = 16 * KB; | 324 static const int kMaxBufferSize = 16 * KB; |
301 | 325 |
302 static int NextCapacity(int capacity) { | 326 static int NextCapacity(int capacity) { |
303 return Min(kMaxBufferSize, capacity * 2); | 327 return Min(kMaxBufferSize, capacity * 2); |
304 } | 328 } |
305 | 329 |
306 static TypedSlot ToTypedSlot(SlotType type, int offset) { | |
307 return TypeField::encode(type) | OffsetField::encode(offset); | |
308 } | |
309 | |
310 class OffsetField : public BitField<int, 0, 29> {}; | 330 class OffsetField : public BitField<int, 0, 29> {}; |
311 class TypeField : public BitField<SlotType, 29, 3> {}; | 331 class TypeField : public BitField<SlotType, 29, 3> {}; |
312 | 332 |
313 struct Chunk : Malloced { | 333 struct Chunk : Malloced { |
314 explicit Chunk(Chunk* next_chunk, int capacity) | 334 explicit Chunk(Chunk* next_chunk, int capacity) |
315 : next(next_chunk), count(0), capacity(capacity) { | 335 : next(next_chunk), count(0), capacity(capacity) { |
316 buffer = NewArray<TypedSlot>(capacity); | 336 buffer = NewArray<TypedSlot>(capacity); |
317 } | 337 } |
318 bool AddSlot(TypedSlot slot) { | 338 bool AddSlot(TypedSlot slot) { |
319 if (count == capacity) return false; | 339 if (count == capacity) return false; |
320 buffer[count++] = slot; | 340 buffer[count++] = slot; |
321 return true; | 341 return true; |
322 } | 342 } |
323 ~Chunk() { DeleteArray(buffer); } | 343 ~Chunk() { DeleteArray(buffer); } |
324 Chunk* next; | 344 Chunk* next; |
325 int count; | 345 int count; |
326 int capacity; | 346 int capacity; |
327 TypedSlot* buffer; | 347 TypedSlot* buffer; |
328 }; | 348 }; |
329 | 349 |
330 Address page_start_; | 350 Address page_start_; |
331 Chunk* chunk_; | 351 Chunk* chunk_; |
332 }; | 352 }; |
333 | 353 |
334 } // namespace internal | 354 } // namespace internal |
335 } // namespace v8 | 355 } // namespace v8 |
336 | 356 |
337 #endif // V8_SLOT_SET_H | 357 #endif // V8_SLOT_SET_H |
OLD | NEW |