[wasm-c-api] Roll bf31edf: Fix life times of host info
Host info used to be stored on the global reference underlying a Ref; now it is stored in a JSWeakMap and hence tied to the lifetime of the actual object on V8's heap. Additionally, the internal metadata needed for C-API functions is now stored on the SharedFunctionInfo and no longer overlaps with the host info mechanism. Bonus content: Roll 6db391e: Remove a few more leftover uses of _enum types Change-Id: Ibb1fa4b0dd5157fef15c030bac705a11aa3beaea Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1768368 Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#63400}
This commit is contained in:
parent
763f63fff6
commit
3aa4f05d0c
@ -1000,7 +1000,7 @@ extern class WasmJSFunctionData extends Struct {
|
|||||||
|
|
||||||
extern class WasmCapiFunctionData extends Struct {
|
extern class WasmCapiFunctionData extends Struct {
|
||||||
call_target: RawPtr;
|
call_target: RawPtr;
|
||||||
embedder_data: RawPtr;
|
embedder_data: Foreign; // Managed<wasm::FuncData>
|
||||||
wrapper_code: Code;
|
wrapper_code: Code;
|
||||||
serialized_signature: ByteArray; // PodArray<wasm::ValueType>
|
serialized_signature: ByteArray; // PodArray<wasm::ValueType>
|
||||||
}
|
}
|
||||||
|
@ -5952,9 +5952,9 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
|||||||
Node* sfi_data = LOAD_RAW(
|
Node* sfi_data = LOAD_RAW(
|
||||||
shared, SharedFunctionInfo::kFunctionDataOffset - kHeapObjectTag,
|
shared, SharedFunctionInfo::kFunctionDataOffset - kHeapObjectTag,
|
||||||
MachineType::TypeCompressedTagged());
|
MachineType::TypeCompressedTagged());
|
||||||
Node* host_data = LOAD_RAW(
|
Node* host_data_foreign = LOAD_RAW(
|
||||||
sfi_data, WasmCapiFunctionData::kEmbedderDataOffset - kHeapObjectTag,
|
sfi_data, WasmCapiFunctionData::kEmbedderDataOffset - kHeapObjectTag,
|
||||||
MachineType::Pointer());
|
MachineType::TypeCompressedTagged());
|
||||||
|
|
||||||
BuildModifyThreadInWasmFlag(false);
|
BuildModifyThreadInWasmFlag(false);
|
||||||
Node* isolate_root = BuildLoadIsolateRoot();
|
Node* isolate_root = BuildLoadIsolateRoot();
|
||||||
@ -5968,11 +5968,12 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
|||||||
Node* function =
|
Node* function =
|
||||||
graph()->NewNode(mcgraph()->common()->ExternalConstant(ref));
|
graph()->NewNode(mcgraph()->common()->ExternalConstant(ref));
|
||||||
|
|
||||||
// Parameters: void* data, Address arguments.
|
// Parameters: Address host_data_foreign, Address arguments.
|
||||||
MachineType host_sig_types[] = {
|
MachineType host_sig_types[] = {
|
||||||
MachineType::Pointer(), MachineType::Pointer(), MachineType::Pointer()};
|
MachineType::Pointer(), MachineType::Pointer(), MachineType::Pointer()};
|
||||||
MachineSignature host_sig(1, 2, host_sig_types);
|
MachineSignature host_sig(1, 2, host_sig_types);
|
||||||
Node* return_value = BuildCCall(&host_sig, function, host_data, values);
|
Node* return_value =
|
||||||
|
BuildCCall(&host_sig, function, host_data_foreign, values);
|
||||||
|
|
||||||
BuildModifyThreadInWasmFlag(true);
|
BuildModifyThreadInWasmFlag(true);
|
||||||
|
|
||||||
|
@ -2061,7 +2061,7 @@ void WasmCapiFunctionData::WasmCapiFunctionDataPrint(
|
|||||||
std::ostream& os) { // NOLINT
|
std::ostream& os) { // NOLINT
|
||||||
PrintHeader(os, "WasmCapiFunctionData");
|
PrintHeader(os, "WasmCapiFunctionData");
|
||||||
os << "\n - call_target: " << call_target();
|
os << "\n - call_target: " << call_target();
|
||||||
os << "\n - embedder_data: " << embedder_data();
|
os << "\n - embedder_data: " << Brief(embedder_data());
|
||||||
os << "\n - wrapper_code: " << Brief(wrapper_code());
|
os << "\n - wrapper_code: " << Brief(wrapper_code());
|
||||||
os << "\n - serialized_signature: " << Brief(serialized_signature());
|
os << "\n - serialized_signature: " << Brief(serialized_signature());
|
||||||
os << "\n";
|
os << "\n";
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
#include "include/libplatform/libplatform.h"
|
#include "include/libplatform/libplatform.h"
|
||||||
#include "src/api/api-inl.h"
|
#include "src/api/api-inl.h"
|
||||||
#include "src/compiler/wasm-compiler.h"
|
#include "src/compiler/wasm-compiler.h"
|
||||||
|
#include "src/objects/js-collection-inl.h"
|
||||||
|
#include "src/objects/managed.h"
|
||||||
#include "src/objects/stack-frame-info-inl.h"
|
#include "src/objects/stack-frame-info-inl.h"
|
||||||
#include "src/wasm/leb-helper.h"
|
#include "src/wasm/leb-helper.h"
|
||||||
#include "src/wasm/module-instantiate.h"
|
#include "src/wasm/module-instantiate.h"
|
||||||
@ -270,6 +272,38 @@ StoreImpl::~StoreImpl() {
|
|||||||
delete create_params_.array_buffer_allocator;
|
delete create_params_.array_buffer_allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ManagedData {
|
||||||
|
ManagedData(void* info, void (*finalizer)(void*))
|
||||||
|
: info(info), finalizer(finalizer) {}
|
||||||
|
|
||||||
|
~ManagedData() {
|
||||||
|
if (finalizer) (*finalizer)(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* info;
|
||||||
|
void (*finalizer)(void*);
|
||||||
|
};
|
||||||
|
|
||||||
|
void StoreImpl::SetHostInfo(i::Handle<i::Object> object, void* info,
|
||||||
|
void (*finalizer)(void*)) {
|
||||||
|
i::HandleScope scope(i_isolate());
|
||||||
|
// Ideally we would specify the total size kept alive by {info} here,
|
||||||
|
// but all we get from the embedder is a {void*}, so our best estimate
|
||||||
|
// is the size of the metadata.
|
||||||
|
size_t estimated_size = sizeof(ManagedData);
|
||||||
|
i::Handle<i::Object> wrapper = i::Managed<ManagedData>::FromRawPtr(
|
||||||
|
i_isolate(), estimated_size, new ManagedData(info, finalizer));
|
||||||
|
int32_t hash = object->GetOrCreateHash(i_isolate()).value();
|
||||||
|
i::JSWeakCollection::Set(host_info_map_, object, wrapper, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* StoreImpl::GetHostInfo(i::Handle<i::Object> key) {
|
||||||
|
i::Object raw =
|
||||||
|
i::EphemeronHashTable::cast(host_info_map_->table()).Lookup(key);
|
||||||
|
if (raw.IsTheHole(i_isolate())) return nullptr;
|
||||||
|
return i::Managed<ManagedData>::cast(raw).raw()->info;
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct implement<Store> {
|
struct implement<Store> {
|
||||||
using type = StoreImpl;
|
using type = StoreImpl;
|
||||||
@ -286,26 +320,29 @@ auto Store::make(Engine*) -> own<Store> {
|
|||||||
// Create isolate.
|
// Create isolate.
|
||||||
store->create_params_.array_buffer_allocator =
|
store->create_params_.array_buffer_allocator =
|
||||||
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
|
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
|
||||||
auto isolate = v8::Isolate::New(store->create_params_);
|
v8::Isolate* isolate = v8::Isolate::New(store->create_params_);
|
||||||
if (!isolate) return own<Store>();
|
if (!isolate) return own<Store>();
|
||||||
|
store->isolate_ = isolate;
|
||||||
|
isolate->SetData(0, store.get());
|
||||||
|
// We intentionally do not call isolate->Enter() here, because that would
|
||||||
|
// prevent embedders from using stores with overlapping but non-nested
|
||||||
|
// lifetimes. The consequence is that Isolate::Current() is dysfunctional
|
||||||
|
// and hence must not be called by anything reachable via this file.
|
||||||
|
|
||||||
{
|
{
|
||||||
v8::HandleScope handle_scope(isolate);
|
v8::HandleScope handle_scope(isolate);
|
||||||
|
|
||||||
// Create context.
|
// Create context.
|
||||||
auto context = v8::Context::New(isolate);
|
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||||
if (context.IsEmpty()) return own<Store>();
|
if (context.IsEmpty()) return own<Store>();
|
||||||
v8::Context::Scope context_scope(context);
|
context->Enter(); // The Exit() call is in ~StoreImpl.
|
||||||
|
|
||||||
store->isolate_ = isolate;
|
|
||||||
store->context_ = v8::Eternal<v8::Context>(isolate, context);
|
store->context_ = v8::Eternal<v8::Context>(isolate, context);
|
||||||
|
|
||||||
|
// Create weak map for Refs with host info.
|
||||||
|
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||||
|
store->host_info_map_ = i_isolate->global_handles()->Create(
|
||||||
|
*i_isolate->factory()->NewJSWeakMap());
|
||||||
}
|
}
|
||||||
// We intentionally do not call isolate->Enter() here, because that would
|
|
||||||
// prevent embedders from using stores with overlapping but non-nested
|
|
||||||
// lifetimes. The consequence is that Isolate::Current() is dysfunctional
|
|
||||||
// and hence must not be called by anything reachable via this file.
|
|
||||||
store->context()->Enter();
|
|
||||||
isolate->SetData(0, store.get());
|
|
||||||
// We want stack traces for traps.
|
// We want stack traces for traps.
|
||||||
constexpr int kStackLimit = 10;
|
constexpr int kStackLimit = 10;
|
||||||
isolate->SetCaptureStackTraceForUncaughtExceptions(true, kStackLimit,
|
isolate->SetCaptureStackTraceForUncaughtExceptions(true, kStackLimit,
|
||||||
@ -712,15 +749,7 @@ class RefImpl {
|
|||||||
return make_own(seal<Ref>(self));
|
return make_own(seal<Ref>(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset() {
|
~RefImpl() { i::GlobalHandles::Destroy(location()); }
|
||||||
i::GlobalHandles::Destroy(location());
|
|
||||||
if (host_data_) {
|
|
||||||
if (host_data_->finalizer) {
|
|
||||||
host_data_->finalizer(host_data_->info);
|
|
||||||
}
|
|
||||||
delete host_data_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
own<Ref> copy() const { return make(store(), v8_object()); }
|
own<Ref> copy() const { return make(store(), v8_object()); }
|
||||||
|
|
||||||
@ -730,41 +759,20 @@ class RefImpl {
|
|||||||
|
|
||||||
i::Handle<JSType> v8_object() const { return i::Handle<JSType>::cast(val_); }
|
i::Handle<JSType> v8_object() const { return i::Handle<JSType>::cast(val_); }
|
||||||
|
|
||||||
void* get_host_info() const {
|
void* get_host_info() const { return store()->GetHostInfo(v8_object()); }
|
||||||
if (host_data_ == nullptr) return nullptr;
|
|
||||||
return host_data_->info;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_host_info(void* info, void (*finalizer)(void*)) {
|
void set_host_info(void* info, void (*finalizer)(void*)) {
|
||||||
host_data_ = new HostData(location(), info, finalizer);
|
store()->SetHostInfo(v8_object(), info, finalizer);
|
||||||
i::GlobalHandles::MakeWeak(host_data_->location, host_data_, &v8_finalizer,
|
|
||||||
v8::WeakCallbackType::kParameter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct HostData {
|
|
||||||
HostData(i::Address* location, void* info, void (*finalizer)(void*))
|
|
||||||
: location(location), info(info), finalizer(finalizer) {}
|
|
||||||
i::Address* location;
|
|
||||||
void* info;
|
|
||||||
void (*finalizer)(void*);
|
|
||||||
};
|
|
||||||
|
|
||||||
RefImpl() {}
|
RefImpl() {}
|
||||||
|
|
||||||
static void v8_finalizer(const v8::WeakCallbackInfo<void>& info) {
|
|
||||||
HostData* data = reinterpret_cast<HostData*>(info.GetParameter());
|
|
||||||
i::GlobalHandles::Destroy(data->location);
|
|
||||||
if (data->finalizer) (*data->finalizer)(data->info);
|
|
||||||
delete data;
|
|
||||||
}
|
|
||||||
|
|
||||||
i::Address* location() const {
|
i::Address* location() const {
|
||||||
return reinterpret_cast<i::Address*>(val_.address());
|
return reinterpret_cast<i::Address*>(val_.address());
|
||||||
}
|
}
|
||||||
|
|
||||||
i::Handle<i::JSReceiver> val_;
|
i::Handle<i::JSReceiver> val_;
|
||||||
HostData* host_data_ = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@ -773,7 +781,6 @@ struct implement<Ref> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ref::~Ref() {
|
Ref::~Ref() {
|
||||||
impl(this)->Reset();
|
|
||||||
delete impl(this);
|
delete impl(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1197,8 +1204,7 @@ struct FuncData {
|
|||||||
if (finalizer) (*finalizer)(env);
|
if (finalizer) (*finalizer)(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
static i::Address v8_callback(void* data, i::Address argv);
|
static i::Address v8_callback(i::Address host_data_foreign, i::Address argv);
|
||||||
static void finalize_func_data(void* data);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -1270,11 +1276,12 @@ auto make_func(Store* store_abs, FuncData* data) -> own<Func> {
|
|||||||
auto store = impl(store_abs);
|
auto store = impl(store_abs);
|
||||||
i::Isolate* isolate = store->i_isolate();
|
i::Isolate* isolate = store->i_isolate();
|
||||||
i::HandleScope handle_scope(isolate);
|
i::HandleScope handle_scope(isolate);
|
||||||
|
i::Handle<i::Managed<FuncData>> embedder_data =
|
||||||
|
i::Managed<FuncData>::FromRawPtr(isolate, sizeof(FuncData), data);
|
||||||
i::Handle<i::WasmCapiFunction> function = i::WasmCapiFunction::New(
|
i::Handle<i::WasmCapiFunction> function = i::WasmCapiFunction::New(
|
||||||
isolate, reinterpret_cast<i::Address>(&FuncData::v8_callback), data,
|
isolate, reinterpret_cast<i::Address>(&FuncData::v8_callback),
|
||||||
SignatureHelper::Serialize(isolate, data->type.get()));
|
embedder_data, SignatureHelper::Serialize(isolate, data->type.get()));
|
||||||
auto func = implement<Func>::type::make(store, function);
|
auto func = implement<Func>::type::make(store, function);
|
||||||
func->set_host_info(data, &FuncData::finalize_func_data);
|
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1435,7 +1442,7 @@ void PopArgs(i::wasm::FunctionSig* sig, Val results[],
|
|||||||
|
|
||||||
own<Trap> CallWasmCapiFunction(i::WasmCapiFunctionData data, const Val args[],
|
own<Trap> CallWasmCapiFunction(i::WasmCapiFunctionData data, const Val args[],
|
||||||
Val results[]) {
|
Val results[]) {
|
||||||
FuncData* func_data = reinterpret_cast<FuncData*>(data.embedder_data());
|
FuncData* func_data = i::Managed<FuncData>::cast(data.embedder_data()).raw();
|
||||||
if (func_data->kind == FuncData::kCallback) {
|
if (func_data->kind == FuncData::kCallback) {
|
||||||
return (func_data->callback)(args, results);
|
return (func_data->callback)(args, results);
|
||||||
}
|
}
|
||||||
@ -1530,8 +1537,10 @@ auto Func::call(const Val args[], Val results[]) const -> own<Trap> {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
i::Address FuncData::v8_callback(void* data, i::Address argv) {
|
i::Address FuncData::v8_callback(i::Address host_data_foreign,
|
||||||
FuncData* self = reinterpret_cast<FuncData*>(data);
|
i::Address argv) {
|
||||||
|
FuncData* self =
|
||||||
|
i::Managed<FuncData>::cast(i::Object(host_data_foreign))->raw();
|
||||||
StoreImpl* store = impl(self->store);
|
StoreImpl* store = impl(self->store);
|
||||||
i::Isolate* isolate = store->i_isolate();
|
i::Isolate* isolate = store->i_isolate();
|
||||||
i::HandleScope scope(isolate);
|
i::HandleScope scope(isolate);
|
||||||
@ -1619,10 +1628,6 @@ i::Address FuncData::v8_callback(void* data, i::Address argv) {
|
|||||||
return i::kNullAddress;
|
return i::kNullAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FuncData::finalize_func_data(void* data) {
|
|
||||||
delete reinterpret_cast<FuncData*>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global Instances
|
// Global Instances
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@ -2251,7 +2256,7 @@ extern "C++" inline auto hide_mutability(wasm::Mutability mutability)
|
|||||||
return static_cast<wasm_mutability_t>(mutability);
|
return static_cast<wasm_mutability_t>(mutability);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C++" inline auto reveal_mutability(wasm_mutability_enum mutability)
|
extern "C++" inline auto reveal_mutability(wasm_mutability_t mutability)
|
||||||
-> wasm::Mutability {
|
-> wasm::Mutability {
|
||||||
return static_cast<wasm::Mutability>(mutability);
|
return static_cast<wasm::Mutability>(mutability);
|
||||||
}
|
}
|
||||||
@ -2278,7 +2283,7 @@ extern "C++" inline auto hide_externkind(wasm::ExternKind kind)
|
|||||||
return static_cast<wasm_externkind_t>(kind);
|
return static_cast<wasm_externkind_t>(kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C++" inline auto reveal_externkind(wasm_externkind_enum kind)
|
extern "C++" inline auto reveal_externkind(wasm_externkind_t kind)
|
||||||
-> wasm::ExternKind {
|
-> wasm::ExternKind {
|
||||||
return static_cast<wasm::ExternKind>(kind);
|
return static_cast<wasm::ExternKind>(kind);
|
||||||
}
|
}
|
||||||
@ -2330,8 +2335,7 @@ WASM_DEFINE_TYPE(globaltype, wasm::GlobalType)
|
|||||||
wasm_globaltype_t* wasm_globaltype_new(wasm_valtype_t* content,
|
wasm_globaltype_t* wasm_globaltype_new(wasm_valtype_t* content,
|
||||||
wasm_mutability_t mutability) {
|
wasm_mutability_t mutability) {
|
||||||
return release_globaltype(wasm::GlobalType::make(
|
return release_globaltype(wasm::GlobalType::make(
|
||||||
adopt_valtype(content),
|
adopt_valtype(content), reveal_mutability(mutability)));
|
||||||
reveal_mutability(static_cast<wasm_mutability_enum>(mutability))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const wasm_valtype_t* wasm_globaltype_content(const wasm_globaltype_t* gt) {
|
const wasm_valtype_t* wasm_globaltype_content(const wasm_globaltype_t* gt) {
|
||||||
|
@ -7,8 +7,17 @@
|
|||||||
|
|
||||||
#include "include/v8.h"
|
#include "include/v8.h"
|
||||||
#include "src/common/globals.h"
|
#include "src/common/globals.h"
|
||||||
|
#include "src/handles/handles.h"
|
||||||
#include "third_party/wasm-api/wasm.hh"
|
#include "third_party/wasm-api/wasm.hh"
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class JSWeakMap;
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace v8
|
||||||
|
|
||||||
namespace wasm {
|
namespace wasm {
|
||||||
|
|
||||||
class StoreImpl {
|
class StoreImpl {
|
||||||
@ -27,6 +36,10 @@ class StoreImpl {
|
|||||||
reinterpret_cast<v8::Isolate*>(isolate)->GetData(0));
|
reinterpret_cast<v8::Isolate*>(isolate)->GetData(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetHostInfo(i::Handle<i::Object> object, void* info,
|
||||||
|
void (*finalizer)(void*));
|
||||||
|
void* GetHostInfo(i::Handle<i::Object> key);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend own<Store> Store::make(Engine*);
|
friend own<Store> Store::make(Engine*);
|
||||||
|
|
||||||
@ -35,6 +48,7 @@ class StoreImpl {
|
|||||||
v8::Isolate::CreateParams create_params_;
|
v8::Isolate::CreateParams create_params_;
|
||||||
v8::Isolate* isolate_ = nullptr;
|
v8::Isolate* isolate_ = nullptr;
|
||||||
v8::Eternal<v8::Context> context_;
|
v8::Eternal<v8::Context> context_;
|
||||||
|
i::Handle<i::JSWeakMap> host_info_map_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wasm
|
} // namespace wasm
|
||||||
|
@ -357,8 +357,7 @@ OBJECT_CONSTRUCTORS_IMPL(WasmCapiFunctionData, Struct)
|
|||||||
CAST_ACCESSOR(WasmCapiFunctionData)
|
CAST_ACCESSOR(WasmCapiFunctionData)
|
||||||
PRIMITIVE_ACCESSORS(WasmCapiFunctionData, call_target, Address,
|
PRIMITIVE_ACCESSORS(WasmCapiFunctionData, call_target, Address,
|
||||||
kCallTargetOffset)
|
kCallTargetOffset)
|
||||||
PRIMITIVE_ACCESSORS(WasmCapiFunctionData, embedder_data, void*,
|
ACCESSORS(WasmCapiFunctionData, embedder_data, Foreign, kEmbedderDataOffset)
|
||||||
kEmbedderDataOffset)
|
|
||||||
ACCESSORS(WasmCapiFunctionData, wrapper_code, Code, kWrapperCodeOffset)
|
ACCESSORS(WasmCapiFunctionData, wrapper_code, Code, kWrapperCodeOffset)
|
||||||
ACCESSORS(WasmCapiFunctionData, serialized_signature, PodArray<wasm::ValueType>,
|
ACCESSORS(WasmCapiFunctionData, serialized_signature, PodArray<wasm::ValueType>,
|
||||||
kSerializedSignatureOffset)
|
kSerializedSignatureOffset)
|
||||||
|
@ -2162,13 +2162,13 @@ bool WasmCapiFunction::IsWasmCapiFunction(Object object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Handle<WasmCapiFunction> WasmCapiFunction::New(
|
Handle<WasmCapiFunction> WasmCapiFunction::New(
|
||||||
Isolate* isolate, Address call_target, void* embedder_data,
|
Isolate* isolate, Address call_target, Handle<Foreign> embedder_data,
|
||||||
Handle<PodArray<wasm::ValueType>> serialized_signature) {
|
Handle<PodArray<wasm::ValueType>> serialized_signature) {
|
||||||
Handle<WasmCapiFunctionData> fun_data =
|
Handle<WasmCapiFunctionData> fun_data =
|
||||||
Handle<WasmCapiFunctionData>::cast(isolate->factory()->NewStruct(
|
Handle<WasmCapiFunctionData>::cast(isolate->factory()->NewStruct(
|
||||||
WASM_CAPI_FUNCTION_DATA_TYPE, AllocationType::kOld));
|
WASM_CAPI_FUNCTION_DATA_TYPE, AllocationType::kOld));
|
||||||
fun_data->set_call_target(call_target);
|
fun_data->set_call_target(call_target);
|
||||||
fun_data->set_embedder_data(embedder_data);
|
fun_data->set_embedder_data(*embedder_data);
|
||||||
fun_data->set_serialized_signature(*serialized_signature);
|
fun_data->set_serialized_signature(*serialized_signature);
|
||||||
// TODO(jkummerow): Install a JavaScript wrapper. For now, calling
|
// TODO(jkummerow): Install a JavaScript wrapper. For now, calling
|
||||||
// these functions directly is unsupported; they can only be called
|
// these functions directly is unsupported; they can only be called
|
||||||
|
@ -707,7 +707,7 @@ class WasmCapiFunction : public JSFunction {
|
|||||||
static bool IsWasmCapiFunction(Object object);
|
static bool IsWasmCapiFunction(Object object);
|
||||||
|
|
||||||
static Handle<WasmCapiFunction> New(
|
static Handle<WasmCapiFunction> New(
|
||||||
Isolate* isolate, Address call_target, void* embedder_data,
|
Isolate* isolate, Address call_target, Handle<Foreign> embedder_data,
|
||||||
Handle<PodArray<wasm::ValueType>> serialized_signature);
|
Handle<PodArray<wasm::ValueType>> serialized_signature);
|
||||||
|
|
||||||
Address GetHostCallTarget() const;
|
Address GetHostCallTarget() const;
|
||||||
@ -764,7 +764,7 @@ class WasmIndirectFunctionTable : public Struct {
|
|||||||
class WasmCapiFunctionData : public Struct {
|
class WasmCapiFunctionData : public Struct {
|
||||||
public:
|
public:
|
||||||
DECL_PRIMITIVE_ACCESSORS(call_target, Address)
|
DECL_PRIMITIVE_ACCESSORS(call_target, Address)
|
||||||
DECL_PRIMITIVE_ACCESSORS(embedder_data, void*)
|
DECL_ACCESSORS(embedder_data, Foreign)
|
||||||
DECL_ACCESSORS(wrapper_code, Code)
|
DECL_ACCESSORS(wrapper_code, Code)
|
||||||
DECL_ACCESSORS(serialized_signature, PodArray<wasm::ValueType>)
|
DECL_ACCESSORS(serialized_signature, PodArray<wasm::ValueType>)
|
||||||
|
|
||||||
@ -776,7 +776,7 @@ class WasmCapiFunctionData : public Struct {
|
|||||||
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
|
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
|
||||||
TORQUE_GENERATED_WASM_CAPI_FUNCTION_DATA_FIELDS)
|
TORQUE_GENERATED_WASM_CAPI_FUNCTION_DATA_FIELDS)
|
||||||
|
|
||||||
STATIC_ASSERT(kStartOfStrongFieldsOffset == kWrapperCodeOffset);
|
STATIC_ASSERT(kStartOfStrongFieldsOffset == kEmbedderDataOffset);
|
||||||
using BodyDescriptor = FlexibleBodyDescriptor<kStartOfStrongFieldsOffset>;
|
using BodyDescriptor = FlexibleBodyDescriptor<kStartOfStrongFieldsOffset>;
|
||||||
|
|
||||||
OBJECT_CONSTRUCTORS(WasmCapiFunctionData, Struct);
|
OBJECT_CONSTRUCTORS(WasmCapiFunctionData, Struct);
|
||||||
|
@ -15,6 +15,8 @@ int g_functions_finalized = 0;
|
|||||||
int g_foreigns_finalized = 0;
|
int g_foreigns_finalized = 0;
|
||||||
int g_modules_finalized = 0;
|
int g_modules_finalized = 0;
|
||||||
|
|
||||||
|
const int kModuleMagic = 42;
|
||||||
|
|
||||||
void FinalizeInstance(void* data) {
|
void FinalizeInstance(void* data) {
|
||||||
int iteration = static_cast<int>(reinterpret_cast<intptr_t>(data));
|
int iteration = static_cast<int>(reinterpret_cast<intptr_t>(data));
|
||||||
g_instances_finalized += iteration;
|
g_instances_finalized += iteration;
|
||||||
@ -34,6 +36,31 @@ void FinalizeModule(void* data) {
|
|||||||
g_modules_finalized += static_cast<int>(reinterpret_cast<intptr_t>(data));
|
g_modules_finalized += static_cast<int>(reinterpret_cast<intptr_t>(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RunInStore(Store* store, ZoneBuffer* wire_bytes, int iterations) {
|
||||||
|
size_t size = wire_bytes->end() - wire_bytes->begin();
|
||||||
|
vec<byte_t> binary = vec<byte_t>::make(
|
||||||
|
size, reinterpret_cast<byte_t*>(const_cast<byte*>(wire_bytes->begin())));
|
||||||
|
own<Module> module = Module::make(store, binary);
|
||||||
|
module->set_host_info(reinterpret_cast<void*>(kModuleMagic), &FinalizeModule);
|
||||||
|
for (int iteration = 0; iteration < iterations; iteration++) {
|
||||||
|
void* finalizer_data = reinterpret_cast<void*>(iteration);
|
||||||
|
own<Instance> instance = Instance::make(store, module.get(), nullptr);
|
||||||
|
EXPECT_NE(nullptr, instance.get());
|
||||||
|
instance->set_host_info(finalizer_data, &FinalizeInstance);
|
||||||
|
|
||||||
|
own<Func> func = instance->exports()[0]->func()->copy();
|
||||||
|
ASSERT_NE(func, nullptr);
|
||||||
|
func->set_host_info(finalizer_data, &FinalizeFunction);
|
||||||
|
Val args[] = {Val::i32(iteration)};
|
||||||
|
Val results[1];
|
||||||
|
func->call(args, results);
|
||||||
|
EXPECT_EQ(iteration, results[0].i32());
|
||||||
|
|
||||||
|
own<Foreign> foreign = Foreign::make(store);
|
||||||
|
foreign->set_host_info(finalizer_data, &FinalizeForeign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST_F(WasmCapiTest, InstanceFinalization) {
|
TEST_F(WasmCapiTest, InstanceFinalization) {
|
||||||
@ -45,31 +72,114 @@ TEST_F(WasmCapiTest, InstanceFinalization) {
|
|||||||
g_functions_finalized = 0;
|
g_functions_finalized = 0;
|
||||||
g_foreigns_finalized = 0;
|
g_foreigns_finalized = 0;
|
||||||
g_modules_finalized = 0;
|
g_modules_finalized = 0;
|
||||||
module()->set_host_info(reinterpret_cast<void*>(42), &FinalizeModule);
|
module()->set_host_info(reinterpret_cast<void*>(kModuleMagic),
|
||||||
|
&FinalizeModule);
|
||||||
static const int kIterations = 10;
|
static const int kIterations = 10;
|
||||||
for (int iteration = 0; iteration < kIterations; iteration++) {
|
RunInStore(store(), wire_bytes(), kIterations);
|
||||||
void* finalizer_data = reinterpret_cast<void*>(iteration);
|
{
|
||||||
own<Instance> instance = Instance::make(store(), module(), nullptr);
|
own<Store> store2 = Store::make(engine());
|
||||||
EXPECT_NE(nullptr, instance.get());
|
RunInStore(store2.get(), wire_bytes(), kIterations);
|
||||||
instance->set_host_info(finalizer_data, &FinalizeInstance);
|
|
||||||
|
|
||||||
own<Func> func = instance->exports()[0]->func()->copy();
|
|
||||||
ASSERT_NE(func, nullptr);
|
|
||||||
func->set_host_info(finalizer_data, &FinalizeFunction);
|
|
||||||
|
|
||||||
own<Foreign> foreign = Foreign::make(store());
|
|
||||||
foreign->set_host_info(finalizer_data, &FinalizeForeign);
|
|
||||||
}
|
}
|
||||||
|
RunInStore(store(), wire_bytes(), kIterations);
|
||||||
Shutdown();
|
Shutdown();
|
||||||
// Verify that (1) all finalizers were called, and (2) they passed the
|
// Verify that (1) all finalizers were called, and (2) they passed the
|
||||||
// correct host data: the loop above sets {i} as data, and the finalizer
|
// correct host data: the loop above sets {i} as data, and the finalizer
|
||||||
// callbacks add them all up, so the expected value is
|
// callbacks add them all up, so the expected value after three rounds is
|
||||||
// sum([0, 1, ..., kIterations - 1]), which per Gauss's formula is:
|
// 3 * sum([0, 1, ..., kIterations - 1]), which per Gauss's formula is:
|
||||||
static const int kExpected = (kIterations * (kIterations - 1)) / 2;
|
static const int kExpected = 3 * ((kIterations * (kIterations - 1)) / 2);
|
||||||
EXPECT_EQ(g_instances_finalized, kExpected);
|
EXPECT_EQ(g_instances_finalized, kExpected);
|
||||||
|
// There are two functions per iteration.
|
||||||
EXPECT_EQ(g_functions_finalized, kExpected);
|
EXPECT_EQ(g_functions_finalized, kExpected);
|
||||||
EXPECT_EQ(g_foreigns_finalized, kExpected);
|
EXPECT_EQ(g_foreigns_finalized, kExpected);
|
||||||
EXPECT_EQ(g_modules_finalized, 42);
|
EXPECT_EQ(g_modules_finalized, 4 * kModuleMagic);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
own<Trap> CapiFunction(void* env, const Val args[], Val results[]) {
|
||||||
|
int offset = static_cast<int>(reinterpret_cast<intptr_t>(env));
|
||||||
|
results[0] = Val::i32(offset + args[0].i32());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int g_host_data_finalized = 0;
|
||||||
|
int g_capi_function_finalized = 0;
|
||||||
|
|
||||||
|
void FinalizeCapiFunction(void* data) {
|
||||||
|
int value = static_cast<int>(reinterpret_cast<intptr_t>(data));
|
||||||
|
g_capi_function_finalized += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FinalizeHostData(void* data) {
|
||||||
|
g_host_data_finalized += static_cast<int>(reinterpret_cast<intptr_t>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST_F(WasmCapiTest, CapiFunctionLifetimes) {
|
||||||
|
uint32_t func_index = builder()->AddImport(CStrVector("f"), wasm_i_i_sig());
|
||||||
|
builder()->ExportImportedFunction(CStrVector("f"), func_index);
|
||||||
|
Compile();
|
||||||
|
own<Instance> instance;
|
||||||
|
void* kHostData = reinterpret_cast<void*>(1234);
|
||||||
|
int base_summand = 1000;
|
||||||
|
{
|
||||||
|
// Test that the own<> pointers for Func and FuncType can go out of scope
|
||||||
|
// without affecting the ability of the Func to be called later.
|
||||||
|
own<FuncType> capi_func_type =
|
||||||
|
FuncType::make(ownvec<ValType>::make(ValType::make(::wasm::I32)),
|
||||||
|
ownvec<ValType>::make(ValType::make(::wasm::I32)));
|
||||||
|
own<Func> capi_func =
|
||||||
|
Func::make(store(), capi_func_type.get(), &CapiFunction,
|
||||||
|
reinterpret_cast<void*>(base_summand));
|
||||||
|
Extern* imports[] = {capi_func.get()};
|
||||||
|
instance = Instance::make(store(), module(), imports);
|
||||||
|
// TODO(jkummerow): It may or may not be desirable to be able to set
|
||||||
|
// host data even here and have it survive the import/export dance.
|
||||||
|
// We are awaiting resolution of the discussion at:
|
||||||
|
// https://github.com/WebAssembly/wasm-c-api/issues/100
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ownvec<Extern> exports = instance->exports();
|
||||||
|
Func* exported_func = exports[0]->func();
|
||||||
|
constexpr int kArg = 123;
|
||||||
|
Val args[] = {Val::i32(kArg)};
|
||||||
|
Val results[1];
|
||||||
|
exported_func->call(args, results);
|
||||||
|
EXPECT_EQ(base_summand + kArg, results[0].i32());
|
||||||
|
// Host data should survive destruction of the own<> pointer.
|
||||||
|
exported_func->set_host_info(kHostData);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ownvec<Extern> exports = instance->exports();
|
||||||
|
Func* exported_func = exports[0]->func();
|
||||||
|
EXPECT_EQ(kHostData, exported_func->get_host_info());
|
||||||
|
}
|
||||||
|
// Test that a Func can have its own internal metadata, an {env}, and
|
||||||
|
// separate {host info}, without any of that interfering with each other.
|
||||||
|
g_host_data_finalized = 0;
|
||||||
|
g_capi_function_finalized = 0;
|
||||||
|
base_summand = 23;
|
||||||
|
constexpr int kFinalizerData = 345;
|
||||||
|
{
|
||||||
|
own<FuncType> capi_func_type =
|
||||||
|
FuncType::make(ownvec<ValType>::make(ValType::make(::wasm::I32)),
|
||||||
|
ownvec<ValType>::make(ValType::make(::wasm::I32)));
|
||||||
|
own<Func> capi_func = Func::make(
|
||||||
|
store(), capi_func_type.get(), &CapiFunction,
|
||||||
|
reinterpret_cast<void*>(base_summand), &FinalizeCapiFunction);
|
||||||
|
capi_func->set_host_info(reinterpret_cast<void*>(kFinalizerData),
|
||||||
|
&FinalizeHostData);
|
||||||
|
constexpr int kArg = 19;
|
||||||
|
Val args[] = {Val::i32(kArg)};
|
||||||
|
Val results[1];
|
||||||
|
capi_func->call(args, results);
|
||||||
|
EXPECT_EQ(base_summand + kArg, results[0].i32());
|
||||||
|
}
|
||||||
|
instance.reset();
|
||||||
|
Shutdown();
|
||||||
|
EXPECT_EQ(base_summand, g_capi_function_finalized);
|
||||||
|
EXPECT_EQ(kFinalizerData, g_host_data_finalized);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace wasm
|
} // namespace wasm
|
||||||
|
@ -115,6 +115,7 @@ class WasmCapiTest : public ::testing::Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown() {
|
void Shutdown() {
|
||||||
|
exports_.reset();
|
||||||
instance_.reset();
|
instance_.reset();
|
||||||
module_.reset();
|
module_.reset();
|
||||||
store_.reset();
|
store_.reset();
|
||||||
|
4
third_party/wasm-api/README.v8
vendored
4
third_party/wasm-api/README.v8
vendored
@ -2,8 +2,8 @@ Name: Wasm C/C++ API
|
|||||||
Short Name: wasm-c-api
|
Short Name: wasm-c-api
|
||||||
URL: https://github.com/WebAssembly/wasm-c-api/
|
URL: https://github.com/WebAssembly/wasm-c-api/
|
||||||
Version: 0
|
Version: 0
|
||||||
Revision: 5c742b048f7766a0c00be3a7af23fb71ba816026
|
Revision: 6db391ee7121a0695602945d11001ea3e00b0afb
|
||||||
Date: 2019-03-18
|
Date: 2019-08-08
|
||||||
License: Apache 2.0
|
License: Apache 2.0
|
||||||
License File: LICENSE
|
License File: LICENSE
|
||||||
Security Critical: yes
|
Security Critical: yes
|
||||||
|
55
third_party/wasm-api/example/finalize.c
vendored
55
third_party/wasm-api/example/finalize.c
vendored
@ -9,23 +9,21 @@
|
|||||||
|
|
||||||
const int iterations = 100000;
|
const int iterations = 100000;
|
||||||
|
|
||||||
|
int live_count = 0;
|
||||||
|
|
||||||
void finalize(void* data) {
|
void finalize(void* data) {
|
||||||
int i = (int)data;
|
int i = (int)data;
|
||||||
if (i % (iterations / 10) == 0) printf("Finalizing #%d...\n", i);
|
if (i % (iterations / 10) == 0) printf("Finalizing #%d...\n", i);
|
||||||
|
--live_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
void run_in_store(wasm_store_t* store) {
|
||||||
// Initialize.
|
|
||||||
printf("Initializing...\n");
|
|
||||||
wasm_engine_t* engine = wasm_engine_new();
|
|
||||||
wasm_store_t* store = wasm_store_new(engine);
|
|
||||||
|
|
||||||
// Load binary.
|
// Load binary.
|
||||||
printf("Loading binary...\n");
|
printf("Loading binary...\n");
|
||||||
FILE* file = fopen("finalize.wasm", "r");
|
FILE* file = fopen("finalize.wasm", "r");
|
||||||
if (!file) {
|
if (!file) {
|
||||||
printf("> Error loading module!\n");
|
printf("> Error loading module!\n");
|
||||||
return 1;
|
exit(1);
|
||||||
}
|
}
|
||||||
fseek(file, 0L, SEEK_END);
|
fseek(file, 0L, SEEK_END);
|
||||||
size_t file_size = ftell(file);
|
size_t file_size = ftell(file);
|
||||||
@ -34,7 +32,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
wasm_byte_vec_new_uninitialized(&binary, file_size);
|
wasm_byte_vec_new_uninitialized(&binary, file_size);
|
||||||
if (fread(binary.data, file_size, 1, file) != 1) {
|
if (fread(binary.data, file_size, 1, file) != 1) {
|
||||||
printf("> Error loading module!\n");
|
printf("> Error loading module!\n");
|
||||||
return 1;
|
exit(1);
|
||||||
}
|
}
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
@ -43,7 +41,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
own wasm_module_t* module = wasm_module_new(store, &binary);
|
own wasm_module_t* module = wasm_module_new(store, &binary);
|
||||||
if (!module) {
|
if (!module) {
|
||||||
printf("> Error compiling module!\n");
|
printf("> Error compiling module!\n");
|
||||||
return 1;
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm_byte_vec_delete(&binary);
|
wasm_byte_vec_delete(&binary);
|
||||||
@ -56,18 +54,53 @@ int main(int argc, const char* argv[]) {
|
|||||||
wasm_instance_new(store, module, NULL, NULL);
|
wasm_instance_new(store, module, NULL, NULL);
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
printf("> Error instantiating module %d!\n", i);
|
printf("> Error instantiating module %d!\n", i);
|
||||||
return 1;
|
exit(1);
|
||||||
}
|
}
|
||||||
void* data = (void*)(intptr_t)i;
|
void* data = (void*)(intptr_t)i;
|
||||||
wasm_instance_set_host_info_with_finalizer(instance, data, &finalize);
|
wasm_instance_set_host_info_with_finalizer(instance, data, &finalize);
|
||||||
wasm_instance_delete(instance);
|
wasm_instance_delete(instance);
|
||||||
|
++live_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm_module_delete(module);
|
wasm_module_delete(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[]) {
|
||||||
|
// Initialize.
|
||||||
|
printf("Initializing...\n");
|
||||||
|
wasm_engine_t* engine = wasm_engine_new();
|
||||||
|
|
||||||
|
printf("Live count %d\n", live_count);
|
||||||
|
printf("Creating store 1...\n");
|
||||||
|
wasm_store_t* store1 = wasm_store_new(engine);
|
||||||
|
|
||||||
|
printf("Running in store 1...\n");
|
||||||
|
run_in_store(store1);
|
||||||
|
printf("Live count %d\n", live_count);
|
||||||
|
|
||||||
|
printf("Creating store 2...\n");
|
||||||
|
wasm_store_t* store2 = wasm_store_new(engine);
|
||||||
|
|
||||||
|
printf("Running in store 2...\n");
|
||||||
|
run_in_store(store2);
|
||||||
|
printf("Live count %d\n", live_count);
|
||||||
|
|
||||||
|
printf("Deleting store 2...\n");
|
||||||
|
wasm_store_delete(store2);
|
||||||
|
printf("Live count %d\n", live_count);
|
||||||
|
|
||||||
|
printf("Running in store 1...\n");
|
||||||
|
run_in_store(store1);
|
||||||
|
printf("Live count %d\n", live_count);
|
||||||
|
|
||||||
|
printf("Deleting store 1...\n");
|
||||||
|
wasm_store_delete(store1);
|
||||||
|
printf("Live count %d\n", live_count);
|
||||||
|
|
||||||
|
assert(live_count == 0);
|
||||||
|
|
||||||
// Shut down.
|
// Shut down.
|
||||||
printf("Shutting down...\n");
|
printf("Shutting down...\n");
|
||||||
wasm_store_delete(store);
|
|
||||||
wasm_engine_delete(engine);
|
wasm_engine_delete(engine);
|
||||||
|
|
||||||
// All done.
|
// All done.
|
||||||
|
47
third_party/wasm-api/example/finalize.cc
vendored
47
third_party/wasm-api/example/finalize.cc
vendored
@ -9,20 +9,17 @@
|
|||||||
|
|
||||||
const int iterations = 100000;
|
const int iterations = 100000;
|
||||||
|
|
||||||
|
int live_count = 0;
|
||||||
|
|
||||||
void finalize(void* data) {
|
void finalize(void* data) {
|
||||||
intptr_t i = reinterpret_cast<intptr_t>(data);
|
intptr_t i = reinterpret_cast<intptr_t>(data);
|
||||||
if (i % (iterations / 10) == 0) {
|
if (i % (iterations / 10) == 0) {
|
||||||
std::cout << "Finalizing #" << i << "..." << std::endl;
|
std::cout << "Finalizing #" << i << "..." << std::endl;
|
||||||
}
|
}
|
||||||
|
--live_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() {
|
void run_in_store(wasm::Store* store) {
|
||||||
// Initialize.
|
|
||||||
std::cout << "Initializing..." << std::endl;
|
|
||||||
auto engine = wasm::Engine::make();
|
|
||||||
auto store_ = wasm::Store::make(engine.get());
|
|
||||||
auto store = store_.get();
|
|
||||||
|
|
||||||
// Load binary.
|
// Load binary.
|
||||||
std::cout << "Loading binary..." << std::endl;
|
std::cout << "Loading binary..." << std::endl;
|
||||||
std::ifstream file("finalize.wasm");
|
std::ifstream file("finalize.wasm");
|
||||||
@ -55,6 +52,7 @@ void run() {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
instance->set_host_info(reinterpret_cast<void*>(i), &finalize);
|
instance->set_host_info(reinterpret_cast<void*>(i), &finalize);
|
||||||
|
++live_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shut down.
|
// Shut down.
|
||||||
@ -62,8 +60,43 @@ void run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
// Initialize.
|
||||||
|
std::cout << "Initializing..." << std::endl;
|
||||||
|
auto engine = wasm::Engine::make();
|
||||||
|
|
||||||
|
std::cout << "Live count " << live_count << std::endl;
|
||||||
|
std::cout << "Creating store 1..." << std::endl;
|
||||||
|
auto store1 = wasm::Store::make(engine.get());
|
||||||
|
|
||||||
|
std::cout << "Running in store 1..." << std::endl;
|
||||||
|
run_in_store(store1.get());
|
||||||
|
std::cout << "Live count " << live_count << std::endl;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::cout << "Creating store 2..." << std::endl;
|
||||||
|
auto store2 = wasm::Store::make(engine.get());
|
||||||
|
|
||||||
|
std::cout << "Running in store 2..." << std::endl;
|
||||||
|
run_in_store(store2.get());
|
||||||
|
std::cout << "Live count " << live_count << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Deleting store 2..." << std::endl;
|
||||||
|
std::cout << "Live count " << live_count << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Running in store 1..." << std::endl;
|
||||||
|
run_in_store(store1.get());
|
||||||
|
std::cout << "Live count " << live_count << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Deleting store 1..." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
run();
|
run();
|
||||||
|
std::cout << "Live count " << live_count << std::endl;
|
||||||
|
assert(live_count == 0);
|
||||||
std::cout << "Done." << std::endl;
|
std::cout << "Done." << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user