Index: src/heap/slot-set.h |
diff --git a/src/heap/slot-set.h b/src/heap/slot-set.h |
index 6144706f71e3ed34d81693557b4fe87492499619..e55ffe98e60aa88f74c2e886f226f37eb21bab93 100644 |
--- a/src/heap/slot-set.h |
+++ b/src/heap/slot-set.h |
@@ -7,10 +7,13 @@ |
#include "src/allocation.h" |
#include "src/base/bits.h" |
+#include "src/utils.h" |
namespace v8 { |
namespace internal { |
+enum SlotCallbackResult { KEEP_SLOT, REMOVE_SLOT }; |
+ |
// Data structure for maintaining a set of slots in a standard (non-large) |
// page. The base address of the page must be set with SetPageStart before any |
// operation. |
@@ -19,8 +22,6 @@ namespace internal { |
// Each bucket is a bitmap with a bit corresponding to a single slot offset. |
class SlotSet : public Malloced { |
public: |
- enum CallbackResult { KEEP_SLOT, REMOVE_SLOT }; |
- |
SlotSet() { |
for (int i = 0; i < kBuckets; i++) { |
bucket[i] = nullptr; |
@@ -213,6 +214,124 @@ class SlotSet : public Malloced { |
Address page_start_; |
}; |
+enum SlotType { |
+ EMBEDDED_OBJECT_SLOT, |
+ OBJECT_SLOT, |
+ RELOCATED_CODE_OBJECT, |
+ CELL_TARGET_SLOT, |
+ CODE_TARGET_SLOT, |
+ CODE_ENTRY_SLOT, |
+ DEBUG_TARGET_SLOT, |
+ NUMBER_OF_SLOT_TYPES |
+}; |
+ |
+// Data structure for maintaining a multiset of typed slots in a page. |
+// Typed slots can only appear in Code and JSFunction objects, so |
+// the maximum possible offset is limited by the LargePage::kMaxCodePageSize. |
+// The implementation is a chain of chunks, where each chunks is an array of |
+// encoded (slot type, slot offset) pairs. |
+// There is no duplicate detection and we do not expect many duplicates because |
+// typed slots contain V8 internal pointers that are not directly exposed to JS. |
+class TypedSlotSet { |
+ public: |
+ typedef uint32_t TypedSlot; |
+ static const int kMaxOffset = 1 << 29; |
+ |
+ explicit TypedSlotSet(Address page_start) : page_start_(page_start) { |
+ chunk_ = new Chunk(nullptr, kInitialBufferSize); |
+ } |
+ |
+ ~TypedSlotSet() { |
+ Chunk* chunk = chunk_; |
+ while (chunk != nullptr) { |
+ Chunk* next = chunk->next; |
+ delete chunk; |
+ chunk = next; |
+ } |
+ } |
+ |
+ // The slot offset specifies a slot at address page_start_ + offset. |
+ void Insert(SlotType type, int offset) { |
+ TypedSlot slot = ToTypedSlot(type, offset); |
+ if (!chunk_->AddSlot(slot)) { |
+ chunk_ = new Chunk(chunk_, NextCapacity(chunk_->capacity)); |
+ bool added = chunk_->AddSlot(slot); |
+ DCHECK(added); |
+ USE(added); |
+ } |
+ } |
+ |
+ // Iterate over all slots in the set and for each slot invoke the callback. |
+ // If the callback returns REMOVE_SLOT then the slot is removed from the set. |
+ // Returns the new number of slots. |
+ // |
+ // Sample usage: |
+ // Iterate([](SlotType slot_type, Address slot_address) { |
+ // if (good(slot_type, slot_address)) return KEEP_SLOT; |
+ // else return REMOVE_SLOT; |
+ // }); |
+ template <typename Callback> |
+ int Iterate(Callback callback) { |
+ STATIC_ASSERT(NUMBER_OF_SLOT_TYPES < 8); |
+ const TypedSlot kRemovedSlot = TypeField::encode(NUMBER_OF_SLOT_TYPES); |
+ Chunk* chunk = chunk_; |
+ int new_count = 0; |
+ while (chunk != nullptr) { |
+ TypedSlot* buffer = chunk->buffer; |
+ int count = chunk->count; |
+ for (int i = 0; i < count; i++) { |
+ TypedSlot slot = buffer[i]; |
+ if (slot != kRemovedSlot) { |
+ SlotType type = TypeField::decode(slot); |
+ Address addr = page_start_ + OffsetField::decode(slot); |
+ if (callback(type, addr) == KEEP_SLOT) { |
+ new_count++; |
+ } else { |
+ buffer[i] = kRemovedSlot; |
+ } |
+ } |
+ } |
+ chunk = chunk->next; |
+ } |
+ return new_count; |
+ } |
+ |
+ private: |
+ static const int kInitialBufferSize = 100; |
+ static const int kMaxBufferSize = 16 * KB; |
+ |
+ static int NextCapacity(int capacity) { |
+ return Min(kMaxBufferSize, capacity * 2); |
+ } |
+ |
+ static TypedSlot ToTypedSlot(SlotType type, int offset) { |
+ return TypeField::encode(type) | OffsetField::encode(offset); |
+ } |
+ |
+ class OffsetField : public BitField<int, 0, 29> {}; |
+ class TypeField : public BitField<SlotType, 29, 3> {}; |
+ |
+ struct Chunk : Malloced { |
+ explicit Chunk(Chunk* next_chunk, int capacity) |
+ : next(next_chunk), count(0), capacity(capacity) { |
+ buffer = NewArray<TypedSlot>(capacity); |
+ } |
+ bool AddSlot(TypedSlot slot) { |
+ if (count == capacity) return false; |
+ buffer[count++] = slot; |
+ return true; |
+ } |
+ ~Chunk() { DeleteArray(buffer); } |
+ Chunk* next; |
+ int count; |
+ int capacity; |
+ TypedSlot* buffer; |
+ }; |
+ |
+ Address page_start_; |
+ Chunk* chunk_; |
+}; |
+ |
} // namespace internal |
} // namespace v8 |