| 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 |