Commit 9c191a0c authored by hpayer's avatar hpayer Committed by Commit bot

[heap] Use callbacks to dispatch store buffer operations.

BUG=chromium:648568, chromium:669920

Review-Url: https://codereview.chromium.org/2548213004
Cr-Commit-Position: refs/heads/master@{#41592}
parent dcbd3758
......@@ -286,6 +286,10 @@ GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space,
return YoungGenerationCollector();
}
void Heap::SetGCState(HeapState state) {
gc_state_ = state;
store_buffer_->SetMode(gc_state_);
}
// TODO(1238405): Combine the infrastructure for --heap-stats and
// --log-gc to avoid the complicated preprocessor and flag testing.
......@@ -1430,7 +1434,8 @@ void Heap::CallGCEpilogueCallbacks(GCType gc_type,
void Heap::MarkCompact() {
PauseAllocationObserversScope pause_observers(this);
gc_state_ = MARK_COMPACT;
SetGCState(MARK_COMPACT);
LOG(isolate_, ResourceEvent("markcompact", "begin"));
uint64_t size_of_objects_before_gc = SizeOfObjects();
......@@ -1456,7 +1461,7 @@ void Heap::MinorMarkCompact() { UNREACHABLE(); }
void Heap::MarkCompactEpilogue() {
TRACE_GC(tracer(), GCTracer::Scope::MC_EPILOGUE);
gc_state_ = NOT_IN_GC;
SetGCState(NOT_IN_GC);
isolate_->counters()->objs_since_last_full()->Set(0);
......@@ -1587,7 +1592,7 @@ void Heap::Scavenge() {
mark_compact_collector()->sweeper().EnsureNewSpaceCompleted();
gc_state_ = SCAVENGE;
SetGCState(SCAVENGE);
// Implements Cheney's copying algorithm
LOG(isolate_, ResourceEvent("scavenge", "begin"));
......@@ -1713,7 +1718,7 @@ void Heap::Scavenge() {
LOG(isolate_, ResourceEvent("scavenge", "end"));
gc_state_ = NOT_IN_GC;
SetGCState(NOT_IN_GC);
}
......
......@@ -818,6 +818,7 @@ class Heap {
void PrintShortHeapStatistics();
inline HeapState gc_state() { return gc_state_; }
void SetGCState(HeapState state);
inline bool IsInGCPostProcessing() { return gc_post_processing_depth_ > 0; }
......
......@@ -23,6 +23,8 @@ StoreBuffer::StoreBuffer(Heap* heap)
lazy_top_[i] = nullptr;
}
task_running_ = false;
insertion_callback = &InsertDuringRuntime;
deletion_callback = &DeleteDuringRuntime;
}
void StoreBuffer::SetUp() {
......@@ -137,29 +139,5 @@ void StoreBuffer::ConcurrentlyProcessStoreBuffer() {
task_running_ = false;
}
void StoreBuffer::DeleteEntry(Address start, Address end) {
// Deletions coming from the GC are directly deleted from the remembered
// set. Deletions coming from the runtime are added to the store buffer
// to allow concurrent processing.
if (heap_->gc_state() == Heap::NOT_IN_GC) {
if (top_ + sizeof(Address) * 2 > limit_[current_]) {
StoreBufferOverflow(heap_->isolate());
}
*top_ = MarkDeletionAddress(start);
top_++;
*top_ = end;
top_++;
} else {
// In GC the store buffer has to be empty at any time.
DCHECK(Empty());
Page* page = Page::FromAddress(start);
if (end) {
RememberedSet<OLD_TO_NEW>::RemoveRange(page, start, end,
SlotSet::PREFREE_EMPTY_BUCKETS);
} else {
RememberedSet<OLD_TO_NEW>::Remove(page, start);
}
}
}
} // namespace internal
} // namespace v8
......@@ -63,22 +63,76 @@ class StoreBuffer {
// If we only want to delete a single slot, end should be set to null which
// will be written into the second field. When processing the store buffer
// the more efficient Remove method will be called in this case.
void DeleteEntry(Address start, Address end = nullptr);
void DeleteEntry(Address start, Address end = nullptr) {
// Deletions coming from the GC are directly deleted from the remembered
// set. Deletions coming from the runtime are added to the store buffer
// to allow concurrent processing.
deletion_callback(this, start, end);
}
static void DeleteDuringGarbageCollection(StoreBuffer* store_buffer,
Address start, Address end) {
// In GC the store buffer has to be empty at any time.
DCHECK(store_buffer->Empty());
DCHECK(store_buffer->heap()->gc_state() != Heap::NOT_IN_GC);
Page* page = Page::FromAddress(start);
if (end) {
RememberedSet<OLD_TO_NEW>::RemoveRange(page, start, end,
SlotSet::PREFREE_EMPTY_BUCKETS);
} else {
RememberedSet<OLD_TO_NEW>::Remove(page, start);
}
}
static void DeleteDuringRuntime(StoreBuffer* store_buffer, Address start,
Address end) {
DCHECK(store_buffer->heap()->gc_state() == Heap::NOT_IN_GC);
store_buffer->InsertDeletionIntoStoreBuffer(start, end);
}
void InsertDeletionIntoStoreBuffer(Address start, Address end) {
if (top_ + sizeof(Address) * 2 > limit_[current_]) {
StoreBufferOverflow(heap_->isolate());
}
*top_ = MarkDeletionAddress(start);
top_++;
*top_ = end;
top_++;
}
static void InsertDuringGarbageCollection(StoreBuffer* store_buffer,
Address slot) {
DCHECK(store_buffer->heap()->gc_state() != Heap::NOT_IN_GC);
RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot);
}
static void InsertDuringRuntime(StoreBuffer* store_buffer, Address slot) {
DCHECK(store_buffer->heap()->gc_state() == Heap::NOT_IN_GC);
store_buffer->InsertIntoStoreBuffer(slot);
}
void InsertIntoStoreBuffer(Address slot) {
if (top_ + sizeof(Address) > limit_[current_]) {
StoreBufferOverflow(heap_->isolate());
}
*top_ = slot;
top_++;
}
void InsertEntry(Address slot) {
// Insertions coming from the GC are directly inserted into the remembered
// set. Insertions coming from the runtime are added to the store buffer to
// allow concurrent processing.
if (heap_->gc_state() == Heap::NOT_IN_GC) {
if (top_ + sizeof(Address) > limit_[current_]) {
StoreBufferOverflow(heap_->isolate());
}
*top_ = slot;
top_++;
insertion_callback(this, slot);
}
void SetMode(Heap::HeapState state) {
if (state == Heap::NOT_IN_GC) {
insertion_callback = &InsertDuringRuntime;
deletion_callback = &DeleteDuringRuntime;
} else {
// In GC the store buffer has to be empty at any time.
DCHECK(Empty());
RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot);
insertion_callback = &InsertDuringGarbageCollection;
deletion_callback = &DeleteDuringGarbageCollection;
}
}
......@@ -95,6 +149,8 @@ class StoreBuffer {
return top_ == start_[current_];
}
Heap* heap() { return heap_; }
private:
// There are two store buffers. If one store buffer fills up, the main thread
// publishes the top pointer of the store buffer that needs processing in its
......@@ -143,6 +199,11 @@ class StoreBuffer {
int current_;
base::VirtualMemory* virtual_memory_;
// Callbacks are more efficient than reading out the gc state for every
// store buffer operation.
std::function<void(StoreBuffer*, Address)> insertion_callback;
std::function<void(StoreBuffer*, Address, Address)> deletion_callback;
};
} // namespace internal
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment