[heap] Optimize ArrayBuffer tracking

With the current approach we only need to track using an unordered set as we can
still access the backing store pointer and length by the time we free the
backing store.

BUG=chromium:619491, chromium:611688
LOG=N
R=ulan@chromium.org

Review-Url: https://codereview.chromium.org/2107443002
Cr-Commit-Position: refs/heads/master@{#37318}
This commit is contained in:
mlippautz 2016-06-28 01:36:33 -07:00 committed by Commit bot
parent 43d0b7e765
commit 8d2ae27808
3 changed files with 30 additions and 29 deletions

View File

@ -24,7 +24,7 @@ void ArrayBufferTracker::RegisterNew(Heap* heap, JSArrayBuffer* buffer) {
tracker = page->local_tracker();
}
DCHECK_NOT_NULL(tracker);
tracker->Add(buffer, std::make_pair(data, length));
tracker->Add(buffer);
}
// We may go over the limit of externally allocated memory here. We call the
// api function to trigger a GC in this case.
@ -37,30 +37,29 @@ void ArrayBufferTracker::Unregister(Heap* heap, JSArrayBuffer* buffer) {
if (!data) return;
Page* page = Page::FromAddress(buffer->address());
size_t length = 0;
size_t length = NumberToSize(heap->isolate(), buffer->byte_length());
{
base::LockGuard<base::Mutex> guard(page->mutex());
LocalArrayBufferTracker* tracker = page->local_tracker();
DCHECK_NOT_NULL(tracker);
length = tracker->Remove(buffer).second;
tracker->Remove(buffer);
}
heap->update_external_memory(-static_cast<intptr_t>(length));
}
void LocalArrayBufferTracker::Add(Key key, const Value& value) {
auto ret = array_buffers_.insert(std::make_pair(key, value));
void LocalArrayBufferTracker::Add(Key key) {
auto ret = array_buffers_.insert(key);
USE(ret);
// Check that we indeed inserted a new value and did not overwrite an existing
// one (which would be a bug).
DCHECK(ret.second);
}
LocalArrayBufferTracker::Value LocalArrayBufferTracker::Remove(Key key) {
TrackingMap::iterator it = array_buffers_.find(key);
void LocalArrayBufferTracker::Remove(Key key) {
TrackingData::iterator it = array_buffers_.find(key);
// Check that we indeed find a key to remove.
DCHECK(it != array_buffers_.end());
Value value = it->second;
array_buffers_.erase(it);
return value;
}
} // namespace internal

View File

@ -16,16 +16,18 @@ LocalArrayBufferTracker::~LocalArrayBufferTracker() {
template <LocalArrayBufferTracker::FreeMode free_mode>
void LocalArrayBufferTracker::Free() {
size_t freed_memory = 0;
for (TrackingMap::iterator it = array_buffers_.begin();
for (TrackingData::iterator it = array_buffers_.begin();
it != array_buffers_.end();) {
JSArrayBuffer* buffer = reinterpret_cast<JSArrayBuffer*>(*it);
if ((free_mode == kFreeAll) ||
Marking::IsWhite(Marking::MarkBitFrom(it->first))) {
heap_->isolate()->array_buffer_allocator()->Free(it->second.first,
it->second.second);
freed_memory += it->second.second;
Marking::IsWhite(Marking::MarkBitFrom(buffer))) {
const size_t len = NumberToSize(heap_->isolate(), buffer->byte_length());
heap_->isolate()->array_buffer_allocator()->Free(buffer->backing_store(),
len);
freed_memory += len;
it = array_buffers_.erase(it);
} else {
it++;
++it;
}
}
if (freed_memory > 0) {
@ -38,11 +40,11 @@ template <typename Callback>
void LocalArrayBufferTracker::Process(Callback callback) {
JSArrayBuffer* new_buffer = nullptr;
size_t freed_memory = 0;
for (TrackingMap::iterator it = array_buffers_.begin();
for (TrackingData::iterator it = array_buffers_.begin();
it != array_buffers_.end();) {
const CallbackResult result = callback(it->first, &new_buffer);
const CallbackResult result = callback(*it, &new_buffer);
if (result == kKeepEntry) {
it++;
++it;
} else if (result == kUpdateEntry) {
DCHECK_NOT_NULL(new_buffer);
Page* target_page = Page::FromAddress(new_buffer->address());
@ -55,13 +57,14 @@ void LocalArrayBufferTracker::Process(Callback callback) {
tracker = target_page->local_tracker();
}
DCHECK_NOT_NULL(tracker);
tracker->Add(new_buffer, it->second);
tracker->Add(new_buffer);
if (target_page->InNewSpace()) target_page->mutex()->Unlock();
it = array_buffers_.erase(it);
} else if (result == kRemoveEntry) {
heap_->isolate()->array_buffer_allocator()->Free(it->second.first,
it->second.second);
freed_memory += it->second.second;
const size_t len = NumberToSize(heap_->isolate(), (*it)->byte_length());
heap_->isolate()->array_buffer_allocator()->Free((*it)->backing_store(),
len);
freed_memory += len;
it = array_buffers_.erase(it);
} else {
UNREACHABLE();

View File

@ -5,7 +5,7 @@
#ifndef V8_HEAP_ARRAY_BUFFER_TRACKER_H_
#define V8_HEAP_ARRAY_BUFFER_TRACKER_H_
#include <unordered_map>
#include <unordered_set>
#include "src/allocation.h"
#include "src/base/platform/mutex.h"
@ -59,7 +59,6 @@ class ArrayBufferTracker : public AllStatic {
// Never use directly but instead always call through |ArrayBufferTracker|.
class LocalArrayBufferTracker {
public:
typedef std::pair<void*, size_t> Value;
typedef JSArrayBuffer* Key;
enum CallbackResult { kKeepEntry, kUpdateEntry, kRemoveEntry };
@ -68,8 +67,8 @@ class LocalArrayBufferTracker {
explicit LocalArrayBufferTracker(Heap* heap) : heap_(heap) {}
~LocalArrayBufferTracker();
inline void Add(Key key, const Value& value);
inline Value Remove(Key key);
inline void Add(Key key);
inline void Remove(Key key);
// Frees up array buffers determined by |free_mode|.
template <FreeMode free_mode>
@ -81,7 +80,7 @@ class LocalArrayBufferTracker {
// Callback should be of type:
// CallbackResult fn(JSArrayBuffer* buffer, JSArrayBuffer** new_buffer);
template <typename Callback>
inline void Process(Callback callback);
void Process(Callback callback);
bool IsEmpty() { return array_buffers_.empty(); }
@ -90,10 +89,10 @@ class LocalArrayBufferTracker {
}
private:
typedef std::unordered_map<Key, Value> TrackingMap;
typedef std::unordered_set<Key> TrackingData;
Heap* heap_;
TrackingMap array_buffers_;
TrackingData array_buffers_;
};
} // namespace internal