// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #ifndef RUNTIME_VM_HEAP_POINTER_BLOCK_H_ #define RUNTIME_VM_HEAP_POINTER_BLOCK_H_ #include "platform/assert.h" #include "vm/globals.h" #include "vm/os_thread.h" namespace dart { // Forward declarations. class Isolate; class RawObject; class ObjectPointerVisitor; // A set of RawObject*. Must be emptied before destruction (using Pop/Reset). template class PointerBlock { public: enum { kSize = Size }; void Reset() { top_ = 0; next_ = NULL; } PointerBlock* next() const { return next_; } intptr_t Count() const { return top_; } bool IsFull() const { return Count() == kSize; } bool IsEmpty() const { return Count() == 0; } void Push(RawObject* obj) { ASSERT(!IsFull()); pointers_[top_++] = obj; } RawObject* Pop() { ASSERT(!IsEmpty()); return pointers_[--top_]; } #if defined(TESTING) bool Contains(RawObject* obj) const { for (intptr_t i = 0; i < Count(); i++) { if (pointers_[i] == obj) { return true; } } return false; } #endif // TESTING static intptr_t top_offset() { return OFFSET_OF(PointerBlock, top_); } static intptr_t pointers_offset() { return OFFSET_OF(PointerBlock, pointers_); } void VisitObjectPointers(ObjectPointerVisitor* visitor); private: PointerBlock() : next_(NULL), top_(0) {} ~PointerBlock() { ASSERT(IsEmpty()); // Guard against unintentionally discarding pointers. } PointerBlock* next_; int32_t top_; RawObject* pointers_[kSize]; template friend class BlockStack; DISALLOW_COPY_AND_ASSIGN(PointerBlock); }; // A synchronized collection of pointer blocks of a particular size. // This class is meant to be used as a base (note PushBlockImpl is protected). // The global list of cached empty blocks is currently per-size. template class BlockStack { public: typedef PointerBlock Block; BlockStack(); ~BlockStack(); static void Init(); static void Cleanup(); // 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. Block* PopNonFullBlock(); Block* PopEmptyBlock(); Block* PopNonEmptyBlock(); // Pops and returns all non-empty blocks as a linked list (owned by caller). Block* Blocks(); // Discards the contents of all non-empty blocks. void Reset(); bool IsEmpty(); protected: class List { public: List() : head_(NULL), length_(0) {} ~List(); void Push(Block* block); Block* Pop(); intptr_t length() const { return length_; } bool IsEmpty() const { return head_ == NULL; } Block* PopAll(); Block* Peek() { return head_; } private: Block* head_; intptr_t length_; DISALLOW_COPY_AND_ASSIGN(List); }; // Adds and transfers ownership of the block to the buffer. void PushBlockImpl(Block* block); // If needed, trims the global cache of empty blocks. static void TrimGlobalEmpty(); List full_; List partial_; Mutex mutex_; // Note: This is shared on the basis of block size. static const intptr_t kMaxGlobalEmpty = 100; static List* global_empty_; static Mutex* global_mutex_; private: DISALLOW_COPY_AND_ASSIGN(BlockStack); }; static const int kStoreBufferBlockSize = 1024; class StoreBuffer : public BlockStack { public: // Interrupt when crossing this threshold of non-empty blocks in the buffer. static const intptr_t kMaxNonEmpty = 100; enum ThresholdPolicy { kCheckThreshold, kIgnoreThreshold }; // Adds and transfers ownership of the block to the buffer. Optionally // checks the number of non-empty blocks for overflow, and schedules an // interrupt on the current isolate if so. void PushBlock(Block* block, ThresholdPolicy policy); // Check whether non-empty blocks have exceeded kMaxNonEmpty (but takes no // action). bool Overflowed(); void VisitObjectPointers(ObjectPointerVisitor* visitor); }; typedef StoreBuffer::Block StoreBufferBlock; static const int kMarkingStackBlockSize = 64; class MarkingStack : public BlockStack { public: // Adds and transfers ownership of the block to the buffer. void PushBlock(Block* block) { BlockStack::PushBlockImpl(block); } }; typedef MarkingStack::Block MarkingStackBlock; } // namespace dart #endif // RUNTIME_VM_HEAP_POINTER_BLOCK_H_