| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef CallbackStack_h | 5 #ifndef CallbackStack_h |
| 6 #define CallbackStack_h | 6 #define CallbackStack_h |
| 7 | 7 |
| 8 #include "platform/heap/BlinkGC.h" | 8 #include "platform/heap/BlinkGC.h" |
| 9 #include "wtf/Allocator.h" | 9 #include "wtf/Allocator.h" |
| 10 #include "wtf/Assertions.h" | 10 #include "wtf/Assertions.h" |
| 11 #include "wtf/Threading.h" |
| 12 #include "wtf/ThreadingPrimitives.h" |
| 11 | 13 |
| 12 namespace blink { | 14 namespace blink { |
| 13 | 15 |
| 14 // The CallbackStack contains all the visitor callbacks used to trace and mark | 16 // The CallbackStack contains all the visitor callbacks used to trace and mark |
| 15 // objects. A specific CallbackStack instance contains at most bufferSize elemen
ts. | 17 // objects. A specific CallbackStack instance contains at most bufferSize elemen
ts. |
| 16 // If more space is needed a new CallbackStack instance is created and chained | 18 // If more space is needed a new CallbackStack instance is created and chained |
| 17 // together with the former instance. I.e. a logical CallbackStack can be made o
f | 19 // together with the former instance. I.e. a logical CallbackStack can be made o
f |
| 18 // multiple chained CallbackStack object instances. | 20 // multiple chained CallbackStack object instances. |
| 19 class CallbackStack final { | 21 class CallbackStack final { |
| 20 USING_FAST_MALLOC(CallbackStack); | 22 USING_FAST_MALLOC(CallbackStack); |
| 21 public: | 23 public: |
| 22 class Item { | 24 class Item { |
| 23 DISALLOW_NEW(); | 25 DISALLOW_NEW(); |
| 24 public: | 26 public: |
| 25 Item() { } | 27 Item() { } |
| 26 Item(void* object, VisitorCallback callback) | 28 Item(void* object, VisitorCallback callback) |
| 27 : m_object(object) | 29 : m_object(object) |
| 28 , m_callback(callback) | 30 , m_callback(callback) |
| 29 { | 31 { |
| 30 } | 32 } |
| 31 void* object() { return m_object; } | 33 void* object() { return m_object; } |
| 32 VisitorCallback callback() { return m_callback; } | 34 VisitorCallback callback() { return m_callback; } |
| 33 void call(Visitor* visitor) { m_callback(visitor, m_object); } | 35 void call(Visitor* visitor) { m_callback(visitor, m_object); } |
| 34 | 36 |
| 35 private: | 37 private: |
| 36 void* m_object; | 38 void* m_object; |
| 37 VisitorCallback m_callback; | 39 VisitorCallback m_callback; |
| 38 }; | 40 }; |
| 39 | 41 |
| 40 explicit CallbackStack(size_t blockSize = kDefaultBlockSize); | 42 static std::unique_ptr<CallbackStack> create(); |
| 41 ~CallbackStack(); | 43 ~CallbackStack(); |
| 42 | 44 |
| 43 void clear(); | 45 void commit(); |
| 44 void decommit(); | 46 void decommit(); |
| 45 | 47 |
| 46 Item* allocateEntry(); | 48 Item* allocateEntry(); |
| 47 Item* pop(); | 49 Item* pop(); |
| 48 | 50 |
| 49 bool isEmpty() const; | 51 bool isEmpty() const; |
| 50 | 52 |
| 51 void invokeEphemeronCallbacks(Visitor*); | 53 void invokeEphemeronCallbacks(Visitor*); |
| 52 | 54 |
| 53 #if ENABLE(ASSERT) | 55 #if ENABLE(ASSERT) |
| 54 bool hasCallbackForObject(const void*); | 56 bool hasCallbackForObject(const void*); |
| 55 #endif | 57 #endif |
| 58 bool hasJustOneBlock() const; |
| 56 | 59 |
| 57 static const size_t kMinimalBlockSize; | 60 static const size_t kMinimalBlockSize; |
| 58 static const size_t kDefaultBlockSize = (1 << 13); | 61 static const size_t kDefaultBlockSize = (1 << 13); |
| 59 | 62 |
| 60 private: | 63 private: |
| 61 class Block { | 64 class Block { |
| 62 USING_FAST_MALLOC(Block); | 65 USING_FAST_MALLOC(Block); |
| 63 public: | 66 public: |
| 64 Block(Block* next, size_t blockSize); | 67 explicit Block(Block* next); |
| 65 ~Block(); | 68 ~Block(); |
| 66 | 69 |
| 67 #if ENABLE(ASSERT) | 70 #if ENABLE(ASSERT) |
| 68 void clear(); | 71 void clear(); |
| 69 #endif | 72 #endif |
| 70 void reset(); | |
| 71 void decommit(); | |
| 72 | |
| 73 Block* next() const { return m_next; } | 73 Block* next() const { return m_next; } |
| 74 void setNext(Block* next) { m_next = next; } | 74 void setNext(Block* next) { m_next = next; } |
| 75 | 75 |
| 76 bool isEmptyBlock() const | 76 bool isEmptyBlock() const |
| 77 { | 77 { |
| 78 return m_current == &(m_buffer[0]); | 78 return m_current == &(m_buffer[0]); |
| 79 } | 79 } |
| 80 | 80 |
| 81 size_t blockSize() const { return m_blockSize; } | 81 size_t blockSize() const { return m_blockSize; } |
| 82 | 82 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 102 | 102 |
| 103 private: | 103 private: |
| 104 size_t m_blockSize; | 104 size_t m_blockSize; |
| 105 | 105 |
| 106 Item* m_buffer; | 106 Item* m_buffer; |
| 107 Item* m_limit; | 107 Item* m_limit; |
| 108 Item* m_current; | 108 Item* m_current; |
| 109 Block* m_next; | 109 Block* m_next; |
| 110 }; | 110 }; |
| 111 | 111 |
| 112 CallbackStack(); |
| 112 Item* popSlow(); | 113 Item* popSlow(); |
| 113 Item* allocateEntrySlow(); | 114 Item* allocateEntrySlow(); |
| 114 void invokeOldestCallbacks(Block*, Block*, Visitor*); | 115 void invokeOldestCallbacks(Block*, Block*, Visitor*); |
| 115 bool hasJustOneBlock() const; | |
| 116 | 116 |
| 117 Block* m_first; | 117 Block* m_first; |
| 118 Block* m_last; | 118 Block* m_last; |
| 119 }; | 119 }; |
| 120 | 120 |
| 121 class CallbackStackMemoryPool final { |
| 122 USING_FAST_MALLOC(CallbackStackMemoryPool); |
| 123 public: |
| 124 // 2048 * 8 * sizeof(Item) = 256 KB (64bit) is pre-allocated for the |
| 125 // underlying buffer of CallbackStacks. |
| 126 static const size_t kBlockSize = 2048; |
| 127 static const size_t kPooledBlockCount = 8; |
| 128 static const size_t kBlockBytes = kBlockSize * sizeof(CallbackStack::Item); |
| 129 |
| 130 static CallbackStackMemoryPool& instance(); |
| 131 |
| 132 void initialize(); |
| 133 void shutdown(); |
| 134 CallbackStack::Item* allocate(); |
| 135 void free(CallbackStack::Item*); |
| 136 |
| 137 private: |
| 138 Mutex m_mutex; |
| 139 int m_freeListFirst; |
| 140 int m_freeListNext[kPooledBlockCount]; |
| 141 CallbackStack::Item* m_pooledMemory; |
| 142 }; |
| 143 |
| 121 ALWAYS_INLINE CallbackStack::Item* CallbackStack::allocateEntry() | 144 ALWAYS_INLINE CallbackStack::Item* CallbackStack::allocateEntry() |
| 122 { | 145 { |
| 146 DCHECK(m_first); |
| 123 Item* item = m_first->allocateEntry(); | 147 Item* item = m_first->allocateEntry(); |
| 124 if (LIKELY(!!item)) | 148 if (LIKELY(!!item)) |
| 125 return item; | 149 return item; |
| 126 | 150 |
| 127 return allocateEntrySlow(); | 151 return allocateEntrySlow(); |
| 128 } | 152 } |
| 129 | 153 |
| 130 ALWAYS_INLINE CallbackStack::Item* CallbackStack::pop() | 154 ALWAYS_INLINE CallbackStack::Item* CallbackStack::pop() |
| 131 { | 155 { |
| 132 Item* item = m_first->pop(); | 156 Item* item = m_first->pop(); |
| 133 if (LIKELY(!!item)) | 157 if (LIKELY(!!item)) |
| 134 return item; | 158 return item; |
| 135 | 159 |
| 136 return popSlow(); | 160 return popSlow(); |
| 137 } | 161 } |
| 138 | 162 |
| 139 } // namespace blink | 163 } // namespace blink |
| 140 | 164 |
| 141 #endif // CallbackStack_h | 165 #endif // CallbackStack_h |
| OLD | NEW |