| 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);
|
| };
|
|
|