Files
sdk/runtime/vm/store_buffer.h
T
Daniel Andersson 8b4ac45038 Reuse empty StoreBufferBlocks.
Keep cache of empty blocks shared among all isolates, limited in size.
Change overflow threshold check to include partially filled blocks.
Make Isolate::store_buffer_ a pointer, now that it's less frequently accessed, to keep the offsets of other fields small

BUG=
R=iposva@google.com

Review URL: https://codereview.chromium.org//1173043002.
2015-06-18 16:16:50 -07:00

137 lines
3.3 KiB
C++

// 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();
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);
};
// Check if we run over the max number of deduplication sets.
// If we did schedule an interrupt.
void CheckThresholdNonEmpty();
// 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_