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

[wasm] Implement Managed<T> with std::shared_ptr<T>

This CL simplifies and extends the implementation of Managed<T>
and now uses a std::shared_ptr<T> underneath in order to offer
cross-isolate management of C++ allocated memory.

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

Bug: v8:7424
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: Id43a26f565677e8c9cdfd73810568d4f2b1871fe
Reviewed-on: https://chromium-review.googlesource.com/1028190Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Ben Titzer <titzer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52820}
parent 3f99a376
...@@ -1994,7 +1994,6 @@ v8_source_set("v8_base") { ...@@ -1994,7 +1994,6 @@ v8_source_set("v8_base") {
"src/machine-type.h", "src/machine-type.h",
"src/macro-assembler-inl.h", "src/macro-assembler-inl.h",
"src/macro-assembler.h", "src/macro-assembler.h",
"src/managed.h",
"src/map-updater.cc", "src/map-updater.cc",
"src/map-updater.h", "src/map-updater.h",
"src/messages.cc", "src/messages.cc",
...@@ -2041,6 +2040,8 @@ v8_source_set("v8_base") { ...@@ -2041,6 +2040,8 @@ v8_source_set("v8_base") {
"src/objects/literal-objects-inl.h", "src/objects/literal-objects-inl.h",
"src/objects/literal-objects.cc", "src/objects/literal-objects.cc",
"src/objects/literal-objects.h", "src/objects/literal-objects.h",
"src/objects/managed.cc",
"src/objects/managed.h",
"src/objects/map-inl.h", "src/objects/map-inl.h",
"src/objects/map.h", "src/objects/map.h",
"src/objects/maybe-object-inl.h", "src/objects/maybe-object-inl.h",
......
...@@ -2303,43 +2303,39 @@ Isolate::ThreadDataTable::ThreadDataTable() : table_() {} ...@@ -2303,43 +2303,39 @@ Isolate::ThreadDataTable::ThreadDataTable() : table_() {}
Isolate::ThreadDataTable::~ThreadDataTable() {} Isolate::ThreadDataTable::~ThreadDataTable() {}
void Isolate::ReleaseManagedObjects() { void Isolate::ReleaseSharedPtrs() {
Isolate::ManagedObjectFinalizer* current = while (managed_ptr_destructors_head_) {
managed_object_finalizers_list_.next_; ManagedPtrDestructor* l = managed_ptr_destructors_head_;
managed_object_finalizers_list_.next_ = nullptr; ManagedPtrDestructor* n = nullptr;
while (current != nullptr) { managed_ptr_destructors_head_ = nullptr;
Isolate::ManagedObjectFinalizer* next = current->next_; for (; l != nullptr; l = n) {
current->Dispose(); l->destructor_(l->shared_ptr_ptr_);
current = next; n = l->next_;
delete l;
}
} }
// No new managed objects should pop up during finalization.
DCHECK_NULL(managed_object_finalizers_list_.next_);
} }
void Isolate::RegisterForReleaseAtTeardown( void Isolate::RegisterManagedPtrDestructor(ManagedPtrDestructor* destructor) {
Isolate::ManagedObjectFinalizer* finalizer) { DCHECK_NULL(destructor->prev_);
DCHECK_NOT_NULL(finalizer->value_); DCHECK_NULL(destructor->next_);
DCHECK_NOT_NULL(finalizer->deleter_); if (managed_ptr_destructors_head_) {
DCHECK_NULL(finalizer->prev_); managed_ptr_destructors_head_->prev_ = destructor;
DCHECK_NULL(finalizer->next_); }
destructor->next_ = managed_ptr_destructors_head_;
// Insert at head. We keep the head alive for the lifetime of the Isolate managed_ptr_destructors_head_ = destructor;
// because otherwise we can't reset the head, should we delete it before
// the isolate expires
Isolate::ManagedObjectFinalizer* next = managed_object_finalizers_list_.next_;
managed_object_finalizers_list_.next_ = finalizer;
finalizer->prev_ = &managed_object_finalizers_list_;
finalizer->next_ = next;
if (next != nullptr) next->prev_ = finalizer;
} }
void Isolate::UnregisterFromReleaseAtTeardown( void Isolate::UnregisterManagedPtrDestructor(ManagedPtrDestructor* destructor) {
Isolate::ManagedObjectFinalizer* finalizer) { if (destructor->prev_) {
DCHECK_NOT_NULL(finalizer); destructor->prev_->next_ = destructor->next_;
DCHECK_NOT_NULL(finalizer->prev_); } else {
DCHECK_EQ(destructor, managed_ptr_destructors_head_);
finalizer->prev_->next_ = finalizer->next_; managed_ptr_destructors_head_ = destructor->next_;
if (finalizer->next_ != nullptr) finalizer->next_->prev_ = finalizer->prev_; }
if (destructor->next_) destructor->next_->prev_ = destructor->prev_;
destructor->prev_ = nullptr;
destructor->next_ = nullptr;
} }
Isolate::PerIsolateThreadData::~PerIsolateThreadData() { Isolate::PerIsolateThreadData::~PerIsolateThreadData() {
...@@ -2662,9 +2658,8 @@ void Isolate::Deinit() { ...@@ -2662,9 +2658,8 @@ void Isolate::Deinit() {
// We start with the heap tear down so that releasing managed objects does // We start with the heap tear down so that releasing managed objects does
// not cause a GC. // not cause a GC.
heap_.StartTearDown(); heap_.StartTearDown();
// Release managed objects before shutting down the heap. The finalizer might
// need to access heap objects. ReleaseSharedPtrs();
ReleaseManagedObjects();
delete deoptimizer_data_; delete deoptimizer_data_;
deoptimizer_data_ = nullptr; deoptimizer_data_ = nullptr;
......
...@@ -103,6 +103,7 @@ class ThreadState; ...@@ -103,6 +103,7 @@ class ThreadState;
class ThreadVisitor; // Defined in v8threads.h class ThreadVisitor; // Defined in v8threads.h
class TracingCpuProfilerImpl; class TracingCpuProfilerImpl;
class UnicodeCache; class UnicodeCache;
struct ManagedPtrDestructor;
template <StateTag Tag> class VMState; template <StateTag Tag> class VMState;
...@@ -550,7 +551,7 @@ class Isolate : private HiddenFactory { ...@@ -550,7 +551,7 @@ class Isolate : private HiddenFactory {
// for legacy API reasons. // for legacy API reasons.
void TearDown(); void TearDown();
void ReleaseManagedObjects(); void ReleaseSharedPtrs();
void ClearSerializerData(); void ClearSerializerData();
...@@ -1350,41 +1351,11 @@ class Isolate : private HiddenFactory { ...@@ -1350,41 +1351,11 @@ class Isolate : private HiddenFactory {
void set_allow_atomics_wait(bool set) { allow_atomics_wait_ = set; } void set_allow_atomics_wait(bool set) { allow_atomics_wait_ = set; }
bool allow_atomics_wait() { return allow_atomics_wait_; } bool allow_atomics_wait() { return allow_atomics_wait_; }
// List of native heap values allocated by the runtime as part of its
// implementation that must be freed at isolate deinit.
class ManagedObjectFinalizer {
public:
using Deleter = void (*)(ManagedObjectFinalizer*);
ManagedObjectFinalizer(void* value, Deleter deleter)
: value_(value), deleter_(deleter) {}
void Dispose() { deleter_(this); }
void* value() const { return value_; }
private:
friend class Isolate;
ManagedObjectFinalizer() = default;
void* value_ = nullptr;
Deleter deleter_ = nullptr;
ManagedObjectFinalizer* prev_ = nullptr;
ManagedObjectFinalizer* next_ = nullptr;
};
static_assert(offsetof(ManagedObjectFinalizer, value_) == 0,
"value_ must be the first member");
// Register a finalizer to be called at isolate teardown. // Register a finalizer to be called at isolate teardown.
void RegisterForReleaseAtTeardown(ManagedObjectFinalizer*); void RegisterManagedPtrDestructor(ManagedPtrDestructor* finalizer);
// Unregister a previously registered value from release at // Removes a previously-registered shared object finalizer.
// isolate teardown. void UnregisterManagedPtrDestructor(ManagedPtrDestructor* finalizer);
// This transfers the responsibility of the previously managed value's
// deletion to the caller.
void UnregisterFromReleaseAtTeardown(ManagedObjectFinalizer*);
size_t elements_deletion_counter() { return elements_deletion_counter_; } size_t elements_deletion_counter() { return elements_deletion_counter_; }
void set_elements_deletion_counter(size_t value) { void set_elements_deletion_counter(size_t value) {
...@@ -1698,7 +1669,7 @@ class Isolate : private HiddenFactory { ...@@ -1698,7 +1669,7 @@ class Isolate : private HiddenFactory {
bool allow_atomics_wait_; bool allow_atomics_wait_;
ManagedObjectFinalizer managed_object_finalizers_list_; ManagedPtrDestructor* managed_ptr_destructors_head_ = nullptr;
size_t total_regexp_code_generated_; size_t total_regexp_code_generated_;
......
// 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_MANAGED_H_
#define V8_MANAGED_H_
#include "src/global-handles.h"
#include "src/handles.h"
#include "src/heap/factory.h"
#include "src/isolate.h"
namespace v8 {
namespace internal {
// An object that wraps a pointer to a C++ object and manages its lifetime.
// The C++ object will be deleted when the managed wrapper object is
// garbage collected, or, last resort, if the isolate is torn down before GC,
// as part of Isolate::Dispose().
// Managed<CppType> may be used polymorphically as Foreign, where the held
// address is typed as CppType**. The double indirection is due to the
// use, by Managed, of Isolate::ManagedObjectFinalizer, which has a CppType*
// first field.
// Calling Foreign::set_foreign_address is not allowed on a Managed object.
template <class CppType>
class Managed : public Foreign {
class FinalizerWithHandle : public Isolate::ManagedObjectFinalizer {
public:
FinalizerWithHandle(void* value,
Isolate::ManagedObjectFinalizer::Deleter deleter)
: Isolate::ManagedObjectFinalizer(value, deleter) {}
Object** global_handle_location;
};
public:
V8_INLINE CppType* get() {
return reinterpret_cast<CppType*>(GetFinalizer()->value());
}
static Managed<CppType>* cast(Object* obj) {
SLOW_DCHECK(obj->IsForeign());
return reinterpret_cast<Managed<CppType>*>(obj);
}
// Allocate a new CppType and wrap it in a Managed.
template <typename... Args>
static Handle<Managed<CppType>> Allocate(Isolate* isolate, Args&&... args) {
CppType* ptr = new CppType(std::forward<Args>(args)...);
return From(isolate, ptr);
}
// Create a Managed from an existing CppType*. Takes ownership of the passed
// object.
static Handle<Managed<CppType>> From(Isolate* isolate, CppType* ptr) {
FinalizerWithHandle* finalizer =
new FinalizerWithHandle(ptr, &NativeDelete);
isolate->RegisterForReleaseAtTeardown(finalizer);
Handle<Managed<CppType>> handle = Handle<Managed<CppType>>::cast(
isolate->factory()->NewForeign(reinterpret_cast<Address>(finalizer)));
Handle<Object> global_handle = isolate->global_handles()->Create(*handle);
finalizer->global_handle_location = global_handle.location();
GlobalHandles::MakeWeak(
finalizer->global_handle_location, handle->GetFinalizer(),
&ResetWeakAndScheduleGCDelete, v8::WeakCallbackType::kParameter);
return handle;
}
private:
static void ResetWeakAndScheduleGCDelete(
const v8::WeakCallbackInfo<void>& data) {
FinalizerWithHandle* finalizer =
reinterpret_cast<FinalizerWithHandle*>(data.GetParameter());
GlobalHandles::Destroy(finalizer->global_handle_location);
Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate());
isolate->UnregisterFromReleaseAtTeardown(finalizer);
// We need to call GCDelete as a second pass callback because
// it can trigger garbage collection. The first pass callbacks
// are not allowed to invoke V8 API.
data.SetSecondPassCallback(&GCDelete);
}
static void GCDelete(const v8::WeakCallbackInfo<void>& data) {
FinalizerWithHandle* finalizer =
reinterpret_cast<FinalizerWithHandle*>(data.GetParameter());
NativeDelete(finalizer);
}
static void NativeDelete(Isolate::ManagedObjectFinalizer* finalizer) {
CppType* typed_value = reinterpret_cast<CppType*>(finalizer->value());
delete typed_value;
FinalizerWithHandle* finalizer_with_handle =
static_cast<FinalizerWithHandle*>(finalizer);
delete finalizer_with_handle;
}
FinalizerWithHandle* GetFinalizer() {
return reinterpret_cast<FinalizerWithHandle*>(foreign_address());
}
};
} // namespace internal
} // namespace v8
#endif // V8_MANAGED_H_
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
#include "src/global-handles.h" #include "src/global-handles.h"
#include "src/heap/factory.h" #include "src/heap/factory.h"
#include "src/isolate.h" #include "src/isolate.h"
#include "src/managed.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/objects/managed.h"
#include "src/property-descriptor.h" #include "src/property-descriptor.h"
#include "unicode/brkiter.h" #include "unicode/brkiter.h"
#include "unicode/bytestream.h" #include "unicode/bytestream.h"
...@@ -952,7 +952,7 @@ bool Collator::InitializeCollator(Isolate* isolate, ...@@ -952,7 +952,7 @@ bool Collator::InitializeCollator(Isolate* isolate,
} }
Handle<Managed<icu::Collator>> managed = Handle<Managed<icu::Collator>> managed =
Managed<icu::Collator>::From(isolate, collator); Managed<icu::Collator>::FromRawPtr(isolate, collator);
collator_holder->SetEmbedderField(0, *managed); collator_holder->SetEmbedderField(0, *managed);
return true; return true;
...@@ -960,7 +960,7 @@ bool Collator::InitializeCollator(Isolate* isolate, ...@@ -960,7 +960,7 @@ bool Collator::InitializeCollator(Isolate* isolate,
icu::Collator* Collator::UnpackCollator(Isolate* isolate, icu::Collator* Collator::UnpackCollator(Isolate* isolate,
Handle<JSObject> obj) { Handle<JSObject> obj) {
return Managed<icu::Collator>::cast(obj->GetEmbedderField(0))->get(); return Managed<icu::Collator>::cast(obj->GetEmbedderField(0))->raw();
} }
bool PluralRules::InitializePluralRules(Isolate* isolate, Handle<String> locale, bool PluralRules::InitializePluralRules(Isolate* isolate, Handle<String> locale,
......
// Copyright 2018 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/objects/managed.h"
namespace v8 {
namespace internal {
namespace {
// Called by the GC in its second pass when a Managed<CppType> is
// garbage collected.
void ManagedObjectFinalizerSecondPass(const v8::WeakCallbackInfo<void>& data) {
auto destructor =
reinterpret_cast<ManagedPtrDestructor*>(data.GetParameter());
destructor->destructor_(destructor->shared_ptr_ptr_);
delete destructor;
}
} // namespace
// Called by the GC in its first pass when a Managed<CppType> is
// garbage collected.
void ManagedObjectFinalizer(const v8::WeakCallbackInfo<void>& data) {
auto destructor =
reinterpret_cast<ManagedPtrDestructor*>(data.GetParameter());
GlobalHandles::Destroy(destructor->global_handle_location_);
Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate());
isolate->UnregisterManagedPtrDestructor(destructor);
// We need to do the main work as a second pass callback because
// it can trigger garbage collection. The first pass callbacks
// are not allowed to invoke V8 API.
data.SetSecondPassCallback(&ManagedObjectFinalizerSecondPass);
}
} // namespace internal
} // namespace v8
// 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_OBJECTS_MANAGED_H_
#define V8_OBJECTS_MANAGED_H_
#include <memory>
#include "src/global-handles.h"
#include "src/handles.h"
#include "src/heap/factory.h"
#include "src/isolate.h"
namespace v8 {
namespace internal {
// Implements a doubly-linked lists of destructors for the isolate.
struct ManagedPtrDestructor {
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) {}
};
// The GC finalizer of a managed object, which does not depend on
// the template parameter.
void ManagedObjectFinalizer(const v8::WeakCallbackInfo<void>& data);
// {Managed<T>} is essentially a {std::shared_ptr<T>} allocated on the heap
// that can be used to manage the lifetime of C++ objects that are shared
// across multiple isolates.
// When a {Managed<T>} object is garbage collected (or an isolate which
// contains {Managed<T>} is torn down), the {Managed<T>} deletes its underlying
// {std::shared_ptr<T>}, thereby decrementing its internal reference count,
// which will delete the C++ object when the reference count drops to 0.
template <class CppType>
class Managed : public Foreign {
public:
// Get a raw pointer to the C++ object.
V8_INLINE CppType* raw() { return GetSharedPtrPtr()->get(); }
// Get a copy of the shared pointer to the C++ object.
V8_INLINE std::shared_ptr<CppType> get() { return *GetSharedPtrPtr(); }
static Managed<CppType>* cast(Object* obj) {
SLOW_DCHECK(obj->IsForeign());
return reinterpret_cast<Managed<CppType>*>(obj);
}
// Allocate a new {CppType} and wrap it in a {Managed<CppType>}.
template <typename... Args>
static Handle<Managed<CppType>> Allocate(Isolate* isolate, Args&&... args) {
CppType* ptr = new CppType(std::forward<Args>(args)...);
return FromSharedPtr(isolate, 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));
}
// 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));
}
// Create a {Managed<CppType>} from an existing {std::shared_ptr<CppType>}.
static Handle<Managed<CppType>> FromSharedPtr(
Isolate* isolate, std::shared_ptr<CppType> shared_ptr) {
auto destructor = new ManagedPtrDestructor(
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);
destructor->global_handle_location_ = global_handle.location();
GlobalHandles::MakeWeak(destructor->global_handle_location_, destructor,
&ManagedObjectFinalizer,
v8::WeakCallbackType::kParameter);
isolate->RegisterManagedPtrDestructor(destructor);
return handle;
}
private:
// Internally this {Foreign} object stores a pointer to a new
// std::shared_ptr<CppType>.
std::shared_ptr<CppType>* GetSharedPtrPtr() {
auto destructor =
reinterpret_cast<ManagedPtrDestructor*>(foreign_address());
return reinterpret_cast<std::shared_ptr<CppType>*>(
destructor->shared_ptr_ptr_);
}
// Called by either isolate shutdown or the {ManagedObjectFinalizer} in
// order to actually delete the shared pointer (i.e. decrement its refcount).
static void Destructor(void* ptr) {
auto shared_ptr_ptr = reinterpret_cast<std::shared_ptr<CppType>*>(ptr);
delete shared_ptr_ptr;
}
};
} // namespace internal
} // namespace v8
#endif // V8_OBJECTS_MANAGED_H_
...@@ -861,7 +861,7 @@ Address CompileLazy(Isolate* isolate, ...@@ -861,7 +861,7 @@ Address CompileLazy(Isolate* isolate,
} }
IndirectPatcher* patcher = Managed<IndirectPatcher>::cast( IndirectPatcher* patcher = Managed<IndirectPatcher>::cast(
caller_instance->managed_indirect_patcher()) caller_instance->managed_indirect_patcher())
->get(); ->raw();
Address old_target = lazy_stub->instruction_start(); Address old_target = lazy_stub->instruction_start();
patcher->Patch(*caller_instance, *target_instance, target_func_index, patcher->Patch(*caller_instance, *target_instance, target_func_index,
old_target, result); old_target, result);
...@@ -1378,7 +1378,7 @@ MaybeHandle<WasmModuleObject> CompileToModuleObjectInternal( ...@@ -1378,7 +1378,7 @@ MaybeHandle<WasmModuleObject> CompileToModuleObjectInternal(
// The {module_wrapper} will take ownership of the {WasmModule} object, // The {module_wrapper} will take ownership of the {WasmModule} object,
// and it will be destroyed when the GC reclaims the wrapper object. // and it will be destroyed when the GC reclaims the wrapper object.
Handle<WasmModuleWrapper> module_wrapper = Handle<WasmModuleWrapper> module_wrapper =
WasmModuleWrapper::From(isolate, module.release()); WasmModuleWrapper::FromUniquePtr(isolate, std::move(module));
// Create the shared module data. // Create the shared module data.
// TODO(clemensh): For the same module (same bytes / same hash), we should // TODO(clemensh): For the same module (same bytes / same hash), we should
...@@ -2867,8 +2867,8 @@ void AsyncCompileJob::FinishCompile() { ...@@ -2867,8 +2867,8 @@ void AsyncCompileJob::FinishCompile() {
// The {module_wrapper} will take ownership of the {WasmModule} object, // The {module_wrapper} will take ownership of the {WasmModule} object,
// and it will be destroyed when the GC reclaims the wrapper object. // and it will be destroyed when the GC reclaims the wrapper object.
Handle<WasmModuleWrapper> module_wrapper = Handle<Managed<WasmModule>> module_wrapper =
WasmModuleWrapper::From(isolate_, module_.release()); Managed<WasmModule>::FromUniquePtr(isolate_, std::move(module_));
// Create the shared module data. // Create the shared module data.
// TODO(clemensh): For the same module (same bytes / same hash), we should // TODO(clemensh): For the same module (same bytes / same hash), we should
......
...@@ -293,7 +293,7 @@ class InterpreterHandle { ...@@ -293,7 +293,7 @@ class InterpreterHandle {
// interpreter. // interpreter.
DCHECK_EQ(this, Managed<wasm::InterpreterHandle>::cast( DCHECK_EQ(this, Managed<wasm::InterpreterHandle>::cast(
instance_obj->debug_info()->interpreter_handle()) instance_obj->debug_info()->interpreter_handle())
->get()); ->raw());
return instance_obj; return instance_obj;
} }
...@@ -539,19 +539,19 @@ wasm::InterpreterHandle* GetOrCreateInterpreterHandle( ...@@ -539,19 +539,19 @@ wasm::InterpreterHandle* GetOrCreateInterpreterHandle(
debug_info->set_interpreter_handle(*handle); debug_info->set_interpreter_handle(*handle);
} }
return Handle<Managed<wasm::InterpreterHandle>>::cast(handle)->get(); return Handle<Managed<wasm::InterpreterHandle>>::cast(handle)->raw();
} }
wasm::InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info) { wasm::InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info) {
Object* handle_obj = debug_info->interpreter_handle(); Object* handle_obj = debug_info->interpreter_handle();
DCHECK(!handle_obj->IsUndefined(debug_info->GetIsolate())); DCHECK(!handle_obj->IsUndefined(debug_info->GetIsolate()));
return Managed<wasm::InterpreterHandle>::cast(handle_obj)->get(); return Managed<wasm::InterpreterHandle>::cast(handle_obj)->raw();
} }
wasm::InterpreterHandle* GetInterpreterHandleOrNull(WasmDebugInfo* debug_info) { wasm::InterpreterHandle* GetInterpreterHandleOrNull(WasmDebugInfo* debug_info) {
Object* handle_obj = debug_info->interpreter_handle(); Object* handle_obj = debug_info->interpreter_handle();
if (handle_obj->IsUndefined(debug_info->GetIsolate())) return nullptr; if (handle_obj->IsUndefined(debug_info->GetIsolate())) return nullptr;
return Managed<wasm::InterpreterHandle>::cast(handle_obj)->get(); return Managed<wasm::InterpreterHandle>::cast(handle_obj)->raw();
} }
int GetNumFunctions(WasmInstanceObject* instance) { int GetNumFunctions(WasmInstanceObject* instance) {
...@@ -638,7 +638,7 @@ wasm::WasmInterpreter* WasmDebugInfo::SetupForTesting( ...@@ -638,7 +638,7 @@ wasm::WasmInterpreter* WasmDebugInfo::SetupForTesting(
auto interp_handle = auto interp_handle =
Managed<wasm::InterpreterHandle>::Allocate(isolate, isolate, *debug_info); Managed<wasm::InterpreterHandle>::Allocate(isolate, isolate, *debug_info);
debug_info->set_interpreter_handle(*interp_handle); debug_info->set_interpreter_handle(*interp_handle);
auto ret = interp_handle->get()->interpreter(); auto ret = interp_handle->raw()->interpreter();
ret->SetCallIndirectTestMode(); ret->SetCallIndirectTestMode();
return ret; return ret;
} }
...@@ -759,7 +759,7 @@ Handle<JSFunction> WasmDebugInfo::GetCWasmEntry( ...@@ -759,7 +759,7 @@ Handle<JSFunction> WasmDebugInfo::GetCWasmEntry(
debug_info->set_c_wasm_entry_map(*managed_map); debug_info->set_c_wasm_entry_map(*managed_map);
} }
Handle<FixedArray> entries(debug_info->c_wasm_entries(), isolate); Handle<FixedArray> entries(debug_info->c_wasm_entries(), isolate);
wasm::SignatureMap* map = debug_info->c_wasm_entry_map()->get(); wasm::SignatureMap* map = debug_info->c_wasm_entry_map()->raw();
int32_t index = map->Find(sig); int32_t index = map->Find(sig);
if (index == -1) { if (index == -1) {
index = static_cast<int32_t>(map->FindOrInsert(sig)); index = static_cast<int32_t>(map->FindOrInsert(sig));
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include "src/debug/debug-interface.h" #include "src/debug/debug-interface.h"
#include "src/globals.h" #include "src/globals.h"
#include "src/handles.h" #include "src/handles.h"
#include "src/managed.h" #include "src/objects/managed.h"
#include "src/parsing/preparse-data.h" #include "src/parsing/preparse-data.h"
#include "src/wasm/decoder.h" #include "src/wasm/decoder.h"
......
...@@ -131,7 +131,7 @@ WasmInstanceNativeAllocations* GetNativeAllocations( ...@@ -131,7 +131,7 @@ WasmInstanceNativeAllocations* GetNativeAllocations(
WasmInstanceObject* instance) { WasmInstanceObject* instance) {
return reinterpret_cast<Managed<WasmInstanceNativeAllocations>*>( return reinterpret_cast<Managed<WasmInstanceNativeAllocations>*>(
instance->managed_native_allocations()) instance->managed_native_allocations())
->get(); ->raw();
} }
// An iterator that returns first the module itself, then all modules linked via // An iterator that returns first the module itself, then all modules linked via
...@@ -974,13 +974,7 @@ wasm::WasmCode* WasmExportedFunction::GetWasmCode() { ...@@ -974,13 +974,7 @@ wasm::WasmCode* WasmExportedFunction::GetWasmCode() {
} }
WasmModule* WasmSharedModuleData::module() const { WasmModule* WasmSharedModuleData::module() const {
// We populate the kModuleWrapper field with a Foreign holding the return Managed<WasmModule>::cast(module_wrapper())->raw();
// address to the address of a WasmModule. This is because we can
// handle both cases when the WasmModule's lifetime is managed through
// a Managed<WasmModule> object, as well as cases when it's managed
// by the embedder. CcTests fall into the latter case.
return *(reinterpret_cast<WasmModule**>(
Foreign::cast(module_wrapper())->foreign_address()));
} }
Handle<WasmSharedModuleData> WasmSharedModuleData::New( Handle<WasmSharedModuleData> WasmSharedModuleData::New(
...@@ -1377,13 +1371,12 @@ Handle<WasmCompiledModule> WasmCompiledModule::New( ...@@ -1377,13 +1371,12 @@ Handle<WasmCompiledModule> WasmCompiledModule::New(
compiled_module->set_export_wrappers(*export_wrappers); compiled_module->set_export_wrappers(*export_wrappers);
} }
compiled_module->set_weak_owning_instance(isolate->heap()->empty_weak_cell()); compiled_module->set_weak_owning_instance(isolate->heap()->empty_weak_cell());
wasm::NativeModule* native_module = nullptr;
{ {
std::unique_ptr<wasm::NativeModule> native_module_ptr = auto native_module =
isolate->wasm_engine()->code_manager()->NewNativeModule(*module, env); isolate->wasm_engine()->code_manager()->NewNativeModule(*module, env);
native_module = native_module_ptr.release();
Handle<Foreign> native_module_wrapper = Handle<Foreign> native_module_wrapper =
Managed<wasm::NativeModule>::From(isolate, native_module); Managed<wasm::NativeModule>::FromUniquePtr(isolate,
std::move(native_module));
compiled_module->set_native_module(*native_module_wrapper); compiled_module->set_native_module(*native_module_wrapper);
compiled_module->GetNativeModule()->SetCompiledModule(compiled_module); compiled_module->GetNativeModule()->SetCompiledModule(compiled_module);
} }
...@@ -1410,12 +1403,12 @@ Handle<WasmCompiledModule> WasmCompiledModule::Clone( ...@@ -1410,12 +1403,12 @@ Handle<WasmCompiledModule> WasmCompiledModule::Clone(
handle(module->export_wrappers(), isolate)); handle(module->export_wrappers(), isolate));
ret->set_export_wrappers(*export_copy); ret->set_export_wrappers(*export_copy);
std::unique_ptr<wasm::NativeModule> native_module = auto native_module = module->GetNativeModule()->Clone();
module->GetNativeModule()->Clone();
// construct the wrapper in 2 steps, because its construction may trigger GC, // construct the wrapper in 2 steps, because its construction may trigger GC,
// which would shift the this pointer in set_native_module. // which would shift the this pointer in set_native_module.
Handle<Foreign> native_module_wrapper = Handle<Foreign> native_module_wrapper =
Managed<wasm::NativeModule>::From(isolate, native_module.release()); Managed<wasm::NativeModule>::FromUniquePtr(isolate,
std::move(native_module));
ret->set_native_module(*native_module_wrapper); ret->set_native_module(*native_module_wrapper);
ret->GetNativeModule()->SetCompiledModule(ret); ret->GetNativeModule()->SetCompiledModule(ret);
...@@ -1424,7 +1417,7 @@ Handle<WasmCompiledModule> WasmCompiledModule::Clone( ...@@ -1424,7 +1417,7 @@ Handle<WasmCompiledModule> WasmCompiledModule::Clone(
wasm::NativeModule* WasmCompiledModule::GetNativeModule() const { wasm::NativeModule* WasmCompiledModule::GetNativeModule() const {
if (!has_native_module()) return nullptr; if (!has_native_module()) return nullptr;
return Managed<wasm::NativeModule>::cast(native_module())->get(); return Managed<wasm::NativeModule>::cast(native_module())->raw();
} }
void WasmCompiledModule::Reset(Isolate* isolate, void WasmCompiledModule::Reset(Isolate* isolate,
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
#include "src/base/bits.h" #include "src/base/bits.h"
#include "src/debug/debug.h" #include "src/debug/debug.h"
#include "src/debug/interface-types.h" #include "src/debug/interface-types.h"
#include "src/managed.h"
#include "src/objects.h" #include "src/objects.h"
#include "src/objects/managed.h"
#include "src/objects/script.h" #include "src/objects/script.h"
#include "src/wasm/decoder.h" #include "src/wasm/decoder.h"
#include "src/wasm/wasm-interpreter.h" #include "src/wasm/wasm-interpreter.h"
......
...@@ -693,7 +693,7 @@ MaybeHandle<WasmCompiledModule> DeserializeNativeModule( ...@@ -693,7 +693,7 @@ MaybeHandle<WasmCompiledModule> DeserializeNativeModule(
// The {module_wrapper} will take ownership of the {WasmModule} object, // The {module_wrapper} will take ownership of the {WasmModule} object,
// and it will be destroyed when the GC reclaims the wrapper object. // and it will be destroyed when the GC reclaims the wrapper object.
Handle<WasmModuleWrapper> module_wrapper = Handle<WasmModuleWrapper> module_wrapper =
WasmModuleWrapper::From(isolate, decode_result.val.release()); WasmModuleWrapper::FromUniquePtr(isolate, std::move(decode_result.val));
Handle<Script> script = CreateWasmScript(isolate, wire_bytes); Handle<Script> script = CreateWasmScript(isolate, wire_bytes);
Handle<WasmSharedModuleData> shared = WasmSharedModuleData::New( Handle<WasmSharedModuleData> shared = WasmSharedModuleData::New(
isolate, module_wrapper, Handle<SeqOneByteString>::cast(module_bytes), isolate, module_wrapper, Handle<SeqOneByteString>::cast(module_bytes),
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "src/managed.h" #include "src/objects/managed.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "test/cctest/cctest.h" #include "test/cctest/cctest.h"
...@@ -14,84 +14,184 @@ ...@@ -14,84 +14,184 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class DeleteRecorder { class DeleteCounter {
public: public:
explicit DeleteRecorder(bool* deleted) : deleted_(deleted) { explicit DeleteCounter(int* deleted) : deleted_(deleted) { *deleted_ = 0; }
*deleted_ = false; ~DeleteCounter() { (*deleted_)++; }
} static void Deleter(void* arg) {
~DeleteRecorder() { *deleted_ = true; } delete reinterpret_cast<DeleteCounter*>(arg);
static void Deleter(Isolate::ManagedObjectFinalizer* finalizer) {
delete *reinterpret_cast<DeleteRecorder**>(finalizer);
} }
private: private:
bool* deleted_; int* deleted_;
}; };
TEST(ManagedCollect) { TEST(GCCausesDestruction) {
Isolate* isolate = CcTest::InitIsolateOnce(); Isolate* isolate = CcTest::InitIsolateOnce();
bool deleted1 = false; int deleted1 = 0;
bool deleted2 = false; int deleted2 = 0;
DeleteRecorder* d1 = new DeleteRecorder(&deleted1); DeleteCounter* d1 = new DeleteCounter(&deleted1);
DeleteRecorder* d2 = new DeleteRecorder(&deleted2); DeleteCounter* d2 = new DeleteCounter(&deleted2);
Isolate::ManagedObjectFinalizer finalizer(d2, DeleteRecorder::Deleter);
isolate->RegisterForReleaseAtTeardown(&finalizer);
{ {
HandleScope scope(isolate); HandleScope scope(isolate);
auto handle = Managed<DeleteRecorder>::From(isolate, d1); auto handle = Managed<DeleteCounter>::FromRawPtr(isolate, d1);
USE(handle); USE(handle);
} }
CcTest::CollectAllAvailableGarbage(); CcTest::CollectAllAvailableGarbage();
CHECK(deleted1); CHECK_EQ(1, deleted1);
CHECK(!deleted2); CHECK_EQ(0, deleted2);
isolate->UnregisterFromReleaseAtTeardown(&finalizer);
delete d2; delete d2;
CHECK(deleted2); CHECK_EQ(1, deleted2);
} }
TEST(DisposeCollect) { TEST(DisposeCausesDestruction1) {
v8::Isolate::CreateParams create_params; v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = create_params.array_buffer_allocator =
CcTest::InitIsolateOnce()->array_buffer_allocator(); CcTest::InitIsolateOnce()->array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params); v8::Isolate* isolate = v8::Isolate::New(create_params);
Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
isolate->Enter(); isolate->Enter();
int deleted1 = 0;
DeleteCounter* d1 = new DeleteCounter(&deleted1);
{
HandleScope scope(i_isolate);
auto handle = Managed<DeleteCounter>::FromRawPtr(i_isolate, d1);
USE(handle);
}
isolate->Exit();
isolate->Dispose();
CHECK_EQ(1, deleted1);
}
TEST(DisposeCausesDestruction2) {
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator =
CcTest::InitIsolateOnce()->array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
bool deleted1 = false; isolate->Enter();
bool deleted2 = false; int deleted1 = 0;
DeleteRecorder* d1 = new DeleteRecorder(&deleted1); int deleted2 = 0;
DeleteRecorder* d2 = new DeleteRecorder(&deleted2); DeleteCounter* d1 = new DeleteCounter(&deleted1);
DeleteCounter* d2 = new DeleteCounter(&deleted2);
{ {
HandleScope scope(i_isolate); HandleScope scope(i_isolate);
auto handle = Managed<DeleteRecorder>::From(i_isolate, d1); auto handle = Managed<DeleteCounter>::FromRawPtr(i_isolate, d1);
USE(handle); USE(handle);
} }
Isolate::ManagedObjectFinalizer finalizer(d2, DeleteRecorder::Deleter); ManagedPtrDestructor* destructor =
i_isolate->RegisterForReleaseAtTeardown(&finalizer); new ManagedPtrDestructor(d2, DeleteCounter::Deleter);
i_isolate->RegisterManagedPtrDestructor(destructor);
isolate->Exit(); isolate->Exit();
isolate->Dispose(); isolate->Dispose();
CHECK(deleted1); CHECK_EQ(1, deleted1);
CHECK(deleted2); CHECK_EQ(1, deleted2);
} }
TEST(CollectOnGC) { TEST(DisposeWithAnotherSharedPtr) {
i::Isolate* i_isolate = CcTest::InitIsolateOnce(); v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator =
CcTest::InitIsolateOnce()->array_buffer_allocator();
bool deleted = false; v8::Isolate* isolate = v8::Isolate::New(create_params);
Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
isolate->Enter();
int deleted1 = 0;
DeleteCounter* d1 = new DeleteCounter(&deleted1);
{
std::shared_ptr<DeleteCounter> shared1(d1);
{ {
HandleScope scope(i_isolate); HandleScope scope(i_isolate);
Managed<DeleteRecorder>::Allocate(i_isolate, &deleted); auto handle = Managed<DeleteCounter>::FromSharedPtr(i_isolate, shared1);
USE(handle);
} }
// TODO(ulan): It should be possible to trigger a normal gc before the isolate->Exit();
// "critical" one, and the "critical" one should still process pending isolate->Dispose();
// second-pass phantom callbacks (crbug.com/v8/7628). CHECK_EQ(0, deleted1);
// CcTest::CollectAllGarbage(); }
CcTest::CollectAllAvailableGarbage(); // Should be deleted after the second shared pointer is destroyed.
CHECK_EQ(1, deleted1);
}
TEST(DisposeAcrossIsolates) {
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator =
CcTest::InitIsolateOnce()->array_buffer_allocator();
CHECK(deleted); int deleted = 0;
DeleteCounter* delete_counter = new DeleteCounter(&deleted);
v8::Isolate* isolate1 = v8::Isolate::New(create_params);
Isolate* i_isolate1 = reinterpret_cast<i::Isolate*>(isolate1);
isolate1->Enter();
{
HandleScope scope1(i_isolate1);
auto handle1 =
Managed<DeleteCounter>::FromRawPtr(i_isolate1, delete_counter);
v8::Isolate* isolate2 = v8::Isolate::New(create_params);
Isolate* i_isolate2 = reinterpret_cast<i::Isolate*>(isolate2);
isolate2->Enter();
{
HandleScope scope(i_isolate2);
auto handle2 =
Managed<DeleteCounter>::FromSharedPtr(i_isolate2, handle1->get());
USE(handle2);
}
isolate2->Exit();
isolate2->Dispose();
CHECK_EQ(0, deleted);
}
// Should be deleted after the first isolate is destroyed.
isolate1->Exit();
isolate1->Dispose();
CHECK_EQ(1, deleted);
}
TEST(CollectAcrossIsolates) {
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator =
CcTest::InitIsolateOnce()->array_buffer_allocator();
int deleted = 0;
DeleteCounter* delete_counter = new DeleteCounter(&deleted);
v8::Isolate* isolate1 = v8::Isolate::New(create_params);
Isolate* i_isolate1 = reinterpret_cast<i::Isolate*>(isolate1);
isolate1->Enter();
{
HandleScope scope1(i_isolate1);
auto handle1 =
Managed<DeleteCounter>::FromRawPtr(i_isolate1, delete_counter);
v8::Isolate* isolate2 = v8::Isolate::New(create_params);
Isolate* i_isolate2 = reinterpret_cast<i::Isolate*>(isolate2);
isolate2->Enter();
{
HandleScope scope(i_isolate2);
auto handle2 =
Managed<DeleteCounter>::FromSharedPtr(i_isolate2, handle1->get());
USE(handle2);
}
i_isolate2->heap()->CollectAllAvailableGarbage(
i::GarbageCollectionReason::kTesting);
CHECK_EQ(0, deleted);
isolate2->Exit();
isolate2->Dispose();
CHECK_EQ(0, deleted);
}
// Should be deleted after the first isolate is destroyed.
i_isolate1->heap()->CollectAllAvailableGarbage(
i::GarbageCollectionReason::kTesting);
CHECK_EQ(1, deleted);
isolate1->Exit();
isolate1->Dispose();
CHECK_EQ(1, deleted);
} }
} // namespace internal } // namespace internal
......
...@@ -17,13 +17,14 @@ TestingModuleBuilder::TestingModuleBuilder( ...@@ -17,13 +17,14 @@ TestingModuleBuilder::TestingModuleBuilder(
Zone* zone, ManuallyImportedJSFunction* maybe_import, Zone* zone, ManuallyImportedJSFunction* maybe_import,
WasmExecutionMode mode, RuntimeExceptionSupport exception_support, WasmExecutionMode mode, RuntimeExceptionSupport exception_support,
LowerSimd lower_simd) LowerSimd lower_simd)
: test_module_ptr_(&test_module_), : test_module_(std::make_shared<WasmModule>()),
test_module_ptr_(test_module_.get()),
isolate_(CcTest::InitIsolateOnce()), isolate_(CcTest::InitIsolateOnce()),
execution_mode_(mode), execution_mode_(mode),
runtime_exception_support_(exception_support), runtime_exception_support_(exception_support),
lower_simd_(lower_simd) { lower_simd_(lower_simd) {
WasmJs::Install(isolate_, true); WasmJs::Install(isolate_, true);
test_module_.globals_size = kMaxGlobalsSize; test_module_->globals_size = kMaxGlobalsSize;
memset(globals_data_, 0, sizeof(globals_data_)); memset(globals_data_, 0, sizeof(globals_data_));
uint32_t maybe_import_index = 0; uint32_t maybe_import_index = 0;
...@@ -33,8 +34,8 @@ TestingModuleBuilder::TestingModuleBuilder( ...@@ -33,8 +34,8 @@ TestingModuleBuilder::TestingModuleBuilder(
// instance object allocates import entries. // instance object allocates import entries.
maybe_import_index = AddFunction(maybe_import->sig, nullptr); maybe_import_index = AddFunction(maybe_import->sig, nullptr);
DCHECK_EQ(0, maybe_import_index); DCHECK_EQ(0, maybe_import_index);
test_module_.num_imported_functions = 1; test_module_->num_imported_functions = 1;
test_module_.functions[0].imported = true; test_module_->functions[0].imported = true;
} }
instance_object_ = InitInstanceObject(); instance_object_ = InitInstanceObject();
...@@ -44,7 +45,7 @@ TestingModuleBuilder::TestingModuleBuilder( ...@@ -44,7 +45,7 @@ TestingModuleBuilder::TestingModuleBuilder(
CodeSpaceMemoryModificationScope modification_scope(isolate_->heap()); CodeSpaceMemoryModificationScope modification_scope(isolate_->heap());
Handle<Code> code = compiler::CompileWasmToJSWrapper( Handle<Code> code = compiler::CompileWasmToJSWrapper(
isolate_, maybe_import->js_function, maybe_import->sig, isolate_, maybe_import->js_function, maybe_import->sig,
maybe_import_index, test_module_.origin(), maybe_import_index, test_module_->origin(),
trap_handler::IsTrapHandlerEnabled() ? kUseTrapHandler trap_handler::IsTrapHandlerEnabled() ? kUseTrapHandler
: kNoTrapHandler); : kNoTrapHandler);
native_module_->ResizeCodeTableForTesting(maybe_import_index + 1, native_module_->ResizeCodeTableForTesting(maybe_import_index + 1,
...@@ -62,13 +63,13 @@ TestingModuleBuilder::TestingModuleBuilder( ...@@ -62,13 +63,13 @@ TestingModuleBuilder::TestingModuleBuilder(
} }
byte* TestingModuleBuilder::AddMemory(uint32_t size) { byte* TestingModuleBuilder::AddMemory(uint32_t size) {
CHECK(!test_module_.has_memory); CHECK(!test_module_->has_memory);
CHECK_NULL(mem_start_); CHECK_NULL(mem_start_);
CHECK_EQ(0, mem_size_); CHECK_EQ(0, mem_size_);
DCHECK(!instance_object_->has_memory_object()); DCHECK(!instance_object_->has_memory_object());
test_module_.has_memory = true; test_module_->has_memory = true;
const bool enable_guard_regions = const bool enable_guard_regions =
trap_handler::IsTrapHandlerEnabled() && test_module_.is_wasm(); trap_handler::IsTrapHandlerEnabled() && test_module_->is_wasm();
uint32_t alloc_size = uint32_t alloc_size =
enable_guard_regions ? RoundUp(size, CommitPageSize()) : size; enable_guard_regions ? RoundUp(size, CommitPageSize()) : size;
Handle<JSArrayBuffer> new_buffer; Handle<JSArrayBuffer> new_buffer;
...@@ -83,7 +84,7 @@ byte* TestingModuleBuilder::AddMemory(uint32_t size) { ...@@ -83,7 +84,7 @@ byte* TestingModuleBuilder::AddMemory(uint32_t size) {
// Create the WasmMemoryObject. // Create the WasmMemoryObject.
Handle<WasmMemoryObject> memory_object = WasmMemoryObject::New( Handle<WasmMemoryObject> memory_object = WasmMemoryObject::New(
isolate_, new_buffer, isolate_, new_buffer,
(test_module_.maximum_pages != 0) ? test_module_.maximum_pages : -1); (test_module_->maximum_pages != 0) ? test_module_->maximum_pages : -1);
instance_object_->set_memory_object(*memory_object); instance_object_->set_memory_object(*memory_object);
WasmMemoryObject::AddInstance(isolate_, memory_object, instance_object_); WasmMemoryObject::AddInstance(isolate_, memory_object, instance_object_);
// TODO(wasm): Delete the following two lines when test-run-wasm will use a // TODO(wasm): Delete the following two lines when test-run-wasm will use a
...@@ -94,23 +95,23 @@ byte* TestingModuleBuilder::AddMemory(uint32_t size) { ...@@ -94,23 +95,23 @@ byte* TestingModuleBuilder::AddMemory(uint32_t size) {
} }
uint32_t TestingModuleBuilder::AddFunction(FunctionSig* sig, const char* name) { uint32_t TestingModuleBuilder::AddFunction(FunctionSig* sig, const char* name) {
if (test_module_.functions.size() == 0) { if (test_module_->functions.size() == 0) {
// TODO(titzer): Reserving space here to avoid the underlying WasmFunction // TODO(titzer): Reserving space here to avoid the underlying WasmFunction
// structs from moving. // structs from moving.
test_module_.functions.reserve(kMaxFunctions); test_module_->functions.reserve(kMaxFunctions);
} }
uint32_t index = static_cast<uint32_t>(test_module_.functions.size()); uint32_t index = static_cast<uint32_t>(test_module_->functions.size());
if (native_module_) { if (native_module_) {
native_module_->ResizeCodeTableForTesting(index + 1, kMaxFunctions); native_module_->ResizeCodeTableForTesting(index + 1, kMaxFunctions);
} }
test_module_.functions.push_back({sig, index, 0, {0, 0}, false, false}); test_module_->functions.push_back({sig, index, 0, {0, 0}, false, false});
if (name) { if (name) {
Vector<const byte> name_vec = Vector<const byte>::cast(CStrVector(name)); Vector<const byte> name_vec = Vector<const byte>::cast(CStrVector(name));
test_module_.AddNameForTesting( test_module_->AddNameForTesting(
index, {AddBytes(name_vec), static_cast<uint32_t>(name_vec.length())}); index, {AddBytes(name_vec), static_cast<uint32_t>(name_vec.length())});
} }
if (interpreter_) { if (interpreter_) {
interpreter_->AddFunctionForTesting(&test_module_.functions.back()); interpreter_->AddFunctionForTesting(&test_module_->functions.back());
} }
DCHECK_LT(index, kMaxFunctions); // limited for testing. DCHECK_LT(index, kMaxFunctions); // limited for testing.
return index; return index;
...@@ -126,12 +127,12 @@ Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) { ...@@ -126,12 +127,12 @@ Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) {
Handle<WeakCell> weak_instance(compiled_module->weak_owning_instance(), Handle<WeakCell> weak_instance(compiled_module->weak_owning_instance(),
isolate_); isolate_);
Handle<Code> ret_code = compiler::CompileJSToWasmWrapper( Handle<Code> ret_code = compiler::CompileJSToWasmWrapper(
isolate_, &test_module_, weak_instance, code, index, isolate_, test_module_ptr_, weak_instance, code, index,
trap_handler::IsTrapHandlerEnabled() ? kUseTrapHandler : kNoTrapHandler); trap_handler::IsTrapHandlerEnabled() ? kUseTrapHandler : kNoTrapHandler);
Handle<JSFunction> ret = WasmExportedFunction::New( Handle<JSFunction> ret = WasmExportedFunction::New(
isolate_, instance_object(), MaybeHandle<String>(), isolate_, instance_object(), MaybeHandle<String>(),
static_cast<int>(index), static_cast<int>(index),
static_cast<int>(test_module_.functions[index].sig->parameter_count()), static_cast<int>(test_module_->functions[index].sig->parameter_count()),
ret_code); ret_code);
// Add reference to the exported wrapper code. // Add reference to the exported wrapper code.
...@@ -147,8 +148,8 @@ Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) { ...@@ -147,8 +148,8 @@ Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) {
void TestingModuleBuilder::AddIndirectFunctionTable( void TestingModuleBuilder::AddIndirectFunctionTable(
const uint16_t* function_indexes, uint32_t table_size) { const uint16_t* function_indexes, uint32_t table_size) {
test_module_.function_tables.emplace_back(); test_module_->function_tables.emplace_back();
WasmIndirectFunctionTable& table = test_module_.function_tables.back(); WasmIndirectFunctionTable& table = test_module_->function_tables.back();
table.initial_size = table_size; table.initial_size = table_size;
table.maximum_size = table_size; table.maximum_size = table_size;
table.has_maximum_size = true; table.has_maximum_size = true;
...@@ -164,11 +165,11 @@ void TestingModuleBuilder::PopulateIndirectFunctionTable() { ...@@ -164,11 +165,11 @@ void TestingModuleBuilder::PopulateIndirectFunctionTable() {
auto instance = instance_object(); auto instance = instance_object();
uint32_t num_tables = 1; // TODO(titzer): multiple tables. uint32_t num_tables = 1; // TODO(titzer): multiple tables.
for (uint32_t i = 0; i < num_tables; i++) { for (uint32_t i = 0; i < num_tables; i++) {
WasmIndirectFunctionTable& table = test_module_.function_tables[i]; WasmIndirectFunctionTable& table = test_module_->function_tables[i];
int table_size = static_cast<int>(instance->indirect_function_table_size()); int table_size = static_cast<int>(instance->indirect_function_table_size());
for (int j = 0; j < table_size; j++) { for (int j = 0; j < table_size; j++) {
WasmFunction& function = test_module_.functions[table.values[j]]; WasmFunction& function = test_module_->functions[table.values[j]];
int sig_id = test_module_.signature_map.Find(function.sig); int sig_id = test_module_->signature_map.Find(function.sig);
auto wasm_code = native_module_->GetCode(function.func_index); auto wasm_code = native_module_->GetCode(function.func_index);
IndirectFunctionTableEntry(*instance, j) IndirectFunctionTableEntry(*instance, j)
.set(sig_id, *instance, wasm_code); .set(sig_id, *instance, wasm_code);
...@@ -195,7 +196,7 @@ uint32_t TestingModuleBuilder::AddBytes(Vector<const byte> bytes) { ...@@ -195,7 +196,7 @@ uint32_t TestingModuleBuilder::AddBytes(Vector<const byte> bytes) {
ModuleEnv TestingModuleBuilder::CreateModuleEnv() { ModuleEnv TestingModuleBuilder::CreateModuleEnv() {
return { return {
&test_module_, test_module_ptr_,
trap_handler::IsTrapHandlerEnabled() ? kUseTrapHandler : kNoTrapHandler, trap_handler::IsTrapHandlerEnabled() ? kUseTrapHandler : kNoTrapHandler,
runtime_exception_support_}; runtime_exception_support_};
} }
...@@ -203,26 +204,25 @@ ModuleEnv TestingModuleBuilder::CreateModuleEnv() { ...@@ -203,26 +204,25 @@ ModuleEnv TestingModuleBuilder::CreateModuleEnv() {
const WasmGlobal* TestingModuleBuilder::AddGlobal(ValueType type) { const WasmGlobal* TestingModuleBuilder::AddGlobal(ValueType type) {
byte size = ValueTypes::MemSize(ValueTypes::MachineTypeFor(type)); byte size = ValueTypes::MemSize(ValueTypes::MachineTypeFor(type));
global_offset = (global_offset + size - 1) & ~(size - 1); // align global_offset = (global_offset + size - 1) & ~(size - 1); // align
test_module_.globals.push_back( test_module_->globals.push_back(
{type, true, WasmInitExpr(), {global_offset}, false, false}); {type, true, WasmInitExpr(), {global_offset}, false, false});
global_offset += size; global_offset += size;
// limit number of globals. // limit number of globals.
CHECK_LT(global_offset, kMaxGlobalsSize); CHECK_LT(global_offset, kMaxGlobalsSize);
return &test_module_.globals.back(); return &test_module_->globals.back();
} }
Handle<WasmInstanceObject> TestingModuleBuilder::InitInstanceObject() { Handle<WasmInstanceObject> TestingModuleBuilder::InitInstanceObject() {
Handle<SeqOneByteString> empty_string = Handle<SeqOneByteString>::cast( Handle<SeqOneByteString> empty_string = Handle<SeqOneByteString>::cast(
isolate_->factory()->NewStringFromOneByte({}).ToHandleChecked()); isolate_->factory()->NewStringFromOneByte({}).ToHandleChecked());
// The lifetime of the wasm module is tied to this object's, and we cannot auto managed_module =
// rely on the mechanics of Managed<T>. Managed<WasmModule>::FromSharedPtr(isolate_, test_module_);
Handle<Foreign> module_wrapper = isolate_->factory()->NewForeign( DCHECK_EQ(test_module_ptr_, managed_module->raw());
reinterpret_cast<Address>(&test_module_ptr_));
Handle<Script> script = Handle<Script> script =
isolate_->factory()->NewScript(isolate_->factory()->empty_string()); isolate_->factory()->NewScript(isolate_->factory()->empty_string());
script->set_type(Script::TYPE_WASM); script->set_type(Script::TYPE_WASM);
Handle<WasmSharedModuleData> shared_module_data = Handle<WasmSharedModuleData> shared_module_data =
WasmSharedModuleData::New(isolate_, module_wrapper, empty_string, script, WasmSharedModuleData::New(isolate_, managed_module, empty_string, script,
Handle<ByteArray>::null()); Handle<ByteArray>::null());
Handle<FixedArray> export_wrappers = isolate_->factory()->NewFixedArray(0); Handle<FixedArray> export_wrappers = isolate_->factory()->NewFixedArray(0);
ModuleEnv env = CreateModuleEnv(); ModuleEnv env = CreateModuleEnv();
......
...@@ -94,7 +94,7 @@ class TestingModuleBuilder { ...@@ -94,7 +94,7 @@ class TestingModuleBuilder {
TestingModuleBuilder(Zone*, ManuallyImportedJSFunction*, WasmExecutionMode, TestingModuleBuilder(Zone*, ManuallyImportedJSFunction*, WasmExecutionMode,
RuntimeExceptionSupport, LowerSimd); RuntimeExceptionSupport, LowerSimd);
void ChangeOriginToAsmjs() { test_module_.set_origin(kAsmJsOrigin); } void ChangeOriginToAsmjs() { test_module_->set_origin(kAsmJsOrigin); }
byte* AddMemory(uint32_t size); byte* AddMemory(uint32_t size);
...@@ -114,12 +114,12 @@ class TestingModuleBuilder { ...@@ -114,12 +114,12 @@ class TestingModuleBuilder {
} }
byte AddSignature(FunctionSig* sig) { byte AddSignature(FunctionSig* sig) {
DCHECK_EQ(test_module_.signatures.size(), DCHECK_EQ(test_module_->signatures.size(),
test_module_.signature_ids.size()); test_module_->signature_ids.size());
test_module_.signatures.push_back(sig); test_module_->signatures.push_back(sig);
auto canonical_sig_num = test_module_.signature_map.FindOrInsert(sig); auto canonical_sig_num = test_module_->signature_map.FindOrInsert(sig);
test_module_.signature_ids.push_back(canonical_sig_num); test_module_->signature_ids.push_back(canonical_sig_num);
size_t size = test_module_.signatures.size(); size_t size = test_module_->signatures.size();
CHECK_GT(127, size); CHECK_GT(127, size);
return static_cast<byte>(size - 1); return static_cast<byte>(size - 1);
} }
...@@ -173,13 +173,13 @@ class TestingModuleBuilder { ...@@ -173,13 +173,13 @@ class TestingModuleBuilder {
} }
void SetMaxMemPages(uint32_t maximum_pages) { void SetMaxMemPages(uint32_t maximum_pages) {
test_module_.maximum_pages = maximum_pages; test_module_->maximum_pages = maximum_pages;
if (instance_object()->has_memory_object()) { if (instance_object()->has_memory_object()) {
instance_object()->memory_object()->set_maximum_pages(maximum_pages); instance_object()->memory_object()->set_maximum_pages(maximum_pages);
} }
} }
void SetHasSharedMemory() { test_module_.has_shared_memory = true; } void SetHasSharedMemory() { test_module_->has_shared_memory = true; }
uint32_t AddFunction(FunctionSig* sig, const char* name); uint32_t AddFunction(FunctionSig* sig, const char* name);
...@@ -193,7 +193,7 @@ class TestingModuleBuilder { ...@@ -193,7 +193,7 @@ class TestingModuleBuilder {
uint32_t AddBytes(Vector<const byte> bytes); uint32_t AddBytes(Vector<const byte> bytes);
WasmFunction* GetFunctionAt(int index) { WasmFunction* GetFunctionAt(int index) {
return &test_module_.functions[index]; return &test_module_->functions[index];
} }
WasmInterpreter* interpreter() { return interpreter_; } WasmInterpreter* interpreter() { return interpreter_; }
...@@ -224,7 +224,7 @@ class TestingModuleBuilder { ...@@ -224,7 +224,7 @@ class TestingModuleBuilder {
} }
private: private:
WasmModule test_module_; std::shared_ptr<WasmModule> test_module_;
WasmModule* test_module_ptr_; WasmModule* test_module_ptr_;
Isolate* isolate_; Isolate* isolate_;
uint32_t global_offset = 0; uint32_t global_offset = 0;
......
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