Index: runtime/vm/store_buffer.cc |
diff --git a/runtime/vm/store_buffer.cc b/runtime/vm/store_buffer.cc |
index acf7ca6eac6cfbbdb144facf752c0bf0ffc32c88..99a1371a909c10a51ca220d247d10e178617b70e 100644 |
--- a/runtime/vm/store_buffer.cc |
+++ b/runtime/vm/store_buffer.cc |
@@ -5,71 +5,106 @@ |
#include "vm/store_buffer.h" |
#include "platform/assert.h" |
+#include "vm/lockers.h" |
#include "vm/runtime_entry.h" |
namespace dart { |
-DEFINE_LEAF_RUNTIME_ENTRY(void, StoreBufferBlockProcess, 1, Isolate* isolate) { |
- StoreBuffer* buffer = isolate->store_buffer(); |
- buffer->Expand(true); |
+DEFINE_LEAF_RUNTIME_ENTRY(void, StoreBufferBlockProcess, 1, Thread* thread) { |
+ thread->StoreBufferBlockProcess(true); |
} |
END_LEAF_RUNTIME_ENTRY |
+StoreBuffer::StoreBuffer() : mutex_(new Mutex()) { |
+} |
+ |
+ |
StoreBuffer::~StoreBuffer() { |
- StoreBufferBlock* block = blocks_; |
- blocks_ = NULL; |
- while (block != NULL) { |
- StoreBufferBlock* next = block->next(); |
- delete block; |
- block = next; |
- } |
+ Reset(); |
+ delete mutex_; |
} |
void StoreBuffer::Reset() { |
- StoreBufferBlock* block = blocks_->next_; |
- while (block != NULL) { |
- StoreBufferBlock* next = block->next_; |
- delete block; |
- block = next; |
+ MutexLocker ml(mutex_); |
+ // TODO(koda): Reuse and share empty blocks between isolates. |
+ while (!full_.IsEmpty()) { |
+ delete full_.Pop(); |
+ } |
+ while (!partial_.IsEmpty()) { |
+ delete partial_.Pop(); |
} |
- blocks_->next_ = NULL; |
- blocks_->top_ = 0; |
- full_count_ = 0; |
} |
-bool StoreBuffer::Contains(RawObject* raw) { |
- StoreBufferBlock* block = blocks_; |
- while (block != NULL) { |
- intptr_t count = block->Count(); |
- for (intptr_t i = 0; i < count; i++) { |
- if (block->At(i) == raw) { |
- return true; |
- } |
- } |
- block = block->next_; |
+StoreBufferBlock* StoreBuffer::Blocks() { |
+ MutexLocker ml(mutex_); |
+ while (!partial_.IsEmpty()) { |
+ full_.Push(partial_.Pop()); |
} |
- return false; |
+ return full_.PopAll(); |
} |
-void StoreBuffer::Expand(bool check) { |
- ASSERT(blocks_->Count() == StoreBufferBlock::kSize); |
- blocks_ = new StoreBufferBlock(blocks_); |
- full_count_++; |
- if (check) { |
+void StoreBuffer::PushBlock(StoreBufferBlock* block, bool check_threshold) { |
+ MutexLocker ml(mutex_); |
+ List* list = block->IsFull() ? &full_ : &partial_; |
+ list->Push(block); |
+ if (check_threshold) { |
CheckThreshold(); |
} |
} |
+StoreBufferBlock* StoreBuffer::PopBlock() { |
+ MutexLocker ml(mutex_); |
+ return (!partial_.IsEmpty()) ? partial_.Pop() : PopEmptyBlock(); |
+} |
+ |
+ |
+StoreBufferBlock* StoreBuffer::PopEmptyBlock() { |
+ // TODO(koda): Reuse and share empty blocks between isolates. |
+ return new StoreBufferBlock(); |
+} |
+ |
+ |
+StoreBuffer::List::~List() { |
+ while (!IsEmpty()) { |
+ delete Pop(); |
+ } |
+} |
+ |
+ |
+StoreBufferBlock* StoreBuffer::List::Pop() { |
+ StoreBufferBlock* result = head_; |
+ head_ = head_->next_; |
+ --length_; |
+ result->next_ = NULL; |
+ return result; |
+} |
+ |
+ |
+StoreBufferBlock* StoreBuffer::List::PopAll() { |
+ StoreBufferBlock* result = head_; |
+ head_ = NULL; |
+ length_ = 0; |
+ return result; |
+} |
+ |
+ |
+void StoreBuffer::List::Push(StoreBufferBlock* block) { |
+ block->next_ = head_; |
+ head_ = block; |
+ ++length_; |
+} |
+ |
+ |
void StoreBuffer::CheckThreshold() { |
// Schedule an interrupt if we have run over the max number of |
// StoreBufferBlocks. |
- // TODO(iposva): Fix magic number. |
- if (full_count_ > 100) { |
+ // TODO(koda): Pass threshold and callback in constructor. Cap total? |
+ if (full_.length() > 100) { |
Isolate::Current()->ScheduleInterrupts(Isolate::kStoreBufferInterrupt); |
} |
} |