Commit 200dcb05 authored by Ben L. Titzer's avatar Ben L. Titzer Committed by Commit Bot

Add size estimate to Managed<T>

Extends the functionality of Managed<T> to track an estimated size
for the external memory associated with an instance of Managed<T>
in order to allow for proper accounting in the garbage collector.

R=mstarzinger@chromium.org
CC=ulan@chromium.org

Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: I8c49c6245eaf267c9264ebb93b43d5dfbf4671fd
Reviewed-on: https://chromium-review.googlesource.com/1076332
Commit-Queue: Ben Titzer <titzer@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53433}
parent 70b5fd3b
......@@ -952,7 +952,7 @@ bool Collator::InitializeCollator(Isolate* isolate,
}
Handle<Managed<icu::Collator>> managed =
Managed<icu::Collator>::FromRawPtr(isolate, collator);
Managed<icu::Collator>::FromRawPtr(isolate, 0, collator);
collator_holder->SetEmbedderField(0, *managed);
return true;
......
......@@ -13,8 +13,10 @@ namespace {
void ManagedObjectFinalizerSecondPass(const v8::WeakCallbackInfo<void>& data) {
auto destructor =
reinterpret_cast<ManagedPtrDestructor*>(data.GetParameter());
int64_t adjustment = 0 - static_cast<int64_t>(destructor->estimated_size_);
destructor->destructor_(destructor->shared_ptr_ptr_);
delete destructor;
data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(adjustment);
}
} // namespace
......
......@@ -16,14 +16,21 @@ namespace internal {
// Implements a doubly-linked lists of destructors for the isolate.
struct ManagedPtrDestructor {
// Estimated size of external memory associated with the managed object.
// This is used to adjust the garbage collector's heuristics upon
// allocation and deallocation of a managed object.
size_t estimated_size_ = 0;
ManagedPtrDestructor* prev_ = nullptr;
ManagedPtrDestructor* next_ = nullptr;
void* shared_ptr_ptr_ = nullptr;
void (*destructor_)(void* shared_ptr) = nullptr;
Object** global_handle_location_ = nullptr;
ManagedPtrDestructor(void* shared_ptr_ptr, void (*destructor)(void*))
: shared_ptr_ptr_(shared_ptr_ptr), destructor_(destructor) {}
ManagedPtrDestructor(size_t estimated_size, void* shared_ptr_ptr,
void (*destructor)(void*))
: estimated_size_(estimated_size),
shared_ptr_ptr_(shared_ptr_ptr),
destructor_(destructor) {}
};
// The GC finalizer of a managed object, which does not depend on
......@@ -53,30 +60,40 @@ class Managed : public Foreign {
// Allocate a new {CppType} and wrap it in a {Managed<CppType>}.
template <typename... Args>
static Handle<Managed<CppType>> Allocate(Isolate* isolate, Args&&... args) {
static Handle<Managed<CppType>> Allocate(Isolate* isolate,
size_t estimated_size,
Args&&... args) {
CppType* ptr = new CppType(std::forward<Args>(args)...);
return FromSharedPtr(isolate, std::shared_ptr<CppType>(ptr));
return FromSharedPtr(isolate, estimated_size,
std::shared_ptr<CppType>(ptr));
}
// Create a {Managed<CppType>} from an existing raw {CppType*}. The returned
// object will now own the memory pointed to by {CppType}.
static Handle<Managed<CppType>> FromRawPtr(Isolate* isolate, CppType* ptr) {
return FromSharedPtr(isolate, std::shared_ptr<CppType>(ptr));
static Handle<Managed<CppType>> FromRawPtr(Isolate* isolate,
size_t estimated_size,
CppType* ptr) {
return FromSharedPtr(isolate, estimated_size,
std::shared_ptr<CppType>(ptr));
}
// Create a {Managed<CppType>} from an existing {std::unique_ptr<CppType>}.
// The returned object will now own the memory pointed to by {CppType}, and
// the unique pointer will be released.
static Handle<Managed<CppType>> FromUniquePtr(
Isolate* isolate, std::unique_ptr<CppType> unique_ptr) {
return FromSharedPtr(isolate, std::move(unique_ptr));
Isolate* isolate, size_t estimated_size,
std::unique_ptr<CppType> unique_ptr) {
return FromSharedPtr(isolate, estimated_size, std::move(unique_ptr));
}
// Create a {Managed<CppType>} from an existing {std::shared_ptr<CppType>}.
static Handle<Managed<CppType>> FromSharedPtr(
Isolate* isolate, std::shared_ptr<CppType> shared_ptr) {
Isolate* isolate, size_t estimated_size,
std::shared_ptr<CppType> shared_ptr) {
reinterpret_cast<v8::Isolate*>(isolate)
->AdjustAmountOfExternalAllocatedMemory(estimated_size);
auto destructor = new ManagedPtrDestructor(
new std::shared_ptr<CppType>(shared_ptr), Destructor);
estimated_size, new std::shared_ptr<CppType>(shared_ptr), Destructor);
Handle<Managed<CppType>> handle = Handle<Managed<CppType>>::cast(
isolate->factory()->NewForeign(reinterpret_cast<Address>(destructor)));
Handle<Object> global_handle = isolate->global_handles()->Create(*handle);
......
......@@ -849,7 +849,7 @@ Address CompileLazy(Isolate* isolate,
if (indirectly_called) {
DCHECK(!caller_instance.is_null());
if (!caller_instance->has_managed_indirect_patcher()) {
auto patcher = Managed<IndirectPatcher>::Allocate(isolate);
auto patcher = Managed<IndirectPatcher>::Allocate(isolate, 0);
caller_instance->set_managed_indirect_patcher(*patcher);
}
IndirectPatcher* patcher = Managed<IndirectPatcher>::cast(
......@@ -1332,8 +1332,10 @@ MaybeHandle<WasmModuleObject> CompileToModuleObjectInternal(
// The {managed_module} will take ownership of the {WasmModule} object,
// and it will be destroyed when the GC reclaims the wrapper object.
size_t module_size = 0; // TODO(titzer): estimate size of decoded module.
Handle<Managed<WasmModule>> managed_module =
Managed<WasmModule>::FromUniquePtr(isolate, std::move(module));
Managed<WasmModule>::FromUniquePtr(isolate, module_size,
std::move(module));
// Create the shared module data.
// TODO(clemensh): For the same module (same bytes / same hash), we should
......@@ -2830,8 +2832,10 @@ void AsyncCompileJob::FinishCompile() {
// The {managed_module} will take ownership of the {WasmModule} object,
// and it will be destroyed when the GC reclaims the wrapper object.
size_t module_size = 0; // TODO(titzer): estimate size of decoded module.
Handle<Managed<WasmModule>> managed_module =
Managed<WasmModule>::FromUniquePtr(isolate_, std::move(module_));
Managed<WasmModule>::FromUniquePtr(isolate_, module_size,
std::move(module_));
// Create the shared module data.
// TODO(clemensh): For the same module (same bytes / same hash), we should
......
......@@ -533,8 +533,9 @@ wasm::InterpreterHandle* GetOrCreateInterpreterHandle(
Isolate* isolate, Handle<WasmDebugInfo> debug_info) {
Handle<Object> handle(debug_info->interpreter_handle(), isolate);
if (handle->IsUndefined(isolate)) {
handle = Managed<wasm::InterpreterHandle>::Allocate(isolate, isolate,
*debug_info);
size_t interpreter_size = 0; // TODO(titzer): estimate size properly.
handle = Managed<wasm::InterpreterHandle>::Allocate(
isolate, interpreter_size, isolate, *debug_info);
debug_info->set_interpreter_handle(*handle);
}
......@@ -633,8 +634,9 @@ wasm::WasmInterpreter* WasmDebugInfo::SetupForTesting(
Handle<WasmInstanceObject> instance_obj) {
Handle<WasmDebugInfo> debug_info = WasmDebugInfo::New(instance_obj);
Isolate* isolate = instance_obj->GetIsolate();
auto interp_handle =
Managed<wasm::InterpreterHandle>::Allocate(isolate, isolate, *debug_info);
size_t interpreter_size = 0; // TODO(titzer): estimate size properly.
auto interp_handle = Managed<wasm::InterpreterHandle>::Allocate(
isolate, interpreter_size, isolate, *debug_info);
debug_info->set_interpreter_handle(*interp_handle);
auto ret = interp_handle->raw()->interpreter();
ret->SetCallIndirectTestMode();
......@@ -753,7 +755,8 @@ Handle<JSFunction> WasmDebugInfo::GetCWasmEntry(
if (!debug_info->has_c_wasm_entries()) {
auto entries = isolate->factory()->NewFixedArray(4, TENURED);
debug_info->set_c_wasm_entries(*entries);
auto managed_map = Managed<wasm::SignatureMap>::Allocate(isolate);
size_t map_size = 0; // size estimate not so important here.
auto managed_map = Managed<wasm::SignatureMap>::Allocate(isolate, map_size);
debug_info->set_c_wasm_entry_map(*managed_map);
}
Handle<FixedArray> entries(debug_info->c_wasm_entries(), isolate);
......
......@@ -782,8 +782,10 @@ Handle<WasmInstanceObject> WasmInstanceObject::New(
module_object->shared()->module()->num_imported_functions;
auto num_imported_mutable_globals =
module_object->shared()->module()->num_imported_mutable_globals;
size_t native_allocations_size = 0; // TODO(titzer): estimate properly.
auto native_allocations = Managed<WasmInstanceNativeAllocations>::Allocate(
isolate, instance, num_imported_functions, num_imported_mutable_globals);
isolate, native_allocations_size, instance, num_imported_functions,
num_imported_mutable_globals);
instance->set_managed_native_allocations(*native_allocations);
Handle<FixedArray> imported_function_instances =
......@@ -1357,8 +1359,10 @@ Handle<WasmCompiledModule> WasmCompiledModule::New(Isolate* isolate,
{
auto native_module =
isolate->wasm_engine()->code_manager()->NewNativeModule(*module, env);
size_t native_module_size =
0; // TODO(titzer): estimate native module size.
Handle<Foreign> native_module_wrapper =
Managed<wasm::NativeModule>::FromUniquePtr(isolate,
Managed<wasm::NativeModule>::FromUniquePtr(isolate, native_module_size,
std::move(native_module));
compiled_module->set_native_module(*native_module_wrapper);
}
......@@ -1378,9 +1382,10 @@ Handle<WasmCompiledModule> WasmCompiledModule::Clone(
// construct the wrapper in 2 steps, because its construction may trigger GC,
// which would shift the this pointer in set_native_module.
size_t native_module_size = 0;
Handle<Foreign> native_module_wrapper =
Managed<wasm::NativeModule>::FromSharedPtr(
isolate,
isolate, native_module_size,
Managed<wasm::NativeModule>::cast(module->native_module())->get());
ret->set_native_module(*native_module_wrapper);
......
......@@ -552,8 +552,10 @@ MaybeHandle<WasmModuleObject> DeserializeNativeModule(
DCHECK(module_bytes->IsSeqOneByteString());
// The {managed_module} will take ownership of the {WasmModule} object,
// and it will be destroyed when the GC reclaims the wrapper object.
size_t module_size = 0; // TODO(titzer): estimate size properly.
Handle<Managed<WasmModule>> managed_module =
Managed<WasmModule>::FromUniquePtr(isolate, std::move(decode_result.val));
Managed<WasmModule>::FromUniquePtr(isolate, module_size,
std::move(decode_result.val));
Handle<Script> script = CreateWasmScript(isolate, wire_bytes);
Handle<WasmSharedModuleData> shared = WasmSharedModuleData::New(
isolate, managed_module, Handle<SeqOneByteString>::cast(module_bytes),
......
......@@ -34,7 +34,7 @@ TEST(GCCausesDestruction) {
DeleteCounter* d2 = new DeleteCounter(&deleted2);
{
HandleScope scope(isolate);
auto handle = Managed<DeleteCounter>::FromRawPtr(isolate, d1);
auto handle = Managed<DeleteCounter>::FromRawPtr(isolate, 0, d1);
USE(handle);
}
......@@ -58,7 +58,7 @@ TEST(DisposeCausesDestruction1) {
DeleteCounter* d1 = new DeleteCounter(&deleted1);
{
HandleScope scope(i_isolate);
auto handle = Managed<DeleteCounter>::FromRawPtr(i_isolate, d1);
auto handle = Managed<DeleteCounter>::FromRawPtr(i_isolate, 0, d1);
USE(handle);
}
isolate->Exit();
......@@ -80,11 +80,11 @@ TEST(DisposeCausesDestruction2) {
DeleteCounter* d2 = new DeleteCounter(&deleted2);
{
HandleScope scope(i_isolate);
auto handle = Managed<DeleteCounter>::FromRawPtr(i_isolate, d1);
auto handle = Managed<DeleteCounter>::FromRawPtr(i_isolate, 0, d1);
USE(handle);
}
ManagedPtrDestructor* destructor =
new ManagedPtrDestructor(d2, DeleteCounter::Deleter);
new ManagedPtrDestructor(0, d2, DeleteCounter::Deleter);
i_isolate->RegisterManagedPtrDestructor(destructor);
isolate->Exit();
......@@ -107,7 +107,8 @@ TEST(DisposeWithAnotherSharedPtr) {
std::shared_ptr<DeleteCounter> shared1(d1);
{
HandleScope scope(i_isolate);
auto handle = Managed<DeleteCounter>::FromSharedPtr(i_isolate, shared1);
auto handle =
Managed<DeleteCounter>::FromSharedPtr(i_isolate, 0, shared1);
USE(handle);
}
isolate->Exit();
......@@ -132,7 +133,7 @@ TEST(DisposeAcrossIsolates) {
{
HandleScope scope1(i_isolate1);
auto handle1 =
Managed<DeleteCounter>::FromRawPtr(i_isolate1, delete_counter);
Managed<DeleteCounter>::FromRawPtr(i_isolate1, 0, delete_counter);
v8::Isolate* isolate2 = v8::Isolate::New(create_params);
Isolate* i_isolate2 = reinterpret_cast<i::Isolate*>(isolate2);
......@@ -140,7 +141,7 @@ TEST(DisposeAcrossIsolates) {
{
HandleScope scope(i_isolate2);
auto handle2 =
Managed<DeleteCounter>::FromSharedPtr(i_isolate2, handle1->get());
Managed<DeleteCounter>::FromSharedPtr(i_isolate2, 0, handle1->get());
USE(handle2);
}
isolate2->Exit();
......@@ -167,7 +168,7 @@ TEST(CollectAcrossIsolates) {
{
HandleScope scope1(i_isolate1);
auto handle1 =
Managed<DeleteCounter>::FromRawPtr(i_isolate1, delete_counter);
Managed<DeleteCounter>::FromRawPtr(i_isolate1, 0, delete_counter);
v8::Isolate* isolate2 = v8::Isolate::New(create_params);
Isolate* i_isolate2 = reinterpret_cast<i::Isolate*>(isolate2);
......@@ -175,7 +176,7 @@ TEST(CollectAcrossIsolates) {
{
HandleScope scope(i_isolate2);
auto handle2 =
Managed<DeleteCounter>::FromSharedPtr(i_isolate2, handle1->get());
Managed<DeleteCounter>::FromSharedPtr(i_isolate2, 0, handle1->get());
USE(handle2);
}
i_isolate2->heap()->CollectAllAvailableGarbage(
......
......@@ -210,8 +210,9 @@ const WasmGlobal* TestingModuleBuilder::AddGlobal(ValueType type) {
Handle<WasmInstanceObject> TestingModuleBuilder::InitInstanceObject() {
Handle<SeqOneByteString> empty_string = Handle<SeqOneByteString>::cast(
isolate_->factory()->NewStringFromOneByte({}).ToHandleChecked());
size_t module_size = 0;
auto managed_module =
Managed<WasmModule>::FromSharedPtr(isolate_, test_module_);
Managed<WasmModule>::FromSharedPtr(isolate_, module_size, test_module_);
DCHECK_EQ(test_module_ptr_, managed_module->raw());
Handle<Script> script =
isolate_->factory()->NewScript(isolate_->factory()->empty_string());
......
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