Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef VM_STORE_BUFFER_H_ | 5 #ifndef VM_STORE_BUFFER_H_ |
| 6 #define VM_STORE_BUFFER_H_ | 6 #define VM_STORE_BUFFER_H_ |
| 7 | 7 |
| 8 #include "platform/assert.h" | 8 #include "platform/assert.h" |
| 9 #include "vm/globals.h" | 9 #include "vm/globals.h" |
| 10 | 10 |
| 11 namespace dart { | 11 namespace dart { |
| 12 | 12 |
| 13 // Forward declarations. | 13 // Forward declarations. |
| 14 class Isolate; | 14 class Isolate; |
| 15 class Mutex; | 15 class Mutex; |
| 16 class RawObject; | 16 class RawObject; |
| 17 | 17 |
| 18 // A set of RawObject*. Must be emptied before destruction (using Pop/Reset). | 18 // A set of RawObject*. Must be emptied before destruction (using Pop/Reset). |
| 19 class StoreBufferBlock { | 19 template<int Size> |
| 20 class PointerBlock { | |
| 20 public: | 21 public: |
| 21 // Each full block contains kSize pointers. | 22 enum { kSize = Size }; |
| 22 static const int32_t kSize = 1024; | |
| 23 | 23 |
| 24 void Reset() { | 24 void Reset() { |
| 25 top_ = 0; | 25 top_ = 0; |
| 26 next_ = NULL; | 26 next_ = NULL; |
| 27 } | 27 } |
| 28 | 28 |
| 29 StoreBufferBlock* next() const { return next_; } | 29 PointerBlock<Size>* next() const { return next_; } |
| 30 | 30 |
| 31 intptr_t Count() const { return top_; } | 31 intptr_t Count() const { return top_; } |
| 32 bool IsFull() const { return Count() == kSize; } | 32 bool IsFull() const { return Count() == kSize; } |
| 33 bool IsEmpty() const { return Count() == 0; } | 33 bool IsEmpty() const { return Count() == 0; } |
| 34 | 34 |
| 35 void Push(RawObject* obj) { | 35 void Push(RawObject* obj) { |
| 36 ASSERT(!IsFull()); | 36 ASSERT(!IsFull()); |
| 37 pointers_[top_++] = obj; | 37 pointers_[top_++] = obj; |
| 38 } | 38 } |
| 39 | 39 |
| 40 RawObject* Pop() { | 40 RawObject* Pop() { |
| 41 ASSERT(!IsEmpty()); | 41 ASSERT(!IsEmpty()); |
| 42 return pointers_[--top_]; | 42 return pointers_[--top_]; |
| 43 } | 43 } |
| 44 | 44 |
| 45 #if defined(TESTING) | 45 #if defined(TESTING) |
| 46 bool Contains(RawObject* obj) const { | 46 bool Contains(RawObject* obj) const { |
| 47 for (intptr_t i = 0; i < Count(); i++) { | 47 for (intptr_t i = 0; i < Count(); i++) { |
| 48 if (pointers_[i] == obj) { | 48 if (pointers_[i] == obj) { |
| 49 return true; | 49 return true; |
| 50 } | 50 } |
| 51 } | 51 } |
| 52 return false; | 52 return false; |
| 53 } | 53 } |
| 54 #endif // TESTING | 54 #endif // TESTING |
| 55 | 55 |
| 56 static intptr_t top_offset() { return OFFSET_OF(StoreBufferBlock, top_); } | 56 static intptr_t top_offset() { return OFFSET_OF(PointerBlock<Size>, top_); } |
| 57 static intptr_t pointers_offset() { | 57 static intptr_t pointers_offset() { |
| 58 return OFFSET_OF(StoreBufferBlock, pointers_); | 58 return OFFSET_OF(PointerBlock<Size>, pointers_); |
| 59 } | 59 } |
| 60 | 60 |
| 61 private: | 61 private: |
| 62 StoreBufferBlock() : next_(NULL), top_(0) {} | 62 PointerBlock() : next_(NULL), top_(0) {} |
| 63 ~StoreBufferBlock() { | 63 ~PointerBlock() { |
| 64 ASSERT(IsEmpty()); // Guard against unintentionally discarding pointers. | 64 ASSERT(IsEmpty()); // Guard against unintentionally discarding pointers. |
| 65 } | 65 } |
| 66 | 66 |
| 67 StoreBufferBlock* next_; | 67 PointerBlock<Size>* next_; |
| 68 int32_t top_; | 68 int32_t top_; |
| 69 RawObject* pointers_[kSize]; | 69 RawObject* pointers_[kSize]; |
| 70 | 70 |
| 71 friend class StoreBuffer; | 71 template<int> friend class BlockStack; |
| 72 | 72 |
| 73 DISALLOW_COPY_AND_ASSIGN(StoreBufferBlock); | 73 DISALLOW_COPY_AND_ASSIGN(PointerBlock); |
| 74 }; | 74 }; |
| 75 | 75 |
| 76 | 76 |
| 77 class StoreBuffer { | 77 template<int BlockSize> |
| 78 class BlockStack { | |
| 78 public: | 79 public: |
| 79 StoreBuffer(); | 80 typedef PointerBlock<BlockSize> Block; |
| 80 ~StoreBuffer(); | 81 |
| 82 BlockStack(); | |
| 83 ~BlockStack(); | |
| 81 static void InitOnce(); | 84 static void InitOnce(); |
| 82 static void ShutDown(); | 85 static void ShutDown(); |
| 83 | 86 |
| 84 // Interrupt when crossing this threshold of non-empty blocks in the buffer. | |
| 85 static const intptr_t kMaxNonEmpty = 100; | |
| 86 | |
| 87 // Adds and transfers ownership of the block to the buffer. | |
| 88 void PushBlock(StoreBufferBlock* block, bool check_threshold = true); | |
| 89 // Partially filled blocks can be reused, and there is an "inifite" supply | 87 // Partially filled blocks can be reused, and there is an "inifite" supply |
| 90 // of empty blocks (reused or newly allocated). In any case, the caller | 88 // of empty blocks (reused or newly allocated). In any case, the caller |
| 91 // takes ownership of the returned block. | 89 // takes ownership of the returned block. |
| 92 StoreBufferBlock* PopNonFullBlock(); | 90 Block* PopNonFullBlock(); |
| 93 StoreBufferBlock* PopEmptyBlock(); | 91 Block* PopEmptyBlock(); |
| 94 StoreBufferBlock* PopNonEmptyBlock(); | 92 Block* PopNonEmptyBlock(); |
| 95 | 93 |
| 96 // Pops and returns all non-empty blocks as a linked list (owned by caller). | 94 // Pops and returns all non-empty blocks as a linked list (owned by caller). |
| 97 StoreBufferBlock* Blocks(); | 95 Block* Blocks(); |
| 98 | 96 |
| 99 // Discards the contents of this store buffer. | 97 // Discards the contents of all non-empty blocks. |
| 100 void Reset(); | 98 void Reset(); |
| 101 | 99 |
| 102 // Check whether non-empty blocks have exceeded kMaxNonEmpty. | |
| 103 bool Overflowed(); | |
| 104 | |
| 105 bool IsEmpty(); | 100 bool IsEmpty(); |
| 106 | 101 |
| 107 private: | 102 protected: |
| 108 class List { | 103 class List { |
| 109 public: | 104 public: |
| 110 List() : head_(NULL), length_(0) {} | 105 List() : head_(NULL), length_(0) {} |
| 111 ~List(); | 106 ~List(); |
| 112 void Push(StoreBufferBlock* block); | 107 void Push(Block* block); |
| 113 StoreBufferBlock* Pop(); | 108 Block* Pop(); |
| 114 intptr_t length() const { return length_; } | 109 intptr_t length() const { return length_; } |
| 115 bool IsEmpty() const { return head_ == NULL; } | 110 bool IsEmpty() const { return head_ == NULL; } |
| 116 StoreBufferBlock* PopAll(); | 111 Block* PopAll(); |
| 117 private: | 112 private: |
| 118 StoreBufferBlock* head_; | 113 Block* head_; |
| 119 intptr_t length_; | 114 intptr_t length_; |
| 120 DISALLOW_COPY_AND_ASSIGN(List); | 115 DISALLOW_COPY_AND_ASSIGN(List); |
| 121 }; | 116 }; |
| 122 | 117 |
| 118 // Adds and transfers ownership of the block to the buffer. | |
| 119 void PushBlockImpl(Block* block); | |
| 120 | |
| 123 // If needed, trims the the global cache of empty blocks. | 121 // If needed, trims the the global cache of empty blocks. |
| 124 static void TrimGlobalEmpty(); | 122 static void TrimGlobalEmpty(); |
| 125 | 123 |
| 126 List full_; | 124 List full_; |
| 127 List partial_; | 125 List partial_; |
| 128 Mutex* mutex_; | 126 Mutex* mutex_; |
| 129 | 127 |
| 130 static const intptr_t kMaxGlobalEmpty = 100; | 128 static const intptr_t kMaxGlobalEmpty = 100; |
| 131 static List* global_empty_; | 129 static List* global_empty_; |
| 132 static Mutex* global_mutex_; | 130 static Mutex* global_mutex_; |
|
Cutch
2015/09/17 18:04:06
Will it always be true that blocks of the same siz
koda
2015/09/17 19:13:18
Yes, the cache of empty blocks will be shared if w
| |
| 133 | 131 |
| 134 DISALLOW_COPY_AND_ASSIGN(StoreBuffer); | 132 private: |
| 133 DISALLOW_COPY_AND_ASSIGN(BlockStack); | |
| 135 }; | 134 }; |
| 136 | 135 |
| 136 | |
| 137 static const int kStoreBufferBlockSize = 1024; | |
| 138 class StoreBuffer : public BlockStack<kStoreBufferBlockSize> { | |
| 139 public: | |
| 140 // Interrupt when crossing this threshold of non-empty blocks in the buffer. | |
| 141 static const intptr_t kMaxNonEmpty = 100; | |
| 142 | |
| 143 // Adds and transfers ownership of the block to the buffer. Optionally | |
| 144 // checks the number of non-empty blocks for overflow, and schedules an | |
| 145 // interrupt on the current isolate if so. | |
| 146 void PushBlock(Block* block, bool check_threshold); | |
|
Cutch
2015/09/17 18:04:05
Instead of bool check_threshold could we have some
koda
2015/09/17 19:13:18
Done.
| |
| 147 | |
| 148 // Check whether non-empty blocks have exceeded kMaxNonEmpty (but takes no | |
| 149 // action). | |
| 150 bool Overflowed(); | |
| 151 }; | |
| 152 | |
| 153 | |
| 154 typedef StoreBuffer::Block StoreBufferBlock; | |
| 155 | |
| 156 | |
| 157 static const int kMarkingStackBlockSize = 64; | |
| 158 class MarkingStack : public BlockStack<kMarkingStackBlockSize> { | |
| 159 public: | |
| 160 // Adds and transfers ownership of the block to the buffer. | |
| 161 void PushBlock(Block* block) { | |
| 162 BlockStack<Block::kSize>::PushBlockImpl(block); | |
| 163 } | |
| 164 }; | |
| 165 | |
| 166 | |
| 137 } // namespace dart | 167 } // namespace dart |
| 138 | 168 |
| 139 #endif // VM_STORE_BUFFER_H_ | 169 #endif // VM_STORE_BUFFER_H_ |
| OLD | NEW |