// Copyright 2016 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_TRACKER_INL_H_
|
#define V8_HEAP_ARRAY_BUFFER_TRACKER_INL_H_
|
|
#include "src/conversions-inl.h"
|
#include "src/heap/array-buffer-tracker.h"
|
#include "src/heap/heap.h"
|
#include "src/heap/spaces.h"
|
#include "src/objects.h"
|
#include "src/objects/js-array-buffer-inl.h"
|
|
namespace v8 {
|
namespace internal {
|
|
void ArrayBufferTracker::RegisterNew(Heap* heap, JSArrayBuffer* buffer) {
|
if (buffer->backing_store() == nullptr) return;
|
|
const size_t length = NumberToSize(buffer->byte_length());
|
Page* page = Page::FromAddress(buffer->address());
|
{
|
base::LockGuard<base::Mutex> guard(page->mutex());
|
LocalArrayBufferTracker* tracker = page->local_tracker();
|
if (tracker == nullptr) {
|
page->AllocateLocalTracker();
|
tracker = page->local_tracker();
|
}
|
DCHECK_NOT_NULL(tracker);
|
tracker->Add(buffer, length);
|
}
|
|
// TODO(wez): Remove backing-store from external memory accounting.
|
// We may go over the limit of externally allocated memory here. We call the
|
// api function to trigger a GC in this case.
|
reinterpret_cast<v8::Isolate*>(heap->isolate())
|
->AdjustAmountOfExternalAllocatedMemory(length);
|
}
|
|
void ArrayBufferTracker::Unregister(Heap* heap, JSArrayBuffer* buffer) {
|
if (buffer->backing_store() == nullptr) return;
|
|
Page* page = Page::FromAddress(buffer->address());
|
const size_t length = NumberToSize(buffer->byte_length());
|
{
|
base::LockGuard<base::Mutex> guard(page->mutex());
|
LocalArrayBufferTracker* tracker = page->local_tracker();
|
DCHECK_NOT_NULL(tracker);
|
tracker->Remove(buffer, length);
|
}
|
|
// TODO(wez): Remove backing-store from external memory accounting.
|
heap->update_external_memory(-static_cast<intptr_t>(length));
|
}
|
|
Space* LocalArrayBufferTracker::space() { return page_->owner(); }
|
|
template <typename Callback>
|
void LocalArrayBufferTracker::Free(Callback should_free) {
|
size_t freed_memory = 0;
|
Isolate* isolate = page_->heap()->isolate();
|
for (TrackingData::iterator it = array_buffers_.begin();
|
it != array_buffers_.end();) {
|
JSArrayBuffer* buffer = reinterpret_cast<JSArrayBuffer*>(it->first);
|
const size_t length = it->second.length;
|
|
if (should_free(buffer)) {
|
JSArrayBuffer::FreeBackingStore(isolate, it->second);
|
it = array_buffers_.erase(it);
|
freed_memory += length;
|
} else {
|
++it;
|
}
|
}
|
if (freed_memory > 0) {
|
page_->DecrementExternalBackingStoreBytes(
|
ExternalBackingStoreType::kArrayBuffer, freed_memory);
|
|
// TODO(wez): Remove backing-store from external memory accounting.
|
page_->heap()->update_external_memory_concurrently_freed(
|
static_cast<intptr_t>(freed_memory));
|
}
|
}
|
|
template <typename MarkingState>
|
void ArrayBufferTracker::FreeDead(Page* page, MarkingState* marking_state) {
|
// Callers need to ensure having the page lock.
|
LocalArrayBufferTracker* tracker = page->local_tracker();
|
if (tracker == nullptr) return;
|
tracker->Free([marking_state](JSArrayBuffer* buffer) {
|
return marking_state->IsWhite(buffer);
|
});
|
if (tracker->IsEmpty()) {
|
page->ReleaseLocalTracker();
|
}
|
}
|
|
void LocalArrayBufferTracker::Add(JSArrayBuffer* buffer, size_t length) {
|
page_->IncrementExternalBackingStoreBytes(
|
ExternalBackingStoreType::kArrayBuffer, length);
|
|
auto ret = array_buffers_.insert(
|
{buffer,
|
{buffer->backing_store(), length, buffer->backing_store(),
|
buffer->is_wasm_memory()}});
|
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);
|
}
|
|
void LocalArrayBufferTracker::Remove(JSArrayBuffer* buffer, size_t length) {
|
page_->DecrementExternalBackingStoreBytes(
|
ExternalBackingStoreType::kArrayBuffer, length);
|
|
TrackingData::iterator it = array_buffers_.find(buffer);
|
// Check that we indeed find a key to remove.
|
DCHECK(it != array_buffers_.end());
|
DCHECK_EQ(length, it->second.length);
|
array_buffers_.erase(it);
|
}
|
|
} // namespace internal
|
} // namespace v8
|
|
#endif // V8_HEAP_ARRAY_BUFFER_TRACKER_INL_H_
|