Index: runtime/vm/store_buffer.h |
diff --git a/runtime/vm/store_buffer.h b/runtime/vm/store_buffer.h |
index cc92d72db3143fb878f285ba46552cd89ecc229f..b437f8532fba385e0193574b43129e3a0d5d98f6 100644 |
--- a/runtime/vm/store_buffer.h |
+++ b/runtime/vm/store_buffer.h |
@@ -12,20 +12,26 @@ namespace dart { |
// Forward declarations. |
class Isolate; |
+class Mutex; |
class RawObject; |
class StoreBufferBlock { |
public: |
- // Each block contains kSize pointers. |
+ // Each full block contains kSize pointers. |
static const int32_t kSize = 1024; |
- explicit StoreBufferBlock(StoreBufferBlock* next) : next_(next), top_(0) {} |
- |
void Reset() { top_ = 0; } |
+ // TODO(koda): Make private after adding visitor interface to StoreBuffer. |
StoreBufferBlock* next() const { return next_; } |
intptr_t Count() const { return top_; } |
+ bool IsFull() const { return Count() == kSize; } |
+ |
+ void Add(RawObject* obj) { |
+ ASSERT(!IsFull()); |
+ pointers_[top_++] = obj; |
+ } |
RawObject* At(intptr_t i) const { |
ASSERT(i >= 0); |
@@ -33,12 +39,25 @@ class StoreBufferBlock { |
return pointers_[i]; |
} |
+#if defined(TESTING) |
+ bool Contains(RawObject* obj) const { |
+ for (intptr_t i = 0; i < Count(); i++) { |
+ if (At(i) == obj) { |
+ return true; |
+ } |
+ } |
+ return false; |
+ } |
+#endif // TESTING |
+ |
static intptr_t top_offset() { return OFFSET_OF(StoreBufferBlock, top_); } |
static intptr_t pointers_offset() { |
return OFFSET_OF(StoreBufferBlock, pointers_); |
} |
private: |
+ StoreBufferBlock() : next_(NULL), top_(0) {} |
+ |
StoreBufferBlock* next_; |
int32_t top_; |
RawObject* pointers_[kSize]; |
@@ -51,59 +70,48 @@ class StoreBufferBlock { |
class StoreBuffer { |
public: |
- StoreBuffer() : blocks_(new StoreBufferBlock(NULL)), full_count_(0) {} |
- explicit StoreBuffer(bool shallow_copy) : blocks_(NULL), full_count_(0) { |
- // The value shallow_copy is only used to select this non-allocating |
- // constructor. It is always expected to be true. |
- ASSERT(shallow_copy); |
- } |
+ StoreBuffer(); |
~StoreBuffer(); |
- intptr_t Count() const { |
- return blocks_->Count() + (full_count_ * StoreBufferBlock::kSize); |
- } |
- |
- void Reset(); |
- |
- void AddObject(RawObject* obj) { |
- StoreBufferBlock* block = blocks_; |
- ASSERT(block->top_ < StoreBufferBlock::kSize); |
- block->pointers_[block->top_++] = obj; |
- if (block->top_ == StoreBufferBlock::kSize) { |
- Expand(true); |
- } |
- } |
+ // Adds and transfers ownership of the block to the buffer. |
+ void PushBlock(StoreBufferBlock* block, bool check_threshold = true); |
+ // Partially filled blocks can be reused, and there is an "inifite" supply |
+ // of empty blocks (reused or newly allocated). In any case, the caller |
+ // takes ownership of the returned block. |
+ StoreBufferBlock* PopBlock(); |
+ StoreBufferBlock* PopEmptyBlock(); |
- void AddObjectGC(RawObject* obj) { |
- StoreBufferBlock* block = blocks_; |
- ASSERT(block->top_ < StoreBufferBlock::kSize); |
- block->pointers_[block->top_++] = obj; |
- if (block->top_ == StoreBufferBlock::kSize) { |
- Expand(false); |
- } |
- } |
+ // Pops and returns all non-empty blocks as a linked list (owned by caller). |
+ // TODO(koda): Replace with VisitObjectPointers. |
+ StoreBufferBlock* Blocks(); |
- StoreBufferBlock* Blocks() { |
- StoreBufferBlock* result = blocks_; |
- blocks_ = new StoreBufferBlock(NULL); |
- full_count_ = 0; |
- return result; |
- } |
- |
- // Expand the storage and optionally check whethe to schedule an interrupt. |
- void Expand(bool check); |
- |
- bool Contains(RawObject* raw); |
- |
- static int blocks_offset() { return OFFSET_OF(StoreBuffer, blocks_); } |
+ // Discards the contents of this store buffer. |
+ void Reset(); |
private: |
+ class List { |
+ public: |
+ List() : head_(NULL), length_(0) {} |
+ ~List(); |
+ void Push(StoreBufferBlock* block); |
+ StoreBufferBlock* Pop(); |
+ intptr_t length() const { return length_; } |
+ bool IsEmpty() const { return head_ == NULL; } |
+ StoreBufferBlock* PopAll(); |
+ private: |
+ StoreBufferBlock* head_; |
+ intptr_t length_; |
+ DISALLOW_COPY_AND_ASSIGN(List); |
+ }; |
+ |
// Check if we run over the max number of deduplication sets. |
// If we did schedule an interrupt. |
void CheckThreshold(); |
- StoreBufferBlock* blocks_; |
- intptr_t full_count_; |
+ List full_; |
+ List partial_; |
+ // TODO(koda): static List empty_ |
+ Mutex* mutex_; |
DISALLOW_COPY_AND_ASSIGN(StoreBuffer); |
}; |