Keep track of ArrayBuffers based on collector type, not space
Since Mark/Compact also collects garbage in the new space, we can't just free old space ArrayBuffers during MC - otherwise we run the risk of never freeing new array buffers BUG=v8:4201 R=hpayer@chromium.org LOG=n Review URL: https://codereview.chromium.org/1199913002 Cr-Commit-Position: refs/heads/master@{#29190}
This commit is contained in:
parent
2197ef2aaf
commit
839170e785
@ -1863,9 +1863,11 @@ void Heap::TearDownArrayBuffersHelper(
|
||||
void Heap::RegisterNewArrayBuffer(bool in_new_space, void* data,
|
||||
size_t length) {
|
||||
if (!data) return;
|
||||
RegisterNewArrayBufferHelper(
|
||||
in_new_space ? live_new_array_buffers_ : live_array_buffers_, data,
|
||||
length);
|
||||
RegisterNewArrayBufferHelper(live_array_buffers_, data, length);
|
||||
if (in_new_space) {
|
||||
RegisterNewArrayBufferHelper(live_array_buffers_for_scavenge_, data,
|
||||
length);
|
||||
}
|
||||
reinterpret_cast<v8::Isolate*>(isolate_)
|
||||
->AdjustAmountOfExternalAllocatedMemory(length);
|
||||
}
|
||||
@ -1873,29 +1875,46 @@ void Heap::RegisterNewArrayBuffer(bool in_new_space, void* data,
|
||||
|
||||
void Heap::UnregisterArrayBuffer(bool in_new_space, void* data) {
|
||||
if (!data) return;
|
||||
UnregisterArrayBufferHelper(
|
||||
in_new_space ? live_new_array_buffers_ : live_array_buffers_,
|
||||
in_new_space ? not_yet_discovered_new_array_buffers_
|
||||
: not_yet_discovered_array_buffers_,
|
||||
UnregisterArrayBufferHelper(live_array_buffers_,
|
||||
not_yet_discovered_array_buffers_, data);
|
||||
if (in_new_space) {
|
||||
UnregisterArrayBufferHelper(live_array_buffers_for_scavenge_,
|
||||
not_yet_discovered_array_buffers_for_scavenge_,
|
||||
data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Heap::RegisterLiveArrayBuffer(bool from_scavenge, void* data) {
|
||||
// ArrayBuffer might be in the middle of being constructed.
|
||||
if (data == undefined_value()) return;
|
||||
RegisterLiveArrayBufferHelper(
|
||||
from_scavenge ? not_yet_discovered_array_buffers_for_scavenge_
|
||||
: not_yet_discovered_array_buffers_,
|
||||
data);
|
||||
}
|
||||
|
||||
|
||||
void Heap::RegisterLiveArrayBuffer(bool in_new_space, void* data) {
|
||||
// ArrayBuffer might be in the middle of being constructed.
|
||||
if (data == undefined_value()) return;
|
||||
RegisterLiveArrayBufferHelper(in_new_space
|
||||
? not_yet_discovered_new_array_buffers_
|
||||
: not_yet_discovered_array_buffers_,
|
||||
data);
|
||||
}
|
||||
|
||||
|
||||
void Heap::FreeDeadArrayBuffers(bool in_new_space) {
|
||||
void Heap::FreeDeadArrayBuffers(bool from_scavenge) {
|
||||
if (from_scavenge) {
|
||||
for (auto& buffer : not_yet_discovered_array_buffers_for_scavenge_) {
|
||||
not_yet_discovered_array_buffers_.erase(buffer.first);
|
||||
live_array_buffers_.erase(buffer.first);
|
||||
}
|
||||
} else {
|
||||
for (auto& buffer : not_yet_discovered_array_buffers_) {
|
||||
// Scavenge can't happend during evacuation, so we only need to update
|
||||
// live_array_buffers_for_scavenge_.
|
||||
// not_yet_discovered_array_buffers_for_scanvenge_ will be reset before
|
||||
// the next scavenge run in PrepareArrayBufferDiscoveryInNewSpace.
|
||||
live_array_buffers_for_scavenge_.erase(buffer.first);
|
||||
}
|
||||
}
|
||||
size_t freed_memory = FreeDeadArrayBuffersHelper(
|
||||
isolate_, in_new_space ? live_new_array_buffers_ : live_array_buffers_,
|
||||
in_new_space ? not_yet_discovered_new_array_buffers_
|
||||
: not_yet_discovered_array_buffers_);
|
||||
isolate_,
|
||||
from_scavenge ? live_array_buffers_for_scavenge_ : live_array_buffers_,
|
||||
from_scavenge ? not_yet_discovered_array_buffers_for_scavenge_
|
||||
: not_yet_discovered_array_buffers_);
|
||||
if (freed_memory) {
|
||||
reinterpret_cast<v8::Isolate*>(isolate_)
|
||||
->AdjustAmountOfExternalAllocatedMemory(
|
||||
@ -1907,13 +1926,12 @@ void Heap::FreeDeadArrayBuffers(bool in_new_space) {
|
||||
void Heap::TearDownArrayBuffers() {
|
||||
TearDownArrayBuffersHelper(isolate_, live_array_buffers_,
|
||||
not_yet_discovered_array_buffers_);
|
||||
TearDownArrayBuffersHelper(isolate_, live_new_array_buffers_,
|
||||
not_yet_discovered_new_array_buffers_);
|
||||
}
|
||||
|
||||
|
||||
void Heap::PrepareArrayBufferDiscoveryInNewSpace() {
|
||||
not_yet_discovered_new_array_buffers_ = live_new_array_buffers_;
|
||||
not_yet_discovered_array_buffers_for_scavenge_ =
|
||||
live_array_buffers_for_scavenge_;
|
||||
}
|
||||
|
||||
|
||||
@ -1924,10 +1942,10 @@ void Heap::PromoteArrayBuffer(Object* obj) {
|
||||
if (!data) return;
|
||||
// ArrayBuffer might be in the middle of being constructed.
|
||||
if (data == undefined_value()) return;
|
||||
DCHECK(live_new_array_buffers_.count(data) > 0);
|
||||
live_array_buffers_[data] = live_new_array_buffers_[data];
|
||||
live_new_array_buffers_.erase(data);
|
||||
not_yet_discovered_new_array_buffers_.erase(data);
|
||||
DCHECK(live_array_buffers_for_scavenge_.count(data) > 0);
|
||||
DCHECK(live_array_buffers_.count(data) > 0);
|
||||
live_array_buffers_for_scavenge_.erase(data);
|
||||
not_yet_discovered_array_buffers_for_scavenge_.erase(data);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1599,11 +1599,11 @@ class Heap {
|
||||
void UnregisterArrayBuffer(bool in_new_space, void* data);
|
||||
|
||||
// A live ArrayBuffer was discovered during marking/scavenge.
|
||||
void RegisterLiveArrayBuffer(bool in_new_space, void* data);
|
||||
void RegisterLiveArrayBuffer(bool from_scavenge, void* data);
|
||||
|
||||
// Frees all backing store pointers that weren't discovered in the previous
|
||||
// marking or scavenge phase.
|
||||
void FreeDeadArrayBuffers(bool in_new_space);
|
||||
void FreeDeadArrayBuffers(bool from_scavenge);
|
||||
|
||||
// Prepare for a new scavenge phase. A new marking phase is implicitly
|
||||
// prepared by finishing the previous one.
|
||||
@ -2373,10 +2373,24 @@ class Heap {
|
||||
|
||||
bool concurrent_sweeping_enabled_;
|
||||
|
||||
// |live_array_buffers_| maps externally allocated memory used as backing
|
||||
// store for ArrayBuffers to the length of the respective memory blocks.
|
||||
//
|
||||
// At the beginning of mark/compact, |not_yet_discovered_array_buffers_| is
|
||||
// a copy of |live_array_buffers_| and we remove pointers as we discover live
|
||||
// ArrayBuffer objects during marking. At the end of mark/compact, the
|
||||
// remaining memory blocks can be freed.
|
||||
std::map<void*, size_t> live_array_buffers_;
|
||||
std::map<void*, size_t> live_new_array_buffers_;
|
||||
std::map<void*, size_t> not_yet_discovered_array_buffers_;
|
||||
std::map<void*, size_t> not_yet_discovered_new_array_buffers_;
|
||||
|
||||
// To be able to free memory held by ArrayBuffers during scavenge as well, we
|
||||
// have a separate list of allocated memory held by ArrayBuffers in new space.
|
||||
//
|
||||
// Since mark/compact also evacuates the new space, all pointers in the
|
||||
// |live_array_buffers_for_scavenge_| list are also in the
|
||||
// |live_array_buffers_| list.
|
||||
std::map<void*, size_t> live_array_buffers_for_scavenge_;
|
||||
std::map<void*, size_t> not_yet_discovered_array_buffers_for_scavenge_;
|
||||
|
||||
struct StrongRootsList;
|
||||
StrongRootsList* strong_roots_list_;
|
||||
|
@ -508,7 +508,7 @@ void StaticMarkingVisitor<StaticVisitor>::VisitJSArrayBuffer(
|
||||
HeapObject::RawField(object, JSArrayBuffer::BodyDescriptor::kStartOffset),
|
||||
HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields));
|
||||
if (!JSArrayBuffer::cast(object)->is_external()) {
|
||||
heap->RegisterLiveArrayBuffer(heap->InNewSpace(object),
|
||||
heap->RegisterLiveArrayBuffer(false,
|
||||
JSArrayBuffer::cast(object)->backing_store());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user