Commit d8981833 authored by Peter Marshall's avatar Peter Marshall Committed by Commit Bot

reland: [heap] Concurrently free ArrayBuffer allocations.

Free ArrayBuffer backing stores on a background thread, rather than
blocking the main thread after processing. Could potentially cause
contention with the array buffer allocator once JS execution resumes.

The new ArrayBufferCollector class tracks these dead allocations.

Later, the processing of array buffers can happen in parallel.

Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng;master.tryserver.v8:v8_linux64_tsan_rel;master.tryserver.v8:v8_linux64_tsan_concurrent_marking_rel_ng;master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel;master.tryserver.chromium.android:android_optional_gpu_tests_rel

Bug: v8:6992
Change-Id: I2b74f008f79521414374f607ed510f66508af160
Reviewed-on: https://chromium-review.googlesource.com/779182
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49505}
parent 712fa675
...@@ -1617,6 +1617,8 @@ v8_source_set("v8_base") { ...@@ -1617,6 +1617,8 @@ v8_source_set("v8_base") {
"src/handles.cc", "src/handles.cc",
"src/handles.h", "src/handles.h",
"src/heap-symbols.h", "src/heap-symbols.h",
"src/heap/array-buffer-collector.cc",
"src/heap/array-buffer-collector.h",
"src/heap/array-buffer-tracker-inl.h", "src/heap/array-buffer-tracker-inl.h",
"src/heap/array-buffer-tracker.cc", "src/heap/array-buffer-tracker.cc",
"src/heap/array-buffer-tracker.h", "src/heap/array-buffer-tracker.h",
......
...@@ -635,6 +635,8 @@ DEFINE_BOOL(trace_gc_object_stats, false, ...@@ -635,6 +635,8 @@ DEFINE_BOOL(trace_gc_object_stats, false,
"trace object counts and memory usage") "trace object counts and memory usage")
DEFINE_BOOL(track_retaining_path, false, DEFINE_BOOL(track_retaining_path, false,
"enable support for tracking retaining path") "enable support for tracking retaining path")
DEFINE_BOOL(concurrent_array_buffer_freeing, true,
"free array buffer allocations on a background thread")
DEFINE_INT(gc_stats, 0, "Used by tracing internally to enable gc statistics") DEFINE_INT(gc_stats, 0, "Used by tracing internally to enable gc statistics")
DEFINE_IMPLICATION(trace_gc_object_stats, track_gc_object_stats) DEFINE_IMPLICATION(trace_gc_object_stats, track_gc_object_stats)
DEFINE_VALUE_IMPLICATION(track_gc_object_stats, gc_stats, 1) DEFINE_VALUE_IMPLICATION(track_gc_object_stats, gc_stats, 1)
...@@ -1255,6 +1257,7 @@ DEFINE_NEG_IMPLICATION(single_threaded_gc, parallel_pointer_update) ...@@ -1255,6 +1257,7 @@ DEFINE_NEG_IMPLICATION(single_threaded_gc, parallel_pointer_update)
DEFINE_NEG_IMPLICATION(single_threaded_gc, parallel_scavenge) DEFINE_NEG_IMPLICATION(single_threaded_gc, parallel_scavenge)
DEFINE_NEG_IMPLICATION(single_threaded_gc, concurrent_store_buffer) DEFINE_NEG_IMPLICATION(single_threaded_gc, concurrent_store_buffer)
DEFINE_NEG_IMPLICATION(single_threaded_gc, minor_mc_parallel_marking) DEFINE_NEG_IMPLICATION(single_threaded_gc, minor_mc_parallel_marking)
DEFINE_NEG_IMPLICATION(single_threaded_gc, concurrent_array_buffer_freeing)
#undef FLAG #undef FLAG
......
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/heap/array-buffer-collector.h"
#include "src/heap/array-buffer-tracker.h"
#include "src/heap/heap-inl.h"
namespace v8 {
namespace internal {
void ArrayBufferCollector::AddGarbageAllocations(
std::vector<JSArrayBuffer::Allocation>* allocations) {
base::LockGuard<base::Mutex> guard(&allocations_mutex_);
allocations_.push_back(allocations);
}
void ArrayBufferCollector::FreeAllocations() {
base::LockGuard<base::Mutex> guard(&allocations_mutex_);
for (std::vector<JSArrayBuffer::Allocation>* allocations : allocations_) {
for (auto alloc : *allocations) {
JSArrayBuffer::FreeBackingStore(heap_->isolate(), alloc);
}
delete allocations;
}
allocations_.clear();
}
class ArrayBufferCollector::FreeingTask final : public CancelableTask {
public:
explicit FreeingTask(Heap* heap)
: CancelableTask(heap->isolate()), heap_(heap) {}
virtual ~FreeingTask() {}
private:
void RunInternal() final {
heap_->array_buffer_collector()->FreeAllocations();
}
Heap* heap_;
};
void ArrayBufferCollector::FreeAllocationsOnBackgroundThread() {
heap_->account_external_memory_concurrently_freed();
if (heap_->use_tasks() && FLAG_concurrent_array_buffer_freeing) {
FreeingTask* task = new FreeingTask(heap_);
V8::GetCurrentPlatform()->CallOnBackgroundThread(
task, v8::Platform::kShortRunningTask);
} else {
// Fallback for when concurrency is disabled/restricted.
FreeAllocations();
}
}
} // namespace internal
} // namespace v8
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_HEAP_ARRAY_BUFFER_COLLECTOR_H_
#define V8_HEAP_ARRAY_BUFFER_COLLECTOR_H_
#include <vector>
#include "src/base/platform/mutex.h"
#include "src/objects/js-array.h"
namespace v8 {
namespace internal {
class Heap;
// To support background processing of array buffer backing stores, we process
// array buffers using the ArrayBufferTracker class. The ArrayBufferCollector
// keeps track of garbage backing stores so that they can be freed on a
// background thread.
class ArrayBufferCollector {
public:
explicit ArrayBufferCollector(Heap* heap) : heap_(heap) {}
~ArrayBufferCollector() { FreeAllocations(); }
// These allocations will begin to be freed once FreeAllocations() is called,
// or on TearDown.
void AddGarbageAllocations(
std::vector<JSArrayBuffer::Allocation>* allocations);
// Calls FreeAllocations() on a background thread.
void FreeAllocationsOnBackgroundThread();
private:
class FreeingTask;
// Begin freeing the allocations added through AddGarbageAllocations. Also
// called by TearDown.
void FreeAllocations();
Heap* heap_;
base::Mutex allocations_mutex_;
std::vector<std::vector<JSArrayBuffer::Allocation>*> allocations_;
};
} // namespace internal
} // namespace v8
#endif // V8_HEAP_ARRAY_BUFFER_COLLECTOR_H_
...@@ -3,6 +3,10 @@ ...@@ -3,6 +3,10 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "src/heap/array-buffer-tracker.h" #include "src/heap/array-buffer-tracker.h"
#include <vector>
#include "src/heap/array-buffer-collector.h"
#include "src/heap/array-buffer-tracker-inl.h" #include "src/heap/array-buffer-tracker-inl.h"
#include "src/heap/heap.h" #include "src/heap/heap.h"
#include "src/heap/spaces.h" #include "src/heap/spaces.h"
...@@ -16,6 +20,9 @@ LocalArrayBufferTracker::~LocalArrayBufferTracker() { ...@@ -16,6 +20,9 @@ LocalArrayBufferTracker::~LocalArrayBufferTracker() {
template <typename Callback> template <typename Callback>
void LocalArrayBufferTracker::Process(Callback callback) { void LocalArrayBufferTracker::Process(Callback callback) {
std::vector<JSArrayBuffer::Allocation>* backing_stores_to_free =
new std::vector<JSArrayBuffer::Allocation>();
JSArrayBuffer* new_buffer = nullptr; JSArrayBuffer* new_buffer = nullptr;
JSArrayBuffer* old_buffer = nullptr; JSArrayBuffer* old_buffer = nullptr;
size_t new_retained_size = 0; size_t new_retained_size = 0;
...@@ -45,7 +52,12 @@ void LocalArrayBufferTracker::Process(Callback callback) { ...@@ -45,7 +52,12 @@ void LocalArrayBufferTracker::Process(Callback callback) {
it = array_buffers_.erase(it); it = array_buffers_.erase(it);
} else if (result == kRemoveEntry) { } else if (result == kRemoveEntry) {
// Size of freed memory is computed to avoid looking at dead objects. // Size of freed memory is computed to avoid looking at dead objects.
old_buffer->FreeBackingStore(); void* allocation_base = old_buffer->allocation_base();
DCHECK_NOT_NULL(allocation_base);
backing_stores_to_free->emplace_back(allocation_base,
old_buffer->allocation_length(),
old_buffer->allocation_mode());
it = array_buffers_.erase(it); it = array_buffers_.erase(it);
} else { } else {
UNREACHABLE(); UNREACHABLE();
...@@ -57,16 +69,21 @@ void LocalArrayBufferTracker::Process(Callback callback) { ...@@ -57,16 +69,21 @@ void LocalArrayBufferTracker::Process(Callback callback) {
static_cast<intptr_t>(freed_memory)); static_cast<intptr_t>(freed_memory));
} }
retained_size_ = new_retained_size; retained_size_ = new_retained_size;
// Pass the backing stores that need to be freed to the main thread for later
// distribution.
// ArrayBufferCollector takes ownership of this pointer.
heap_->array_buffer_collector()->AddGarbageAllocations(
backing_stores_to_free);
} }
void ArrayBufferTracker::FreeDeadInNewSpace(Heap* heap) { void ArrayBufferTracker::PrepareToFreeDeadInNewSpace(Heap* heap) {
DCHECK_EQ(heap->gc_state(), Heap::HeapState::SCAVENGE); DCHECK_EQ(heap->gc_state(), Heap::HeapState::SCAVENGE);
for (Page* page : PageRange(heap->new_space()->FromSpaceStart(), for (Page* page : PageRange(heap->new_space()->FromSpaceStart(),
heap->new_space()->FromSpaceEnd())) { heap->new_space()->FromSpaceEnd())) {
bool empty = ProcessBuffers(page, kUpdateForwardedRemoveOthers); bool empty = ProcessBuffers(page, kUpdateForwardedRemoveOthers);
CHECK(empty); CHECK(empty);
} }
heap->account_external_memory_concurrently_freed();
} }
size_t ArrayBufferTracker::RetainedInNewSpace(Heap* heap) { size_t ArrayBufferTracker::RetainedInNewSpace(Heap* heap) {
......
...@@ -34,9 +34,9 @@ class ArrayBufferTracker : public AllStatic { ...@@ -34,9 +34,9 @@ class ArrayBufferTracker : public AllStatic {
inline static void RegisterNew(Heap* heap, JSArrayBuffer* buffer); inline static void RegisterNew(Heap* heap, JSArrayBuffer* buffer);
inline static void Unregister(Heap* heap, JSArrayBuffer* buffer); inline static void Unregister(Heap* heap, JSArrayBuffer* buffer);
// Frees all backing store pointers for dead JSArrayBuffers in new space. // Identifies all backing store pointers for dead JSArrayBuffers in new space.
// Does not take any locks and can only be called during Scavenge. // Does not take any locks and can only be called during Scavenge.
static void FreeDeadInNewSpace(Heap* heap); static void PrepareToFreeDeadInNewSpace(Heap* heap);
// Number of array buffer bytes retained from new space. // Number of array buffer bytes retained from new space.
static size_t RetainedInNewSpace(Heap* heap); static size_t RetainedInNewSpace(Heap* heap);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "src/deoptimizer.h" #include "src/deoptimizer.h"
#include "src/feedback-vector.h" #include "src/feedback-vector.h"
#include "src/global-handles.h" #include "src/global-handles.h"
#include "src/heap/array-buffer-collector.h"
#include "src/heap/array-buffer-tracker-inl.h" #include "src/heap/array-buffer-tracker-inl.h"
#include "src/heap/barrier.h" #include "src/heap/barrier.h"
#include "src/heap/code-stats.h" #include "src/heap/code-stats.h"
...@@ -191,6 +192,7 @@ Heap::Heap() ...@@ -191,6 +192,7 @@ Heap::Heap()
last_gc_time_(0.0), last_gc_time_(0.0),
mark_compact_collector_(nullptr), mark_compact_collector_(nullptr),
minor_mark_compact_collector_(nullptr), minor_mark_compact_collector_(nullptr),
array_buffer_collector_(nullptr),
memory_allocator_(nullptr), memory_allocator_(nullptr),
store_buffer_(nullptr), store_buffer_(nullptr),
incremental_marking_(nullptr), incremental_marking_(nullptr),
...@@ -2059,8 +2061,10 @@ void Heap::Scavenge() { ...@@ -2059,8 +2061,10 @@ void Heap::Scavenge() {
{ {
TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_PROCESS_ARRAY_BUFFERS); TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_PROCESS_ARRAY_BUFFERS);
ArrayBufferTracker::FreeDeadInNewSpace(this); ArrayBufferTracker::PrepareToFreeDeadInNewSpace(this);
} }
array_buffer_collector()->FreeAllocationsOnBackgroundThread();
RememberedSet<OLD_TO_NEW>::IterateMemoryChunks(this, [](MemoryChunk* chunk) { RememberedSet<OLD_TO_NEW>::IterateMemoryChunks(this, [](MemoryChunk* chunk) {
if (chunk->SweepingDone()) { if (chunk->SweepingDone()) {
RememberedSet<OLD_TO_NEW>::FreeEmptyBuckets(chunk); RememberedSet<OLD_TO_NEW>::FreeEmptyBuckets(chunk);
...@@ -5505,6 +5509,7 @@ bool Heap::SetUp() { ...@@ -5505,6 +5509,7 @@ bool Heap::SetUp() {
tracer_ = new GCTracer(this); tracer_ = new GCTracer(this);
minor_mark_compact_collector_ = new MinorMarkCompactCollector(this); minor_mark_compact_collector_ = new MinorMarkCompactCollector(this);
array_buffer_collector_ = new ArrayBufferCollector(this);
gc_idle_time_handler_ = new GCIdleTimeHandler(); gc_idle_time_handler_ = new GCIdleTimeHandler();
memory_reducer_ = new MemoryReducer(this); memory_reducer_ = new MemoryReducer(this);
if (V8_UNLIKELY(FLAG_gc_stats)) { if (V8_UNLIKELY(FLAG_gc_stats)) {
...@@ -5653,6 +5658,11 @@ void Heap::TearDown() { ...@@ -5653,6 +5658,11 @@ void Heap::TearDown() {
minor_mark_compact_collector_ = nullptr; minor_mark_compact_collector_ = nullptr;
} }
if (array_buffer_collector_ != nullptr) {
delete array_buffer_collector_;
array_buffer_collector_ = nullptr;
}
delete incremental_marking_; delete incremental_marking_;
incremental_marking_ = nullptr; incremental_marking_ = nullptr;
......
...@@ -388,6 +388,7 @@ using v8::MemoryPressureLevel; ...@@ -388,6 +388,7 @@ using v8::MemoryPressureLevel;
} while (false) } while (false)
class AllocationObserver; class AllocationObserver;
class ArrayBufferCollector;
class ArrayBufferTracker; class ArrayBufferTracker;
class ConcurrentMarking; class ConcurrentMarking;
class GCIdleTimeAction; class GCIdleTimeAction;
...@@ -1009,6 +1010,10 @@ class Heap { ...@@ -1009,6 +1010,10 @@ class Heap {
return minor_mark_compact_collector_; return minor_mark_compact_collector_;
} }
ArrayBufferCollector* array_buffer_collector() {
return array_buffer_collector_;
}
// =========================================================================== // ===========================================================================
// Root set access. ========================================================== // Root set access. ==========================================================
// =========================================================================== // ===========================================================================
...@@ -2407,6 +2412,8 @@ class Heap { ...@@ -2407,6 +2412,8 @@ class Heap {
MarkCompactCollector* mark_compact_collector_; MarkCompactCollector* mark_compact_collector_;
MinorMarkCompactCollector* minor_mark_compact_collector_; MinorMarkCompactCollector* minor_mark_compact_collector_;
ArrayBufferCollector* array_buffer_collector_;
MemoryAllocator* memory_allocator_; MemoryAllocator* memory_allocator_;
StoreBuffer* store_buffer_; StoreBuffer* store_buffer_;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "src/execution.h" #include "src/execution.h"
#include "src/frames-inl.h" #include "src/frames-inl.h"
#include "src/global-handles.h" #include "src/global-handles.h"
#include "src/heap/array-buffer-collector.h"
#include "src/heap/array-buffer-tracker-inl.h" #include "src/heap/array-buffer-tracker-inl.h"
#include "src/heap/concurrent-marking.h" #include "src/heap/concurrent-marking.h"
#include "src/heap/gc-tracer.h" #include "src/heap/gc-tracer.h"
...@@ -4292,6 +4293,7 @@ void MarkCompactCollector::UpdatePointersAfterEvacuation() { ...@@ -4292,6 +4293,7 @@ void MarkCompactCollector::UpdatePointersAfterEvacuation() {
updating_job.AddTask(new PointersUpdatingTask(isolate())); updating_job.AddTask(new PointersUpdatingTask(isolate()));
} }
updating_job.Run(); updating_job.Run();
heap()->array_buffer_collector()->FreeAllocationsOnBackgroundThread();
} }
} }
...@@ -4349,6 +4351,7 @@ void MinorMarkCompactCollector::UpdatePointersAfterEvacuation() { ...@@ -4349,6 +4351,7 @@ void MinorMarkCompactCollector::UpdatePointersAfterEvacuation() {
TRACE_GC(heap()->tracer(), TRACE_GC(heap()->tracer(),
GCTracer::Scope::MINOR_MC_EVACUATE_UPDATE_POINTERS_SLOTS); GCTracer::Scope::MINOR_MC_EVACUATE_UPDATE_POINTERS_SLOTS);
updating_job.Run(); updating_job.Run();
heap()->array_buffer_collector()->FreeAllocationsOnBackgroundThread();
} }
{ {
......
...@@ -18858,7 +18858,7 @@ void JSArrayBuffer::FreeBackingStore() { ...@@ -18858,7 +18858,7 @@ void JSArrayBuffer::FreeBackingStore() {
using AllocationMode = ArrayBuffer::Allocator::AllocationMode; using AllocationMode = ArrayBuffer::Allocator::AllocationMode;
const size_t length = allocation_length(); const size_t length = allocation_length();
const AllocationMode mode = allocation_mode(); const AllocationMode mode = allocation_mode();
GetIsolate()->array_buffer_allocator()->Free(allocation_base(), length, mode); FreeBackingStore(GetIsolate(), {allocation_base(), length, mode});
// Zero out the backing store and allocation base to avoid dangling // Zero out the backing store and allocation base to avoid dangling
// pointers. // pointers.
...@@ -18870,6 +18870,12 @@ void JSArrayBuffer::FreeBackingStore() { ...@@ -18870,6 +18870,12 @@ void JSArrayBuffer::FreeBackingStore() {
set_allocation_length(0); set_allocation_length(0);
} }
// static
void JSArrayBuffer::FreeBackingStore(Isolate* isolate, Allocation allocation) {
isolate->array_buffer_allocator()->Free(allocation.allocation_base,
allocation.length, allocation.mode);
}
void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate, void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
bool is_external, void* data, size_t allocated_length, bool is_external, void* data, size_t allocated_length,
SharedFlag shared) { SharedFlag shared) {
......
...@@ -179,7 +179,19 @@ class JSArrayBuffer : public JSObject { ...@@ -179,7 +179,19 @@ class JSArrayBuffer : public JSObject {
inline ArrayBuffer::Allocator::AllocationMode allocation_mode() const; inline ArrayBuffer::Allocator::AllocationMode allocation_mode() const;
struct Allocation {
using AllocationMode = ArrayBuffer::Allocator::AllocationMode;
Allocation(void* allocation_base, size_t length, AllocationMode mode)
: allocation_base(allocation_base), length(length), mode(mode) {}
void* allocation_base;
size_t length;
AllocationMode mode;
};
void FreeBackingStore(); void FreeBackingStore();
static void FreeBackingStore(Isolate* isolate, Allocation allocation);
V8_EXPORT_PRIVATE static void Setup( V8_EXPORT_PRIVATE static void Setup(
Handle<JSArrayBuffer> array_buffer, Isolate* isolate, bool is_external, Handle<JSArrayBuffer> array_buffer, Isolate* isolate, bool is_external,
......
...@@ -990,6 +990,8 @@ ...@@ -990,6 +990,8 @@
'handles.cc', 'handles.cc',
'handles.h', 'handles.h',
'heap-symbols.h', 'heap-symbols.h',
'heap/array-buffer-collector.cc',
'heap/array-buffer-collector.h',
'heap/array-buffer-tracker-inl.h', 'heap/array-buffer-tracker-inl.h',
'heap/array-buffer-tracker.cc', 'heap/array-buffer-tracker.cc',
'heap/array-buffer-tracker.h', 'heap/array-buffer-tracker.h',
......
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