blob: b1bd387e8fb87d8d657fd0a310adf5a94528ca57 [file] [log] [blame]
// 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 VM_STORE_BUFFER_H_
#define VM_STORE_BUFFER_H_
#include "platform/assert.h"
#include "vm/globals.h"
namespace dart {
// Forward declarations.
class Isolate;
class Mutex;
class RawObject;
// A set of RawObject*. Must be emptied before destruction (using Pop/Reset).
class StoreBufferBlock {
public:
// Each full block contains kSize pointers.
static const int32_t kSize = 1024;
void Reset() {
top_ = 0;
next_ = NULL;
}
StoreBufferBlock* 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(StoreBufferBlock, top_); }
static intptr_t pointers_offset() {
return OFFSET_OF(StoreBufferBlock, pointers_);
}
private:
StoreBufferBlock() : next_(NULL), top_(0) {}
~StoreBufferBlock() {
ASSERT(IsEmpty()); // Guard against unintentionally discarding pointers.
}
StoreBufferBlock* next_;
int32_t top_;
RawObject* pointers_[kSize];
friend class StoreBuffer;
DISALLOW_COPY_AND_ASSIGN(StoreBufferBlock);
};
class StoreBuffer {
public:
StoreBuffer();
~StoreBuffer();
static void InitOnce();
// Interrupt when crossing this threshold of non-empty blocks in the buffer.
static const intptr_t kMaxNonEmpty = 100;
// 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();
// Pops and returns all non-empty blocks as a linked list (owned by caller).
StoreBufferBlock* Blocks();
// Discards the contents of this store buffer.
void Reset();
// Check whether non-empty blocks have exceeded kMaxNonEmpty.
bool Overflowed();
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);
};
// If needed, trims the the global cache of empty blocks.
static void TrimGlobalEmpty();
List full_;
List partial_;
Mutex* mutex_;
static const intptr_t kMaxGlobalEmpty = 100;
static List* global_empty_;
static Mutex* global_mutex_;
DISALLOW_COPY_AND_ASSIGN(StoreBuffer);
};
} // namespace dart
#endif // VM_STORE_BUFFER_H_