summaryrefslogtreecommitdiff
path: root/deps/v8/src/wasm
diff options
context:
space:
mode:
authorMyles Borins <mylesborins@google.com>2019-09-24 11:56:38 -0400
committerMyles Borins <myles.borins@gmail.com>2019-10-07 03:19:23 -0400
commitf7f6c928c1c9c136b7926f892b8a2fda11d8b4b2 (patch)
treef5edbccb3ffda2573d70a6e291e7157f290e0ae0 /deps/v8/src/wasm
parentffd22e81983056d09c064c59343a0e488236272d (diff)
downloadandroid-node-v8-f7f6c928c1c9c136b7926f892b8a2fda11d8b4b2.tar.gz
android-node-v8-f7f6c928c1c9c136b7926f892b8a2fda11d8b4b2.tar.bz2
android-node-v8-f7f6c928c1c9c136b7926f892b8a2fda11d8b4b2.zip
deps: update V8 to 7.8.279.9
PR-URL: https://github.com/nodejs/node/pull/29694 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Jiawen Geng <technicalcute@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com>
Diffstat (limited to 'deps/v8/src/wasm')
-rw-r--r--deps/v8/src/wasm/baseline/arm64/liftoff-assembler-arm64.h4
-rw-r--r--deps/v8/src/wasm/baseline/liftoff-compiler.cc33
-rw-r--r--deps/v8/src/wasm/c-api.cc1396
-rw-r--r--deps/v8/src/wasm/c-api.h16
-rw-r--r--deps/v8/src/wasm/function-body-decoder-impl.h103
-rw-r--r--deps/v8/src/wasm/function-compiler.cc22
-rw-r--r--deps/v8/src/wasm/function-compiler.h11
-rw-r--r--deps/v8/src/wasm/graph-builder-interface.cc53
-rw-r--r--deps/v8/src/wasm/jump-table-assembler.h15
-rw-r--r--deps/v8/src/wasm/module-compiler.cc341
-rw-r--r--deps/v8/src/wasm/module-compiler.h4
-rw-r--r--deps/v8/src/wasm/module-instantiate.cc52
-rw-r--r--deps/v8/src/wasm/wasm-code-manager.cc239
-rw-r--r--deps/v8/src/wasm/wasm-code-manager.h68
-rw-r--r--deps/v8/src/wasm/wasm-engine.cc40
-rw-r--r--deps/v8/src/wasm/wasm-engine.h3
-rw-r--r--deps/v8/src/wasm/wasm-external-refs.cc96
-rw-r--r--deps/v8/src/wasm/wasm-feature-flags.h46
-rw-r--r--deps/v8/src/wasm/wasm-features.cc16
-rw-r--r--deps/v8/src/wasm/wasm-features.h57
-rw-r--r--deps/v8/src/wasm/wasm-interpreter.cc85
-rw-r--r--deps/v8/src/wasm/wasm-js.cc203
-rw-r--r--deps/v8/src/wasm/wasm-module-builder.cc73
-rw-r--r--deps/v8/src/wasm/wasm-module-builder.h12
-rw-r--r--deps/v8/src/wasm/wasm-module-sourcemap.cc161
-rw-r--r--deps/v8/src/wasm/wasm-module-sourcemap.h83
-rw-r--r--deps/v8/src/wasm/wasm-module.cc203
-rw-r--r--deps/v8/src/wasm/wasm-module.h21
-rw-r--r--deps/v8/src/wasm/wasm-objects-inl.h21
-rw-r--r--deps/v8/src/wasm/wasm-objects.cc96
-rw-r--r--deps/v8/src/wasm/wasm-objects.h65
-rw-r--r--deps/v8/src/wasm/wasm-opcodes.cc17
-rw-r--r--deps/v8/src/wasm/wasm-opcodes.h67
-rw-r--r--deps/v8/src/wasm/wasm-serialization.cc16
-rw-r--r--deps/v8/src/wasm/wasm-text.cc17
35 files changed, 2384 insertions, 1371 deletions
diff --git a/deps/v8/src/wasm/baseline/arm64/liftoff-assembler-arm64.h b/deps/v8/src/wasm/baseline/arm64/liftoff-assembler-arm64.h
index 57a157d3a7..dc68267825 100644
--- a/deps/v8/src/wasm/baseline/arm64/liftoff-assembler-arm64.h
+++ b/deps/v8/src/wasm/baseline/arm64/liftoff-assembler-arm64.h
@@ -210,7 +210,9 @@ void LiftoffAssembler::LoadFromInstance(Register dst, uint32_t offset,
void LiftoffAssembler::LoadTaggedPointerFromInstance(Register dst,
uint32_t offset) {
- LoadFromInstance(dst, offset, kTaggedSize);
+ DCHECK_LE(offset, kMaxInt);
+ Ldr(dst, liftoff::GetInstanceOperand());
+ LoadTaggedPointerField(dst, MemOperand(dst, offset));
}
void LiftoffAssembler::SpillInstance(Register instance) {
diff --git a/deps/v8/src/wasm/baseline/liftoff-compiler.cc b/deps/v8/src/wasm/baseline/liftoff-compiler.cc
index 7a87ae1a95..02de06763c 100644
--- a/deps/v8/src/wasm/baseline/liftoff-compiler.cc
+++ b/deps/v8/src/wasm/baseline/liftoff-compiler.cc
@@ -1606,32 +1606,35 @@ class LiftoffCompiler {
void GenerateRuntimeCall(Runtime::FunctionId runtime_function, int num_args,
Register* args) {
- auto call_descriptor = compiler::Linkage::GetRuntimeCallDescriptor(
- compilation_zone_, runtime_function, num_args,
- compiler::Operator::kNoProperties, compiler::CallDescriptor::kNoFlags);
// Currently, only one argument is supported. More arguments require some
// caution for the parallel register moves (reuse StackTransferRecipe).
DCHECK_EQ(1, num_args);
+#ifdef DEBUG
+ auto call_descriptor = compiler::Linkage::GetRuntimeCallDescriptor(
+ compilation_zone_, runtime_function, num_args,
+ compiler::Operator::kNoProperties, compiler::CallDescriptor::kNoFlags);
constexpr size_t kInputShift = 1; // Input 0 is the call target.
compiler::LinkageLocation param_loc =
call_descriptor->GetInputLocation(kInputShift);
- if (param_loc.IsRegister()) {
- Register reg = Register::from_code(param_loc.AsRegister());
- __ Move(LiftoffRegister(reg), LiftoffRegister(args[0]),
- LiftoffAssembler::kWasmIntPtr);
- } else {
- DCHECK(param_loc.IsCallerFrameSlot());
- LiftoffStackSlots stack_slots(&asm_);
- stack_slots.Add(LiftoffAssembler::VarState(LiftoffAssembler::kWasmIntPtr,
- LiftoffRegister(args[0])));
- stack_slots.Construct();
- }
+ // Runtime calls take their arguments on the stack.
+ DCHECK(param_loc.IsCallerFrameSlot());
+#endif
+ LiftoffStackSlots stack_slots(&asm_);
+ stack_slots.Add(LiftoffAssembler::VarState(LiftoffAssembler::kWasmIntPtr,
+ LiftoffRegister(args[0])));
+ stack_slots.Construct();
// Set context to "no context" for the runtime call.
__ TurboAssembler::Move(kContextRegister,
Smi::FromInt(Context::kNoContext));
Register centry = kJavaScriptCallCodeStartRegister;
- LOAD_TAGGED_PTR_INSTANCE_FIELD(centry, CEntryStub);
+ LOAD_INSTANCE_FIELD(centry, IsolateRoot, kSystemPointerSize);
+ // All cache registers are spilled and there are no register arguments.
+ LiftoffRegList pinned;
+ auto centry_id =
+ Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit;
+ __ LoadTaggedPointer(centry, centry, no_reg,
+ IsolateData::builtin_slot_offset(centry_id), pinned);
__ CallRuntimeWithCEntry(runtime_function, centry);
safepoint_table_builder_.DefineSafepoint(&asm_, Safepoint::kNoLazyDeopt);
}
diff --git a/deps/v8/src/wasm/c-api.cc b/deps/v8/src/wasm/c-api.cc
index 86bba189b8..e812dd7994 100644
--- a/deps/v8/src/wasm/c-api.cc
+++ b/deps/v8/src/wasm/c-api.cc
@@ -29,6 +29,9 @@
#include "include/libplatform/libplatform.h"
#include "src/api/api-inl.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/wasm/leb-helper.h"
#include "src/wasm/module-instantiate.h"
#include "src/wasm/wasm-arguments.h"
@@ -37,6 +40,10 @@
#include "src/wasm/wasm-result.h"
#include "src/wasm/wasm-serialization.h"
+#ifdef WASM_API_DEBUG
+#error "WASM_API_DEBUG is unsupported"
+#endif
+
namespace wasm {
namespace {
@@ -98,35 +105,36 @@ Name GetNameFromWireBytes(const i::wasm::WireBytesRef& ref,
const i::Vector<const uint8_t>& wire_bytes) {
DCHECK_LE(ref.offset(), wire_bytes.length());
DCHECK_LE(ref.end_offset(), wire_bytes.length());
+ if (ref.length() == 0) return Name::make();
Name name = Name::make_uninitialized(ref.length());
std::memcpy(name.get(), wire_bytes.begin() + ref.offset(), ref.length());
return name;
}
-own<FuncType*> FunctionSigToFuncType(const i::wasm::FunctionSig* sig) {
+own<FuncType> FunctionSigToFuncType(const i::wasm::FunctionSig* sig) {
size_t param_count = sig->parameter_count();
- vec<ValType*> params = vec<ValType*>::make_uninitialized(param_count);
+ ownvec<ValType> params = ownvec<ValType>::make_uninitialized(param_count);
for (size_t i = 0; i < param_count; i++) {
params[i] = ValType::make(V8ValueTypeToWasm(sig->GetParam(i)));
}
size_t return_count = sig->return_count();
- vec<ValType*> results = vec<ValType*>::make_uninitialized(return_count);
+ ownvec<ValType> results = ownvec<ValType>::make_uninitialized(return_count);
for (size_t i = 0; i < return_count; i++) {
results[i] = ValType::make(V8ValueTypeToWasm(sig->GetReturn(i)));
}
return FuncType::make(std::move(params), std::move(results));
}
-own<ExternType*> GetImportExportType(const i::wasm::WasmModule* module,
- const i::wasm::ImportExportKindCode kind,
- const uint32_t index) {
+own<ExternType> GetImportExportType(const i::wasm::WasmModule* module,
+ const i::wasm::ImportExportKindCode kind,
+ const uint32_t index) {
switch (kind) {
case i::wasm::kExternalFunction: {
return FunctionSigToFuncType(module->functions[index].sig);
}
case i::wasm::kExternalTable: {
const i::wasm::WasmTable& table = module->tables[index];
- own<ValType*> elem = ValType::make(V8ValueTypeToWasm(table.type));
+ own<ValType> elem = ValType::make(V8ValueTypeToWasm(table.type));
Limits limits(table.initial_size,
table.has_maximum_size ? table.maximum_size : -1);
return TableType::make(std::move(elem), limits);
@@ -139,7 +147,7 @@ own<ExternType*> GetImportExportType(const i::wasm::WasmModule* module,
}
case i::wasm::kExternalGlobal: {
const i::wasm::WasmGlobal& global = module->globals[index];
- own<ValType*> content = ValType::make(V8ValueTypeToWasm(global.type));
+ own<ValType> content = ValType::make(V8ValueTypeToWasm(global.type));
Mutability mutability = global.mutability ? VAR : CONST;
return GlobalType::make(std::move(content), mutability);
}
@@ -187,14 +195,6 @@ auto seal(const typename implement<C>::type* x) -> const C* {
return reinterpret_cast<const C*>(x);
}
-#ifdef DEBUG
-template <class T>
-void vec<T>::make_data() {}
-
-template <class T>
-void vec<T>::free_data() {}
-#endif
-
///////////////////////////////////////////////////////////////////////////////
// Runtime Environment
@@ -214,8 +214,8 @@ Config::~Config() { impl(this)->~ConfigImpl(); }
void Config::operator delete(void* p) { ::operator delete(p); }
-auto Config::make() -> own<Config*> {
- return own<Config*>(seal<Config>(new (std::nothrow) ConfigImpl()));
+auto Config::make() -> own<Config> {
+ return own<Config>(seal<Config>(new (std::nothrow) ConfigImpl()));
}
// Engine
@@ -247,13 +247,13 @@ Engine::~Engine() { impl(this)->~EngineImpl(); }
void Engine::operator delete(void* p) { ::operator delete(p); }
-auto Engine::make(own<Config*>&& config) -> own<Engine*> {
+auto Engine::make(own<Config>&& config) -> own<Engine> {
i::FLAG_expose_gc = true;
i::FLAG_experimental_wasm_anyref = true;
i::FLAG_experimental_wasm_bigint = true;
i::FLAG_experimental_wasm_mv = true;
auto engine = new (std::nothrow) EngineImpl;
- if (!engine) return own<Engine*>();
+ if (!engine) return own<Engine>();
engine->platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(engine->platform.get());
v8::V8::Initialize();
@@ -273,6 +273,38 @@ StoreImpl::~StoreImpl() {
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 <>
struct implement<Store> {
using type = StoreImpl;
@@ -282,33 +314,40 @@ Store::~Store() { impl(this)->~StoreImpl(); }
void Store::operator delete(void* p) { ::operator delete(p); }
-auto Store::make(Engine*) -> own<Store*> {
+auto Store::make(Engine*) -> own<Store> {
auto store = make_own(new (std::nothrow) StoreImpl());
- if (!store) return own<Store*>();
+ if (!store) return own<Store>();
// Create isolate.
store->create_params_.array_buffer_allocator =
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
- auto isolate = v8::Isolate::New(store->create_params_);
- if (!isolate) return own<Store*>();
+ v8::Isolate* isolate = v8::Isolate::New(store->create_params_);
+ 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);
// Create context.
- auto context = v8::Context::New(isolate);
- if (context.IsEmpty()) return own<Store*>();
- v8::Context::Scope context_scope(context);
-
- store->isolate_ = isolate;
+ v8::Local<v8::Context> context = v8::Context::New(isolate);
+ if (context.IsEmpty()) return own<Store>();
+ context->Enter(); // The Exit() call is in ~StoreImpl.
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.
+ constexpr int kStackLimit = 10;
+ isolate->SetCaptureStackTraceForUncaughtExceptions(true, kStackLimit,
+ v8::StackTrace::kOverview);
return make_own(seal<Store>(store.release()));
}
@@ -329,21 +368,46 @@ struct implement<ValType> {
using type = ValTypeImpl;
};
-ValTypeImpl* valtypes[] = {
- new ValTypeImpl(I32), new ValTypeImpl(I64), new ValTypeImpl(F32),
- new ValTypeImpl(F64), new ValTypeImpl(ANYREF), new ValTypeImpl(FUNCREF),
-};
+ValTypeImpl* valtype_i32 = new ValTypeImpl(I32);
+ValTypeImpl* valtype_i64 = new ValTypeImpl(I64);
+ValTypeImpl* valtype_f32 = new ValTypeImpl(F32);
+ValTypeImpl* valtype_f64 = new ValTypeImpl(F64);
+ValTypeImpl* valtype_anyref = new ValTypeImpl(ANYREF);
+ValTypeImpl* valtype_funcref = new ValTypeImpl(FUNCREF);
ValType::~ValType() {}
void ValType::operator delete(void*) {}
-auto ValType::make(ValKind k) -> own<ValType*> {
- auto result = seal<ValType>(valtypes[k]);
- return own<ValType*>(result);
+own<ValType> ValType::make(ValKind k) {
+ ValTypeImpl* valtype;
+ switch (k) {
+ case I32:
+ valtype = valtype_i32;
+ break;
+ case I64:
+ valtype = valtype_i64;
+ break;
+ case F32:
+ valtype = valtype_f32;
+ break;
+ case F64:
+ valtype = valtype_f64;
+ break;
+ case ANYREF:
+ valtype = valtype_anyref;
+ break;
+ case FUNCREF:
+ valtype = valtype_funcref;
+ break;
+ default:
+ // TODO(wasm+): support new value types
+ UNREACHABLE();
+ }
+ return own<ValType>(seal<ValType>(valtype));
}
-auto ValType::copy() const -> own<ValType*> { return make(kind()); }
+auto ValType::copy() const -> own<ValType> { return make(kind()); }
auto ValType::kind() const -> ValKind { return impl(this)->kind; }
@@ -365,7 +429,7 @@ ExternType::~ExternType() { impl(this)->~ExternTypeImpl(); }
void ExternType::operator delete(void* p) { ::operator delete(p); }
-auto ExternType::copy() const -> own<ExternType*> {
+auto ExternType::copy() const -> own<ExternType> {
switch (kind()) {
case EXTERN_FUNC:
return func()->copy();
@@ -383,11 +447,11 @@ auto ExternType::kind() const -> ExternKind { return impl(this)->kind; }
// Function Types
struct FuncTypeImpl : ExternTypeImpl {
- vec<ValType*> params;
- vec<ValType*> results;
+ ownvec<ValType> params;
+ ownvec<ValType> results;
- FuncTypeImpl(vec<ValType*>& params, // NOLINT(runtime/references)
- vec<ValType*>& results) // NOLINT(runtime/references)
+ FuncTypeImpl(ownvec<ValType>& params, // NOLINT(runtime/references)
+ ownvec<ValType>& results) // NOLINT(runtime/references)
: ExternTypeImpl(EXTERN_FUNC),
params(std::move(params)),
results(std::move(results)) {}
@@ -402,23 +466,23 @@ struct implement<FuncType> {
FuncType::~FuncType() {}
-auto FuncType::make(vec<ValType*>&& params, vec<ValType*>&& results)
- -> own<FuncType*> {
+auto FuncType::make(ownvec<ValType>&& params, ownvec<ValType>&& results)
+ -> own<FuncType> {
return params && results
- ? own<FuncType*>(seal<FuncType>(new (std::nothrow)
- FuncTypeImpl(params, results)))
- : own<FuncType*>();
+ ? own<FuncType>(seal<FuncType>(new (std::nothrow)
+ FuncTypeImpl(params, results)))
+ : own<FuncType>();
}
-auto FuncType::copy() const -> own<FuncType*> {
- return make(params().copy(), results().copy());
+auto FuncType::copy() const -> own<FuncType> {
+ return make(params().deep_copy(), results().deep_copy());
}
-auto FuncType::params() const -> const vec<ValType*>& {
+auto FuncType::params() const -> const ownvec<ValType>& {
return impl(this)->params;
}
-auto FuncType::results() const -> const vec<ValType*>& {
+auto FuncType::results() const -> const ownvec<ValType>& {
return impl(this)->results;
}
@@ -437,10 +501,10 @@ auto ExternType::func() const -> const FuncType* {
// Global Types
struct GlobalTypeImpl : ExternTypeImpl {
- own<ValType*> content;
+ own<ValType> content;
Mutability mutability;
- GlobalTypeImpl(own<ValType*>& content, // NOLINT(runtime/references)
+ GlobalTypeImpl(own<ValType>& content, // NOLINT(runtime/references)
Mutability mutability)
: ExternTypeImpl(EXTERN_GLOBAL),
content(std::move(content)),
@@ -456,14 +520,14 @@ struct implement<GlobalType> {
GlobalType::~GlobalType() {}
-auto GlobalType::make(own<ValType*>&& content, Mutability mutability)
- -> own<GlobalType*> {
- return content ? own<GlobalType*>(seal<GlobalType>(
+auto GlobalType::make(own<ValType>&& content, Mutability mutability)
+ -> own<GlobalType> {
+ return content ? own<GlobalType>(seal<GlobalType>(
new (std::nothrow) GlobalTypeImpl(content, mutability)))
- : own<GlobalType*>();
+ : own<GlobalType>();
}
-auto GlobalType::copy() const -> own<GlobalType*> {
+auto GlobalType::copy() const -> own<GlobalType> {
return make(content()->copy(), mutability());
}
@@ -490,10 +554,10 @@ auto ExternType::global() const -> const GlobalType* {
// Table Types
struct TableTypeImpl : ExternTypeImpl {
- own<ValType*> element;
+ own<ValType> element;
Limits limits;
- TableTypeImpl(own<ValType*>& element, // NOLINT(runtime/references)
+ TableTypeImpl(own<ValType>& element, // NOLINT(runtime/references)
Limits limits)
: ExternTypeImpl(EXTERN_TABLE),
element(std::move(element)),
@@ -509,14 +573,13 @@ struct implement<TableType> {
TableType::~TableType() {}
-auto TableType::make(own<ValType*>&& element, Limits limits)
- -> own<TableType*> {
- return element ? own<TableType*>(seal<TableType>(
+auto TableType::make(own<ValType>&& element, Limits limits) -> own<TableType> {
+ return element ? own<TableType>(seal<TableType>(
new (std::nothrow) TableTypeImpl(element, limits)))
- : own<TableType*>();
+ : own<TableType>();
}
-auto TableType::copy() const -> own<TableType*> {
+auto TableType::copy() const -> own<TableType> {
return make(element()->copy(), limits());
}
@@ -556,12 +619,12 @@ struct implement<MemoryType> {
MemoryType::~MemoryType() {}
-auto MemoryType::make(Limits limits) -> own<MemoryType*> {
- return own<MemoryType*>(
+auto MemoryType::make(Limits limits) -> own<MemoryType> {
+ return own<MemoryType>(
seal<MemoryType>(new (std::nothrow) MemoryTypeImpl(limits)));
}
-auto MemoryType::copy() const -> own<MemoryType*> {
+auto MemoryType::copy() const -> own<MemoryType> {
return MemoryType::make(limits());
}
@@ -584,11 +647,11 @@ auto ExternType::memory() const -> const MemoryType* {
struct ImportTypeImpl {
Name module;
Name name;
- own<ExternType*> type;
+ own<ExternType> type;
- ImportTypeImpl(Name& module, // NOLINT(runtime/references)
- Name& name, // NOLINT(runtime/references)
- own<ExternType*>& type) // NOLINT(runtime/references)
+ ImportTypeImpl(Name& module, // NOLINT(runtime/references)
+ Name& name, // NOLINT(runtime/references)
+ own<ExternType>& type) // NOLINT(runtime/references)
: module(std::move(module)),
name(std::move(name)),
type(std::move(type)) {}
@@ -605,15 +668,15 @@ ImportType::~ImportType() { impl(this)->~ImportTypeImpl(); }
void ImportType::operator delete(void* p) { ::operator delete(p); }
-auto ImportType::make(Name&& module, Name&& name, own<ExternType*>&& type)
- -> own<ImportType*> {
+auto ImportType::make(Name&& module, Name&& name, own<ExternType>&& type)
+ -> own<ImportType> {
return module && name && type
- ? own<ImportType*>(seal<ImportType>(
+ ? own<ImportType>(seal<ImportType>(
new (std::nothrow) ImportTypeImpl(module, name, type)))
- : own<ImportType*>();
+ : own<ImportType>();
}
-auto ImportType::copy() const -> own<ImportType*> {
+auto ImportType::copy() const -> own<ImportType> {
return make(module().copy(), name().copy(), type()->copy());
}
@@ -629,10 +692,10 @@ auto ImportType::type() const -> const ExternType* {
struct ExportTypeImpl {
Name name;
- own<ExternType*> type;
+ own<ExternType> type;
- ExportTypeImpl(Name& name, // NOLINT(runtime/references)
- own<ExternType*>& type) // NOLINT(runtime/references)
+ ExportTypeImpl(Name& name, // NOLINT(runtime/references)
+ own<ExternType>& type) // NOLINT(runtime/references)
: name(std::move(name)), type(std::move(type)) {}
~ExportTypeImpl() {}
@@ -647,14 +710,13 @@ ExportType::~ExportType() { impl(this)->~ExportTypeImpl(); }
void ExportType::operator delete(void* p) { ::operator delete(p); }
-auto ExportType::make(Name&& name, own<ExternType*>&& type)
- -> own<ExportType*> {
- return name && type ? own<ExportType*>(seal<ExportType>(
+auto ExportType::make(Name&& name, own<ExternType>&& type) -> own<ExportType> {
+ return name && type ? own<ExportType>(seal<ExportType>(
new (std::nothrow) ExportTypeImpl(name, type)))
- : own<ExportType*>();
+ : own<ExportType>();
}
-auto ExportType::copy() const -> own<ExportType*> {
+auto ExportType::copy() const -> own<ExportType> {
return make(name().copy(), type()->copy());
}
@@ -680,7 +742,7 @@ i::Handle<i::String> VecToString(i::Isolate* isolate,
template <class Ref, class JSType>
class RefImpl {
public:
- static own<Ref*> make(StoreImpl* store, i::Handle<JSType> obj) {
+ static own<Ref> make(StoreImpl* store, i::Handle<JSType> obj) {
RefImpl* self = new (std::nothrow) RefImpl();
if (!self) return nullptr;
i::Isolate* isolate = store->i_isolate();
@@ -688,17 +750,9 @@ class RefImpl {
return make_own(seal<Ref>(self));
}
- void Reset() {
- i::GlobalHandles::Destroy(location());
- if (host_data_) {
- if (host_data_->finalizer) {
- host_data_->finalizer(host_data_->info);
- }
- delete host_data_;
- }
- }
+ ~RefImpl() { i::GlobalHandles::Destroy(location()); }
- own<Ref*> copy() const { return make(store(), v8_object()); }
+ own<Ref> copy() const { return make(store(), v8_object()); }
StoreImpl* store() const { return StoreImpl::get(isolate()); }
@@ -706,41 +760,20 @@ class RefImpl {
i::Handle<JSType> v8_object() const { return i::Handle<JSType>::cast(val_); }
- void* get_host_info() const {
- if (host_data_ == nullptr) return nullptr;
- return host_data_->info;
- }
+ void* get_host_info() const { return store()->GetHostInfo(v8_object()); }
void set_host_info(void* info, void (*finalizer)(void*)) {
- host_data_ = new HostData(location(), info, finalizer);
- i::GlobalHandles::MakeWeak(host_data_->location, host_data_, &v8_finalizer,
- v8::WeakCallbackType::kParameter);
+ store()->SetHostInfo(v8_object(), info, finalizer);
}
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() {}
- 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 {
return reinterpret_cast<i::Address*>(val_.address());
}
i::Handle<i::JSReceiver> val_;
- HostData* host_data_ = nullptr;
};
template <>
@@ -749,13 +782,17 @@ struct implement<Ref> {
};
Ref::~Ref() {
- impl(this)->Reset();
delete impl(this);
}
void Ref::operator delete(void* p) {}
-auto Ref::copy() const -> own<Ref*> { return impl(this)->copy(); }
+auto Ref::copy() const -> own<Ref> { return impl(this)->copy(); }
+
+auto Ref::same(const Ref* that) const -> bool {
+ i::HandleScope handle_scope(impl(this)->isolate());
+ return impl(this)->v8_object()->SameValue(*impl(that)->v8_object());
+}
auto Ref::get_host_info() const -> void* { return impl(this)->get_host_info(); }
@@ -766,6 +803,52 @@ void Ref::set_host_info(void* info, void (*finalizer)(void*)) {
///////////////////////////////////////////////////////////////////////////////
// Runtime Objects
+// Frames
+
+namespace {
+
+struct FrameImpl {
+ FrameImpl(own<Instance>&& instance, uint32_t func_index, size_t func_offset,
+ size_t module_offset)
+ : instance(std::move(instance)),
+ func_index(func_index),
+ func_offset(func_offset),
+ module_offset(module_offset) {}
+
+ ~FrameImpl() {}
+
+ own<Instance> instance;
+ uint32_t func_index;
+ size_t func_offset;
+ size_t module_offset;
+};
+
+} // namespace
+
+template <>
+struct implement<Frame> {
+ using type = FrameImpl;
+};
+
+Frame::~Frame() { impl(this)->~FrameImpl(); }
+
+void Frame::operator delete(void* p) { ::operator delete(p); }
+
+own<Frame> Frame::copy() const {
+ auto self = impl(this);
+ return own<Frame>(seal<Frame>(
+ new (std::nothrow) FrameImpl(self->instance->copy(), self->func_index,
+ self->func_offset, self->module_offset)));
+}
+
+Instance* Frame::instance() const { return impl(this)->instance.get(); }
+
+uint32_t Frame::func_index() const { return impl(this)->func_index; }
+
+size_t Frame::func_offset() const { return impl(this)->func_offset; }
+
+size_t Frame::module_offset() const { return impl(this)->module_offset; }
+
// Traps
template <>
@@ -775,9 +858,9 @@ struct implement<Trap> {
Trap::~Trap() {}
-auto Trap::copy() const -> own<Trap*> { return impl(this)->copy(); }
+auto Trap::copy() const -> own<Trap> { return impl(this)->copy(); }
-auto Trap::make(Store* store_abs, const Message& message) -> own<Trap*> {
+auto Trap::make(Store* store_abs, const Message& message) -> own<Trap> {
auto store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope handle_scope(isolate);
@@ -801,6 +884,58 @@ auto Trap::message() const -> Message {
return vec<byte_t>::adopt(length, utf8.release());
}
+namespace {
+
+own<Instance> GetInstance(StoreImpl* store,
+ i::Handle<i::WasmInstanceObject> instance);
+
+own<Frame> CreateFrameFromInternal(i::Handle<i::FixedArray> frames, int index,
+ i::Isolate* isolate, StoreImpl* store) {
+ i::Handle<i::StackTraceFrame> frame(i::StackTraceFrame::cast(frames->get(0)),
+ isolate);
+ i::Handle<i::WasmInstanceObject> instance =
+ i::StackTraceFrame::GetWasmInstance(frame);
+ uint32_t func_index = i::StackTraceFrame::GetLineNumber(frame);
+ size_t func_offset = i::StackTraceFrame::GetFunctionOffset(frame);
+ size_t module_offset = i::StackTraceFrame::GetColumnNumber(frame);
+ return own<Frame>(seal<Frame>(new (std::nothrow) FrameImpl(
+ GetInstance(store, instance), func_index, func_offset, module_offset)));
+}
+
+} // namespace
+
+own<Frame> Trap::origin() const {
+ i::Isolate* isolate = impl(this)->isolate();
+ i::HandleScope handle_scope(isolate);
+
+ i::Handle<i::JSMessageObject> message =
+ isolate->CreateMessage(impl(this)->v8_object(), nullptr);
+ i::Handle<i::FixedArray> frames(i::FixedArray::cast(message->stack_frames()),
+ isolate);
+ if (frames->length() == 0) {
+ return own<Frame>();
+ }
+ return CreateFrameFromInternal(frames, 0, isolate, impl(this)->store());
+}
+
+ownvec<Frame> Trap::trace() const {
+ i::Isolate* isolate = impl(this)->isolate();
+ i::HandleScope handle_scope(isolate);
+
+ i::Handle<i::JSMessageObject> message =
+ isolate->CreateMessage(impl(this)->v8_object(), nullptr);
+ i::Handle<i::FixedArray> frames(i::FixedArray::cast(message->stack_frames()),
+ isolate);
+ int num_frames = frames->length();
+ // {num_frames} can be 0; the code below can handle that case.
+ ownvec<Frame> result = ownvec<Frame>::make_uninitialized(num_frames);
+ for (int i = 0; i < num_frames; i++) {
+ result[i] =
+ CreateFrameFromInternal(frames, i, isolate, impl(this)->store());
+ }
+ return result;
+}
+
// Foreign Objects
template <>
@@ -810,9 +945,9 @@ struct implement<Foreign> {
Foreign::~Foreign() {}
-auto Foreign::copy() const -> own<Foreign*> { return impl(this)->copy(); }
+auto Foreign::copy() const -> own<Foreign> { return impl(this)->copy(); }
-auto Foreign::make(Store* store_abs) -> own<Foreign*> {
+auto Foreign::make(Store* store_abs) -> own<Foreign> {
StoreImpl* store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope handle_scope(isolate);
@@ -831,7 +966,7 @@ struct implement<Module> {
Module::~Module() {}
-auto Module::copy() const -> own<Module*> { return impl(this)->copy(); }
+auto Module::copy() const -> own<Module> { return impl(this)->copy(); }
auto Module::validate(Store* store_abs, const vec<byte_t>& binary) -> bool {
i::wasm::ModuleWireBytes bytes(
@@ -841,66 +976,60 @@ auto Module::validate(Store* store_abs, const vec<byte_t>& binary) -> bool {
return isolate->wasm_engine()->SyncValidate(isolate, features, bytes);
}
-class NopErrorThrower : public i::wasm::ErrorThrower {
- public:
- explicit NopErrorThrower(i::Isolate* isolate)
- : i::wasm::ErrorThrower(isolate, "ignored") {}
- ~NopErrorThrower() { Reset(); }
-};
-
-auto Module::make(Store* store_abs, const vec<byte_t>& binary) -> own<Module*> {
+auto Module::make(Store* store_abs, const vec<byte_t>& binary) -> own<Module> {
StoreImpl* store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope scope(isolate);
i::wasm::ModuleWireBytes bytes(
{reinterpret_cast<const uint8_t*>(binary.get()), binary.size()});
i::wasm::WasmFeatures features = i::wasm::WasmFeaturesFromIsolate(isolate);
- NopErrorThrower thrower(isolate);
+ i::wasm::ErrorThrower thrower(isolate, "ignored");
i::Handle<i::WasmModuleObject> module;
if (!isolate->wasm_engine()
->SyncCompile(isolate, features, &thrower, bytes)
.ToHandle(&module)) {
+ thrower.Reset(); // The API provides no way to expose the error.
return nullptr;
}
return implement<Module>::type::make(store, module);
}
-auto Module::imports() const -> vec<ImportType*> {
+auto Module::imports() const -> ownvec<ImportType> {
const i::wasm::NativeModule* native_module =
impl(this)->v8_object()->native_module();
const i::wasm::WasmModule* module = native_module->module();
const i::Vector<const uint8_t> wire_bytes = native_module->wire_bytes();
const std::vector<i::wasm::WasmImport>& import_table = module->import_table;
size_t size = import_table.size();
- vec<ImportType*> imports = vec<ImportType*>::make_uninitialized(size);
+ ownvec<ImportType> imports = ownvec<ImportType>::make_uninitialized(size);
for (uint32_t i = 0; i < size; i++) {
const i::wasm::WasmImport& imp = import_table[i];
Name module_name = GetNameFromWireBytes(imp.module_name, wire_bytes);
Name name = GetNameFromWireBytes(imp.field_name, wire_bytes);
- own<ExternType*> type = GetImportExportType(module, imp.kind, imp.index);
+ own<ExternType> type = GetImportExportType(module, imp.kind, imp.index);
imports[i] = ImportType::make(std::move(module_name), std::move(name),
std::move(type));
}
return imports;
}
-vec<ExportType*> ExportsImpl(i::Handle<i::WasmModuleObject> module_obj) {
+ownvec<ExportType> ExportsImpl(i::Handle<i::WasmModuleObject> module_obj) {
const i::wasm::NativeModule* native_module = module_obj->native_module();
const i::wasm::WasmModule* module = native_module->module();
const i::Vector<const uint8_t> wire_bytes = native_module->wire_bytes();
const std::vector<i::wasm::WasmExport>& export_table = module->export_table;
size_t size = export_table.size();
- vec<ExportType*> exports = vec<ExportType*>::make_uninitialized(size);
+ ownvec<ExportType> exports = ownvec<ExportType>::make_uninitialized(size);
for (uint32_t i = 0; i < size; i++) {
const i::wasm::WasmExport& exp = export_table[i];
Name name = GetNameFromWireBytes(exp.name, wire_bytes);
- own<ExternType*> type = GetImportExportType(module, exp.kind, exp.index);
+ own<ExternType> type = GetImportExportType(module, exp.kind, exp.index);
exports[i] = ExportType::make(std::move(name), std::move(type));
}
return exports;
}
-auto Module::exports() const -> vec<ExportType*> {
+auto Module::exports() const -> ownvec<ExportType> {
return ExportsImpl(impl(this)->v8_object());
}
@@ -923,11 +1052,11 @@ auto Module::serialize() const -> vec<byte_t> {
{reinterpret_cast<uint8_t*>(ptr), serial_size})) {
buffer.reset();
}
- return std::move(buffer);
+ return buffer;
}
auto Module::deserialize(Store* store_abs, const vec<byte_t>& serialized)
- -> own<Module*> {
+ -> own<Module> {
StoreImpl* store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope handle_scope(isolate);
@@ -963,13 +1092,12 @@ void Shared<Module>::operator delete(void* p) {
::operator delete(p);
}
-auto Module::share() const -> own<Shared<Module>*> {
+auto Module::share() const -> own<Shared<Module>> {
auto shared = seal<Shared<Module>>(new vec<byte_t>(serialize()));
return make_own(shared);
}
-auto Module::obtain(Store* store, const Shared<Module>* shared)
- -> own<Module*> {
+auto Module::obtain(Store* store, const Shared<Module>* shared) -> own<Module> {
return Module::deserialize(store, *impl(shared));
}
@@ -982,7 +1110,7 @@ struct implement<Extern> {
Extern::~Extern() {}
-auto Extern::copy() const -> own<Extern*> { return impl(this)->copy(); }
+auto Extern::copy() const -> own<Extern> { return impl(this)->copy(); }
auto Extern::kind() const -> ExternKind {
i::Handle<i::JSReceiver> obj = impl(this)->v8_object();
@@ -995,7 +1123,7 @@ auto Extern::kind() const -> ExternKind {
UNREACHABLE();
}
-auto Extern::type() const -> own<ExternType*> {
+auto Extern::type() const -> own<ExternType> {
switch (kind()) {
case EXTERN_FUNC:
return func()->type();
@@ -1053,11 +1181,11 @@ struct implement<Func> {
Func::~Func() {}
-auto Func::copy() const -> own<Func*> { return impl(this)->copy(); }
+auto Func::copy() const -> own<Func> { return impl(this)->copy(); }
struct FuncData {
Store* store;
- own<FuncType*> type;
+ own<FuncType> type;
enum Kind { kCallback, kCallbackWithEnv } kind;
union {
Func::callback callback;
@@ -1077,8 +1205,7 @@ struct FuncData {
if (finalizer) (*finalizer)(env);
}
- static i::Address v8_callback(void* data, i::Address argv);
- static void finalize_func_data(void* data);
+ static i::Address v8_callback(i::Address host_data_foreign, i::Address argv);
};
namespace {
@@ -1111,11 +1238,11 @@ class SignatureHelper : public i::AllStatic {
return sig;
}
- static own<FuncType*> Deserialize(i::PodArray<i::wasm::ValueType> sig) {
+ static own<FuncType> Deserialize(i::PodArray<i::wasm::ValueType> sig) {
int result_arity = ResultArity(sig);
int param_arity = sig.length() - result_arity - 1;
- vec<ValType*> results = vec<ValType*>::make_uninitialized(result_arity);
- vec<ValType*> params = vec<ValType*>::make_uninitialized(param_arity);
+ ownvec<ValType> results = ownvec<ValType>::make_uninitialized(result_arity);
+ ownvec<ValType> params = ownvec<ValType>::make_uninitialized(param_arity);
int i = 0;
for (; i < result_arity; ++i) {
@@ -1146,29 +1273,30 @@ class SignatureHelper : public i::AllStatic {
}
};
-auto make_func(Store* store_abs, FuncData* data) -> own<Func*> {
+auto make_func(Store* store_abs, FuncData* data) -> own<Func> {
auto store = impl(store_abs);
i::Isolate* isolate = store->i_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(
- isolate, reinterpret_cast<i::Address>(&FuncData::v8_callback), data,
- SignatureHelper::Serialize(isolate, data->type.get()));
+ isolate, reinterpret_cast<i::Address>(&FuncData::v8_callback),
+ embedder_data, SignatureHelper::Serialize(isolate, data->type.get()));
auto func = implement<Func>::type::make(store, function);
- func->set_host_info(data, &FuncData::finalize_func_data);
return func;
}
} // namespace
auto Func::make(Store* store, const FuncType* type, Func::callback callback)
- -> own<Func*> {
+ -> own<Func> {
auto data = new FuncData(store, type, FuncData::kCallback);
data->callback = callback;
return make_func(store, data);
}
auto Func::make(Store* store, const FuncType* type, callback_with_env callback,
- void* env, void (*finalizer)(void*)) -> own<Func*> {
+ void* env, void (*finalizer)(void*)) -> own<Func> {
auto data = new FuncData(store, type, FuncData::kCallbackWithEnv);
data->callback_with_env = callback;
data->env = env;
@@ -1176,7 +1304,7 @@ auto Func::make(Store* store, const FuncType* type, callback_with_env callback,
return make_func(store, data);
}
-auto Func::type() const -> own<FuncType*> {
+auto Func::type() const -> own<FuncType> {
i::Handle<i::JSFunction> func = impl(this)->v8_object();
if (i::WasmCapiFunction::IsWasmCapiFunction(*func)) {
return SignatureHelper::Deserialize(SignatureHelper::GetSig(func));
@@ -1216,6 +1344,37 @@ auto Func::result_arity() const -> size_t {
namespace {
+own<Ref> V8RefValueToWasm(StoreImpl* store, i::Handle<i::Object> value) {
+ if (value->IsNull(store->i_isolate())) return nullptr;
+ return implement<Ref>::type::make(store,
+ i::Handle<i::JSReceiver>::cast(value));
+}
+
+i::Handle<i::Object> WasmRefToV8(i::Isolate* isolate, const Ref* ref) {
+ if (ref == nullptr) return i::ReadOnlyRoots(isolate).null_value_handle();
+ return impl(ref)->v8_object();
+}
+
+i::Handle<i::Object> CallTargetForCaching(i::Isolate* isolate,
+ i::Address real_call_target) {
+ if (i::kTaggedSize == i::kInt32Size) {
+ return isolate->factory()->NewForeign(real_call_target);
+ } else {
+ // 64-bit uncompressed platform.
+ return i::handle(i::Smi((real_call_target << i::kSmiTagSize) | i::kSmiTag),
+ isolate);
+ }
+}
+
+i::Address CallTargetFromCache(i::Object cached_call_target) {
+ if (i::kTaggedSize == i::kInt32Size) {
+ return i::Foreign::cast(cached_call_target).foreign_address();
+ } else {
+ // 64-bit uncompressed platform.
+ return cached_call_target.ptr() >> i::kSmiTagSize;
+ }
+}
+
void PrepareFunctionData(i::Isolate* isolate,
i::Handle<i::WasmExportedFunctionData> function_data,
i::wasm::FunctionSig* sig) {
@@ -1228,16 +1387,16 @@ void PrepareFunctionData(i::Isolate* isolate,
// Compute packed args size.
function_data->set_packed_args_size(
i::wasm::CWasmArgumentsPacker::TotalSize(sig));
- // Get call target (function table offset). This is an Address, we store
- // it as a pseudo-Smi by shifting it by one bit, so the GC leaves it alone.
- i::Address call_target =
- function_data->instance().GetCallTarget(function_data->function_index());
- i::Smi smi_target((call_target << i::kSmiTagSize) | i::kSmiTag);
- function_data->set_wasm_call_target(smi_target);
+ // Get call target (function table offset), and wrap it as a cacheable object
+ // (pseudo-Smi or Foreign, depending on platform).
+ i::Handle<i::Object> call_target = CallTargetForCaching(
+ isolate,
+ function_data->instance().GetCallTarget(function_data->function_index()));
+ function_data->set_wasm_call_target(*call_target);
}
void PushArgs(i::wasm::FunctionSig* sig, const Val args[],
- i::wasm::CWasmArgumentsPacker* packer) {
+ i::wasm::CWasmArgumentsPacker* packer, StoreImpl* store) {
for (size_t i = 0; i < sig->parameter_count(); i++) {
i::wasm::ValueType type = sig->GetParam(i);
switch (type) {
@@ -1255,7 +1414,7 @@ void PushArgs(i::wasm::FunctionSig* sig, const Val args[],
break;
case i::wasm::kWasmAnyRef:
case i::wasm::kWasmFuncRef:
- packer->Push(impl(args[i].ref())->v8_object()->ptr());
+ packer->Push(WasmRefToV8(store->i_isolate(), args[i].ref())->ptr());
break;
case i::wasm::kWasmExnRef:
// TODO(jkummerow): Implement these.
@@ -1288,13 +1447,8 @@ void PopArgs(i::wasm::FunctionSig* sig, Val results[],
case i::wasm::kWasmAnyRef:
case i::wasm::kWasmFuncRef: {
i::Address raw = packer->Pop<i::Address>();
- if (raw == i::kNullAddress) {
- results[i] = Val(nullptr);
- } else {
- i::JSReceiver raw_obj = i::JSReceiver::cast(i::Object(raw));
- i::Handle<i::JSReceiver> obj(raw_obj, store->i_isolate());
- results[i] = Val(implement<Ref>::type::make(store, obj));
- }
+ i::Handle<i::Object> obj(i::Object(raw), store->i_isolate());
+ results[i] = Val(V8RefValueToWasm(store, obj));
break;
}
case i::wasm::kWasmExnRef:
@@ -1307,9 +1461,9 @@ void PopArgs(i::wasm::FunctionSig* sig, Val results[],
}
}
-own<Trap*> CallWasmCapiFunction(i::WasmCapiFunctionData data, const Val args[],
- Val results[]) {
- FuncData* func_data = reinterpret_cast<FuncData*>(data.embedder_data());
+own<Trap> CallWasmCapiFunction(i::WasmCapiFunctionData data, const Val args[],
+ Val results[]) {
+ FuncData* func_data = i::Managed<FuncData>::cast(data.embedder_data()).raw();
if (func_data->kind == FuncData::kCallback) {
return (func_data->callback)(args, results);
}
@@ -1317,9 +1471,28 @@ own<Trap*> CallWasmCapiFunction(i::WasmCapiFunctionData data, const Val args[],
return (func_data->callback_with_env)(func_data->env, args, results);
}
+i::Handle<i::JSReceiver> GetProperException(
+ i::Isolate* isolate, i::Handle<i::Object> maybe_exception) {
+ if (maybe_exception->IsJSReceiver()) {
+ return i::Handle<i::JSReceiver>::cast(maybe_exception);
+ }
+ i::MaybeHandle<i::String> maybe_string =
+ i::Object::ToString(isolate, maybe_exception);
+ i::Handle<i::String> string = isolate->factory()->empty_string();
+ if (!maybe_string.ToHandle(&string)) {
+ // If converting the {maybe_exception} to string threw another exception,
+ // just give up and leave {string} as the empty string.
+ isolate->clear_pending_exception();
+ }
+ // {NewError} cannot fail when its input is a plain String, so we always
+ // get an Error object here.
+ return i::Handle<i::JSReceiver>::cast(
+ isolate->factory()->NewError(isolate->error_function(), string));
+}
+
} // namespace
-auto Func::call(const Val args[], Val results[]) const -> own<Trap*> {
+auto Func::call(const Val args[], Val results[]) const -> own<Trap> {
auto func = impl(this);
auto store = func->store();
auto isolate = store->i_isolate();
@@ -1343,10 +1516,10 @@ auto Func::call(const Val args[], Val results[]) const -> own<Trap*> {
i::Handle<i::Code> wrapper_code = i::Handle<i::Code>(
i::Code::cast(function_data->c_wrapper_code()), isolate);
i::Address call_target =
- function_data->wasm_call_target().ptr() >> i::kSmiTagSize;
+ CallTargetFromCache(function_data->wasm_call_target());
i::wasm::CWasmArgumentsPacker packer(function_data->packed_args_size());
- PushArgs(sig, args, &packer);
+ PushArgs(sig, args, &packer, store);
i::Handle<i::Object> object_ref = instance;
if (function_index <
@@ -1377,28 +1550,24 @@ auto Func::call(const Val args[], Val results[]) const -> own<Trap*> {
if (isolate->has_pending_exception()) {
i::Handle<i::Object> exception(isolate->pending_exception(), isolate);
isolate->clear_pending_exception();
- if (!exception->IsJSReceiver()) {
- i::MaybeHandle<i::String> maybe_string =
- i::Object::ToString(isolate, exception);
- i::Handle<i::String> string = maybe_string.is_null()
- ? isolate->factory()->empty_string()
- : maybe_string.ToHandleChecked();
- exception =
- isolate->factory()->NewError(isolate->error_function(), string);
- }
- return implement<Trap>::type::make(
- store, i::Handle<i::JSReceiver>::cast(exception));
+ return implement<Trap>::type::make(store,
+ GetProperException(isolate, exception));
}
PopArgs(sig, results, &packer, store);
return nullptr;
}
-i::Address FuncData::v8_callback(void* data, i::Address argv) {
- FuncData* self = reinterpret_cast<FuncData*>(data);
+i::Address FuncData::v8_callback(i::Address host_data_foreign,
+ i::Address argv) {
+ FuncData* self =
+ i::Managed<FuncData>::cast(i::Object(host_data_foreign))->raw();
+ StoreImpl* store = impl(self->store);
+ i::Isolate* isolate = store->i_isolate();
+ i::HandleScope scope(isolate);
- const vec<ValType*>& param_types = self->type->params();
- const vec<ValType*>& result_types = self->type->results();
+ const ownvec<ValType>& param_types = self->type->params();
+ const ownvec<ValType>& result_types = self->type->results();
int num_param_types = static_cast<int>(param_types.size());
int num_result_types = static_cast<int>(result_types.size());
@@ -1428,19 +1597,14 @@ i::Address FuncData::v8_callback(void* data, i::Address argv) {
case FUNCREF: {
i::Address raw = v8::base::ReadUnalignedValue<i::Address>(p);
p += sizeof(raw);
- if (raw == i::kNullAddress) {
- params[i] = Val(nullptr);
- } else {
- i::JSReceiver raw_obj = i::JSReceiver::cast(i::Object(raw));
- i::Handle<i::JSReceiver> obj(raw_obj, raw_obj.GetIsolate());
- params[i] = Val(implement<Ref>::type::make(impl(self->store), obj));
- }
+ i::Handle<i::Object> obj(i::Object(raw), isolate);
+ params[i] = Val(V8RefValueToWasm(store, obj));
break;
}
}
}
- own<Trap*> trap;
+ own<Trap> trap;
if (self->kind == kCallbackWithEnv) {
trap = self->callback_with_env(self->env, params.get(), results.get());
} else {
@@ -1448,7 +1612,6 @@ i::Address FuncData::v8_callback(void* data, i::Address argv) {
}
if (trap) {
- i::Isolate* isolate = impl(self->store)->i_isolate();
isolate->Throw(*impl(trap.get())->v8_object());
i::Object ex = isolate->pending_exception();
isolate->clear_pending_exception();
@@ -1476,12 +1639,8 @@ i::Address FuncData::v8_callback(void* data, i::Address argv) {
break;
case ANYREF:
case FUNCREF: {
- if (results[i].ref() == nullptr) {
- v8::base::WriteUnalignedValue(p, i::kNullAddress);
- } else {
- v8::base::WriteUnalignedValue(
- p, impl(results[i].ref())->v8_object()->ptr());
- }
+ v8::base::WriteUnalignedValue(
+ p, WasmRefToV8(isolate, results[i].ref())->ptr());
p += sizeof(i::Address);
break;
}
@@ -1490,10 +1649,6 @@ i::Address FuncData::v8_callback(void* data, i::Address argv) {
return i::kNullAddress;
}
-void FuncData::finalize_func_data(void* data) {
- delete reinterpret_cast<FuncData*>(data);
-}
-
// Global Instances
template <>
@@ -1503,10 +1658,10 @@ struct implement<Global> {
Global::~Global() {}
-auto Global::copy() const -> own<Global*> { return impl(this)->copy(); }
+auto Global::copy() const -> own<Global> { return impl(this)->copy(); }
auto Global::make(Store* store_abs, const GlobalType* type, const Val& val)
- -> own<Global*> {
+ -> own<Global> {
StoreImpl* store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope handle_scope(isolate);
@@ -1528,7 +1683,7 @@ auto Global::make(Store* store_abs, const GlobalType* type, const Val& val)
return global;
}
-auto Global::type() const -> own<GlobalType*> {
+auto Global::type() const -> own<GlobalType> {
i::Handle<i::WasmGlobalObject> v8_global = impl(this)->v8_object();
ValKind kind = V8ValueTypeToWasm(v8_global->type());
Mutability mutability = v8_global->is_mutable() ? VAR : CONST;
@@ -1546,15 +1701,11 @@ auto Global::get() const -> Val {
return Val(v8_global->GetF32());
case F64:
return Val(v8_global->GetF64());
- case ANYREF: {
- i::Handle<i::JSReceiver> obj =
- i::Handle<i::JSReceiver>::cast(v8_global->GetRef());
- return Val(RefImpl<Ref, i::JSReceiver>::make(impl(this)->store(), obj));
- }
+ case ANYREF:
case FUNCREF: {
- i::Handle<i::JSFunction> obj =
- i::Handle<i::JSFunction>::cast(v8_global->GetRef());
- return Val(implement<Func>::type::make(impl(this)->store(), obj));
+ StoreImpl* store = impl(this)->store();
+ i::HandleScope scope(store->i_isolate());
+ return Val(V8RefValueToWasm(store, v8_global->GetRef()));
}
default:
// TODO(wasm+): support new value types
@@ -1574,10 +1725,12 @@ void Global::set(const Val& val) {
case F64:
return v8_global->SetF64(val.f64());
case ANYREF:
- return v8_global->SetAnyRef(impl(val.ref())->v8_object());
+ return v8_global->SetAnyRef(
+ WasmRefToV8(impl(this)->store()->i_isolate(), val.ref()));
case FUNCREF: {
- bool result = v8_global->SetFuncRef(impl(this)->store()->i_isolate(),
- impl(val.ref())->v8_object());
+ i::Isolate* isolate = impl(this)->store()->i_isolate();
+ bool result =
+ v8_global->SetFuncRef(isolate, WasmRefToV8(isolate, val.ref()));
DCHECK(result);
USE(result);
return;
@@ -1597,14 +1750,13 @@ struct implement<Table> {
Table::~Table() {}
-auto Table::copy() const -> own<Table*> { return impl(this)->copy(); }
+auto Table::copy() const -> own<Table> { return impl(this)->copy(); }
auto Table::make(Store* store_abs, const TableType* type, const Ref* ref)
- -> own<Table*> {
+ -> own<Table> {
StoreImpl* store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope scope(isolate);
- auto enabled_features = i::wasm::WasmFeaturesFromFlags();
// Get "element".
i::wasm::ValueType i_type;
@@ -1613,13 +1765,11 @@ auto Table::make(Store* store_abs, const TableType* type, const Ref* ref)
i_type = i::wasm::kWasmFuncRef;
break;
case ANYREF:
- if (enabled_features.anyref) {
- i_type = i::wasm::kWasmAnyRef;
- break;
- } // Else fall through.
- V8_FALLTHROUGH;
+ DCHECK(i::wasm::WasmFeaturesFromFlags().anyref); // See Engine::make().
+ i_type = i::wasm::kWasmAnyRef;
+ break;
default:
- UNREACHABLE(); // 'element' must be 'FUNCREF'.
+ UNREACHABLE();
return nullptr;
}
@@ -1652,42 +1802,44 @@ auto Table::make(Store* store_abs, const TableType* type, const Ref* ref)
return implement<Table>::type::make(store, table_obj);
}
-auto Table::type() const -> own<TableType*> {
+auto Table::type() const -> own<TableType> {
i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
uint32_t min = table->current_length();
uint32_t max;
if (!table->maximum_length().ToUint32(&max)) max = 0xFFFFFFFFu;
- // TODO(wasm+): support new element types.
- return TableType::make(ValType::make(FUNCREF), Limits(min, max));
+ ValKind kind;
+ switch (table->type()) {
+ case i::wasm::kWasmFuncRef:
+ kind = FUNCREF;
+ break;
+ case i::wasm::kWasmAnyRef:
+ kind = ANYREF;
+ break;
+ default:
+ UNREACHABLE();
+ }
+ return TableType::make(ValType::make(kind), Limits(min, max));
}
-auto Table::get(size_t index) const -> own<Ref*> {
+auto Table::get(size_t index) const -> own<Ref> {
i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
- if (index >= table->current_length()) return own<Ref*>();
+ if (index >= table->current_length()) return own<Ref>();
i::Isolate* isolate = table->GetIsolate();
i::HandleScope handle_scope(isolate);
i::Handle<i::Object> result =
i::WasmTableObject::Get(isolate, table, static_cast<uint32_t>(index));
- if (!result->IsJSFunction()) return own<Ref*>();
- DCHECK(i::WasmExportedFunction::IsWasmExportedFunction(*result) ||
- i::WasmCapiFunction::IsWasmCapiFunction(*result));
- // TODO(wasm+): other references
- return implement<Func>::type::make(impl(this)->store(),
- i::Handle<i::JSFunction>::cast(result));
+ // TODO(jkummerow): If we support both JavaScript and the C-API at the same
+ // time, we need to handle Smis and other JS primitives here.
+ DCHECK(result->IsNull(isolate) || result->IsJSReceiver());
+ return V8RefValueToWasm(impl(this)->store(), result);
}
auto Table::set(size_t index, const Ref* ref) -> bool {
- if (ref && !impl(ref)->v8_object()->IsFunction()) {
- WASM_UNIMPLEMENTED("non-function table elements");
- }
i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
if (index >= table->current_length()) return false;
i::Isolate* isolate = table->GetIsolate();
i::HandleScope handle_scope(isolate);
- i::Handle<i::Object> obj =
- ref ? i::Handle<i::Object>::cast(impl(ref)->v8_object())
- : i::Handle<i::Object>::cast(
- i::ReadOnlyRoots(isolate).null_value_handle());
+ i::Handle<i::Object> obj = WasmRefToV8(isolate, ref);
i::WasmTableObject::Set(isolate, table, static_cast<uint32_t>(index), obj);
return true;
}
@@ -1701,10 +1853,7 @@ auto Table::grow(size_t delta, const Ref* ref) -> bool {
i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
i::Isolate* isolate = table->GetIsolate();
i::HandleScope scope(isolate);
- i::Handle<i::Object> init_value =
- ref == nullptr
- ? i::Handle<i::Object>::cast(isolate->factory()->null_value())
- : i::Handle<i::Object>::cast(impl(ref)->v8_object());
+ i::Handle<i::Object> init_value = WasmRefToV8(isolate, ref);
int result = i::WasmTableObject::Grow(
isolate, table, static_cast<uint32_t>(delta), init_value);
return result >= 0;
@@ -1719,9 +1868,9 @@ struct implement<Memory> {
Memory::~Memory() {}
-auto Memory::copy() const -> own<Memory*> { return impl(this)->copy(); }
+auto Memory::copy() const -> own<Memory> { return impl(this)->copy(); }
-auto Memory::make(Store* store_abs, const MemoryType* type) -> own<Memory*> {
+auto Memory::make(Store* store_abs, const MemoryType* type) -> own<Memory> {
StoreImpl* store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope scope(isolate);
@@ -1738,12 +1887,12 @@ auto Memory::make(Store* store_abs, const MemoryType* type) -> own<Memory*> {
i::Handle<i::WasmMemoryObject> memory_obj;
if (!i::WasmMemoryObject::New(isolate, minimum, maximum, is_shared)
.ToHandle(&memory_obj)) {
- return own<Memory*>();
+ return own<Memory>();
}
return implement<Memory>::type::make(store, memory_obj);
}
-auto Memory::type() const -> own<MemoryType*> {
+auto Memory::type() const -> own<MemoryType> {
i::Handle<i::WasmMemoryObject> memory = impl(this)->v8_object();
uint32_t min = static_cast<uint32_t>(memory->array_buffer().byte_length() /
i::wasm::kWasmPageSize);
@@ -1784,10 +1933,10 @@ struct implement<Instance> {
Instance::~Instance() {}
-auto Instance::copy() const -> own<Instance*> { return impl(this)->copy(); }
+auto Instance::copy() const -> own<Instance> { return impl(this)->copy(); }
-auto Instance::make(Store* store_abs, const Module* module_abs,
- const Extern* const imports[]) -> own<Instance*> {
+own<Instance> Instance::make(Store* store_abs, const Module* module_abs,
+ const Extern* const imports[], own<Trap>* trap) {
StoreImpl* store = impl(store_abs);
const implement<Module>::type* module = impl(module_abs);
i::Isolate* isolate = store->i_isolate();
@@ -1795,11 +1944,12 @@ auto Instance::make(Store* store_abs, const Module* module_abs,
DCHECK_EQ(module->v8_object()->GetIsolate(), isolate);
- vec<ImportType*> import_types = module_abs->imports();
+ if (trap) *trap = nullptr;
+ ownvec<ImportType> import_types = module_abs->imports();
i::Handle<i::JSObject> imports_obj =
isolate->factory()->NewJSObject(isolate->object_function());
for (size_t i = 0; i < import_types.size(); ++i) {
- auto type = import_types[i];
+ ImportType* type = import_types[i].get();
i::Handle<i::String> module_str = VecToString(isolate, type->module());
i::Handle<i::String> name_str = VecToString(isolate, type->name());
@@ -1817,17 +1967,45 @@ auto Instance::make(Store* store_abs, const Module* module_abs,
ignore(i::Object::SetProperty(isolate, module_obj, name_str,
impl(imports[i])->v8_object()));
}
+ i::wasm::ErrorThrower thrower(isolate, "instantiation");
+ i::MaybeHandle<i::WasmInstanceObject> instance_obj =
+ isolate->wasm_engine()->SyncInstantiate(
+ isolate, &thrower, module->v8_object(), imports_obj,
+ i::MaybeHandle<i::JSArrayBuffer>());
+ if (trap) {
+ if (thrower.error()) {
+ *trap = implement<Trap>::type::make(
+ store, GetProperException(isolate, thrower.Reify()));
+ DCHECK(!thrower.error()); // Reify() called Reset().
+ DCHECK(!isolate->has_pending_exception()); // Hasn't been thrown yet.
+ return own<Instance>();
+ } else if (isolate->has_pending_exception()) {
+ i::Handle<i::Object> maybe_exception(isolate->pending_exception(),
+ isolate);
+ *trap = implement<Trap>::type::make(
+ store, GetProperException(isolate, maybe_exception));
+ isolate->clear_pending_exception();
+ return own<Instance>();
+ }
+ } else if (instance_obj.is_null()) {
+ // If no {trap} output is specified, silently swallow all errors.
+ thrower.Reset();
+ isolate->clear_pending_exception();
+ return own<Instance>();
+ }
+ return implement<Instance>::type::make(store, instance_obj.ToHandleChecked());
+}
- NopErrorThrower thrower(isolate);
- i::Handle<i::WasmInstanceObject> instance_obj =
- isolate->wasm_engine()
- ->SyncInstantiate(isolate, &thrower, module->v8_object(), imports_obj,
- i::MaybeHandle<i::JSArrayBuffer>())
- .ToHandleChecked();
- return implement<Instance>::type::make(store, instance_obj);
+namespace {
+
+own<Instance> GetInstance(StoreImpl* store,
+ i::Handle<i::WasmInstanceObject> instance) {
+ return implement<Instance>::type::make(store, instance);
}
-auto Instance::exports() const -> vec<Extern*> {
+} // namespace
+
+auto Instance::exports() const -> ownvec<Extern> {
const implement<Instance>::type* instance = impl(this);
StoreImpl* store = instance->store();
i::Isolate* isolate = store->i_isolate();
@@ -1837,9 +2015,10 @@ auto Instance::exports() const -> vec<Extern*> {
isolate);
i::Handle<i::JSObject> exports_obj(instance_obj->exports_object(), isolate);
- vec<ExportType*> export_types = ExportsImpl(module_obj);
- vec<Extern*> exports = vec<Extern*>::make_uninitialized(export_types.size());
- if (!exports) return vec<Extern*>::invalid();
+ ownvec<ExportType> export_types = ExportsImpl(module_obj);
+ ownvec<Extern> exports =
+ ownvec<Extern>::make_uninitialized(export_types.size());
+ if (!exports) return ownvec<Extern>::invalid();
for (size_t i = 0; i < export_types.size(); ++i) {
auto& name = export_types[i]->name();
@@ -1852,20 +2031,20 @@ auto Instance::exports() const -> vec<Extern*> {
switch (type->kind()) {
case EXTERN_FUNC: {
DCHECK(i::WasmExportedFunction::IsWasmExportedFunction(*obj));
- exports[i].reset(implement<Func>::type::make(
- store, i::Handle<i::WasmExportedFunction>::cast(obj)));
+ exports[i] = implement<Func>::type::make(
+ store, i::Handle<i::WasmExportedFunction>::cast(obj));
} break;
case EXTERN_GLOBAL: {
- exports[i].reset(implement<Global>::type::make(
- store, i::Handle<i::WasmGlobalObject>::cast(obj)));
+ exports[i] = implement<Global>::type::make(
+ store, i::Handle<i::WasmGlobalObject>::cast(obj));
} break;
case EXTERN_TABLE: {
- exports[i].reset(implement<Table>::type::make(
- store, i::Handle<i::WasmTableObject>::cast(obj)));
+ exports[i] = implement<Table>::type::make(
+ store, i::Handle<i::WasmTableObject>::cast(obj));
} break;
case EXTERN_MEMORY: {
- exports[i].reset(implement<Memory>::type::make(
- store, i::Handle<i::WasmMemoryObject>::cast(obj)));
+ exports[i] = implement<Memory>::type::make(
+ store, i::Handle<i::WasmMemoryObject>::cast(obj));
} break;
}
}
@@ -1898,152 +2077,151 @@ struct borrowed_vec {
} // extern "C++"
-#define WASM_DEFINE_OWN(name, Name) \
- struct wasm_##name##_t : Name {}; \
- \
- void wasm_##name##_delete(wasm_##name##_t* x) { delete x; } \
- \
- extern "C++" inline auto hide(Name* x)->wasm_##name##_t* { \
- return static_cast<wasm_##name##_t*>(x); \
- } \
- extern "C++" inline auto hide(const Name* x)->const wasm_##name##_t* { \
- return static_cast<const wasm_##name##_t*>(x); \
- } \
- extern "C++" inline auto reveal(wasm_##name##_t* x)->Name* { return x; } \
- extern "C++" inline auto reveal(const wasm_##name##_t* x)->const Name* { \
- return x; \
- } \
- extern "C++" inline auto get(wasm::own<Name*>& x)->wasm_##name##_t* { \
- return hide(x.get()); \
- } \
- extern "C++" inline auto get(const wasm::own<Name*>& x) \
- ->const wasm_##name##_t* { \
- return hide(x.get()); \
- } \
- extern "C++" inline auto release(wasm::own<Name*>&& x)->wasm_##name##_t* { \
- return hide(x.release()); \
- } \
- extern "C++" inline auto adopt(wasm_##name##_t* x)->wasm::own<Name*> { \
- return make_own(x); \
+#define WASM_DEFINE_OWN(name, Name) \
+ struct wasm_##name##_t : Name {}; \
+ \
+ void wasm_##name##_delete(wasm_##name##_t* x) { delete x; } \
+ \
+ extern "C++" inline auto hide_##name(Name* x)->wasm_##name##_t* { \
+ return static_cast<wasm_##name##_t*>(x); \
+ } \
+ extern "C++" inline auto hide_##name(const Name* x) \
+ ->const wasm_##name##_t* { \
+ return static_cast<const wasm_##name##_t*>(x); \
+ } \
+ extern "C++" inline auto reveal_##name(wasm_##name##_t* x)->Name* { \
+ return x; \
+ } \
+ extern "C++" inline auto reveal_##name(const wasm_##name##_t* x) \
+ ->const Name* { \
+ return x; \
+ } \
+ extern "C++" inline auto get_##name(wasm::own<Name>& x)->wasm_##name##_t* { \
+ return hide_##name(x.get()); \
+ } \
+ extern "C++" inline auto get_##name(const wasm::own<Name>& x) \
+ ->const wasm_##name##_t* { \
+ return hide_##name(x.get()); \
+ } \
+ extern "C++" inline auto release_##name(wasm::own<Name>&& x) \
+ ->wasm_##name##_t* { \
+ return hide_##name(x.release()); \
+ } \
+ extern "C++" inline auto adopt_##name(wasm_##name##_t* x)->wasm::own<Name> { \
+ return make_own(x); \
}
// Vectors
-#define WASM_DEFINE_VEC_BASE(name, Name, ptr_or_none) \
- extern "C++" inline auto hide(wasm::vec<Name ptr_or_none>& v) \
- ->wasm_##name##_vec_t* { \
- static_assert(sizeof(wasm_##name##_vec_t) == sizeof(wasm::vec<Name>), \
- "C/C++ incompatibility"); \
- return reinterpret_cast<wasm_##name##_vec_t*>(&v); \
- } \
- extern "C++" inline auto hide(const wasm::vec<Name ptr_or_none>& v) \
- ->const wasm_##name##_vec_t* { \
- static_assert(sizeof(wasm_##name##_vec_t) == sizeof(wasm::vec<Name>), \
- "C/C++ incompatibility"); \
- return reinterpret_cast<const wasm_##name##_vec_t*>(&v); \
- } \
- extern "C++" inline auto hide(Name ptr_or_none* v) \
- ->wasm_##name##_t ptr_or_none* { \
- static_assert( \
- sizeof(wasm_##name##_t ptr_or_none) == sizeof(Name ptr_or_none), \
- "C/C++ incompatibility"); \
- return reinterpret_cast<wasm_##name##_t ptr_or_none*>(v); \
- } \
- extern "C++" inline auto hide(Name ptr_or_none const* v) \
- ->wasm_##name##_t ptr_or_none const* { \
- static_assert( \
- sizeof(wasm_##name##_t ptr_or_none) == sizeof(Name ptr_or_none), \
- "C/C++ incompatibility"); \
- return reinterpret_cast<wasm_##name##_t ptr_or_none const*>(v); \
- } \
- extern "C++" inline auto reveal(wasm_##name##_t ptr_or_none* v) \
- ->Name ptr_or_none* { \
- static_assert( \
- sizeof(wasm_##name##_t ptr_or_none) == sizeof(Name ptr_or_none), \
- "C/C++ incompatibility"); \
- return reinterpret_cast<Name ptr_or_none*>(v); \
- } \
- extern "C++" inline auto reveal(wasm_##name##_t ptr_or_none const* v) \
- ->Name ptr_or_none const* { \
- static_assert( \
- sizeof(wasm_##name##_t ptr_or_none) == sizeof(Name ptr_or_none), \
- "C/C++ incompatibility"); \
- return reinterpret_cast<Name ptr_or_none const*>(v); \
- } \
- extern "C++" inline auto get(wasm::vec<Name ptr_or_none>& v) \
- ->wasm_##name##_vec_t { \
- wasm_##name##_vec_t v2 = {v.size(), hide(v.get())}; \
- return v2; \
- } \
- extern "C++" inline auto get(const wasm::vec<Name ptr_or_none>& v) \
- ->const wasm_##name##_vec_t { \
- wasm_##name##_vec_t v2 = { \
- v.size(), const_cast<wasm_##name##_t ptr_or_none*>(hide(v.get()))}; \
- return v2; \
- } \
- extern "C++" inline auto release(wasm::vec<Name ptr_or_none>&& v) \
- ->wasm_##name##_vec_t { \
- wasm_##name##_vec_t v2 = {v.size(), hide(v.release())}; \
- return v2; \
- } \
- extern "C++" inline auto adopt(wasm_##name##_vec_t* v) \
- ->wasm::vec<Name ptr_or_none> { \
- return wasm::vec<Name ptr_or_none>::adopt(v->size, reveal(v->data)); \
- } \
- extern "C++" inline auto borrow(const wasm_##name##_vec_t* v) \
- ->borrowed_vec<Name ptr_or_none> { \
- return borrowed_vec<Name ptr_or_none>( \
- wasm::vec<Name ptr_or_none>::adopt(v->size, reveal(v->data))); \
- } \
- \
- void wasm_##name##_vec_new_uninitialized(wasm_##name##_vec_t* out, \
- size_t size) { \
- *out = release(wasm::vec<Name ptr_or_none>::make_uninitialized(size)); \
- } \
- void wasm_##name##_vec_new_empty(wasm_##name##_vec_t* out) { \
- wasm_##name##_vec_new_uninitialized(out, 0); \
- } \
- \
- void wasm_##name##_vec_delete(wasm_##name##_vec_t* v) { adopt(v); }
+#define WASM_DEFINE_VEC_BASE(name, Name, vec, ptr_or_none) \
+ static_assert(sizeof(wasm_##name##_vec_t) == sizeof(vec<Name>), \
+ "C/C++ incompatibility"); \
+ static_assert( \
+ sizeof(wasm_##name##_t ptr_or_none) == sizeof(vec<Name>::elem_type), \
+ "C/C++ incompatibility"); \
+ extern "C++" inline auto hide_##name##_vec(vec<Name>& v) \
+ ->wasm_##name##_vec_t* { \
+ return reinterpret_cast<wasm_##name##_vec_t*>(&v); \
+ } \
+ extern "C++" inline auto hide_##name##_vec(const vec<Name>& v) \
+ ->const wasm_##name##_vec_t* { \
+ return reinterpret_cast<const wasm_##name##_vec_t*>(&v); \
+ } \
+ extern "C++" inline auto hide_##name##_vec(vec<Name>::elem_type* v) \
+ ->wasm_##name##_t ptr_or_none* { \
+ return reinterpret_cast<wasm_##name##_t ptr_or_none*>(v); \
+ } \
+ extern "C++" inline auto hide_##name##_vec(const vec<Name>::elem_type* v) \
+ ->wasm_##name##_t ptr_or_none const* { \
+ return reinterpret_cast<wasm_##name##_t ptr_or_none const*>(v); \
+ } \
+ extern "C++" inline auto reveal_##name##_vec(wasm_##name##_t ptr_or_none* v) \
+ ->vec<Name>::elem_type* { \
+ return reinterpret_cast<vec<Name>::elem_type*>(v); \
+ } \
+ extern "C++" inline auto reveal_##name##_vec( \
+ wasm_##name##_t ptr_or_none const* v) \
+ ->const vec<Name>::elem_type* { \
+ return reinterpret_cast<const vec<Name>::elem_type*>(v); \
+ } \
+ extern "C++" inline auto get_##name##_vec(vec<Name>& v) \
+ ->wasm_##name##_vec_t { \
+ wasm_##name##_vec_t v2 = {v.size(), hide_##name##_vec(v.get())}; \
+ return v2; \
+ } \
+ extern "C++" inline auto get_##name##_vec(const vec<Name>& v) \
+ ->const wasm_##name##_vec_t { \
+ wasm_##name##_vec_t v2 = { \
+ v.size(), \
+ const_cast<wasm_##name##_t ptr_or_none*>(hide_##name##_vec(v.get()))}; \
+ return v2; \
+ } \
+ extern "C++" inline auto release_##name##_vec(vec<Name>&& v) \
+ ->wasm_##name##_vec_t { \
+ wasm_##name##_vec_t v2 = {v.size(), hide_##name##_vec(v.release())}; \
+ return v2; \
+ } \
+ extern "C++" inline auto adopt_##name##_vec(wasm_##name##_vec_t* v) \
+ ->vec<Name> { \
+ return vec<Name>::adopt(v->size, reveal_##name##_vec(v->data)); \
+ } \
+ extern "C++" inline auto borrow_##name##_vec(const wasm_##name##_vec_t* v) \
+ ->borrowed_vec<vec<Name>::elem_type> { \
+ return borrowed_vec<vec<Name>::elem_type>( \
+ vec<Name>::adopt(v->size, reveal_##name##_vec(v->data))); \
+ } \
+ \
+ void wasm_##name##_vec_new_uninitialized(wasm_##name##_vec_t* out, \
+ size_t size) { \
+ *out = release_##name##_vec(vec<Name>::make_uninitialized(size)); \
+ } \
+ void wasm_##name##_vec_new_empty(wasm_##name##_vec_t* out) { \
+ wasm_##name##_vec_new_uninitialized(out, 0); \
+ } \
+ \
+ void wasm_##name##_vec_delete(wasm_##name##_vec_t* v) { \
+ adopt_##name##_vec(v); \
+ }
// Vectors with no ownership management of elements
-#define WASM_DEFINE_VEC_PLAIN(name, Name, ptr_or_none) \
- WASM_DEFINE_VEC_BASE(name, Name, ptr_or_none) \
- \
- void wasm_##name##_vec_new(wasm_##name##_vec_t* out, size_t size, \
- wasm_##name##_t ptr_or_none const data[]) { \
- auto v2 = wasm::vec<Name ptr_or_none>::make_uninitialized(size); \
- if (v2.size() != 0) { \
- memcpy(v2.get(), data, size * sizeof(wasm_##name##_t ptr_or_none)); \
- } \
- *out = release(std::move(v2)); \
- } \
- \
- void wasm_##name##_vec_copy(wasm_##name##_vec_t* out, \
- wasm_##name##_vec_t* v) { \
- wasm_##name##_vec_new(out, v->size, v->data); \
- }
-
-// Vectors who own their elements
-#define WASM_DEFINE_VEC(name, Name, ptr_or_none) \
- WASM_DEFINE_VEC_BASE(name, Name, ptr_or_none) \
- \
- void wasm_##name##_vec_new(wasm_##name##_vec_t* out, size_t size, \
- wasm_##name##_t ptr_or_none const data[]) { \
- auto v2 = wasm::vec<Name ptr_or_none>::make_uninitialized(size); \
- for (size_t i = 0; i < v2.size(); ++i) { \
- v2[i] = adopt(data[i]); \
- } \
- *out = release(std::move(v2)); \
- } \
- \
- void wasm_##name##_vec_copy(wasm_##name##_vec_t* out, \
- wasm_##name##_vec_t* v) { \
- auto v2 = wasm::vec<Name ptr_or_none>::make_uninitialized(v->size); \
- for (size_t i = 0; i < v2.size(); ++i) { \
- v2[i] = adopt(wasm_##name##_copy(v->data[i])); \
- } \
- *out = release(std::move(v2)); \
+#define WASM_DEFINE_VEC_PLAIN(name, Name) \
+ WASM_DEFINE_VEC_BASE(name, Name, \
+ wasm::vec, ) /* NOLINT(whitespace/parens) */ \
+ \
+ void wasm_##name##_vec_new(wasm_##name##_vec_t* out, size_t size, \
+ const wasm_##name##_t data[]) { \
+ auto v2 = wasm::vec<Name>::make_uninitialized(size); \
+ if (v2.size() != 0) { \
+ memcpy(v2.get(), data, size * sizeof(wasm_##name##_t)); \
+ } \
+ *out = release_##name##_vec(std::move(v2)); \
+ } \
+ \
+ void wasm_##name##_vec_copy(wasm_##name##_vec_t* out, \
+ wasm_##name##_vec_t* v) { \
+ wasm_##name##_vec_new(out, v->size, v->data); \
+ }
+
+// Vectors that own their elements
+#define WASM_DEFINE_VEC_OWN(name, Name) \
+ WASM_DEFINE_VEC_BASE(name, Name, wasm::ownvec, *) \
+ \
+ void wasm_##name##_vec_new(wasm_##name##_vec_t* out, size_t size, \
+ wasm_##name##_t* const data[]) { \
+ auto v2 = wasm::ownvec<Name>::make_uninitialized(size); \
+ for (size_t i = 0; i < v2.size(); ++i) { \
+ v2[i] = adopt_##name(data[i]); \
+ } \
+ *out = release_##name##_vec(std::move(v2)); \
+ } \
+ \
+ void wasm_##name##_vec_copy(wasm_##name##_vec_t* out, \
+ wasm_##name##_vec_t* v) { \
+ auto v2 = wasm::ownvec<Name>::make_uninitialized(v->size); \
+ for (size_t i = 0; i < v2.size(); ++i) { \
+ v2[i] = adopt_##name(wasm_##name##_copy(v->data[i])); \
+ } \
+ *out = release_##name##_vec(std::move(v2)); \
}
extern "C++" {
@@ -2056,7 +2234,7 @@ inline auto is_empty(T* p) -> bool {
// Byte vectors
using byte = byte_t;
-WASM_DEFINE_VEC_PLAIN(byte, byte, )
+WASM_DEFINE_VEC_PLAIN(byte, byte)
///////////////////////////////////////////////////////////////////////////////
// Runtime Environment
@@ -2065,16 +2243,20 @@ WASM_DEFINE_VEC_PLAIN(byte, byte, )
WASM_DEFINE_OWN(config, wasm::Config)
-wasm_config_t* wasm_config_new() { return release(wasm::Config::make()); }
+wasm_config_t* wasm_config_new() {
+ return release_config(wasm::Config::make());
+}
// Engine
WASM_DEFINE_OWN(engine, wasm::Engine)
-wasm_engine_t* wasm_engine_new() { return release(wasm::Engine::make()); }
+wasm_engine_t* wasm_engine_new() {
+ return release_engine(wasm::Engine::make());
+}
wasm_engine_t* wasm_engine_new_with_config(wasm_config_t* config) {
- return release(wasm::Engine::make(adopt(config)));
+ return release_engine(wasm::Engine::make(adopt_config(config)));
}
// Stores
@@ -2082,7 +2264,7 @@ wasm_engine_t* wasm_engine_new_with_config(wasm_config_t* config) {
WASM_DEFINE_OWN(store, wasm::Store)
wasm_store_t* wasm_store_new(wasm_engine_t* engine) {
- return release(wasm::Store::make(engine));
+ return release_store(wasm::Store::make(engine));
}
///////////////////////////////////////////////////////////////////////////////
@@ -2090,38 +2272,40 @@ wasm_store_t* wasm_store_new(wasm_engine_t* engine) {
// Type attributes
-extern "C++" inline auto hide(wasm::Mutability mutability)
+extern "C++" inline auto hide_mutability(wasm::Mutability mutability)
-> wasm_mutability_t {
return static_cast<wasm_mutability_t>(mutability);
}
-extern "C++" inline auto reveal(wasm_mutability_t mutability)
+extern "C++" inline auto reveal_mutability(wasm_mutability_t mutability)
-> wasm::Mutability {
return static_cast<wasm::Mutability>(mutability);
}
-extern "C++" inline auto hide(const wasm::Limits& limits)
+extern "C++" inline auto hide_limits(const wasm::Limits& limits)
-> const wasm_limits_t* {
return reinterpret_cast<const wasm_limits_t*>(&limits);
}
-extern "C++" inline auto reveal(wasm_limits_t limits) -> wasm::Limits {
+extern "C++" inline auto reveal_limits(wasm_limits_t limits) -> wasm::Limits {
return wasm::Limits(limits.min, limits.max);
}
-extern "C++" inline auto hide(wasm::ValKind kind) -> wasm_valkind_t {
+extern "C++" inline auto hide_valkind(wasm::ValKind kind) -> wasm_valkind_t {
return static_cast<wasm_valkind_t>(kind);
}
-extern "C++" inline auto reveal(wasm_valkind_t kind) -> wasm::ValKind {
+extern "C++" inline auto reveal_valkind(wasm_valkind_t kind) -> wasm::ValKind {
return static_cast<wasm::ValKind>(kind);
}
-extern "C++" inline auto hide(wasm::ExternKind kind) -> wasm_externkind_t {
+extern "C++" inline auto hide_externkind(wasm::ExternKind kind)
+ -> wasm_externkind_t {
return static_cast<wasm_externkind_t>(kind);
}
-extern "C++" inline auto reveal(wasm_externkind_t kind) -> wasm::ExternKind {
+extern "C++" inline auto reveal_externkind(wasm_externkind_t kind)
+ -> wasm::ExternKind {
return static_cast<wasm::ExternKind>(kind);
}
@@ -2129,10 +2313,10 @@ extern "C++" inline auto reveal(wasm_externkind_t kind) -> wasm::ExternKind {
#define WASM_DEFINE_TYPE(name, Name) \
WASM_DEFINE_OWN(name, Name) \
- WASM_DEFINE_VEC(name, Name, *) \
+ WASM_DEFINE_VEC_OWN(name, Name) \
\
wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t* t) { \
- return release(t->copy()); \
+ return release_##name(t->copy()); \
}
// Value Types
@@ -2140,11 +2324,11 @@ extern "C++" inline auto reveal(wasm_externkind_t kind) -> wasm::ExternKind {
WASM_DEFINE_TYPE(valtype, wasm::ValType)
wasm_valtype_t* wasm_valtype_new(wasm_valkind_t k) {
- return release(wasm::ValType::make(reveal(k)));
+ return release_valtype(wasm::ValType::make(reveal_valkind(k)));
}
wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t* t) {
- return hide(t->kind());
+ return hide_valkind(t->kind());
}
// Function Types
@@ -2153,15 +2337,16 @@ WASM_DEFINE_TYPE(functype, wasm::FuncType)
wasm_functype_t* wasm_functype_new(wasm_valtype_vec_t* params,
wasm_valtype_vec_t* results) {
- return release(wasm::FuncType::make(adopt(params), adopt(results)));
+ return release_functype(wasm::FuncType::make(adopt_valtype_vec(params),
+ adopt_valtype_vec(results)));
}
const wasm_valtype_vec_t* wasm_functype_params(const wasm_functype_t* ft) {
- return hide(ft->params());
+ return hide_valtype_vec(ft->params());
}
const wasm_valtype_vec_t* wasm_functype_results(const wasm_functype_t* ft) {
- return hide(ft->results());
+ return hide_valtype_vec(ft->results());
}
// Global Types
@@ -2170,15 +2355,16 @@ WASM_DEFINE_TYPE(globaltype, wasm::GlobalType)
wasm_globaltype_t* wasm_globaltype_new(wasm_valtype_t* content,
wasm_mutability_t mutability) {
- return release(wasm::GlobalType::make(adopt(content), reveal(mutability)));
+ return release_globaltype(wasm::GlobalType::make(
+ adopt_valtype(content), reveal_mutability(mutability)));
}
const wasm_valtype_t* wasm_globaltype_content(const wasm_globaltype_t* gt) {
- return hide(gt->content());
+ return hide_valtype(gt->content());
}
wasm_mutability_t wasm_globaltype_mutability(const wasm_globaltype_t* gt) {
- return hide(gt->mutability());
+ return hide_mutability(gt->mutability());
}
// Table Types
@@ -2187,15 +2373,16 @@ WASM_DEFINE_TYPE(tabletype, wasm::TableType)
wasm_tabletype_t* wasm_tabletype_new(wasm_valtype_t* element,
const wasm_limits_t* limits) {
- return release(wasm::TableType::make(adopt(element), reveal(*limits)));
+ return release_tabletype(
+ wasm::TableType::make(adopt_valtype(element), reveal_limits(*limits)));
}
const wasm_valtype_t* wasm_tabletype_element(const wasm_tabletype_t* tt) {
- return hide(tt->element());
+ return hide_valtype(tt->element());
}
const wasm_limits_t* wasm_tabletype_limits(const wasm_tabletype_t* tt) {
- return hide(tt->limits());
+ return hide_limits(tt->limits());
}
// Memory Types
@@ -2203,11 +2390,11 @@ const wasm_limits_t* wasm_tabletype_limits(const wasm_tabletype_t* tt) {
WASM_DEFINE_TYPE(memorytype, wasm::MemoryType)
wasm_memorytype_t* wasm_memorytype_new(const wasm_limits_t* limits) {
- return release(wasm::MemoryType::make(reveal(*limits)));
+ return release_memorytype(wasm::MemoryType::make(reveal_limits(*limits)));
}
const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t* mt) {
- return hide(mt->limits());
+ return hide_limits(mt->limits());
}
// Extern Types
@@ -2215,82 +2402,90 @@ const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t* mt) {
WASM_DEFINE_TYPE(externtype, wasm::ExternType)
wasm_externkind_t wasm_externtype_kind(const wasm_externtype_t* et) {
- return hide(et->kind());
+ return hide_externkind(et->kind());
}
wasm_externtype_t* wasm_functype_as_externtype(wasm_functype_t* ft) {
- return hide(static_cast<wasm::ExternType*>(ft));
+ return hide_externtype(static_cast<wasm::ExternType*>(ft));
}
wasm_externtype_t* wasm_globaltype_as_externtype(wasm_globaltype_t* gt) {
- return hide(static_cast<wasm::ExternType*>(gt));
+ return hide_externtype(static_cast<wasm::ExternType*>(gt));
}
wasm_externtype_t* wasm_tabletype_as_externtype(wasm_tabletype_t* tt) {
- return hide(static_cast<wasm::ExternType*>(tt));
+ return hide_externtype(static_cast<wasm::ExternType*>(tt));
}
wasm_externtype_t* wasm_memorytype_as_externtype(wasm_memorytype_t* mt) {
- return hide(static_cast<wasm::ExternType*>(mt));
+ return hide_externtype(static_cast<wasm::ExternType*>(mt));
}
const wasm_externtype_t* wasm_functype_as_externtype_const(
const wasm_functype_t* ft) {
- return hide(static_cast<const wasm::ExternType*>(ft));
+ return hide_externtype(static_cast<const wasm::ExternType*>(ft));
}
const wasm_externtype_t* wasm_globaltype_as_externtype_const(
const wasm_globaltype_t* gt) {
- return hide(static_cast<const wasm::ExternType*>(gt));
+ return hide_externtype(static_cast<const wasm::ExternType*>(gt));
}
const wasm_externtype_t* wasm_tabletype_as_externtype_const(
const wasm_tabletype_t* tt) {
- return hide(static_cast<const wasm::ExternType*>(tt));
+ return hide_externtype(static_cast<const wasm::ExternType*>(tt));
}
const wasm_externtype_t* wasm_memorytype_as_externtype_const(
const wasm_memorytype_t* mt) {
- return hide(static_cast<const wasm::ExternType*>(mt));
+ return hide_externtype(static_cast<const wasm::ExternType*>(mt));
}
wasm_functype_t* wasm_externtype_as_functype(wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_FUNC
- ? hide(static_cast<wasm::FuncType*>(reveal(et)))
+ ? hide_functype(
+ static_cast<wasm::FuncType*>(reveal_externtype(et)))
: nullptr;
}
wasm_globaltype_t* wasm_externtype_as_globaltype(wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_GLOBAL
- ? hide(static_cast<wasm::GlobalType*>(reveal(et)))
+ ? hide_globaltype(
+ static_cast<wasm::GlobalType*>(reveal_externtype(et)))
: nullptr;
}
wasm_tabletype_t* wasm_externtype_as_tabletype(wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_TABLE
- ? hide(static_cast<wasm::TableType*>(reveal(et)))
+ ? hide_tabletype(
+ static_cast<wasm::TableType*>(reveal_externtype(et)))
: nullptr;
}
wasm_memorytype_t* wasm_externtype_as_memorytype(wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_MEMORY
- ? hide(static_cast<wasm::MemoryType*>(reveal(et)))
+ ? hide_memorytype(
+ static_cast<wasm::MemoryType*>(reveal_externtype(et)))
: nullptr;
}
const wasm_functype_t* wasm_externtype_as_functype_const(
const wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_FUNC
- ? hide(static_cast<const wasm::FuncType*>(reveal(et)))
+ ? hide_functype(
+ static_cast<const wasm::FuncType*>(reveal_externtype(et)))
: nullptr;
}
const wasm_globaltype_t* wasm_externtype_as_globaltype_const(
const wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_GLOBAL
- ? hide(static_cast<const wasm::GlobalType*>(reveal(et)))
+ ? hide_globaltype(
+ static_cast<const wasm::GlobalType*>(reveal_externtype(et)))
: nullptr;
}
const wasm_tabletype_t* wasm_externtype_as_tabletype_const(
const wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_TABLE
- ? hide(static_cast<const wasm::TableType*>(reveal(et)))
+ ? hide_tabletype(
+ static_cast<const wasm::TableType*>(reveal_externtype(et)))
: nullptr;
}
const wasm_memorytype_t* wasm_externtype_as_memorytype_const(
const wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_MEMORY
- ? hide(static_cast<const wasm::MemoryType*>(reveal(et)))
+ ? hide_memorytype(
+ static_cast<const wasm::MemoryType*>(reveal_externtype(et)))
: nullptr;
}
@@ -2300,20 +2495,20 @@ WASM_DEFINE_TYPE(importtype, wasm::ImportType)
wasm_importtype_t* wasm_importtype_new(wasm_name_t* module, wasm_name_t* name,
wasm_externtype_t* type) {
- return release(
- wasm::ImportType::make(adopt(module), adopt(name), adopt(type)));
+ return release_importtype(wasm::ImportType::make(
+ adopt_byte_vec(module), adopt_byte_vec(name), adopt_externtype(type)));
}
const wasm_name_t* wasm_importtype_module(const wasm_importtype_t* it) {
- return hide(it->module());
+ return hide_byte_vec(it->module());
}
const wasm_name_t* wasm_importtype_name(const wasm_importtype_t* it) {
- return hide(it->name());
+ return hide_byte_vec(it->name());
}
const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t* it) {
- return hide(it->type());
+ return hide_externtype(it->type());
}
// Export Types
@@ -2322,15 +2517,16 @@ WASM_DEFINE_TYPE(exporttype, wasm::ExportType)
wasm_exporttype_t* wasm_exporttype_new(wasm_name_t* name,
wasm_externtype_t* type) {
- return release(wasm::ExportType::make(adopt(name), adopt(type)));
+ return release_exporttype(
+ wasm::ExportType::make(adopt_byte_vec(name), adopt_externtype(type)));
}
const wasm_name_t* wasm_exporttype_name(const wasm_exporttype_t* et) {
- return hide(et->name());
+ return hide_byte_vec(et->name());
}
const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t* et) {
- return hide(et->type());
+ return hide_externtype(et->type());
}
///////////////////////////////////////////////////////////////////////////////
@@ -2342,7 +2538,12 @@ const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t* et) {
WASM_DEFINE_OWN(name, Name) \
\
wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t* t) { \
- return release(t->copy()); \
+ return release_##name(t->copy()); \
+ } \
+ \
+ bool wasm_##name##_same(const wasm_##name##_t* t1, \
+ const wasm_##name##_t* t2) { \
+ return t1->same(t2); \
} \
\
void* wasm_##name##_get_host_info(const wasm_##name##_t* r) { \
@@ -2360,17 +2561,17 @@ const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t* et) {
WASM_DEFINE_REF_BASE(name, Name) \
\
wasm_ref_t* wasm_##name##_as_ref(wasm_##name##_t* r) { \
- return hide(static_cast<wasm::Ref*>(reveal(r))); \
+ return hide_ref(static_cast<wasm::Ref*>(reveal_##name(r))); \
} \
wasm_##name##_t* wasm_ref_as_##name(wasm_ref_t* r) { \
- return hide(static_cast<Name*>(reveal(r))); \
+ return hide_##name(static_cast<Name*>(reveal_ref(r))); \
} \
\
const wasm_ref_t* wasm_##name##_as_ref_const(const wasm_##name##_t* r) { \
- return hide(static_cast<const wasm::Ref*>(reveal(r))); \
+ return hide_ref(static_cast<const wasm::Ref*>(reveal_##name(r))); \
} \
const wasm_##name##_t* wasm_ref_as_##name##_const(const wasm_ref_t* r) { \
- return hide(static_cast<const Name*>(reveal(r))); \
+ return hide_##name(static_cast<const Name*>(reveal_ref(r))); \
}
#define WASM_DEFINE_SHARABLE_REF(name, Name) \
@@ -2384,11 +2585,11 @@ WASM_DEFINE_REF_BASE(ref, wasm::Ref)
extern "C++" {
inline auto is_empty(wasm_val_t v) -> bool {
- return !is_ref(reveal(v.kind)) || !v.of.ref;
+ return !is_ref(reveal_valkind(v.kind)) || !v.of.ref;
}
-inline auto hide(wasm::Val v) -> wasm_val_t {
- wasm_val_t v2 = {hide(v.kind()), {}};
+inline auto hide_val(wasm::Val v) -> wasm_val_t {
+ wasm_val_t v2 = {hide_valkind(v.kind()), {}};
switch (v.kind()) {
case wasm::I32:
v2.of.i32 = v.i32();
@@ -2404,7 +2605,7 @@ inline auto hide(wasm::Val v) -> wasm_val_t {
break;
case wasm::ANYREF:
case wasm::FUNCREF:
- v2.of.ref = hide(v.ref());
+ v2.of.ref = hide_ref(v.ref());
break;
default:
UNREACHABLE();
@@ -2412,8 +2613,8 @@ inline auto hide(wasm::Val v) -> wasm_val_t {
return v2;
}
-inline auto release(wasm::Val v) -> wasm_val_t {
- wasm_val_t v2 = {hide(v.kind()), {}};
+inline auto release_val(wasm::Val v) -> wasm_val_t {
+ wasm_val_t v2 = {hide_valkind(v.kind()), {}};
switch (v.kind()) {
case wasm::I32:
v2.of.i32 = v.i32();
@@ -2429,7 +2630,7 @@ inline auto release(wasm::Val v) -> wasm_val_t {
break;
case wasm::ANYREF:
case wasm::FUNCREF:
- v2.of.ref = release(v.release_ref());
+ v2.of.ref = release_ref(v.release_ref());
break;
default:
UNREACHABLE();
@@ -2437,8 +2638,8 @@ inline auto release(wasm::Val v) -> wasm_val_t {
return v2;
}
-inline auto adopt(wasm_val_t v) -> wasm::Val {
- switch (reveal(v.kind)) {
+inline auto adopt_val(wasm_val_t v) -> wasm::Val {
+ switch (reveal_valkind(v.kind)) {
case wasm::I32:
return wasm::Val(v.of.i32);
case wasm::I64:
@@ -2449,7 +2650,7 @@ inline auto adopt(wasm_val_t v) -> wasm::Val {
return wasm::Val(v.of.f64);
case wasm::ANYREF:
case wasm::FUNCREF:
- return wasm::Val(adopt(v.of.ref));
+ return wasm::Val(adopt_ref(v.of.ref));
default:
UNREACHABLE();
}
@@ -2460,13 +2661,13 @@ struct borrowed_val {
explicit borrowed_val(wasm::Val&& v) : it(std::move(v)) {}
borrowed_val(borrowed_val&& that) : it(std::move(that.it)) {}
~borrowed_val() {
- if (it.is_ref()) it.release_ref();
+ if (it.is_ref()) it.release_ref().release();
}
};
-inline auto borrow(const wasm_val_t* v) -> borrowed_val {
+inline auto borrow_val(const wasm_val_t* v) -> borrowed_val {
wasm::Val v2;
- switch (reveal(v->kind)) {
+ switch (reveal_valkind(v->kind)) {
case wasm::I32:
v2 = wasm::Val(v->of.i32);
break;
@@ -2481,7 +2682,7 @@ inline auto borrow(const wasm_val_t* v) -> borrowed_val {
break;
case wasm::ANYREF:
case wasm::FUNCREF:
- v2 = wasm::Val(adopt(v->of.ref));
+ v2 = wasm::Val(adopt_ref(v->of.ref));
break;
default:
UNREACHABLE();
@@ -2491,15 +2692,15 @@ inline auto borrow(const wasm_val_t* v) -> borrowed_val {
} // extern "C++"
-WASM_DEFINE_VEC_BASE(val, wasm::Val, )
+WASM_DEFINE_VEC_BASE(val, wasm::Val, wasm::vec, )
void wasm_val_vec_new(wasm_val_vec_t* out, size_t size,
wasm_val_t const data[]) {
auto v2 = wasm::vec<wasm::Val>::make_uninitialized(size);
for (size_t i = 0; i < v2.size(); ++i) {
- v2[i] = adopt(data[i]);
+ v2[i] = adopt_val(data[i]);
}
- *out = release(std::move(v2));
+ *out = release_val_vec(std::move(v2));
}
void wasm_val_vec_copy(wasm_val_vec_t* out, wasm_val_vec_t* v) {
@@ -2507,36 +2708,70 @@ void wasm_val_vec_copy(wasm_val_vec_t* out, wasm_val_vec_t* v) {
for (size_t i = 0; i < v2.size(); ++i) {
wasm_val_t val;
wasm_val_copy(&v->data[i], &val);
- v2[i] = adopt(val);
+ v2[i] = adopt_val(val);
}
- *out = release(std::move(v2));
+ *out = release_val_vec(std::move(v2));
}
void wasm_val_delete(wasm_val_t* v) {
- if (is_ref(reveal(v->kind))) adopt(v->of.ref);
+ if (is_ref(reveal_valkind(v->kind))) {
+ adopt_ref(v->of.ref);
+ }
}
void wasm_val_copy(wasm_val_t* out, const wasm_val_t* v) {
*out = *v;
- if (is_ref(reveal(v->kind))) {
- out->of.ref = release(v->of.ref->copy());
+ if (is_ref(reveal_valkind(v->kind))) {
+ out->of.ref = v->of.ref ? release_ref(v->of.ref->copy()) : nullptr;
}
}
///////////////////////////////////////////////////////////////////////////////
// Runtime Objects
+// Frames
+
+WASM_DEFINE_OWN(frame, wasm::Frame)
+WASM_DEFINE_VEC_OWN(frame, wasm::Frame)
+
+wasm_frame_t* wasm_frame_copy(const wasm_frame_t* frame) {
+ return release_frame(frame->copy());
+}
+
+wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame);
+// Defined below along with wasm_instance_t.
+
+uint32_t wasm_frame_func_index(const wasm_frame_t* frame) {
+ return reveal_frame(frame)->func_index();
+}
+
+size_t wasm_frame_func_offset(const wasm_frame_t* frame) {
+ return reveal_frame(frame)->func_offset();
+}
+
+size_t wasm_frame_module_offset(const wasm_frame_t* frame) {
+ return reveal_frame(frame)->module_offset();
+}
+
// Traps
WASM_DEFINE_REF(trap, wasm::Trap)
wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t* message) {
- auto message_ = borrow(message);
- return release(wasm::Trap::make(store, message_.it));
+ auto message_ = borrow_byte_vec(message);
+ return release_trap(wasm::Trap::make(store, message_.it));
}
void wasm_trap_message(const wasm_trap_t* trap, wasm_message_t* out) {
- *out = release(reveal(trap)->message());
+ *out = release_byte_vec(reveal_trap(trap)->message());
+}
+
+wasm_frame_t* wasm_trap_origin(const wasm_trap_t* trap) {
+ return release_frame(reveal_trap(trap)->origin());
+}
+
+void wasm_trap_trace(const wasm_trap_t* trap, wasm_frame_vec_t* out) {
+ *out = release_frame_vec(reveal_trap(trap)->trace());
}
// Foreign Objects
@@ -2544,7 +2779,7 @@ void wasm_trap_message(const wasm_trap_t* trap, wasm_message_t* out) {
WASM_DEFINE_REF(foreign, wasm::Foreign)
wasm_foreign_t* wasm_foreign_new(wasm_store_t* store) {
- return release(wasm::Foreign::make(store));
+ return release_foreign(wasm::Foreign::make(store));
}
// Modules
@@ -2552,43 +2787,43 @@ wasm_foreign_t* wasm_foreign_new(wasm_store_t* store) {
WASM_DEFINE_SHARABLE_REF(module, wasm::Module)
bool wasm_module_validate(wasm_store_t* store, const wasm_byte_vec_t* binary) {
- auto binary_ = borrow(binary);
+ auto binary_ = borrow_byte_vec(binary);
return wasm::Module::validate(store, binary_.it);
}
wasm_module_t* wasm_module_new(wasm_store_t* store,
const wasm_byte_vec_t* binary) {
- auto binary_ = borrow(binary);
- return release(wasm::Module::make(store, binary_.it));
+ auto binary_ = borrow_byte_vec(binary);
+ return release_module(wasm::Module::make(store, binary_.it));
}
void wasm_module_imports(const wasm_module_t* module,
wasm_importtype_vec_t* out) {
- *out = release(reveal(module)->imports());
+ *out = release_importtype_vec(reveal_module(module)->imports());
}
void wasm_module_exports(const wasm_module_t* module,
wasm_exporttype_vec_t* out) {
- *out = release(reveal(module)->exports());
+ *out = release_exporttype_vec(reveal_module(module)->exports());
}
void wasm_module_serialize(const wasm_module_t* module, wasm_byte_vec_t* out) {
- *out = release(reveal(module)->serialize());
+ *out = release_byte_vec(reveal_module(module)->serialize());
}
wasm_module_t* wasm_module_deserialize(wasm_store_t* store,
const wasm_byte_vec_t* binary) {
- auto binary_ = borrow(binary);
- return release(wasm::Module::deserialize(store, binary_.it));
+ auto binary_ = borrow_byte_vec(binary);
+ return release_module(wasm::Module::deserialize(store, binary_.it));
}
wasm_shared_module_t* wasm_module_share(const wasm_module_t* module) {
- return release(reveal(module)->share());
+ return release_shared_module(reveal_module(module)->share());
}
wasm_module_t* wasm_module_obtain(wasm_store_t* store,
const wasm_shared_module_t* shared) {
- return release(wasm::Module::obtain(store, shared));
+ return release_module(wasm::Module::obtain(store, shared));
}
// Function Instances
@@ -2598,9 +2833,9 @@ WASM_DEFINE_REF(func, wasm::Func)
extern "C++" {
auto wasm_callback(void* env, const wasm::Val args[], wasm::Val results[])
- -> wasm::own<wasm::Trap*> {
+ -> wasm::own<wasm::Trap> {
auto f = reinterpret_cast<wasm_func_callback_t>(env);
- return adopt(f(hide(args), hide(results)));
+ return adopt_trap(f(hide_val_vec(args), hide_val_vec(results)));
}
struct wasm_callback_env_t {
@@ -2610,9 +2845,10 @@ struct wasm_callback_env_t {
};
auto wasm_callback_with_env(void* env, const wasm::Val args[],
- wasm::Val results[]) -> wasm::own<wasm::Trap*> {
+ wasm::Val results[]) -> wasm::own<wasm::Trap> {
auto t = static_cast<wasm_callback_env_t*>(env);
- return adopt(t->callback(t->env, hide(args), hide(results)));
+ return adopt_trap(
+ t->callback(t->env, hide_val_vec(args), hide_val_vec(results)));
}
void wasm_callback_env_finalizer(void* env) {
@@ -2625,8 +2861,8 @@ void wasm_callback_env_finalizer(void* env) {
wasm_func_t* wasm_func_new(wasm_store_t* store, const wasm_functype_t* type,
wasm_func_callback_t callback) {
- return release(wasm::Func::make(store, type, wasm_callback,
- reinterpret_cast<void*>(callback)));
+ return release_func(wasm::Func::make(store, type, wasm_callback,
+ reinterpret_cast<void*>(callback)));
}
wasm_func_t* wasm_func_new_with_env(wasm_store_t* store,
@@ -2634,12 +2870,12 @@ wasm_func_t* wasm_func_new_with_env(wasm_store_t* store,
wasm_func_callback_with_env_t callback,
void* env, void (*finalizer)(void*)) {
auto env2 = new wasm_callback_env_t{callback, env, finalizer};
- return release(wasm::Func::make(store, type, wasm_callback_with_env, env2,
- wasm_callback_env_finalizer));
+ return release_func(wasm::Func::make(store, type, wasm_callback_with_env,
+ env2, wasm_callback_env_finalizer));
}
wasm_functype_t* wasm_func_type(const wasm_func_t* func) {
- return release(func->type());
+ return release_functype(func->type());
}
size_t wasm_func_param_arity(const wasm_func_t* func) {
@@ -2652,7 +2888,8 @@ size_t wasm_func_result_arity(const wasm_func_t* func) {
wasm_trap_t* wasm_func_call(const wasm_func_t* func, const wasm_val_t args[],
wasm_val_t results[]) {
- return release(func->call(reveal(args), reveal(results)));
+ return release_trap(
+ func->call(reveal_val_vec(args), reveal_val_vec(results)));
}
// Global Instances
@@ -2662,20 +2899,20 @@ WASM_DEFINE_REF(global, wasm::Global)
wasm_global_t* wasm_global_new(wasm_store_t* store,
const wasm_globaltype_t* type,
const wasm_val_t* val) {
- auto val_ = borrow(val);
- return release(wasm::Global::make(store, type, val_.it));
+ auto val_ = borrow_val(val);
+ return release_global(wasm::Global::make(store, type, val_.it));
}
wasm_globaltype_t* wasm_global_type(const wasm_global_t* global) {
- return release(global->type());
+ return release_globaltype(global->type());
}
void wasm_global_get(const wasm_global_t* global, wasm_val_t* out) {
- *out = release(global->get());
+ *out = release_val(global->get());
}
void wasm_global_set(wasm_global_t* global, const wasm_val_t* val) {
- auto val_ = borrow(val);
+ auto val_ = borrow_val(val);
global->set(val_.it);
}
@@ -2685,15 +2922,15 @@ WASM_DEFINE_REF(table, wasm::Table)
wasm_table_t* wasm_table_new(wasm_store_t* store, const wasm_tabletype_t* type,
wasm_ref_t* ref) {
- return release(wasm::Table::make(store, type, ref));
+ return release_table(wasm::Table::make(store, type, ref));
}
wasm_tabletype_t* wasm_table_type(const wasm_table_t* table) {
- return release(table->type());
+ return release_tabletype(table->type());
}
wasm_ref_t* wasm_table_get(const wasm_table_t* table, wasm_table_size_t index) {
- return release(table->get(index));
+ return release_ref(table->get(index));
}
bool wasm_table_set(wasm_table_t* table, wasm_table_size_t index,
@@ -2716,11 +2953,11 @@ WASM_DEFINE_REF(memory, wasm::Memory)
wasm_memory_t* wasm_memory_new(wasm_store_t* store,
const wasm_memorytype_t* type) {
- return release(wasm::Memory::make(store, type));
+ return release_memory(wasm::Memory::make(store, type));
}
wasm_memorytype_t* wasm_memory_type(const wasm_memory_t* memory) {
- return release(memory->type());
+ return release_memorytype(memory->type());
}
wasm_byte_t* wasm_memory_data(wasm_memory_t* memory) { return memory->data(); }
@@ -2740,67 +2977,67 @@ bool wasm_memory_grow(wasm_memory_t* memory, wasm_memory_pages_t delta) {
// Externals
WASM_DEFINE_REF(extern, wasm::Extern)
-WASM_DEFINE_VEC(extern, wasm::Extern, *)
+WASM_DEFINE_VEC_OWN(extern, wasm::Extern)
wasm_externkind_t wasm_extern_kind(const wasm_extern_t* external) {
- return hide(external->kind());
+ return hide_externkind(external->kind());
}
wasm_externtype_t* wasm_extern_type(const wasm_extern_t* external) {
- return release(external->type());
+ return release_externtype(external->type());
}
wasm_extern_t* wasm_func_as_extern(wasm_func_t* func) {
- return hide(static_cast<wasm::Extern*>(reveal(func)));
+ return hide_extern(static_cast<wasm::Extern*>(reveal_func(func)));
}
wasm_extern_t* wasm_global_as_extern(wasm_global_t* global) {
- return hide(static_cast<wasm::Extern*>(reveal(global)));
+ return hide_extern(static_cast<wasm::Extern*>(reveal_global(global)));
}
wasm_extern_t* wasm_table_as_extern(wasm_table_t* table) {
- return hide(static_cast<wasm::Extern*>(reveal(table)));
+ return hide_extern(static_cast<wasm::Extern*>(reveal_table(table)));
}
wasm_extern_t* wasm_memory_as_extern(wasm_memory_t* memory) {
- return hide(static_cast<wasm::Extern*>(reveal(memory)));
+ return hide_extern(static_cast<wasm::Extern*>(reveal_memory(memory)));
}
const wasm_extern_t* wasm_func_as_extern_const(const wasm_func_t* func) {
- return hide(static_cast<const wasm::Extern*>(reveal(func)));
+ return hide_extern(static_cast<const wasm::Extern*>(reveal_func(func)));
}
const wasm_extern_t* wasm_global_as_extern_const(const wasm_global_t* global) {
- return hide(static_cast<const wasm::Extern*>(reveal(global)));
+ return hide_extern(static_cast<const wasm::Extern*>(reveal_global(global)));
}
const wasm_extern_t* wasm_table_as_extern_const(const wasm_table_t* table) {
- return hide(static_cast<const wasm::Extern*>(reveal(table)));
+ return hide_extern(static_cast<const wasm::Extern*>(reveal_table(table)));
}
const wasm_extern_t* wasm_memory_as_extern_const(const wasm_memory_t* memory) {
- return hide(static_cast<const wasm::Extern*>(reveal(memory)));
+ return hide_extern(static_cast<const wasm::Extern*>(reveal_memory(memory)));
}
wasm_func_t* wasm_extern_as_func(wasm_extern_t* external) {
- return hide(external->func());
+ return hide_func(external->func());
}
wasm_global_t* wasm_extern_as_global(wasm_extern_t* external) {
- return hide(external->global());
+ return hide_global(external->global());
}
wasm_table_t* wasm_extern_as_table(wasm_extern_t* external) {
- return hide(external->table());
+ return hide_table(external->table());
}
wasm_memory_t* wasm_extern_as_memory(wasm_extern_t* external) {
- return hide(external->memory());
+ return hide_memory(external->memory());
}
const wasm_func_t* wasm_extern_as_func_const(const wasm_extern_t* external) {
- return hide(external->func());
+ return hide_func(external->func());
}
const wasm_global_t* wasm_extern_as_global_const(
const wasm_extern_t* external) {
- return hide(external->global());
+ return hide_global(external->global());
}
const wasm_table_t* wasm_extern_as_table_const(const wasm_extern_t* external) {
- return hide(external->table());
+ return hide_table(external->table());
}
const wasm_memory_t* wasm_extern_as_memory_const(
const wasm_extern_t* external) {
- return hide(external->memory());
+ return hide_memory(external->memory());
}
// Module Instances
@@ -2809,20 +3046,29 @@ WASM_DEFINE_REF(instance, wasm::Instance)
wasm_instance_t* wasm_instance_new(wasm_store_t* store,
const wasm_module_t* module,
- const wasm_extern_t* const imports[]) {
- return release(wasm::Instance::make(
- store, module, reinterpret_cast<const wasm::Extern* const*>(imports)));
+ const wasm_extern_t* const imports[],
+ wasm_trap_t** trap) {
+ wasm::own<wasm::Trap> error;
+ wasm_instance_t* instance = release_instance(wasm::Instance::make(
+ store, module, reinterpret_cast<const wasm::Extern* const*>(imports),
+ &error));
+ if (trap) *trap = hide_trap(error.release());
+ return instance;
}
void wasm_instance_exports(const wasm_instance_t* instance,
wasm_extern_vec_t* out) {
- *out = release(instance->exports());
+ *out = release_extern_vec(instance->exports());
+}
+
+wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame) {
+ return hide_instance(reveal_frame(frame)->instance());
}
#undef WASM_DEFINE_OWN
#undef WASM_DEFINE_VEC_BASE
#undef WASM_DEFINE_VEC_PLAIN
-#undef WASM_DEFINE_VEC
+#undef WASM_DEFINE_VEC_OWN
#undef WASM_DEFINE_TYPE
#undef WASM_DEFINE_REF_BASE
#undef WASM_DEFINE_REF
diff --git a/deps/v8/src/wasm/c-api.h b/deps/v8/src/wasm/c-api.h
index c1a914a16e..43a0fb73b2 100644
--- a/deps/v8/src/wasm/c-api.h
+++ b/deps/v8/src/wasm/c-api.h
@@ -7,8 +7,17 @@
#include "include/v8.h"
#include "src/common/globals.h"
+#include "src/handles/handles.h"
#include "third_party/wasm-api/wasm.hh"
+namespace v8 {
+namespace internal {
+
+class JSWeakMap;
+
+} // namespace internal
+} // namespace v8
+
namespace wasm {
class StoreImpl {
@@ -27,14 +36,19 @@ class StoreImpl {
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:
- friend own<Store*> Store::make(Engine*);
+ friend own<Store> Store::make(Engine*);
StoreImpl() {}
v8::Isolate::CreateParams create_params_;
v8::Isolate* isolate_ = nullptr;
v8::Eternal<v8::Context> context_;
+ i::Handle<i::JSWeakMap> host_info_map_;
};
} // namespace wasm
diff --git a/deps/v8/src/wasm/function-body-decoder-impl.h b/deps/v8/src/wasm/function-body-decoder-impl.h
index 9f1ca23c62..582934e19f 100644
--- a/deps/v8/src/wasm/function-body-decoder-impl.h
+++ b/deps/v8/src/wasm/function-body-decoder-impl.h
@@ -339,35 +339,6 @@ struct BranchOnExceptionImmediate {
};
template <Decoder::ValidateFlag validate>
-struct CallIndirectImmediate {
- uint32_t table_index;
- uint32_t sig_index;
- FunctionSig* sig = nullptr;
- uint32_t length = 0;
- inline CallIndirectImmediate(const WasmFeatures enabled, Decoder* decoder,
- const byte* pc) {
- uint32_t len = 0;
- sig_index = decoder->read_u32v<validate>(pc + 1, &len, "signature index");
- table_index = decoder->read_u8<validate>(pc + 1 + len, "table index");
- if (!VALIDATE(table_index == 0 || enabled.anyref)) {
- decoder->errorf(pc + 1 + len, "expected table index 0, found %u",
- table_index);
- }
- length = 1 + len;
- }
-};
-
-template <Decoder::ValidateFlag validate>
-struct CallFunctionImmediate {
- uint32_t index;
- FunctionSig* sig = nullptr;
- uint32_t length;
- inline CallFunctionImmediate(Decoder* decoder, const byte* pc) {
- index = decoder->read_u32v<validate>(pc + 1, &length, "function index");
- }
-};
-
-template <Decoder::ValidateFlag validate>
struct FunctionIndexImmediate {
uint32_t index = 0;
uint32_t length = 1;
@@ -395,7 +366,37 @@ struct TableIndexImmediate {
unsigned length = 1;
inline TableIndexImmediate() = default;
inline TableIndexImmediate(Decoder* decoder, const byte* pc) {
- index = decoder->read_u8<validate>(pc + 1, "table index");
+ index = decoder->read_u32v<validate>(pc + 1, &length, "table index");
+ }
+};
+
+template <Decoder::ValidateFlag validate>
+struct CallIndirectImmediate {
+ uint32_t table_index;
+ uint32_t sig_index;
+ FunctionSig* sig = nullptr;
+ uint32_t length = 0;
+ inline CallIndirectImmediate(const WasmFeatures enabled, Decoder* decoder,
+ const byte* pc) {
+ uint32_t len = 0;
+ sig_index = decoder->read_u32v<validate>(pc + 1, &len, "signature index");
+ TableIndexImmediate<validate> table(decoder, pc + len);
+ if (!VALIDATE((table.index == 0 && table.length == 1) || enabled.anyref)) {
+ decoder->errorf(pc + 1 + len, "expected table index 0, found %u",
+ table.index);
+ }
+ table_index = table.index;
+ length = len + table.length;
+ }
+};
+
+template <Decoder::ValidateFlag validate>
+struct CallFunctionImmediate {
+ uint32_t index;
+ FunctionSig* sig = nullptr;
+ uint32_t length;
+ inline CallFunctionImmediate(Decoder* decoder, const byte* pc) {
+ index = decoder->read_u32v<validate>(pc + 1, &length, "function index");
}
};
@@ -748,8 +749,6 @@ struct ControlBase {
F(SimdOp, WasmOpcode opcode, Vector<Value> args, Value* result) \
F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate<validate>& imm, \
const Vector<Value> inputs, Value* result) \
- F(SimdShiftOp, WasmOpcode opcode, const SimdShiftImmediate<validate>& imm, \
- const Value& input, Value* result) \
F(Simd8x16ShuffleOp, const Simd8x16ShuffleImmediate<validate>& imm, \
const Value& input0, const Value& input1, Value* result) \
F(Throw, const ExceptionIndexImmediate<validate>& imm, \
@@ -849,7 +848,9 @@ class WasmDecoder : public Decoder {
type = kWasmAnyRef;
break;
}
- decoder->error(decoder->pc() - 1, "invalid local type");
+ decoder->error(decoder->pc() - 1,
+ "invalid local type 'anyref', enable with "
+ "--experimental-wasm-anyref");
return false;
case kLocalFuncRef:
if (enabled.anyref) {
@@ -857,7 +858,7 @@ class WasmDecoder : public Decoder {
break;
}
decoder->error(decoder->pc() - 1,
- "local type 'funcref' is not enabled with "
+ "invalid local type 'funcref', enable with "
"--experimental-wasm-anyref");
return false;
case kLocalExnRef:
@@ -865,14 +866,19 @@ class WasmDecoder : public Decoder {
type = kWasmExnRef;
break;
}
- decoder->error(decoder->pc() - 1, "invalid local type");
+ decoder->error(decoder->pc() - 1,
+ "invalid local type 'exception ref', enable with "
+ "--experimental-wasm-eh");
return false;
case kLocalS128:
if (enabled.simd) {
type = kWasmS128;
break;
}
- V8_FALLTHROUGH;
+ decoder->error(decoder->pc() - 1,
+ "invalid local type 'Simd128', enable with "
+ "--experimental-wasm-simd");
+ return false;
default:
decoder->error(decoder->pc() - 1, "invalid local type");
return false;
@@ -2666,16 +2672,6 @@ class WasmFullDecoder : public WasmDecoder<validate> {
return imm.length;
}
- uint32_t SimdShiftOp(WasmOpcode opcode) {
- SimdShiftImmediate<validate> imm(this, this->pc_);
- if (this->Validate(this->pc_, opcode, imm)) {
- auto input = Pop(0, kWasmS128);
- auto* result = Push(kWasmS128);
- CALL_INTERFACE_IF_REACHABLE(SimdShiftOp, opcode, imm, input, result);
- }
- return imm.length;
- }
-
uint32_t Simd8x16ShuffleOp() {
Simd8x16ShuffleImmediate<validate> imm(this, this->pc_);
if (this->Validate(this->pc_, imm)) {
@@ -2727,21 +2723,6 @@ class WasmFullDecoder : public WasmDecoder<validate> {
len = SimdReplaceLane(opcode, kWasmI32);
break;
}
- case kExprI64x2Shl:
- case kExprI64x2ShrS:
- case kExprI64x2ShrU:
- case kExprI32x4Shl:
- case kExprI32x4ShrS:
- case kExprI32x4ShrU:
- case kExprI16x8Shl:
- case kExprI16x8ShrS:
- case kExprI16x8ShrU:
- case kExprI8x16Shl:
- case kExprI8x16ShrS:
- case kExprI8x16ShrU: {
- len = SimdShiftOp(opcode);
- break;
- }
case kExprS8x16Shuffle: {
len = Simd8x16ShuffleOp();
break;
diff --git a/deps/v8/src/wasm/function-compiler.cc b/deps/v8/src/wasm/function-compiler.cc
index 7df5abf5c8..4940134d53 100644
--- a/deps/v8/src/wasm/function-compiler.cc
+++ b/deps/v8/src/wasm/function-compiler.cc
@@ -262,21 +262,18 @@ void WasmCompilationUnit::CompileWasmFunction(Isolate* isolate,
}
}
-JSToWasmWrapperCompilationUnit::JSToWasmWrapperCompilationUnit(Isolate* isolate,
- FunctionSig* sig,
- bool is_import)
- : job_(compiler::NewJSToWasmCompilationJob(isolate, sig, is_import)) {}
+JSToWasmWrapperCompilationUnit::JSToWasmWrapperCompilationUnit(
+ Isolate* isolate, WasmEngine* wasm_engine, FunctionSig* sig, bool is_import,
+ const WasmFeatures& enabled_features)
+ : is_import_(is_import),
+ sig_(sig),
+ job_(compiler::NewJSToWasmCompilationJob(isolate, wasm_engine, sig,
+ is_import, enabled_features)) {}
JSToWasmWrapperCompilationUnit::~JSToWasmWrapperCompilationUnit() = default;
-void JSToWasmWrapperCompilationUnit::Prepare(Isolate* isolate) {
- CompilationJob::Status status = job_->PrepareJob(isolate);
- CHECK_EQ(status, CompilationJob::SUCCEEDED);
-}
-
void JSToWasmWrapperCompilationUnit::Execute() {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "CompileJSToWasmWrapper");
- DCHECK_EQ(job_->state(), CompilationJob::State::kReadyToExecute);
CompilationJob::Status status = job_->ExecuteJob();
CHECK_EQ(status, CompilationJob::SUCCEEDED);
}
@@ -296,8 +293,9 @@ Handle<Code> JSToWasmWrapperCompilationUnit::Finalize(Isolate* isolate) {
Handle<Code> JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper(
Isolate* isolate, FunctionSig* sig, bool is_import) {
// Run the compilation unit synchronously.
- JSToWasmWrapperCompilationUnit unit(isolate, sig, is_import);
- unit.Prepare(isolate);
+ WasmFeatures enabled_features = WasmFeaturesFromIsolate(isolate);
+ JSToWasmWrapperCompilationUnit unit(isolate, isolate->wasm_engine(), sig,
+ is_import, enabled_features);
unit.Execute();
return unit.Finalize(isolate);
}
diff --git a/deps/v8/src/wasm/function-compiler.h b/deps/v8/src/wasm/function-compiler.h
index d0b47b91aa..2da028a047 100644
--- a/deps/v8/src/wasm/function-compiler.h
+++ b/deps/v8/src/wasm/function-compiler.h
@@ -108,19 +108,24 @@ STATIC_ASSERT(sizeof(WasmCompilationUnit) <= 2 * kSystemPointerSize);
class V8_EXPORT_PRIVATE JSToWasmWrapperCompilationUnit final {
public:
- JSToWasmWrapperCompilationUnit(Isolate* isolate, FunctionSig* sig,
- bool is_import);
+ JSToWasmWrapperCompilationUnit(Isolate* isolate, WasmEngine* wasm_engine,
+ FunctionSig* sig, bool is_import,
+ const WasmFeatures& enabled_features);
~JSToWasmWrapperCompilationUnit();
- void Prepare(Isolate* isolate);
void Execute();
Handle<Code> Finalize(Isolate* isolate);
+ bool is_import() const { return is_import_; }
+ FunctionSig* sig() const { return sig_; }
+
// Run a compilation unit synchronously.
static Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, FunctionSig* sig,
bool is_import);
private:
+ bool is_import_;
+ FunctionSig* sig_;
std::unique_ptr<OptimizedCompilationJob> job_;
};
diff --git a/deps/v8/src/wasm/graph-builder-interface.cc b/deps/v8/src/wasm/graph-builder-interface.cc
index 8efac18787..923e1154ea 100644
--- a/deps/v8/src/wasm/graph-builder-interface.cc
+++ b/deps/v8/src/wasm/graph-builder-interface.cc
@@ -258,8 +258,8 @@ class WasmGraphBuildingInterface {
void Drop(FullDecoder* decoder, const Value& value) {}
void DoReturn(FullDecoder* decoder, Vector<Value> values) {
- TFNode** nodes = GetNodes(values);
- BUILD(Return, static_cast<uint32_t>(values.size()), nodes);
+ Vector<TFNode*> nodes = GetNodes(values);
+ BUILD(Return, nodes);
}
void GetLocal(FullDecoder* decoder, Value* result,
@@ -319,10 +319,10 @@ class WasmGraphBuildingInterface {
void BrOrRet(FullDecoder* decoder, uint32_t depth) {
if (depth == decoder->control_depth() - 1) {
uint32_t ret_count = static_cast<uint32_t>(decoder->sig_->return_count());
- TFNode** values =
- ret_count == 0 ? nullptr
+ Vector<TFNode*> values =
+ ret_count == 0 ? Vector<TFNode*>{}
: GetNodes(decoder->stack_value(ret_count), ret_count);
- BUILD(Return, ret_count, values);
+ BUILD(Return, values);
} else {
Br(decoder, decoder->control_at(depth));
}
@@ -431,23 +431,16 @@ class WasmGraphBuildingInterface {
void SimdOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args,
Value* result) {
- TFNode** inputs = GetNodes(args);
- TFNode* node = BUILD(SimdOp, opcode, inputs);
+ Vector<TFNode*> inputs = GetNodes(args);
+ TFNode* node = BUILD(SimdOp, opcode, inputs.begin());
if (result) result->node = node;
}
void SimdLaneOp(FullDecoder* decoder, WasmOpcode opcode,
const SimdLaneImmediate<validate> imm, Vector<Value> inputs,
Value* result) {
- TFNode** nodes = GetNodes(inputs);
- result->node = BUILD(SimdLaneOp, opcode, imm.lane, nodes);
- }
-
- void SimdShiftOp(FullDecoder* decoder, WasmOpcode opcode,
- const SimdShiftImmediate<validate> imm, const Value& input,
- Value* result) {
- TFNode* inputs[] = {input.node};
- result->node = BUILD(SimdShiftOp, opcode, imm.shift, inputs);
+ Vector<TFNode*> nodes = GetNodes(inputs);
+ result->node = BUILD(SimdLaneOp, opcode, imm.lane, nodes.begin());
}
void Simd8x16ShuffleOp(FullDecoder* decoder,
@@ -495,7 +488,7 @@ class WasmGraphBuildingInterface {
SetEnv(if_match_env);
// TODO(mstarzinger): Can't use BUILD() here, GetExceptionValues() returns
// TFNode** rather than TFNode*. Fix to add landing pads.
- TFNode** caught_values =
+ Vector<TFNode*> caught_values =
builder_->GetExceptionValues(exception.node, imm.exception);
for (size_t i = 0, e = values.size(); i < e; ++i) {
values[i].node = caught_values[i];
@@ -526,9 +519,9 @@ class WasmGraphBuildingInterface {
void AtomicOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args,
const MemoryAccessImmediate<validate>& imm, Value* result) {
- TFNode** inputs = GetNodes(args);
- TFNode* node = BUILD(AtomicOp, opcode, inputs, imm.alignment, imm.offset,
- decoder->position());
+ Vector<TFNode*> inputs = GetNodes(args);
+ TFNode* node = BUILD(AtomicOp, opcode, inputs.begin(), imm.alignment,
+ imm.offset, decoder->position());
if (result) result->node = node;
}
@@ -598,15 +591,15 @@ class WasmGraphBuildingInterface {
->try_info;
}
- TFNode** GetNodes(Value* values, size_t count) {
- TFNode** nodes = builder_->Buffer(count);
+ Vector<TFNode*> GetNodes(Value* values, size_t count) {
+ Vector<TFNode*> nodes = builder_->Buffer(count);
for (size_t i = 0; i < count; ++i) {
nodes[i] = values[i].node;
}
return nodes;
}
- TFNode** GetNodes(Vector<Value> values) {
+ Vector<TFNode*> GetNodes(Vector<Value> values) {
return GetNodes(values.begin(), values.size());
}
@@ -885,17 +878,17 @@ class WasmGraphBuildingInterface {
FunctionSig* sig, uint32_t sig_index, const Value args[],
Value returns[]) {
int param_count = static_cast<int>(sig->parameter_count());
- TFNode** arg_nodes = builder_->Buffer(param_count + 1);
+ Vector<TFNode*> arg_nodes = builder_->Buffer(param_count + 1);
TFNode** return_nodes = nullptr;
arg_nodes[0] = index_node;
for (int i = 0; i < param_count; ++i) {
arg_nodes[i + 1] = args[i].node;
}
if (index_node) {
- BUILD(CallIndirect, table_index, sig_index, arg_nodes, &return_nodes,
- decoder->position());
+ BUILD(CallIndirect, table_index, sig_index, arg_nodes.begin(),
+ &return_nodes, decoder->position());
} else {
- BUILD(CallDirect, sig_index, arg_nodes, &return_nodes,
+ BUILD(CallDirect, sig_index, arg_nodes.begin(), &return_nodes,
decoder->position());
}
int return_count = static_cast<int>(sig->return_count());
@@ -911,16 +904,16 @@ class WasmGraphBuildingInterface {
TFNode* index_node, FunctionSig* sig, uint32_t sig_index,
const Value args[]) {
int arg_count = static_cast<int>(sig->parameter_count());
- TFNode** arg_nodes = builder_->Buffer(arg_count + 1);
+ Vector<TFNode*> arg_nodes = builder_->Buffer(arg_count + 1);
arg_nodes[0] = index_node;
for (int i = 0; i < arg_count; ++i) {
arg_nodes[i + 1] = args[i].node;
}
if (index_node) {
- BUILD(ReturnCallIndirect, table_index, sig_index, arg_nodes,
+ BUILD(ReturnCallIndirect, table_index, sig_index, arg_nodes.begin(),
decoder->position());
} else {
- BUILD(ReturnCall, sig_index, arg_nodes, decoder->position());
+ BUILD(ReturnCall, sig_index, arg_nodes.begin(), decoder->position());
}
}
};
diff --git a/deps/v8/src/wasm/jump-table-assembler.h b/deps/v8/src/wasm/jump-table-assembler.h
index 379a547b55..8889c18e9c 100644
--- a/deps/v8/src/wasm/jump-table-assembler.h
+++ b/deps/v8/src/wasm/jump-table-assembler.h
@@ -37,6 +37,21 @@ namespace wasm {
// The above illustrates jump table lines {Li} containing slots {Si} with each
// line containing {n} slots and some padding {x} for alignment purposes.
// Other jump tables are just consecutive.
+//
+// The main jump table will be patched concurrently while other threads execute
+// it. The code at the new target might also have been emitted concurrently, so
+// we need to ensure that there is proper synchronization between code emission,
+// jump table patching and code execution.
+// On Intel platforms, this all works out of the box because there is cache
+// coherency between i-cache and d-cache.
+// On ARM, it is safe because the i-cache flush after code emission executes an
+// "ic ivau" (Instruction Cache line Invalidate by Virtual Address to Point of
+// Unification), which broadcasts to all cores. A core which sees the jump table
+// update thus also sees the new code. Since the other core does not explicitly
+// execute an "isb" (Instruction Synchronization Barrier), it might still
+// execute the old code afterwards, which is no problem, since that code remains
+// available until it is garbage collected. Garbage collection itself is a
+// synchronization barrier though.
class V8_EXPORT_PRIVATE JumpTableAssembler : public MacroAssembler {
public:
// Translate an offset into the continuous jump table to a jump table index.
diff --git a/deps/v8/src/wasm/module-compiler.cc b/deps/v8/src/wasm/module-compiler.cc
index 658f329775..c264bac96e 100644
--- a/deps/v8/src/wasm/module-compiler.cc
+++ b/deps/v8/src/wasm/module-compiler.cc
@@ -152,6 +152,9 @@ class CompilationUnitQueues {
for (int task_id = 0; task_id < max_tasks; ++task_id) {
queues_[task_id].next_steal_task_id = next_task_id(task_id);
}
+ for (auto& atomic_counter : num_units_) {
+ std::atomic_init(&atomic_counter, size_t{0});
+ }
}
base::Optional<WasmCompilationUnit> GetNextUnit(
@@ -254,15 +257,14 @@ class CompilationUnitQueues {
};
struct BigUnitsQueue {
- BigUnitsQueue() = default;
+ BigUnitsQueue() {
+ for (auto& atomic : has_units) std::atomic_init(&atomic, false);
+ }
base::Mutex mutex;
// Can be read concurrently to check whether any elements are in the queue.
- std::atomic_bool has_units[kNumTiers] = {
- ATOMIC_VAR_INIT(false),
- ATOMIC_VAR_INIT(false)
- };
+ std::atomic<bool> has_units[kNumTiers];
// Protected by {mutex}:
std::priority_queue<BigUnit> units[kNumTiers];
@@ -271,11 +273,8 @@ class CompilationUnitQueues {
std::vector<Queue> queues_;
BigUnitsQueue big_units_queue_;
- std::atomic_size_t num_units_[kNumTiers] = {
- ATOMIC_VAR_INIT(0),
- ATOMIC_VAR_INIT(0)
- };
- std::atomic_int next_queue_to_add{0};
+ std::atomic<size_t> num_units_[kNumTiers];
+ std::atomic<int> next_queue_to_add{0};
int next_task_id(int task_id) const {
int next = task_id + 1;
@@ -382,7 +381,7 @@ class CompilationStateImpl {
// Initialize compilation progress. Set compilation tiers to expect for
// baseline and top tier compilation. Must be set before {AddCompilationUnits}
// is invoked which triggers background compilation.
- void InitializeCompilationProgress(bool lazy_module, int num_import_wrappers);
+ void InitializeCompilationProgress(bool lazy_module, int num_wrappers);
// Add the callback function to be called on compilation events. Needs to be
// set before {AddCompilationUnits} is run to ensure that it receives all
@@ -390,13 +389,24 @@ class CompilationStateImpl {
void AddCallback(CompilationState::callback_t);
// Inserts new functions to compile and kicks off compilation.
- void AddCompilationUnits(Vector<WasmCompilationUnit> baseline_units,
- Vector<WasmCompilationUnit> top_tier_units);
+ void AddCompilationUnits(
+ Vector<WasmCompilationUnit> baseline_units,
+ Vector<WasmCompilationUnit> top_tier_units,
+ Vector<std::shared_ptr<JSToWasmWrapperCompilationUnit>>
+ js_to_wasm_wrapper_units);
void AddTopTierCompilationUnit(WasmCompilationUnit);
base::Optional<WasmCompilationUnit> GetNextCompilationUnit(
int task_id, CompileBaselineOnly baseline_only);
+ std::shared_ptr<JSToWasmWrapperCompilationUnit>
+ GetNextJSToWasmWrapperCompilationUnit();
+ void FinalizeJSToWasmWrappers(Isolate* isolate, const WasmModule* module,
+ Handle<FixedArray>* export_wrappers_out);
+
void OnFinishedUnits(Vector<WasmCode*>);
+ void OnFinishedJSToWasmWrapperUnits(int num);
+ void TriggerCallbacks(bool completes_baseline_compilation,
+ bool completes_top_tier_compilation);
void OnBackgroundTaskStopped(int task_id, const WasmFeatures& detected);
void UpdateDetectedFeatures(const WasmFeatures& detected);
@@ -471,7 +481,7 @@ class CompilationStateImpl {
// Compilation error, atomically updated. This flag can be updated and read
// using relaxed semantics.
- std::atomic_bool compile_failed_{false};
+ std::atomic<bool> compile_failed_{false};
const int max_background_tasks_ = 0;
@@ -484,6 +494,13 @@ class CompilationStateImpl {
// tasks a fair chance to utilize the worker threads on a regular basis.
std::atomic<double> next_compilation_deadline_{0};
+ // Index of the next wrapper to compile in {js_to_wasm_wrapper_units_}.
+ std::atomic<int> js_to_wasm_wrapper_id_{0};
+ // Wrapper compilation units are stored in shared_ptrs so that they are kept
+ // alive by the tasks even if the NativeModule dies.
+ std::vector<std::shared_ptr<JSToWasmWrapperCompilationUnit>>
+ js_to_wasm_wrapper_units_;
+
// This mutex protects all information of this {CompilationStateImpl} which is
// being accessed concurrently.
mutable base::Mutex mutex_;
@@ -525,9 +542,9 @@ class CompilationStateImpl {
//////////////////////////////////////////////////////////////////////////////
// Encoding of fields in the {compilation_progress_} vector.
- class RequiredBaselineTierField : public BitField8<ExecutionTier, 0, 2> {};
- class RequiredTopTierField : public BitField8<ExecutionTier, 2, 2> {};
- class ReachedTierField : public BitField8<ExecutionTier, 4, 2> {};
+ using RequiredBaselineTierField = BitField8<ExecutionTier, 0, 2>;
+ using RequiredTopTierField = BitField8<ExecutionTier, 2, 2>;
+ using ReachedTierField = BitField8<ExecutionTier, 4, 2>;
};
CompilationStateImpl* Impl(CompilationState* compilation_state) {
@@ -712,6 +729,11 @@ class CompilationUnitBuilder {
}
}
+ void AddJSToWasmWrapperUnit(
+ std::shared_ptr<JSToWasmWrapperCompilationUnit> unit) {
+ js_to_wasm_wrapper_units_.emplace_back(std::move(unit));
+ }
+
void AddTopTierUnit(int func_index) {
ExecutionTierPair tiers = GetRequestedExecutionTiers(
native_module_->module(), compilation_state()->compile_mode(),
@@ -730,9 +752,13 @@ class CompilationUnitBuilder {
}
bool Commit() {
- if (baseline_units_.empty() && tiering_units_.empty()) return false;
- compilation_state()->AddCompilationUnits(VectorOf(baseline_units_),
- VectorOf(tiering_units_));
+ if (baseline_units_.empty() && tiering_units_.empty() &&
+ js_to_wasm_wrapper_units_.empty()) {
+ return false;
+ }
+ compilation_state()->AddCompilationUnits(
+ VectorOf(baseline_units_), VectorOf(tiering_units_),
+ VectorOf(js_to_wasm_wrapper_units_));
Clear();
return true;
}
@@ -740,6 +766,7 @@ class CompilationUnitBuilder {
void Clear() {
baseline_units_.clear();
tiering_units_.clear();
+ js_to_wasm_wrapper_units_.clear();
}
private:
@@ -751,6 +778,8 @@ class CompilationUnitBuilder {
const ExecutionTier default_tier_;
std::vector<WasmCompilationUnit> baseline_units_;
std::vector<WasmCompilationUnit> tiering_units_;
+ std::vector<std::shared_ptr<JSToWasmWrapperCompilationUnit>>
+ js_to_wasm_wrapper_units_;
};
void SetCompileError(ErrorThrower* thrower, ModuleWireBytes wire_bytes,
@@ -910,6 +939,33 @@ void RecordStats(const Code code, Counters* counters) {
constexpr int kMainThreadTaskId = -1;
+bool ExecuteJSToWasmWrapperCompilationUnits(
+ const std::shared_ptr<BackgroundCompileToken>& token) {
+ std::shared_ptr<JSToWasmWrapperCompilationUnit> wrapper_unit = nullptr;
+ int num_processed_wrappers = 0;
+ do {
+ // TODO(thibaudm): Reschedule the compilation task if it takes too long, so
+ // that the background thread is not blocked.
+ {
+ BackgroundCompileScope compile_scope(token);
+ if (compile_scope.cancelled()) return false;
+ wrapper_unit = compile_scope.compilation_state()
+ ->GetNextJSToWasmWrapperCompilationUnit();
+ }
+ if (wrapper_unit) {
+ wrapper_unit->Execute();
+ ++num_processed_wrappers;
+ }
+ } while (wrapper_unit);
+ {
+ BackgroundCompileScope compile_scope(token);
+ if (compile_scope.cancelled()) return false;
+ compile_scope.compilation_state()->OnFinishedJSToWasmWrapperUnits(
+ num_processed_wrappers);
+ }
+ return true;
+}
+
// Run by the main thread and background tasks to take part in compilation.
// Returns whether any units were executed.
bool ExecuteCompilationUnits(
@@ -918,6 +974,13 @@ bool ExecuteCompilationUnits(
TRACE_COMPILE("Compiling (task %d)...\n", task_id);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "ExecuteCompilationUnits");
+ // Execute JS to WASM wrapper units first, so that they are ready to be
+ // finalized by the main thread when the kFinishedBaselineCompilation event is
+ // triggered.
+ if (!ExecuteJSToWasmWrapperCompilationUnits(token)) {
+ return false;
+ }
+
const bool is_foreground = task_id == kMainThreadTaskId;
// The main thread uses task id 0, which might collide with one of the
// background tasks. This is fine, as it will only cause some contention on
@@ -1050,6 +1113,35 @@ bool ExecuteCompilationUnits(
return true;
}
+using JSToWasmWrapperKey = std::pair<bool, FunctionSig>;
+
+// Returns the number of units added.
+int AddExportWrapperUnits(Isolate* isolate, WasmEngine* wasm_engine,
+ NativeModule* native_module,
+ CompilationUnitBuilder* builder,
+ const WasmFeatures& enabled_features) {
+// Disable asynchronous wrapper compilation when builtins are not embedded,
+// otherwise the isolate might be used after tear down to access builtins.
+#ifdef V8_EMBEDDED_BUILTINS
+ std::unordered_set<JSToWasmWrapperKey, base::hash<JSToWasmWrapperKey>> keys;
+ for (auto exp : native_module->module()->export_table) {
+ if (exp.kind != kExternalFunction) continue;
+ auto& function = native_module->module()->functions[exp.index];
+ JSToWasmWrapperKey key(function.imported, *function.sig);
+ if (keys.insert(key).second) {
+ auto unit = std::make_shared<JSToWasmWrapperCompilationUnit>(
+ isolate, wasm_engine, function.sig, function.imported,
+ enabled_features);
+ builder->AddJSToWasmWrapperUnit(std::move(unit));
+ }
+ }
+
+ return static_cast<int>(keys.size());
+#else
+ return 0;
+#endif
+}
+
// Returns the number of units added.
int AddImportWrapperUnits(NativeModule* native_module,
CompilationUnitBuilder* builder) {
@@ -1059,8 +1151,7 @@ int AddImportWrapperUnits(NativeModule* native_module,
int num_imported_functions = native_module->num_imported_functions();
for (int func_index = 0; func_index < num_imported_functions; func_index++) {
FunctionSig* sig = native_module->module()->functions[func_index].sig;
- bool has_bigint_feature = native_module->enabled_features().bigint;
- if (!IsJSCompatibleSignature(sig, has_bigint_feature)) {
+ if (!IsJSCompatibleSignature(sig, native_module->enabled_features())) {
continue;
}
WasmImportWrapperCache::CacheKey key(compiler::kDefaultImportCallKind, sig);
@@ -1075,7 +1166,7 @@ int AddImportWrapperUnits(NativeModule* native_module,
return static_cast<int>(keys.size());
}
-void InitializeCompilationUnits(NativeModule* native_module) {
+void InitializeCompilationUnits(Isolate* isolate, NativeModule* native_module) {
CompilationStateImpl* compilation_state =
Impl(native_module->compilation_state());
const bool lazy_module = IsLazyModule(native_module->module());
@@ -1099,8 +1190,11 @@ void InitializeCompilationUnits(NativeModule* native_module) {
}
}
int num_import_wrappers = AddImportWrapperUnits(native_module, &builder);
- compilation_state->InitializeCompilationProgress(lazy_module,
- num_import_wrappers);
+ int num_export_wrappers =
+ AddExportWrapperUnits(isolate, isolate->wasm_engine(), native_module,
+ &builder, WasmFeaturesFromIsolate(isolate));
+ compilation_state->InitializeCompilationProgress(
+ lazy_module, num_import_wrappers + num_export_wrappers);
builder.Commit();
}
@@ -1202,7 +1296,7 @@ void CompileNativeModule(Isolate* isolate, ErrorThrower* thrower,
}
// Initialize the compilation units and kick off background compile tasks.
- InitializeCompilationUnits(native_module);
+ InitializeCompilationUnits(isolate, native_module);
// If tiering is disabled, the main thread can execute any unit (all of them
// are part of initial compilation). Otherwise, just execute baseline units.
@@ -1274,26 +1368,23 @@ std::shared_ptr<NativeModule> CompileToNativeModule(
OwnedVector<uint8_t> wire_bytes_copy =
OwnedVector<uint8_t>::Of(wire_bytes.module_bytes());
- // Create and compile the native module.
- size_t code_size_estimate =
- wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
-
// Create a new {NativeModule} first.
auto native_module = isolate->wasm_engine()->NewNativeModule(
- isolate, enabled, code_size_estimate,
- wasm::NativeModule::kCanAllocateMoreMemory, std::move(module));
+ isolate, enabled, std::move(module));
native_module->SetWireBytes(std::move(wire_bytes_copy));
native_module->SetRuntimeStubs(isolate);
CompileNativeModule(isolate, thrower, wasm_module, native_module.get());
if (thrower->error()) return {};
- // Compile JS->wasm wrappers for exported functions.
- int num_wrappers = MaxNumExportWrappers(native_module->module());
- *export_wrappers_out =
- isolate->factory()->NewFixedArray(num_wrappers, AllocationType::kOld);
+#ifdef V8_EMBEDDED_BUILTINS
+ Impl(native_module->compilation_state())
+ ->FinalizeJSToWasmWrappers(isolate, native_module->module(),
+ export_wrappers_out);
+#else
CompileJsToWasmWrappers(isolate, native_module->module(),
- *export_wrappers_out);
+ export_wrappers_out);
+#endif
// Log the code within the generated module for profiling.
native_module->LogWasmCodes(isolate);
@@ -1367,7 +1458,9 @@ class AsyncStreamingProcessor final : public StreamingProcessor {
ModuleDecoder decoder_;
AsyncCompileJob* job_;
+ WasmEngine* wasm_engine_;
std::unique_ptr<CompilationUnitBuilder> compilation_unit_builder_;
+ base::TimeTicks start_time_;
int num_functions_ = 0;
};
@@ -1415,11 +1508,8 @@ void AsyncCompileJob::CreateNativeModule(
// breakpoints on a (potentially empty) subset of the instances.
// Create the module object.
- size_t code_size_estimate =
- wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
native_module_ = isolate_->wasm_engine()->NewNativeModule(
- isolate_, enabled_features_, code_size_estimate,
- wasm::NativeModule::kCanAllocateMoreMemory, std::move(module));
+ isolate_, enabled_features_, std::move(module));
native_module_->SetWireBytes({std::move(bytes_copy_), wire_bytes_.length()});
native_module_->SetRuntimeStubs(isolate_);
@@ -1433,10 +1523,8 @@ void AsyncCompileJob::PrepareRuntimeObjects() {
Handle<Script> script =
CreateWasmScript(isolate_, wire_bytes_, module->source_map_url);
- size_t code_size_estimate =
- wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module);
- Handle<WasmModuleObject> module_object = WasmModuleObject::New(
- isolate_, native_module_, script, code_size_estimate);
+ Handle<WasmModuleObject> module_object =
+ WasmModuleObject::New(isolate_, native_module_, script);
module_object_ = isolate_->global_handles()->Create(*module_object);
}
@@ -1462,17 +1550,25 @@ void AsyncCompileJob::FinishCompile() {
}
isolate_->debug()->OnAfterCompile(script);
- // We can only update the feature counts once the entire compile is done.
auto compilation_state =
Impl(module_object_->native_module()->compilation_state());
- compilation_state->PublishDetectedFeatures(isolate_);
-
// TODO(bbudge) Allow deserialization without wrapper compilation, so we can
// just compile wrappers here.
if (!is_after_deserialization) {
- // TODO(wasm): compiling wrappers should be made async.
- CompileWrappers();
+#ifdef V8_EMBEDDED_BUILTINS
+ Handle<FixedArray> export_wrappers;
+ compilation_state->FinalizeJSToWasmWrappers(
+ isolate_, module_object_->module(), &export_wrappers);
+ module_object_->set_export_wrappers(*export_wrappers);
+#else
+ Handle<FixedArray> export_wrappers;
+ CompileJsToWasmWrappers(isolate_, module_object_->module(),
+ &export_wrappers);
+ module_object_->set_export_wrappers(*export_wrappers);
+#endif
}
+ // We can only update the feature counts once the entire compile is done.
+ compilation_state->PublishDetectedFeatures(isolate_);
FinishModule();
}
@@ -1792,7 +1888,7 @@ class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
// then DoAsync would do the same as NextStep already.
// Add compilation units and kick off compilation.
- InitializeCompilationUnits(job->native_module_.get());
+ InitializeCompilationUnits(job->isolate(), job->native_module_.get());
}
}
};
@@ -1853,17 +1949,8 @@ class AsyncCompileJob::CompileFinished : public CompileStep {
}
};
-void AsyncCompileJob::CompileWrappers() {
- // TODO(wasm): Compile all wrappers here, including the start function wrapper
- // and the wrappers for the function table elements.
- TRACE_COMPILE("(5) Compile wrappers...\n");
- // Compile JS->wasm wrappers for exported functions.
- CompileJsToWasmWrappers(isolate_, module_object_->native_module()->module(),
- handle(module_object_->export_wrappers(), isolate_));
-}
-
void AsyncCompileJob::FinishModule() {
- TRACE_COMPILE("(6) Finish module...\n");
+ TRACE_COMPILE("(4) Finish module...\n");
AsyncCompileSucceeded(module_object_);
isolate_->wasm_engine()->RemoveCompileJob(this);
}
@@ -1871,7 +1958,9 @@ void AsyncCompileJob::FinishModule() {
AsyncStreamingProcessor::AsyncStreamingProcessor(AsyncCompileJob* job)
: decoder_(job->enabled_features_),
job_(job),
- compilation_unit_builder_(nullptr) {}
+ wasm_engine_(job_->isolate_->wasm_engine()),
+ compilation_unit_builder_(nullptr),
+ start_time_(base::TimeTicks::Now()) {}
void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(
const WasmError& error) {
@@ -1973,8 +2062,11 @@ bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
int num_import_wrappers =
AddImportWrapperUnits(native_module, compilation_unit_builder_.get());
- compilation_state->InitializeCompilationProgress(lazy_module,
- num_import_wrappers);
+ int num_export_wrappers = AddExportWrapperUnits(
+ job_->isolate_, wasm_engine_, native_module,
+ compilation_unit_builder_.get(), job_->enabled_features_);
+ compilation_state->InitializeCompilationProgress(
+ lazy_module, num_import_wrappers + num_export_wrappers);
return true;
}
@@ -2097,6 +2189,13 @@ bool AsyncStreamingProcessor::Deserialize(Vector<const uint8_t> module_bytes,
MaybeHandle<WasmModuleObject> result =
DeserializeNativeModule(job_->isolate_, module_bytes, wire_bytes);
+ if (base::TimeTicks::IsHighResolution()) {
+ base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
+ auto* histogram = job_->isolate_->counters()
+ ->wasm_streaming_deserialize_wasm_module_time();
+ histogram->AddSample(static_cast<int>(duration.InMicroseconds()));
+ }
+
if (result.is_null()) return false;
job_->module_object_ =
@@ -2145,8 +2244,8 @@ void CompilationStateImpl::AbortCompilation() {
callbacks_.clear();
}
-void CompilationStateImpl::InitializeCompilationProgress(
- bool lazy_module, int num_import_wrappers) {
+void CompilationStateImpl::InitializeCompilationProgress(bool lazy_module,
+ int num_wrappers) {
DCHECK(!failed());
auto enabled_features = native_module_->enabled_features();
auto* module = native_module_->module();
@@ -2190,7 +2289,7 @@ void CompilationStateImpl::InitializeCompilationProgress(
DCHECK_IMPLIES(lazy_module, outstanding_top_tier_functions_ == 0);
DCHECK_LE(0, outstanding_baseline_units_);
DCHECK_LE(outstanding_baseline_units_, outstanding_top_tier_functions_);
- outstanding_baseline_units_ += num_import_wrappers;
+ outstanding_baseline_units_ += num_wrappers;
// Trigger callbacks if module needs no baseline or top tier compilation. This
// can be the case for an empty or fully lazy module.
@@ -2215,15 +2314,52 @@ void CompilationStateImpl::AddCallback(CompilationState::callback_t callback) {
void CompilationStateImpl::AddCompilationUnits(
Vector<WasmCompilationUnit> baseline_units,
- Vector<WasmCompilationUnit> top_tier_units) {
- compilation_unit_queues_.AddUnits(baseline_units, top_tier_units,
- native_module_->module());
+ Vector<WasmCompilationUnit> top_tier_units,
+ Vector<std::shared_ptr<JSToWasmWrapperCompilationUnit>>
+ js_to_wasm_wrapper_units) {
+ if (!baseline_units.empty() || !top_tier_units.empty()) {
+ compilation_unit_queues_.AddUnits(baseline_units, top_tier_units,
+ native_module_->module());
+ }
+ js_to_wasm_wrapper_units_.insert(js_to_wasm_wrapper_units_.end(),
+ js_to_wasm_wrapper_units.begin(),
+ js_to_wasm_wrapper_units.end());
RestartBackgroundTasks();
}
void CompilationStateImpl::AddTopTierCompilationUnit(WasmCompilationUnit unit) {
- AddCompilationUnits({}, {&unit, 1});
+ AddCompilationUnits({}, {&unit, 1}, {});
+}
+
+std::shared_ptr<JSToWasmWrapperCompilationUnit>
+CompilationStateImpl::GetNextJSToWasmWrapperCompilationUnit() {
+ int wrapper_id =
+ js_to_wasm_wrapper_id_.fetch_add(1, std::memory_order_relaxed);
+ if (wrapper_id < static_cast<int>(js_to_wasm_wrapper_units_.size())) {
+ return js_to_wasm_wrapper_units_[wrapper_id];
+ }
+ return nullptr;
+}
+
+void CompilationStateImpl::FinalizeJSToWasmWrappers(
+ Isolate* isolate, const WasmModule* module,
+ Handle<FixedArray>* export_wrappers_out) {
+ *export_wrappers_out = isolate->factory()->NewFixedArray(
+ MaxNumExportWrappers(module), AllocationType::kOld);
+ // TODO(6792): Wrappers below are allocated with {Factory::NewCode}. As an
+ // optimization we keep the code space unlocked to avoid repeated unlocking
+ // because many such wrapper are allocated in sequence below.
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
+ "FinalizeJSToWasmWrappers");
+ CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
+ for (auto& unit : js_to_wasm_wrapper_units_) {
+ Handle<Code> code = unit->Finalize(isolate);
+ int wrapper_index =
+ GetExportWrapperIndex(module, unit->sig(), unit->is_import());
+ (*export_wrappers_out)->set(wrapper_index, *code);
+ RecordStats(*code, isolate->counters());
+ }
}
base::Optional<WasmCompilationUnit>
@@ -2313,25 +2449,38 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
DCHECK_LE(0, outstanding_baseline_units_);
}
- // Trigger callbacks.
- if (completes_baseline_compilation) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "BaselineFinished");
- for (auto& callback : callbacks_) {
- callback(CompilationEvent::kFinishedBaselineCompilation);
- }
- if (outstanding_top_tier_functions_ == 0) {
- completes_top_tier_compilation = true;
- }
+ TriggerCallbacks(completes_baseline_compilation,
+ completes_top_tier_compilation);
+ }
+}
+
+void CompilationStateImpl::OnFinishedJSToWasmWrapperUnits(int num) {
+ if (num == 0) return;
+ base::MutexGuard guard(&callbacks_mutex_);
+ outstanding_baseline_units_ -= num;
+ bool completes_baseline_compilation = outstanding_baseline_units_ == 0;
+ TriggerCallbacks(completes_baseline_compilation, false);
+}
+
+void CompilationStateImpl::TriggerCallbacks(
+ bool completes_baseline_compilation, bool completes_top_tier_compilation) {
+ if (completes_baseline_compilation) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "BaselineFinished");
+ for (auto& callback : callbacks_) {
+ callback(CompilationEvent::kFinishedBaselineCompilation);
}
- if (outstanding_baseline_units_ == 0 && completes_top_tier_compilation) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "TopTierFinished");
- for (auto& callback : callbacks_) {
- callback(CompilationEvent::kFinishedTopTierCompilation);
- }
- // Clear the callbacks because no more events will be delivered.
- callbacks_.clear();
+ if (outstanding_top_tier_functions_ == 0) {
+ completes_top_tier_compilation = true;
}
}
+ if (outstanding_baseline_units_ == 0 && completes_top_tier_compilation) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "TopTierFinished");
+ for (auto& callback : callbacks_) {
+ callback(CompilationEvent::kFinishedTopTierCompilation);
+ }
+ // Clear the callbacks because no more events will be delivered.
+ callbacks_.clear();
+ }
}
void CompilationStateImpl::OnBackgroundTaskStopped(
@@ -2379,6 +2528,11 @@ void CompilationStateImpl::RestartBackgroundTasks() {
if (failed()) return;
size_t max_num_restart = compilation_unit_queues_.GetTotalSize();
+ if (js_to_wasm_wrapper_id_ <
+ static_cast<int>(js_to_wasm_wrapper_units_.size())) {
+ max_num_restart +=
+ js_to_wasm_wrapper_units_.size() - js_to_wasm_wrapper_id_;
+ }
while (!available_task_ids_.empty() && max_num_restart-- > 0) {
int task_id = available_task_ids_.back();
@@ -2418,7 +2572,6 @@ void CompilationStateImpl::SetError() {
}
namespace {
-using JSToWasmWrapperKey = std::pair<bool, FunctionSig>;
using JSToWasmWrapperQueue =
WrapperQueue<JSToWasmWrapperKey, base::hash<JSToWasmWrapperKey>>;
using JSToWasmWrapperUnitMap =
@@ -2449,9 +2602,13 @@ class CompileJSToWasmWrapperTask final : public CancelableTask {
} // namespace
void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
- Handle<FixedArray> export_wrappers) {
+ Handle<FixedArray>* export_wrappers_out) {
+ *export_wrappers_out = isolate->factory()->NewFixedArray(
+ MaxNumExportWrappers(module), AllocationType::kOld);
+
JSToWasmWrapperQueue queue;
JSToWasmWrapperUnitMap compilation_units;
+ WasmFeatures enabled_features = WasmFeaturesFromIsolate(isolate);
// Prepare compilation units in the main thread.
for (auto exp : module->export_table) {
@@ -2460,8 +2617,8 @@ void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
JSToWasmWrapperKey key(function.imported, *function.sig);
if (queue.insert(key)) {
auto unit = base::make_unique<JSToWasmWrapperCompilationUnit>(
- isolate, function.sig, function.imported);
- unit->Prepare(isolate);
+ isolate, isolate->wasm_engine(), function.sig, function.imported,
+ enabled_features);
compilation_units.emplace(key, std::move(unit));
}
}
@@ -2492,7 +2649,7 @@ void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
JSToWasmWrapperCompilationUnit* unit = pair.second.get();
Handle<Code> code = unit->Finalize(isolate);
int wrapper_index = GetExportWrapperIndex(module, &key.second, key.first);
- export_wrappers->set(wrapper_index, *code);
+ (*export_wrappers_out)->set(wrapper_index, *code);
RecordStats(*code, isolate->counters());
}
}
diff --git a/deps/v8/src/wasm/module-compiler.h b/deps/v8/src/wasm/module-compiler.h
index 27c7bff868..69eb6bb62c 100644
--- a/deps/v8/src/wasm/module-compiler.h
+++ b/deps/v8/src/wasm/module-compiler.h
@@ -46,7 +46,7 @@ std::shared_ptr<NativeModule> CompileToNativeModule(
V8_EXPORT_PRIVATE
void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
- Handle<FixedArray> export_wrappers);
+ Handle<FixedArray>* export_wrappers_out);
// Compiles the wrapper for this (kind, sig) pair and sets the corresponding
// cache entry. Assumes the key already exists in the cache but has not been
@@ -153,8 +153,6 @@ class AsyncCompileJob {
void AsyncCompileSucceeded(Handle<WasmModuleObject> result);
- void CompileWrappers();
-
void FinishModule();
void StartForegroundTask();
diff --git a/deps/v8/src/wasm/module-instantiate.cc b/deps/v8/src/wasm/module-instantiate.cc
index a4b0139ea4..976c3cde00 100644
--- a/deps/v8/src/wasm/module-instantiate.cc
+++ b/deps/v8/src/wasm/module-instantiate.cc
@@ -656,6 +656,7 @@ void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
uint32_t size = segment.source.length();
if (enabled_.bulk_memory) {
+ if (size == 0) continue;
// Passive segments are not copied during instantiation.
if (!segment.active) continue;
@@ -834,10 +835,18 @@ bool InstanceBuilder::ProcessImportedFunction(
module_name, import_name);
return false;
}
+ // Store any {WasmExternalFunction} callable in the instance before the call
+ // is resolved to preserve its identity. This handles exported functions as
+ // well as functions constructed via other means (e.g. WebAssembly.Function).
+ if (WasmExternalFunction::IsWasmExternalFunction(*value)) {
+ WasmInstanceObject::SetWasmExternalFunction(
+ isolate_, instance, func_index,
+ Handle<WasmExternalFunction>::cast(value));
+ }
auto js_receiver = Handle<JSReceiver>::cast(value);
FunctionSig* expected_sig = module_->functions[func_index].sig;
- auto resolved = compiler::ResolveWasmImportCall(js_receiver, expected_sig,
- enabled_.bigint);
+ auto resolved =
+ compiler::ResolveWasmImportCall(js_receiver, expected_sig, enabled_);
compiler::WasmImportCallKind kind = resolved.first;
js_receiver = resolved.second;
switch (kind) {
@@ -854,10 +863,6 @@ bool InstanceBuilder::ProcessImportedFunction(
Address imported_target = imported_function->GetWasmCallTarget();
ImportedFunctionEntry entry(instance, func_index);
entry.SetWasmToWasm(*imported_instance, imported_target);
- // Also store the {WasmExportedFunction} in the instance to preserve its
- // identity.
- WasmInstanceObject::SetWasmExportedFunction(
- isolate_, instance, func_index, imported_function);
break;
}
case compiler::WasmImportCallKind::kWasmToCapi: {
@@ -1218,8 +1223,7 @@ void InstanceBuilder::CompileImportWrappers(
auto js_receiver = Handle<JSReceiver>::cast(value);
uint32_t func_index = module_->import_table[index].index;
FunctionSig* sig = module_->functions[func_index].sig;
- auto resolved =
- compiler::ResolveWasmImportCall(js_receiver, sig, enabled_.bigint);
+ auto resolved = compiler::ResolveWasmImportCall(js_receiver, sig, enabled_);
compiler::WasmImportCallKind kind = resolved.first;
if (kind == compiler::WasmImportCallKind::kWasmToWasm ||
kind == compiler::WasmImportCallKind::kLinkError ||
@@ -1373,7 +1377,7 @@ void InstanceBuilder::InitGlobals(Handle<WasmInstanceObject> instance) {
break;
case WasmInitExpr::kRefFuncConst: {
DCHECK(enabled_.anyref);
- auto function = WasmInstanceObject::GetOrCreateWasmExportedFunction(
+ auto function = WasmInstanceObject::GetOrCreateWasmExternalFunction(
isolate_, instance, global.init.val.function_index);
tagged_globals_->set(global.offset, *function);
break;
@@ -1450,10 +1454,10 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
const WasmImport& import = module_->import_table[index];
if (import.kind == kExternalFunction) {
Handle<Object> value = sanitized_imports_[index].value;
- if (WasmExportedFunction::IsWasmExportedFunction(*value)) {
- WasmInstanceObject::SetWasmExportedFunction(
+ if (WasmExternalFunction::IsWasmExternalFunction(*value)) {
+ WasmInstanceObject::SetWasmExternalFunction(
isolate_, instance, import.index,
- Handle<WasmExportedFunction>::cast(value));
+ Handle<WasmExternalFunction>::cast(value));
}
}
}
@@ -1498,10 +1502,10 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
case kExternalFunction: {
// Wrap and export the code as a JSFunction.
// TODO(wasm): reduce duplication with LoadElemSegment() further below
- MaybeHandle<WasmExportedFunction> wasm_exported_function =
- WasmInstanceObject::GetOrCreateWasmExportedFunction(
+ Handle<WasmExternalFunction> wasm_external_function =
+ WasmInstanceObject::GetOrCreateWasmExternalFunction(
isolate_, instance, exp.index);
- desc.set_value(wasm_exported_function.ToHandleChecked());
+ desc.set_value(wasm_external_function);
if (is_asm_js &&
String::Equals(isolate_, name,
@@ -1629,6 +1633,7 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
uint32_t table_index,
const WasmElemSegment& elem_segment, uint32_t dst,
uint32_t src, size_t count) {
+ if (count == 0) return true;
// TODO(wasm): Move this functionality into wasm-objects, since it is used
// for both instantiation and in the implementation of the table.init
// instruction.
@@ -1660,27 +1665,27 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
.Set(sig_id, instance, func_index);
}
- // For AnyRef tables, we have to generate the WasmExportedFunction eagerly.
+ // For AnyRef tables, we have to generate the WasmExternalFunction eagerly.
// Later we cannot know if an entry is a placeholder or not.
if (table_object->type() == kWasmAnyRef) {
- Handle<WasmExportedFunction> wasm_exported_function =
- WasmInstanceObject::GetOrCreateWasmExportedFunction(isolate, instance,
+ Handle<WasmExternalFunction> wasm_external_function =
+ WasmInstanceObject::GetOrCreateWasmExternalFunction(isolate, instance,
func_index);
WasmTableObject::Set(isolate, table_object, entry_index,
- wasm_exported_function);
+ wasm_external_function);
} else {
// Update the table object's other dispatch tables.
- MaybeHandle<WasmExportedFunction> wasm_exported_function =
- WasmInstanceObject::GetWasmExportedFunction(isolate, instance,
+ MaybeHandle<WasmExternalFunction> wasm_external_function =
+ WasmInstanceObject::GetWasmExternalFunction(isolate, instance,
func_index);
- if (wasm_exported_function.is_null()) {
+ if (wasm_external_function.is_null()) {
// No JSFunction entry yet exists for this function. Create a {Tuple2}
// holding the information to lazily allocate one.
WasmTableObject::SetFunctionTablePlaceholder(
isolate, table_object, entry_index, instance, func_index);
} else {
table_object->entries().set(entry_index,
- *wasm_exported_function.ToHandleChecked());
+ *wasm_external_function.ToHandleChecked());
}
// UpdateDispatchTables() updates all other dispatch tables, since
// we have not yet added the dispatch table we are currently building.
@@ -1701,6 +1706,7 @@ void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
uint32_t dst = EvalUint32InitExpr(instance, elem_segment.offset);
uint32_t src = 0;
size_t count = elem_segment.entries.size();
+ if (enabled_.bulk_memory && count == 0) continue;
bool success = LoadElemSegmentImpl(
isolate_, instance,
diff --git a/deps/v8/src/wasm/wasm-code-manager.cc b/deps/v8/src/wasm/wasm-code-manager.cc
index 3d0cde0cce..91cfc01cea 100644
--- a/deps/v8/src/wasm/wasm-code-manager.cc
+++ b/deps/v8/src/wasm/wasm-code-manager.cc
@@ -25,13 +25,14 @@
#include "src/wasm/function-compiler.h"
#include "src/wasm/jump-table-assembler.h"
#include "src/wasm/wasm-import-wrapper-cache.h"
+#include "src/wasm/wasm-module-sourcemap.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-objects.h"
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
#include "src/diagnostics/unwinding-info-win64.h"
-#endif
+#endif // V8_OS_WIN64
#define TRACE_HEAP(...) \
do { \
@@ -88,13 +89,30 @@ base::AddressRegion DisjointAllocationPool::Merge(base::AddressRegion region) {
}
base::AddressRegion DisjointAllocationPool::Allocate(size_t size) {
+ return AllocateInRegion(size,
+ {kNullAddress, std::numeric_limits<size_t>::max()});
+}
+
+base::AddressRegion DisjointAllocationPool::AllocateInRegion(
+ size_t size, base::AddressRegion region) {
for (auto it = regions_.begin(), end = regions_.end(); it != end; ++it) {
- if (size > it->size()) continue;
- base::AddressRegion ret{it->begin(), size};
+ base::AddressRegion overlap = it->GetOverlap(region);
+ if (size > overlap.size()) continue;
+ base::AddressRegion ret{overlap.begin(), size};
if (size == it->size()) {
+ // We use the full region --> erase the region from {regions_}.
regions_.erase(it);
- } else {
+ } else if (ret.begin() == it->begin()) {
+ // We return a region at the start --> shrink remaining region from front.
*it = base::AddressRegion{it->begin() + size, it->size() - size};
+ } else if (ret.end() == it->end()) {
+ // We return a region at the end --> shrink remaining region.
+ *it = base::AddressRegion{it->begin(), it->size() - size};
+ } else {
+ // We return something in the middle --> split the remaining region.
+ regions_.insert(
+ it, base::AddressRegion{it->begin(), ret.begin() - it->begin()});
+ *it = base::AddressRegion{ret.end(), it->end() - ret.end()};
}
return ret;
}
@@ -164,6 +182,19 @@ void WasmCode::LogCode(Isolate* isolate) const {
WireBytesRef name_ref =
native_module()->module()->LookupFunctionName(wire_bytes, index());
WasmName name_vec = wire_bytes.GetNameOrNull(name_ref);
+
+ const std::string& source_map_url = native_module()->module()->source_map_url;
+ auto load_wasm_source_map = isolate->wasm_load_source_map_callback();
+ auto source_map = native_module()->GetWasmSourceMap();
+ if (!source_map && !source_map_url.empty() && load_wasm_source_map) {
+ HandleScope scope(isolate);
+ v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
+ Local<v8::String> source_map_str =
+ load_wasm_source_map(v8_isolate, source_map_url.c_str());
+ native_module()->SetWasmSourceMap(
+ base::make_unique<WasmModuleSourceMap>(v8_isolate, source_map_str));
+ }
+
if (!name_vec.empty()) {
HandleScope scope(isolate);
MaybeHandle<String> maybe_name = isolate->factory()->NewStringFromUtf8(
@@ -204,11 +235,7 @@ void WasmCode::Validate() const {
switch (mode) {
case RelocInfo::WASM_CALL: {
Address target = it.rinfo()->wasm_call_address();
- WasmCode* code = native_module_->Lookup(target);
- CHECK_NOT_NULL(code);
- CHECK_EQ(WasmCode::kJumpTable, code->kind());
- CHECK_EQ(native_module()->jump_table_, code);
- CHECK(code->contains(target));
+ DCHECK(native_module_->is_jump_table_slot(target));
break;
}
case RelocInfo::WASM_STUB_CALL: {
@@ -464,32 +491,51 @@ base::SmallVector<base::AddressRegion, 1> SplitRangeByReservationsIfNeeded(
Vector<byte> WasmCodeAllocator::AllocateForCode(NativeModule* native_module,
size_t size) {
+ return AllocateForCodeInRegion(
+ native_module, size, {kNullAddress, std::numeric_limits<size_t>::max()});
+}
+
+Vector<byte> WasmCodeAllocator::AllocateForCodeInRegion(
+ NativeModule* native_module, size_t size, base::AddressRegion region) {
base::MutexGuard lock(&mutex_);
DCHECK_EQ(code_manager_, native_module->engine()->code_manager());
DCHECK_LT(0, size);
v8::PageAllocator* page_allocator = GetPlatformPageAllocator();
- // This happens under a lock assumed by the caller.
size = RoundUp<kCodeAlignment>(size);
- base::AddressRegion code_space = free_code_space_.Allocate(size);
+ base::AddressRegion code_space =
+ free_code_space_.AllocateInRegion(size, region);
if (code_space.is_empty()) {
- if (!can_request_more_memory_) {
- V8::FatalProcessOutOfMemory(nullptr, "wasm code reservation");
+ const bool in_specific_region =
+ region.size() < std::numeric_limits<size_t>::max();
+ if (!can_request_more_memory_ || in_specific_region) {
+ auto error = in_specific_region ? "wasm code reservation in region"
+ : "wasm code reservation";
+ V8::FatalProcessOutOfMemory(nullptr, error);
UNREACHABLE();
}
Address hint = owned_code_space_.empty() ? kNullAddress
: owned_code_space_.back().end();
+ // Reserve at least 20% of the total generated code size so far, and of
+ // course at least {size}. Round up to the next power of two.
+ size_t total_reserved = 0;
+ for (auto& vmem : owned_code_space_) total_reserved += vmem.size();
+ size_t reserve_size =
+ base::bits::RoundUpToPowerOfTwo(std::max(size, total_reserved / 5));
VirtualMemory new_mem =
- code_manager_->TryAllocate(size, reinterpret_cast<void*>(hint));
+ code_manager_->TryAllocate(reserve_size, reinterpret_cast<void*>(hint));
if (!new_mem.IsReserved()) {
V8::FatalProcessOutOfMemory(nullptr, "wasm code reservation");
UNREACHABLE();
}
- code_manager_->AssignRange(new_mem.region(), native_module);
- free_code_space_.Merge(new_mem.region());
+ base::AddressRegion new_region = new_mem.region();
+ code_manager_->AssignRange(new_region, native_module);
+ free_code_space_.Merge(new_region);
owned_code_space_.emplace_back(std::move(new_mem));
+ native_module->AddCodeSpace(new_region);
+
code_space = free_code_space_.Allocate(size);
DCHECK(!code_space.is_empty());
async_counters_->wasm_module_num_code_spaces()->AddSample(
@@ -614,6 +660,12 @@ void WasmCodeAllocator::FreeCode(Vector<WasmCode* const> codes) {
}
}
+base::AddressRegion WasmCodeAllocator::GetSingleCodeRegion() const {
+ base::MutexGuard lock(&mutex_);
+ DCHECK_EQ(1, owned_code_space_.size());
+ return owned_code_space_[0].region();
+}
+
NativeModule::NativeModule(WasmEngine* engine, const WasmFeatures& enabled,
bool can_request_more, VirtualMemory code_space,
std::shared_ptr<const WasmModule> module,
@@ -636,27 +688,10 @@ NativeModule::NativeModule(WasmEngine* engine, const WasmFeatures& enabled,
compilation_state_ =
CompilationState::New(*shared_this, std::move(async_counters));
DCHECK_NOT_NULL(module_);
-
-#if defined(V8_OS_WIN_X64)
- // On some platforms, specifically Win64, we need to reserve some pages at
- // the beginning of an executable space.
- // See src/heap/spaces.cc, MemoryAllocator::InitializeCodePageAllocator() and
- // https://cs.chromium.org/chromium/src/components/crash/content/app/crashpad_win.cc?rcl=fd680447881449fba2edcf0589320e7253719212&l=204
- // for details.
- if (engine_->code_manager()
- ->CanRegisterUnwindInfoForNonABICompliantCodeRange()) {
- code_allocator_.AllocateForCode(this, Heap::GetCodeRangeReservedAreaSize());
- }
-#endif
-
- uint32_t num_wasm_functions = module_->num_declared_functions;
- if (num_wasm_functions > 0) {
- code_table_.reset(new WasmCode* [num_wasm_functions] {});
-
- WasmCodeRefScope code_ref_scope;
- jump_table_ = CreateEmptyJumpTable(
- JumpTableAssembler::SizeForNumberOfSlots(num_wasm_functions));
+ if (module_->num_declared_functions > 0) {
+ code_table_.reset(new WasmCode* [module_->num_declared_functions] {});
}
+ AddCodeSpace(code_allocator_.GetSingleCodeRegion());
}
void NativeModule::ReserveCodeTableForTesting(uint32_t max_functions) {
@@ -669,9 +704,12 @@ void NativeModule::ReserveCodeTableForTesting(uint32_t max_functions) {
}
code_table_.reset(new_table);
+ CHECK_EQ(1, code_space_data_.size());
// Re-allocate jump table.
- jump_table_ = CreateEmptyJumpTable(
- JumpTableAssembler::SizeForNumberOfSlots(max_functions));
+ code_space_data_[0].jump_table = CreateEmptyJumpTableInRegion(
+ JumpTableAssembler::SizeForNumberOfSlots(max_functions),
+ code_space_data_[0].region);
+ main_jump_table_ = code_space_data_[0].jump_table;
}
void NativeModule::LogWasmCodes(Isolate* isolate) {
@@ -704,8 +742,10 @@ void NativeModule::UseLazyStub(uint32_t func_index) {
if (!lazy_compile_table_) {
uint32_t num_slots = module_->num_declared_functions;
WasmCodeRefScope code_ref_scope;
- lazy_compile_table_ = CreateEmptyJumpTable(
- JumpTableAssembler::SizeForNumberOfLazyFunctions(num_slots));
+ DCHECK_EQ(1, code_space_data_.size());
+ lazy_compile_table_ = CreateEmptyJumpTableInRegion(
+ JumpTableAssembler::SizeForNumberOfLazyFunctions(num_slots),
+ code_space_data_[0].region);
JumpTableAssembler::GenerateLazyCompileTable(
lazy_compile_table_->instruction_start(), num_slots,
module_->num_imported_functions,
@@ -718,7 +758,7 @@ void NativeModule::UseLazyStub(uint32_t func_index) {
Address lazy_compile_target =
lazy_compile_table_->instruction_start() +
JumpTableAssembler::LazyCompileSlotIndexToOffset(slot_index);
- JumpTableAssembler::PatchJumpTableSlot(jump_table_->instruction_start(),
+ JumpTableAssembler::PatchJumpTableSlot(main_jump_table_->instruction_start(),
slot_index, lazy_compile_target,
WasmCode::kFlushICache);
}
@@ -729,9 +769,10 @@ void NativeModule::SetRuntimeStubs(Isolate* isolate) {
DCHECK_EQ(kNullAddress, runtime_stub_entries_[0]); // Only called once.
#ifdef V8_EMBEDDED_BUILTINS
WasmCodeRefScope code_ref_scope;
- WasmCode* jump_table =
- CreateEmptyJumpTable(JumpTableAssembler::SizeForNumberOfStubSlots(
- WasmCode::kRuntimeStubCount));
+ DCHECK_EQ(1, code_space_data_.size());
+ WasmCode* jump_table = CreateEmptyJumpTableInRegion(
+ JumpTableAssembler::SizeForNumberOfStubSlots(WasmCode::kRuntimeStubCount),
+ code_space_data_[0].region);
Address base = jump_table->instruction_start();
EmbeddedData embedded_data = EmbeddedData::FromBlob();
#define RUNTIME_STUB(Name) Builtins::k##Name,
@@ -995,8 +1036,12 @@ WasmCode* NativeModule::PublishCodeLocked(std::unique_ptr<WasmCode> code) {
// Populate optimized code to the jump table unless there is an active
// redirection to the interpreter that should be preserved.
- bool update_jump_table =
- update_code_table && !has_interpreter_redirection(code->index());
+ DCHECK_IMPLIES(
+ main_jump_table_ == nullptr,
+ engine_->code_manager()->IsImplicitAllocationsDisabledForTesting());
+ bool update_jump_table = update_code_table &&
+ !has_interpreter_redirection(code->index()) &&
+ main_jump_table_;
// Ensure that interpreter entries always populate to the jump table.
if (code->kind_ == WasmCode::Kind::kInterpreterEntry) {
@@ -1006,8 +1051,8 @@ WasmCode* NativeModule::PublishCodeLocked(std::unique_ptr<WasmCode> code) {
if (update_jump_table) {
JumpTableAssembler::PatchJumpTableSlot(
- jump_table_->instruction_start(), slot_idx, code->instruction_start(),
- WasmCode::kFlushICache);
+ main_jump_table_->instruction_start(), slot_idx,
+ code->instruction_start(), WasmCode::kFlushICache);
}
}
WasmCodeRefScope::AddRef(code.get());
@@ -1065,11 +1110,22 @@ bool NativeModule::HasCode(uint32_t index) const {
return code_table_[index - module_->num_imported_functions] != nullptr;
}
-WasmCode* NativeModule::CreateEmptyJumpTable(uint32_t jump_table_size) {
+void NativeModule::SetWasmSourceMap(
+ std::unique_ptr<WasmModuleSourceMap> source_map) {
+ source_map_ = std::move(source_map);
+}
+
+WasmModuleSourceMap* NativeModule::GetWasmSourceMap() const {
+ return source_map_.get();
+}
+
+WasmCode* NativeModule::CreateEmptyJumpTableInRegion(
+ uint32_t jump_table_size, base::AddressRegion region) {
// Only call this if we really need a jump table.
DCHECK_LT(0, jump_table_size);
Vector<uint8_t> code_space =
- code_allocator_.AllocateForCode(this, jump_table_size);
+ code_allocator_.AllocateForCodeInRegion(this, jump_table_size, region);
+ DCHECK(!code_space.empty());
ZapCode(reinterpret_cast<Address>(code_space.begin()), code_space.size());
std::unique_ptr<WasmCode> code{new WasmCode{
this, // native_module
@@ -1090,6 +1146,48 @@ WasmCode* NativeModule::CreateEmptyJumpTable(uint32_t jump_table_size) {
return PublishCode(std::move(code));
}
+void NativeModule::AddCodeSpace(base::AddressRegion region) {
+ // Each code space must be at least twice as large as the overhead per code
+ // space. Otherwise, we are wasting too much memory.
+ const bool is_first_code_space = code_space_data_.empty();
+ const bool implicit_alloc_disabled =
+ engine_->code_manager()->IsImplicitAllocationsDisabledForTesting();
+
+#if defined(V8_OS_WIN64)
+ // On some platforms, specifically Win64, we need to reserve some pages at
+ // the beginning of an executable space.
+ // See src/heap/spaces.cc, MemoryAllocator::InitializeCodePageAllocator() and
+ // https://cs.chromium.org/chromium/src/components/crash/content/app/crashpad_win.cc?rcl=fd680447881449fba2edcf0589320e7253719212&l=204
+ // for details.
+ if (engine_->code_manager()
+ ->CanRegisterUnwindInfoForNonABICompliantCodeRange() &&
+ !implicit_alloc_disabled) {
+ size_t size = Heap::GetCodeRangeReservedAreaSize();
+ DCHECK_LT(0, size);
+ Vector<byte> padding = code_allocator_.AllocateForCode(this, size);
+ CHECK(region.contains(reinterpret_cast<Address>(padding.begin()),
+ padding.size()));
+ }
+#endif // V8_OS_WIN64
+
+ WasmCodeRefScope code_ref_scope;
+ WasmCode* jump_table = nullptr;
+ const uint32_t num_wasm_functions = module_->num_declared_functions;
+ const bool has_functions = num_wasm_functions > 0;
+ const bool needs_jump_table =
+ has_functions && is_first_code_space && !implicit_alloc_disabled;
+
+ if (needs_jump_table) {
+ jump_table = CreateEmptyJumpTableInRegion(
+ JumpTableAssembler::SizeForNumberOfSlots(num_wasm_functions), region);
+ CHECK(region.contains(jump_table->instruction_start()));
+ }
+
+ if (is_first_code_space) main_jump_table_ = jump_table;
+
+ code_space_data_.push_back(CodeSpaceData{region, jump_table});
+}
+
namespace {
class NativeModuleWireBytesStorage final : public WireBytesStorage {
public:
@@ -1137,17 +1235,17 @@ uint32_t NativeModule::GetJumpTableOffset(uint32_t func_index) const {
Address NativeModule::GetCallTargetForFunction(uint32_t func_index) const {
// Return the jump table slot for that function index.
- DCHECK_NOT_NULL(jump_table_);
+ DCHECK_NOT_NULL(main_jump_table_);
uint32_t slot_offset = GetJumpTableOffset(func_index);
- DCHECK_LT(slot_offset, jump_table_->instructions().size());
- return jump_table_->instruction_start() + slot_offset;
+ DCHECK_LT(slot_offset, main_jump_table_->instructions().size());
+ return main_jump_table_->instruction_start() + slot_offset;
}
uint32_t NativeModule::GetFunctionIndexFromJumpTableSlot(
Address slot_address) const {
DCHECK(is_jump_table_slot(slot_address));
- uint32_t slot_offset =
- static_cast<uint32_t>(slot_address - jump_table_->instruction_start());
+ uint32_t slot_offset = static_cast<uint32_t>(
+ slot_address - main_jump_table_->instruction_start());
uint32_t slot_idx = JumpTableAssembler::SlotOffsetToIndex(slot_offset);
DCHECK_LT(slot_idx, module_->num_declared_functions);
return module_->num_imported_functions + slot_idx;
@@ -1181,21 +1279,16 @@ WasmCodeManager::WasmCodeManager(WasmMemoryTracker* memory_tracker,
size_t max_committed)
: memory_tracker_(memory_tracker),
max_committed_code_space_(max_committed),
-#if defined(V8_OS_WIN_X64)
- is_win64_unwind_info_disabled_for_testing_(false),
-#endif
- total_committed_code_space_(0),
critical_committed_code_space_(max_committed / 2) {
DCHECK_LE(max_committed, kMaxWasmCodeMemory);
}
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
bool WasmCodeManager::CanRegisterUnwindInfoForNonABICompliantCodeRange() const {
return win64_unwindinfo::CanRegisterUnwindInfoForNonABICompliantCodeRange() &&
- FLAG_win64_unwinding_info &&
- !is_win64_unwind_info_disabled_for_testing_;
+ FLAG_win64_unwinding_info;
}
-#endif
+#endif // V8_OS_WIN64
bool WasmCodeManager::Commit(base::AddressRegion region) {
// TODO(v8:8462): Remove eager commit once perf supports remapping.
@@ -1241,8 +1334,8 @@ void WasmCodeManager::Decommit(base::AddressRegion region) {
USE(old_committed);
TRACE_HEAP("Discarding system pages 0x%" PRIxPTR ":0x%" PRIxPTR "\n",
region.begin(), region.end());
- CHECK(allocator->DiscardSystemPages(reinterpret_cast<void*>(region.begin()),
- region.size()));
+ CHECK(allocator->SetPermissions(reinterpret_cast<void*>(region.begin()),
+ region.size(), PageAllocator::kNoAccess));
}
void WasmCodeManager::AssignRange(base::AddressRegion region,
@@ -1363,12 +1456,13 @@ std::shared_ptr<NativeModule> WasmCodeManager::NewNativeModule(
TRACE_HEAP("New NativeModule %p: Mem: %" PRIuPTR ",+%zu\n", ret.get(), start,
size);
-#if defined(V8_OS_WIN_X64)
- if (CanRegisterUnwindInfoForNonABICompliantCodeRange()) {
+#if defined(V8_OS_WIN64)
+ if (CanRegisterUnwindInfoForNonABICompliantCodeRange() &&
+ !implicit_allocations_disabled_for_testing_) {
win64_unwindinfo::RegisterNonABICompliantCodeRange(
reinterpret_cast<void*>(start), size);
}
-#endif
+#endif // V8_OS_WIN64
base::MutexGuard lock(&native_modules_mutex_);
lookup_map_.insert(std::make_pair(start, std::make_pair(end, ret.get())));
@@ -1481,12 +1575,13 @@ void WasmCodeManager::FreeNativeModule(Vector<VirtualMemory> owned_code_space,
TRACE_HEAP("VMem Release: 0x%" PRIxPTR ":0x%" PRIxPTR " (%zu)\n",
code_space.address(), code_space.end(), code_space.size());
-#if defined(V8_OS_WIN_X64)
- if (CanRegisterUnwindInfoForNonABICompliantCodeRange()) {
+#if defined(V8_OS_WIN64)
+ if (CanRegisterUnwindInfoForNonABICompliantCodeRange() &&
+ !implicit_allocations_disabled_for_testing_) {
win64_unwindinfo::UnregisterNonABICompliantCodeRange(
reinterpret_cast<void*>(code_space.address()));
}
-#endif
+#endif // V8_OS_WIN64
lookup_map_.erase(code_space.address());
memory_tracker_->ReleaseReservation(code_space.size());
diff --git a/deps/v8/src/wasm/wasm-code-manager.h b/deps/v8/src/wasm/wasm-code-manager.h
index db7b4f061d..c2e5249e5e 100644
--- a/deps/v8/src/wasm/wasm-code-manager.h
+++ b/deps/v8/src/wasm/wasm-code-manager.h
@@ -23,6 +23,7 @@
#include "src/wasm/compilation-environment.h"
#include "src/wasm/wasm-features.h"
#include "src/wasm/wasm-limits.h"
+#include "src/wasm/wasm-module-sourcemap.h"
#include "src/wasm/wasm-tier.h"
namespace v8 {
@@ -61,6 +62,10 @@ class V8_EXPORT_PRIVATE DisjointAllocationPool final {
// failure.
base::AddressRegion Allocate(size_t size);
+ // Allocate a contiguous region of size {size} within {region}. Return an
+ // empty pool on failure.
+ base::AddressRegion AllocateInRegion(size_t size, base::AddressRegion);
+
bool IsEmpty() const { return regions_.empty(); }
const std::list<base::AddressRegion>& regions() const { return regions_; }
@@ -295,6 +300,11 @@ class WasmCodeAllocator {
// Allocate code space. Returns a valid buffer or fails with OOM (crash).
Vector<byte> AllocateForCode(NativeModule*, size_t size);
+ // Allocate code space within a specific region. Returns a valid buffer or
+ // fails with OOM (crash).
+ Vector<byte> AllocateForCodeInRegion(NativeModule*, size_t size,
+ base::AddressRegion);
+
// Sets permissions of all owned code space to executable, or read-write (if
// {executable} is false). Returns true on success.
V8_EXPORT_PRIVATE bool SetExecutable(bool executable);
@@ -302,6 +312,10 @@ class WasmCodeAllocator {
// Free memory pages of all given code objects. Used for wasm code GC.
void FreeCode(Vector<WasmCode* const>);
+ // Returns the region of the single code space managed by this code allocator.
+ // Will fail if more than one code space has been created.
+ base::AddressRegion GetSingleCodeRegion() const;
+
private:
// The engine-wide wasm code manager.
WasmCodeManager* const code_manager_;
@@ -392,6 +406,9 @@ class V8_EXPORT_PRIVATE NativeModule final {
WasmCode* GetCode(uint32_t index) const;
bool HasCode(uint32_t index) const;
+ void SetWasmSourceMap(std::unique_ptr<WasmModuleSourceMap> source_map);
+ WasmModuleSourceMap* GetWasmSourceMap() const;
+
Address runtime_stub_entry(WasmCode::RuntimeStubId index) const {
DCHECK_LT(index, WasmCode::kRuntimeStubCount);
Address entry_address = runtime_stub_entries_[index];
@@ -400,17 +417,18 @@ class V8_EXPORT_PRIVATE NativeModule final {
}
Address jump_table_start() const {
- return jump_table_ ? jump_table_->instruction_start() : kNullAddress;
+ return main_jump_table_ ? main_jump_table_->instruction_start()
+ : kNullAddress;
}
uint32_t GetJumpTableOffset(uint32_t func_index) const;
bool is_jump_table_slot(Address address) const {
- return jump_table_->contains(address);
+ return main_jump_table_->contains(address);
}
- // Returns the target to call for the given function (returns a jump table
- // slot within {jump_table_}).
+ // Returns the canonical target to call for the given function (the slot in
+ // the first jump table).
Address GetCallTargetForFunction(uint32_t func_index) const;
// Reverse lookup from a given call target (i.e. a jump table slot as the
@@ -485,9 +503,15 @@ class V8_EXPORT_PRIVATE NativeModule final {
private:
friend class WasmCode;
+ friend class WasmCodeAllocator;
friend class WasmCodeManager;
friend class NativeModuleModificationScope;
+ struct CodeSpaceData {
+ base::AddressRegion region;
+ WasmCode* jump_table;
+ };
+
// Private constructor, called via {WasmCodeManager::NewNativeModule()}.
NativeModule(WasmEngine* engine, const WasmFeatures& enabled_features,
bool can_request_more, VirtualMemory code_space,
@@ -507,7 +531,11 @@ class V8_EXPORT_PRIVATE NativeModule final {
WasmCode* AddAndPublishAnonymousCode(Handle<Code>, WasmCode::Kind kind,
const char* name = nullptr);
- WasmCode* CreateEmptyJumpTable(uint32_t jump_table_size);
+ WasmCode* CreateEmptyJumpTableInRegion(uint32_t jump_table_size,
+ base::AddressRegion);
+
+ // Called by the {WasmCodeAllocator} to register a new code space.
+ void AddCodeSpace(base::AddressRegion);
// Hold the {allocation_mutex_} when calling this method.
bool has_interpreter_redirection(uint32_t func_index) {
@@ -546,6 +574,8 @@ class V8_EXPORT_PRIVATE NativeModule final {
// tasks can keep this alive.
std::shared_ptr<const WasmModule> module_;
+ std::unique_ptr<WasmModuleSourceMap> source_map_;
+
// Wire bytes, held in a shared_ptr so they can be kept alive by the
// {WireBytesStorage}, held by background compile tasks.
std::shared_ptr<OwnedVector<const uint8_t>> wire_bytes_;
@@ -556,8 +586,9 @@ class V8_EXPORT_PRIVATE NativeModule final {
// Jump table used for runtime stubs (i.e. trampolines to embedded builtins).
WasmCode* runtime_stub_table_ = nullptr;
- // Jump table used to easily redirect wasm function calls.
- WasmCode* jump_table_ = nullptr;
+ // Jump table used by external calls (from JS). Wasm calls use one of the jump
+ // tables stored in {code_space_data_}.
+ WasmCode* main_jump_table_ = nullptr;
// Lazy compile stub table, containing entries to jump to the
// {WasmCompileLazy} builtin, passing the function index.
@@ -587,6 +618,9 @@ class V8_EXPORT_PRIVATE NativeModule final {
// this module marking those functions that have been redirected.
std::unique_ptr<uint8_t[]> interpreter_redirections_;
+ // Data (especially jump table) per code space.
+ std::vector<CodeSpaceData> code_space_data_;
+
// End of fields protected by {allocation_mutex_}.
//////////////////////////////////////////////////////////////////////////////
@@ -610,9 +644,9 @@ class V8_EXPORT_PRIVATE WasmCodeManager final {
}
#endif
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
bool CanRegisterUnwindInfoForNonABICompliantCodeRange() const;
-#endif
+#endif // V8_OS_WIN64
NativeModule* LookupNativeModule(Address pc) const;
WasmCode* LookupCode(Address pc) const;
@@ -622,11 +656,13 @@ class V8_EXPORT_PRIVATE WasmCodeManager final {
void SetMaxCommittedMemoryForTesting(size_t limit);
-#if defined(V8_OS_WIN_X64)
- void DisableWin64UnwindInfoForTesting() {
- is_win64_unwind_info_disabled_for_testing_ = true;
+ void DisableImplicitAllocationsForTesting() {
+ implicit_allocations_disabled_for_testing_ = true;
+ }
+
+ bool IsImplicitAllocationsDisabledForTesting() const {
+ return implicit_allocations_disabled_for_testing_;
}
-#endif
static size_t EstimateNativeModuleCodeSize(const WasmModule* module);
static size_t EstimateNativeModuleNonCodeSize(const WasmModule* module);
@@ -654,11 +690,9 @@ class V8_EXPORT_PRIVATE WasmCodeManager final {
size_t max_committed_code_space_;
-#if defined(V8_OS_WIN_X64)
- bool is_win64_unwind_info_disabled_for_testing_;
-#endif
+ bool implicit_allocations_disabled_for_testing_ = false;
- std::atomic<size_t> total_committed_code_space_;
+ std::atomic<size_t> total_committed_code_space_{0};
// If the committed code space exceeds {critical_committed_code_space_}, then
// we trigger a GC before creating the next module. This value is set to the
// currently committed space plus 50% of the available code space on creation
diff --git a/deps/v8/src/wasm/wasm-engine.cc b/deps/v8/src/wasm/wasm-engine.cc
index 7b91b16b80..97111f8349 100644
--- a/deps/v8/src/wasm/wasm-engine.cc
+++ b/deps/v8/src/wasm/wasm-engine.cc
@@ -278,13 +278,8 @@ Handle<WasmModuleObject> WasmEngine::FinalizeTranslatedAsmJs(
asm_wasm_data->managed_native_module().get();
Handle<FixedArray> export_wrappers =
handle(asm_wasm_data->export_wrappers(), isolate);
- size_t code_size_estimate =
- wasm::WasmCodeManager::EstimateNativeModuleCodeSize(
- native_module->module());
-
- Handle<WasmModuleObject> module_object =
- WasmModuleObject::New(isolate, std::move(native_module), script,
- export_wrappers, code_size_estimate);
+ Handle<WasmModuleObject> module_object = WasmModuleObject::New(
+ isolate, std::move(native_module), script, export_wrappers);
module_object->set_asm_js_offset_table(asm_wasm_data->asm_js_offset_table());
return module_object;
}
@@ -310,9 +305,6 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
Handle<Script> script =
CreateWasmScript(isolate, bytes, native_module->module()->source_map_url);
- size_t code_size_estimate =
- wasm::WasmCodeManager::EstimateNativeModuleCodeSize(
- native_module->module());
// Create the module object.
// TODO(clemensh): For the same module (same bytes / same hash), we should
@@ -323,9 +315,8 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
// and information needed at instantiation time. This object needs to be
// serializable. Instantiation may occur off a deserialized version of this
// object.
- Handle<WasmModuleObject> module_object =
- WasmModuleObject::New(isolate, std::move(native_module), script,
- export_wrappers, code_size_estimate);
+ Handle<WasmModuleObject> module_object = WasmModuleObject::New(
+ isolate, std::move(native_module), script, export_wrappers);
// Finish the Wasm script now and make it public to the debugger.
isolate->debug()->OnAfterCompile(script);
@@ -451,14 +442,13 @@ Handle<WasmModuleObject> WasmEngine::ImportNativeModule(
Isolate* isolate, std::shared_ptr<NativeModule> shared_native_module) {
NativeModule* native_module = shared_native_module.get();
ModuleWireBytes wire_bytes(native_module->wire_bytes());
- const WasmModule* module = native_module->module();
- Handle<Script> script =
- CreateWasmScript(isolate, wire_bytes, module->source_map_url);
- size_t code_size = native_module->committed_code_space();
+ Handle<Script> script = CreateWasmScript(
+ isolate, wire_bytes, native_module->module()->source_map_url);
+ Handle<FixedArray> export_wrappers;
+ CompileJsToWasmWrappers(isolate, native_module->module(), &export_wrappers);
Handle<WasmModuleObject> module_object = WasmModuleObject::New(
- isolate, std::move(shared_native_module), script, code_size);
- CompileJsToWasmWrappers(isolate, native_module->module(),
- handle(module_object->export_wrappers(), isolate));
+ isolate, std::move(shared_native_module), script, export_wrappers,
+ native_module->committed_code_space());
{
base::MutexGuard lock(&mutex_);
DCHECK_EQ(1, isolates_.count(isolate));
@@ -681,6 +671,16 @@ void WasmEngine::LogOutstandingCodesForIsolate(Isolate* isolate) {
}
std::shared_ptr<NativeModule> WasmEngine::NewNativeModule(
+ Isolate* isolate, const WasmFeatures& enabled,
+ std::shared_ptr<const WasmModule> module) {
+ size_t code_size_estimate =
+ wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
+ return NewNativeModule(isolate, enabled, code_size_estimate,
+ wasm::NativeModule::kCanAllocateMoreMemory,
+ std::move(module));
+}
+
+std::shared_ptr<NativeModule> WasmEngine::NewNativeModule(
Isolate* isolate, const WasmFeatures& enabled, size_t code_size_estimate,
bool can_request_more, std::shared_ptr<const WasmModule> module) {
std::shared_ptr<NativeModule> native_module =
diff --git a/deps/v8/src/wasm/wasm-engine.h b/deps/v8/src/wasm/wasm-engine.h
index 69e6cdae6e..401cf2b880 100644
--- a/deps/v8/src/wasm/wasm-engine.h
+++ b/deps/v8/src/wasm/wasm-engine.h
@@ -182,6 +182,9 @@ class V8_EXPORT_PRIVATE WasmEngine {
// TODO(titzer): isolate is only required here for CompilationState.
std::shared_ptr<NativeModule> NewNativeModule(
Isolate* isolate, const WasmFeatures& enabled_features,
+ std::shared_ptr<const WasmModule> module);
+ std::shared_ptr<NativeModule> NewNativeModule(
+ Isolate* isolate, const WasmFeatures& enabled_features,
size_t code_size_estimate, bool can_request_more,
std::shared_ptr<const WasmModule> module);
diff --git a/deps/v8/src/wasm/wasm-external-refs.cc b/deps/v8/src/wasm/wasm-external-refs.cc
index 08e6139abe..9ca45183ef 100644
--- a/deps/v8/src/wasm/wasm-external-refs.cc
+++ b/deps/v8/src/wasm/wasm-external-refs.cc
@@ -80,37 +80,73 @@ void int64_to_float32_wrapper(Address data) {
void uint64_to_float32_wrapper(Address data) {
uint64_t input = ReadUnalignedValue<uint64_t>(data);
- float result = static_cast<float>(input);
-
-#if V8_CC_MSVC
- // With MSVC we use static_cast<float>(uint32_t) instead of
- // static_cast<float>(uint64_t) to achieve round-to-nearest-ties-even
- // semantics. The idea is to calculate
- // static_cast<float>(high_word) * 2^32 + static_cast<float>(low_word). To
- // achieve proper rounding in all cases we have to adjust the high_word
- // with a "rounding bit" sometimes. The rounding bit is stored in the LSB of
- // the high_word if the low_word may affect the rounding of the high_word.
- uint32_t low_word = static_cast<uint32_t>(input & 0xFFFFFFFF);
- uint32_t high_word = static_cast<uint32_t>(input >> 32);
-
- float shift = static_cast<float>(1ull << 32);
- // If the MSB of the high_word is set, then we make space for a rounding bit.
- if (high_word < 0x80000000) {
- high_word <<= 1;
- shift = static_cast<float>(1ull << 31);
+#if defined(V8_OS_WIN)
+ // On Windows, the FP stack registers calculate with less precision, which
+ // leads to a uint64_t to float32 conversion which does not satisfy the
+ // WebAssembly specification. Therefore we do a different approach here:
+ //
+ // / leading 0 \/ 24 float data bits \/ for rounding \/ trailing 0 \
+ // 00000000000001XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX100000000000000
+ //
+ // Float32 can only represent 24 data bit (1 implicit 1 bit + 23 mantissa
+ // bits). Starting from the most significant 1 bit, we can therefore extract
+ // 24 bits and do the conversion only on them. The other bits can affect the
+ // result only through rounding. Rounding works as follows:
+ // * If the most significant rounding bit is not set, then round down.
+ // * If the most significant rounding bit is set, and at least one of the
+ // other rounding bits is set, then round up.
+ // * If the most significant rounding bit is set, but all other rounding bits
+ // are not set, then round to even.
+ // We can aggregate 'all other rounding bits' in the second-most significant
+ // rounding bit.
+ // The resulting algorithm is therefore as follows:
+ // * Check if the distance between the most significant bit (MSB) and the
+ // least significant bit (LSB) is greater than 25 bits. If the distance is
+ // less or equal to 25 bits, the uint64 to float32 conversion is anyways
+ // exact, and we just use the C++ conversion.
+ // * Find the most significant bit (MSB).
+ // * Starting from the MSB, extract 25 bits (24 data bits + the first rounding
+ // bit).
+ // * The remaining rounding bits are guaranteed to contain at least one 1 bit,
+ // due to the check we did above.
+ // * Store the 25 bits + 1 aggregated bit in an uint32_t.
+ // * Convert this uint32_t to float. The conversion does the correct rounding
+ // now.
+ // * Shift the result back to the original magnitude.
+ uint32_t leading_zeros = base::bits::CountLeadingZeros(input);
+ uint32_t trailing_zeros = base::bits::CountTrailingZeros(input);
+ constexpr uint32_t num_extracted_bits = 25;
+ // Check if there are any rounding bits we have to aggregate.
+ if (leading_zeros + trailing_zeros + num_extracted_bits < 64) {
+ // Shift to extract the data bits.
+ uint32_t num_aggregation_bits = 64 - num_extracted_bits - leading_zeros;
+ // We extract the bits we want to convert. Note that we convert one bit more
+ // than necessary. This bit is a placeholder where we will store the
+ // aggregation bit.
+ int32_t extracted_bits =
+ static_cast<int32_t>(input >> (num_aggregation_bits - 1));
+ // Set the aggregation bit. We don't have to clear the slot first, because
+ // the bit there is also part of the aggregation.
+ extracted_bits |= 1;
+ float result = static_cast<float>(extracted_bits);
+ // We have to shift the result back. The shift amount is
+ // (num_aggregation_bits - 1), which is the shift amount we did originally,
+ // and (-2), which is for the two additional bits we kept originally for
+ // rounding.
+ int32_t shift_back = static_cast<int32_t>(num_aggregation_bits) - 1 - 2;
+ // Calculate the multiplier to shift the extracted bits back to the original
+ // magnitude. This multiplier is a power of two, so in the float32 bit
+ // representation we just have to construct the correct exponent and put it
+ // at the correct bit offset. The exponent consists of 8 bits, starting at
+ // the second MSB (a.k.a '<< 23'). The encoded exponent itself is
+ // ('actual exponent' - 127).
+ int32_t multiplier_bits = ((shift_back - 127) & 0xff) << 23;
+ result *= bit_cast<float>(multiplier_bits);
+ WriteUnalignedValue<float>(data, result);
+ return;
}
-
- if ((high_word & 0xFE000000) && low_word) {
- // Set the rounding bit.
- high_word |= 1;
- }
-
- result = static_cast<float>(high_word);
- result *= shift;
- result += static_cast<float>(low_word);
-#endif
-
- WriteUnalignedValue<float>(data, result);
+#endif // defined(V8_OS_WIN)
+ WriteUnalignedValue<float>(data, static_cast<float>(input));
}
void int64_to_float64_wrapper(Address data) {
diff --git a/deps/v8/src/wasm/wasm-feature-flags.h b/deps/v8/src/wasm/wasm-feature-flags.h
index 77d46fdc0d..36f9ebd8a4 100644
--- a/deps/v8/src/wasm/wasm-feature-flags.h
+++ b/deps/v8/src/wasm/wasm-feature-flags.h
@@ -5,29 +5,27 @@
#ifndef V8_WASM_WASM_FEATURE_FLAGS_H_
#define V8_WASM_WASM_FEATURE_FLAGS_H_
-// The SEPARATOR argument allows generating proper comma-separated lists.
-#define FOREACH_WASM_FEATURE_FLAG(V, SEPARATOR) \
- V(mv, "multi-value support", false) \
- SEPARATOR \
- V(eh, "exception handling opcodes", false) \
- SEPARATOR \
- V(se, "sign extension opcodes", true) \
- SEPARATOR \
- V(sat_f2i_conversions, "saturating float conversion opcodes", true) \
- SEPARATOR \
- V(threads, "thread opcodes", false) \
- SEPARATOR \
- V(simd, "SIMD opcodes", false) \
- SEPARATOR \
- V(anyref, "anyref opcodes", false) \
- SEPARATOR \
- V(bigint, "JS BigInt support", false) \
- SEPARATOR \
- V(bulk_memory, "bulk memory opcodes", true) \
- SEPARATOR \
- V(return_call, "return call opcodes", false) \
- SEPARATOR \
- V(type_reflection, "wasm type reflection in JS", false) \
- SEPARATOR \
+#define FOREACH_WASM_EXPERIMENTAL_FEATURE_FLAG(V) \
+ V(mv, "multi-value support", false) \
+ V(eh, "exception handling opcodes", false) \
+ V(threads, "thread opcodes", false) \
+ V(simd, "SIMD opcodes", false) \
+ V(bigint, "JS BigInt support", false) \
+ V(return_call, "return call opcodes", false) \
V(compilation_hints, "compilation hints section", false)
+
+#define FOREACH_WASM_STAGING_FEATURE_FLAG(V) \
+ V(anyref, "anyref opcodes", false) \
+ V(type_reflection, "wasm type reflection in JS", false)
+
+#define FOREACH_WASM_SHIPPED_FEATURE_FLAG(V) \
+ V(bulk_memory, "bulk memory opcodes", true) \
+ V(sat_f2i_conversions, "saturating float conversion opcodes", true) \
+ V(se, "sign extension opcodes", true)
+
+#define FOREACH_WASM_FEATURE_FLAG(V) \
+ FOREACH_WASM_EXPERIMENTAL_FEATURE_FLAG(V) \
+ FOREACH_WASM_STAGING_FEATURE_FLAG(V) \
+ FOREACH_WASM_SHIPPED_FEATURE_FLAG(V)
+
#endif // V8_WASM_WASM_FEATURE_FLAGS_H_
diff --git a/deps/v8/src/wasm/wasm-features.cc b/deps/v8/src/wasm/wasm-features.cc
index fc0286655e..d62db91750 100644
--- a/deps/v8/src/wasm/wasm-features.cc
+++ b/deps/v8/src/wasm/wasm-features.cc
@@ -11,17 +11,17 @@ namespace v8 {
namespace internal {
namespace wasm {
-#define COMMA ,
-#define SPACE
-#define DO_UNION(feat, desc, val) dst->feat |= src.feat;
-#define FLAG_REF(feat, desc, val) FLAG_experimental_wasm_##feat
void UnionFeaturesInto(WasmFeatures* dst, const WasmFeatures& src) {
- FOREACH_WASM_FEATURE(DO_UNION, SPACE);
+#define DO_UNION(feat, desc, val) dst->feat |= src.feat;
+ FOREACH_WASM_FEATURE(DO_UNION);
+#undef DO_UNION
}
WasmFeatures WasmFeaturesFromFlags() {
- return WasmFeatures{FOREACH_WASM_FEATURE(FLAG_REF, COMMA)};
+#define FLAG_REF(feat, desc, val) FLAG_experimental_wasm_##feat,
+ return WasmFeatures(FOREACH_WASM_FEATURE(FLAG_REF){});
+#undef FLAG_REF
}
WasmFeatures WasmFeaturesFromIsolate(Isolate* isolate) {
@@ -31,10 +31,6 @@ WasmFeatures WasmFeaturesFromIsolate(Isolate* isolate) {
return features;
}
-#undef DO_UNION
-#undef FLAG_REF
-#undef SPACE
-#undef COMMA
} // namespace wasm
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/wasm/wasm-features.h b/deps/v8/src/wasm/wasm-features.h
index 2c6ab0f85a..956982536d 100644
--- a/deps/v8/src/wasm/wasm-features.h
+++ b/deps/v8/src/wasm/wasm-features.h
@@ -17,37 +17,50 @@ namespace internal {
class Isolate;
namespace wasm {
-#define COMMA ,
-#define SPACE
-#define DECL_FIELD(feat, desc, val) bool feat = false;
-#define JUST_TRUE(feat, desc, val) true
-#define JUST_FALSE(feat, desc, val) false
-#define DECL_PARAM(feat, desc, val) bool p##feat
-#define DO_INIT(feat, desc, val) feat(p##feat)
+// This is an empty type to indicate the end of the {WasmFeatures} struct. We
+// use the {end_t} type there to avoid trailing commas that get generated by
+// the macro generators. We considered the following alternatives:
+// * Add "separators" to the {FOREACH_WASM_FEATURE_FLAGS} between entries. This
+// does not work when we want to have different kinds of flags, e.g. for
+// experimental, staging, and shipped features.
+// * Use initialization lists, e.g. construct {WasmFeatures} with
+// "WasmFeatures{true, true, ..., true,}". This solves the comma problem,
+// because trailing commas are allowed here. However, we cannot
+// default-initialize the fields of {WasmFeatures} anymore. This seems
+// error-prone, because default-constructed {WasmFeatures} structs are already
+// used in the code base.
+// * Avoid the use of {constexpr}. With that we would be more flexible with how
+// we generate {kAllWasmFeatures} and {kNoWasmFeatures}. These values may be
+// used in performance-critical code, however, e.g. in the decoder or in the
+// interpreter.
+struct end_t {};
// Enabled or detected features.
struct WasmFeatures {
- FOREACH_WASM_FEATURE(DECL_FIELD, SPACE)
+#define DECL_FIELD(feat, desc, val) bool feat = false;
+ FOREACH_WASM_FEATURE(DECL_FIELD)
+#undef DECL_FIELD
+ // Marker for the end of the list, see the comment at {end_t}.
+ end_t end_;
+#define DECL_PARAM(feat, desc, val) bool p##feat,
+#define DO_INIT(feat, desc, val) feat(p##feat),
+ explicit constexpr WasmFeatures(FOREACH_WASM_FEATURE(DECL_PARAM) end_t)
+ : FOREACH_WASM_FEATURE(DO_INIT) end_() {}
+#undef DECL_PARAM
+#undef DO_INIT
constexpr WasmFeatures() = default;
-
- explicit constexpr WasmFeatures(FOREACH_WASM_FEATURE(DECL_PARAM, COMMA))
- : FOREACH_WASM_FEATURE(DO_INIT, COMMA) {}
};
-static constexpr WasmFeatures kAllWasmFeatures{
- FOREACH_WASM_FEATURE(JUST_TRUE, COMMA)};
-
-static constexpr WasmFeatures kNoWasmFeatures{
- FOREACH_WASM_FEATURE(JUST_FALSE, COMMA)};
-
+#define JUST_TRUE(feat, desc, val) true,
+static constexpr WasmFeatures kAllWasmFeatures(
+ FOREACH_WASM_FEATURE(JUST_TRUE){});
#undef JUST_TRUE
+
+#define JUST_FALSE(feat, desc, val) false,
+static constexpr WasmFeatures kNoWasmFeatures(
+ FOREACH_WASM_FEATURE(JUST_FALSE){});
#undef JUST_FALSE
-#undef DECL_FIELD
-#undef DECL_PARAM
-#undef DO_INIT
-#undef COMMA
-#undef SPACE
static constexpr WasmFeatures kAsmjsWasmFeatures = kNoWasmFeatures;
diff --git a/deps/v8/src/wasm/wasm-interpreter.cc b/deps/v8/src/wasm/wasm-interpreter.cc
index 4449439896..299128860d 100644
--- a/deps/v8/src/wasm/wasm-interpreter.cc
+++ b/deps/v8/src/wasm/wasm-interpreter.cc
@@ -1676,7 +1676,7 @@ class ThreadImpl {
converter<ctype, mtype>{}(ReadLittleEndianValue<mtype>(addr)));
Push(result);
- *len = 1 + imm.length;
+ *len += imm.length;
if (FLAG_trace_wasm_memory) {
MemoryTracingInfo info(imm.offset + index, false, rep);
@@ -1702,7 +1702,7 @@ class ThreadImpl {
return false;
}
WriteLittleEndianValue<mtype>(addr, converter<mtype, ctype>{}(val));
- *len = 1 + imm.length;
+ *len += imm.length;
if (FLAG_trace_wasm_memory) {
MemoryTracingInfo info(imm.offset + index, true, rep);
@@ -2241,14 +2241,27 @@ class ThreadImpl {
Push(WasmValue(Simd128(res))); \
return true; \
}
+ BINOP_CASE(F64x2Add, f64x2, float2, 2, a + b)
+ BINOP_CASE(F64x2Sub, f64x2, float2, 2, a - b)
+ BINOP_CASE(F64x2Mul, f64x2, float2, 2, a * b)
+ BINOP_CASE(F64x2Div, f64x2, float2, 2, base::Divide(a, b))
+ BINOP_CASE(F64x2Min, f64x2, float2, 2, JSMin(a, b))
+ BINOP_CASE(F64x2Max, f64x2, float2, 2, JSMax(a, b))
BINOP_CASE(F32x4Add, f32x4, float4, 4, a + b)
BINOP_CASE(F32x4Sub, f32x4, float4, 4, a - b)
BINOP_CASE(F32x4Mul, f32x4, float4, 4, a * b)
- BINOP_CASE(F32x4Min, f32x4, float4, 4, a < b ? a : b)
- BINOP_CASE(F32x4Max, f32x4, float4, 4, a > b ? a : b)
+ BINOP_CASE(F32x4Div, f32x4, float4, 4, a / b)
+ BINOP_CASE(F32x4Min, f32x4, float4, 4, JSMin(a, b))
+ BINOP_CASE(F32x4Max, f32x4, float4, 4, JSMax(a, b))
BINOP_CASE(I64x2Add, i64x2, int2, 2, base::AddWithWraparound(a, b))
BINOP_CASE(I64x2Sub, i64x2, int2, 2, base::SubWithWraparound(a, b))
BINOP_CASE(I64x2Mul, i64x2, int2, 2, base::MulWithWraparound(a, b))
+ BINOP_CASE(I64x2MinS, i64x2, int2, 2, a < b ? a : b)
+ BINOP_CASE(I64x2MinU, i64x2, int2, 2,
+ static_cast<uint64_t>(a) < static_cast<uint64_t>(b) ? a : b)
+ BINOP_CASE(I64x2MaxS, i64x2, int2, 2, a > b ? a : b)
+ BINOP_CASE(I64x2MaxU, i64x2, int2, 2,
+ static_cast<uint64_t>(a) > static_cast<uint64_t>(b) ? a : b)
BINOP_CASE(I32x4Add, i32x4, int4, 4, base::AddWithWraparound(a, b))
BINOP_CASE(I32x4Sub, i32x4, int4, 4, base::SubWithWraparound(a, b))
BINOP_CASE(I32x4Mul, i32x4, int4, 4, base::MulWithWraparound(a, b))
@@ -2422,40 +2435,32 @@ class ThreadImpl {
case kExprS128StoreMem:
return ExecuteStore<Simd128, Simd128>(decoder, code, pc, len,
MachineRepresentation::kSimd128);
-#define SHIFT_CASE(op, name, stype, count, expr) \
- case kExpr##op: { \
- SimdShiftImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc)); \
- *len += 1; \
- WasmValue v = Pop(); \
- stype s = v.to_s128().to_##name(); \
- stype res; \
- for (size_t i = 0; i < count; ++i) { \
- auto a = s.val[i]; \
- res.val[i] = expr; \
- } \
- Push(WasmValue(Simd128(res))); \
- return true; \
- }
- SHIFT_CASE(I64x2Shl, i64x2, int2, 2,
- static_cast<uint64_t>(a) << imm.shift)
- SHIFT_CASE(I64x2ShrS, i64x2, int2, 2, a >> imm.shift)
- SHIFT_CASE(I64x2ShrU, i64x2, int2, 2,
- static_cast<uint64_t>(a) >> imm.shift)
- SHIFT_CASE(I32x4Shl, i32x4, int4, 4,
- static_cast<uint32_t>(a) << imm.shift)
- SHIFT_CASE(I32x4ShrS, i32x4, int4, 4, a >> imm.shift)
- SHIFT_CASE(I32x4ShrU, i32x4, int4, 4,
- static_cast<uint32_t>(a) >> imm.shift)
- SHIFT_CASE(I16x8Shl, i16x8, int8, 8,
- static_cast<uint16_t>(a) << imm.shift)
- SHIFT_CASE(I16x8ShrS, i16x8, int8, 8, a >> imm.shift)
- SHIFT_CASE(I16x8ShrU, i16x8, int8, 8,
- static_cast<uint16_t>(a) >> imm.shift)
- SHIFT_CASE(I8x16Shl, i8x16, int16, 16,
- static_cast<uint8_t>(a) << imm.shift)
- SHIFT_CASE(I8x16ShrS, i8x16, int16, 16, a >> imm.shift)
+#define SHIFT_CASE(op, name, stype, count, expr) \
+ case kExpr##op: { \
+ uint32_t shift = Pop().to<uint32_t>(); \
+ WasmValue v = Pop(); \
+ stype s = v.to_s128().to_##name(); \
+ stype res; \
+ for (size_t i = 0; i < count; ++i) { \
+ auto a = s.val[i]; \
+ res.val[i] = expr; \
+ } \
+ Push(WasmValue(Simd128(res))); \
+ return true; \
+ }
+ SHIFT_CASE(I64x2Shl, i64x2, int2, 2, static_cast<uint64_t>(a) << shift)
+ SHIFT_CASE(I64x2ShrS, i64x2, int2, 2, a >> shift)
+ SHIFT_CASE(I64x2ShrU, i64x2, int2, 2, static_cast<uint64_t>(a) >> shift)
+ SHIFT_CASE(I32x4Shl, i32x4, int4, 4, static_cast<uint32_t>(a) << shift)
+ SHIFT_CASE(I32x4ShrS, i32x4, int4, 4, a >> shift)
+ SHIFT_CASE(I32x4ShrU, i32x4, int4, 4, static_cast<uint32_t>(a) >> shift)
+ SHIFT_CASE(I16x8Shl, i16x8, int8, 8, static_cast<uint16_t>(a) << shift)
+ SHIFT_CASE(I16x8ShrS, i16x8, int8, 8, a >> shift)
+ SHIFT_CASE(I16x8ShrU, i16x8, int8, 8, static_cast<uint16_t>(a) >> shift)
+ SHIFT_CASE(I8x16Shl, i8x16, int16, 16, static_cast<uint8_t>(a) << shift)
+ SHIFT_CASE(I8x16ShrS, i8x16, int16, 16, a >> shift)
SHIFT_CASE(I8x16ShrU, i8x16, int16, 16,
- static_cast<uint8_t>(a) >> imm.shift)
+ static_cast<uint8_t>(a) >> shift)
#undef SHIFT_CASE
#define CONVERT_CASE(op, src_type, name, dst_type, count, start_index, ctype, \
expr) \
@@ -3042,8 +3047,8 @@ class ThreadImpl {
code->at(pc));
HandleScope handle_scope(isolate_); // Avoid leaking handles.
- Handle<WasmExportedFunction> function =
- WasmInstanceObject::GetOrCreateWasmExportedFunction(
+ Handle<WasmExternalFunction> function =
+ WasmInstanceObject::GetOrCreateWasmExternalFunction(
isolate_, instance_object_, imm.index);
Push(WasmValue(function));
len = 1 + imm.length;
@@ -3679,7 +3684,7 @@ class ThreadImpl {
WasmFeatures enabled_features = WasmFeaturesFromIsolate(isolate);
if (code->kind() == WasmCode::kWasmToJsWrapper &&
- !IsJSCompatibleSignature(sig, enabled_features.bigint)) {
+ !IsJSCompatibleSignature(sig, enabled_features)) {
Drop(num_args); // Pop arguments before throwing.
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kWasmTrapTypeError));
diff --git a/deps/v8/src/wasm/wasm-js.cc b/deps/v8/src/wasm/wasm-js.cc
index 1ee76fc11d..f10f5ff2bf 100644
--- a/deps/v8/src/wasm/wasm-js.cc
+++ b/deps/v8/src/wasm/wasm-js.cc
@@ -1223,6 +1223,9 @@ bool GetValueType(Isolate* isolate, MaybeLocal<Value> maybe,
} else if (enabled_features.anyref &&
string->StringEquals(v8_str(isolate, "anyfunc"))) {
*type = i::wasm::kWasmFuncRef;
+ } else if (enabled_features.eh &&
+ string->StringEquals(v8_str(isolate, "exnref"))) {
+ *type = i::wasm::kWasmExnRef;
} else {
// Unrecognized type.
*type = i::wasm::kWasmStmt;
@@ -1337,7 +1340,8 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
global_obj->SetF64(f64_value);
break;
}
- case i::wasm::kWasmAnyRef: {
+ case i::wasm::kWasmAnyRef:
+ case i::wasm::kWasmExnRef: {
if (args.Length() < 2) {
// When no inital value is provided, we have to use the WebAssembly
// default value 'null', and not the JS default value 'undefined'.
@@ -1379,6 +1383,21 @@ void WebAssemblyException(const v8::FunctionCallbackInfo<v8::Value>& args) {
thrower.TypeError("WebAssembly.Exception cannot be called");
}
+namespace {
+
+uint32_t GetIterableLength(i::Isolate* isolate, Local<Context> context,
+ Local<Object> iterable) {
+ Local<String> length = Utils::ToLocal(isolate->factory()->length_string());
+ MaybeLocal<Value> property = iterable->Get(context, length);
+ if (property.IsEmpty()) return i::kMaxUInt32;
+ MaybeLocal<Uint32> number = property.ToLocalChecked()->ToArrayIndex(context);
+ if (number.IsEmpty()) return i::kMaxUInt32;
+ DCHECK_NE(i::kMaxUInt32, number.ToLocalChecked()->Value());
+ return number.ToLocalChecked()->Value();
+}
+
+} // namespace
+
// WebAssembly.Function
void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
@@ -1403,13 +1422,16 @@ void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
function_type->Get(context, parameters_key);
v8::Local<v8::Value> parameters_value;
if (!parameters_maybe.ToLocal(&parameters_value)) return;
- // TODO(7742): Allow any iterable, not just {Array} here.
- if (!parameters_value->IsArray()) {
+ if (!parameters_value->IsObject()) {
thrower.TypeError("Argument 0 must be a function type with 'parameters'");
return;
}
- Local<Array> parameters = parameters_value.As<Array>();
- uint32_t parameters_len = parameters->Length();
+ Local<Object> parameters = parameters_value.As<Object>();
+ uint32_t parameters_len = GetIterableLength(i_isolate, context, parameters);
+ if (parameters_len == i::kMaxUInt32) {
+ thrower.TypeError("Argument 0 contains parameters without 'length'");
+ return;
+ }
if (parameters_len > i::wasm::kV8MaxWasmFunctionParams) {
thrower.TypeError("Argument 0 contains too many parameters");
return;
@@ -1421,13 +1443,16 @@ void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
function_type->Get(context, results_key);
v8::Local<v8::Value> results_value;
if (!results_maybe.ToLocal(&results_value)) return;
- // TODO(7742): Allow any iterable, not just {Array} here.
- if (!results_value->IsArray()) {
+ if (!results_value->IsObject()) {
thrower.TypeError("Argument 0 must be a function type with 'results'");
return;
}
- Local<Array> results = results_value.As<Array>();
- uint32_t results_len = results->Length();
+ Local<Object> results = results_value.As<Object>();
+ uint32_t results_len = GetIterableLength(i_isolate, context, results);
+ if (results_len == i::kMaxUInt32) {
+ thrower.TypeError("Argument 0 contains results without 'length'");
+ return;
+ }
if (results_len > (enabled_features.mv
? i::wasm::kV8MaxWasmFunctionMultiReturns
: i::wasm::kV8MaxWasmFunctionReturns)) {
@@ -1474,37 +1499,6 @@ void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(Utils::ToLocal(result));
}
-// Converts the given {type} into a string representation that can be used in
-// reflective functions. Should be kept in sync with the {GetValueType} helper.
-Local<String> ToValueTypeString(Isolate* isolate, i::wasm::ValueType type) {
- Local<String> string;
- switch (type) {
- case i::wasm::kWasmI32: {
- string = v8_str(isolate, "i32");
- break;
- }
- case i::wasm::kWasmI64: {
- string = v8_str(isolate, "i64");
- break;
- }
- case i::wasm::kWasmF32: {
- string = v8_str(isolate, "f32");
- break;
- }
- case i::wasm::kWasmF64: {
- string = v8_str(isolate, "f64");
- break;
- }
- case i::wasm::kWasmAnyRef: {
- string = v8_str(isolate, "anyref");
- break;
- }
- default:
- UNREACHABLE();
- }
- return string;
-}
-
// WebAssembly.Function.type(WebAssembly.Function) -> FunctionType
void WebAssemblyFunctionType(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
@@ -1524,36 +1518,8 @@ void WebAssemblyFunctionType(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
- // Extract values for the {ValueType[]} arrays.
- size_t param_index = 0;
- i::ScopedVector<Local<Value>> param_values(sig->parameter_count());
- for (i::wasm::ValueType type : sig->parameters()) {
- param_values[param_index++] = ToValueTypeString(isolate, type);
- }
- size_t result_index = 0;
- i::ScopedVector<Local<Value>> result_values(sig->return_count());
- for (i::wasm::ValueType type : sig->returns()) {
- result_values[result_index++] = ToValueTypeString(isolate, type);
- }
-
- // Create the resulting {FunctionType} object.
- Local<Object> ret = v8::Object::New(isolate);
- Local<Context> context = isolate->GetCurrentContext();
- Local<Array> params =
- v8::Array::New(isolate, param_values.begin(), param_values.size());
- if (!ret->CreateDataProperty(context, v8_str(isolate, "parameters"), params)
- .IsJust()) {
- return;
- }
- Local<Array> results =
- v8::Array::New(isolate, result_values.begin(), result_values.size());
- if (!ret->CreateDataProperty(context, v8_str(isolate, "results"), results)
- .IsJust()) {
- return;
- }
-
- v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
- return_value.Set(ret);
+ auto type = i::wasm::GetTypeForFunction(i_isolate, sig);
+ args.GetReturnValue().Set(Utils::ToLocal(type));
}
constexpr const char* kName_WasmGlobalObject = "WebAssembly.Global";
@@ -1681,48 +1647,15 @@ void WebAssemblyTableType(const v8::FunctionCallbackInfo<v8::Value>& args) {
auto maybe_table = GetFirstArgumentAsTable(args, &thrower);
if (thrower.error()) return;
i::Handle<i::WasmTableObject> table = maybe_table.ToHandleChecked();
- v8::Local<v8::Object> ret = v8::Object::New(isolate);
-
- Local<String> element;
- auto enabled_features = i::wasm::WasmFeaturesFromFlags();
- if (table->type() == i::wasm::ValueType::kWasmFuncRef) {
- element = v8_str(isolate, "anyfunc");
- } else if (enabled_features.anyref &&
- table->type() == i::wasm::ValueType::kWasmAnyRef) {
- element = v8_str(isolate, "anyref");
- } else {
- UNREACHABLE();
- }
- if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
- v8_str(isolate, "element"), element)
- .IsJust()) {
- return;
- }
-
- uint32_t curr_size = table->current_length();
- DCHECK_LE(curr_size, std::numeric_limits<uint32_t>::max());
- if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
- v8_str(isolate, "minimum"),
- v8::Integer::NewFromUnsigned(
- isolate, static_cast<uint32_t>(curr_size)))
- .IsJust()) {
- return;
- }
-
+ base::Optional<uint32_t> max_size;
if (!table->maximum_length().IsUndefined()) {
- uint64_t max_size = table->maximum_length().Number();
- DCHECK_LE(max_size, std::numeric_limits<uint32_t>::max());
- if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
- v8_str(isolate, "maximum"),
- v8::Integer::NewFromUnsigned(
- isolate, static_cast<uint32_t>(max_size)))
- .IsJust()) {
- return;
- }
+ uint64_t max_size64 = table->maximum_length().Number();
+ DCHECK_LE(max_size64, std::numeric_limits<uint32_t>::max());
+ max_size.emplace(static_cast<uint32_t>(max_size64));
}
-
- v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
- return_value.Set(ret);
+ auto type = i::wasm::GetTypeForTable(i_isolate, table->type(),
+ table->current_length(), max_size);
+ args.GetReturnValue().Set(Utils::ToLocal(type));
}
// WebAssembly.Memory.grow(num) -> num
@@ -1802,33 +1735,18 @@ void WebAssemblyMemoryType(const v8::FunctionCallbackInfo<v8::Value>& args) {
auto maybe_memory = GetFirstArgumentAsMemory(args, &thrower);
if (thrower.error()) return;
i::Handle<i::WasmMemoryObject> memory = maybe_memory.ToHandleChecked();
- v8::Local<v8::Object> ret = v8::Object::New(isolate);
i::Handle<i::JSArrayBuffer> buffer(memory->array_buffer(), i_isolate);
-
size_t curr_size = buffer->byte_length() / i::wasm::kWasmPageSize;
DCHECK_LE(curr_size, std::numeric_limits<uint32_t>::max());
- if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
- v8_str(isolate, "minimum"),
- v8::Integer::NewFromUnsigned(
- isolate, static_cast<uint32_t>(curr_size)))
- .IsJust()) {
- return;
- }
-
+ uint32_t min_size = static_cast<uint32_t>(curr_size);
+ base::Optional<uint32_t> max_size;
if (memory->has_maximum_pages()) {
- uint64_t max_size = memory->maximum_pages();
- DCHECK_LE(max_size, std::numeric_limits<uint32_t>::max());
- if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
- v8_str(isolate, "maximum"),
- v8::Integer::NewFromUnsigned(
- isolate, static_cast<uint32_t>(max_size)))
- .IsJust()) {
- return;
- }
+ uint64_t max_size64 = memory->maximum_pages();
+ DCHECK_LE(max_size64, std::numeric_limits<uint32_t>::max());
+ max_size.emplace(static_cast<uint32_t>(max_size64));
}
-
- v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
- return_value.Set(ret);
+ auto type = i::wasm::GetTypeForMemory(i_isolate, min_size, max_size);
+ args.GetReturnValue().Set(Utils::ToLocal(type));
}
void WebAssemblyGlobalGetValueCommon(
@@ -1960,24 +1878,9 @@ void WebAssemblyGlobalType(const v8::FunctionCallbackInfo<v8::Value>& args) {
auto maybe_global = GetFirstArgumentAsGlobal(args, &thrower);
if (thrower.error()) return;
i::Handle<i::WasmGlobalObject> global = maybe_global.ToHandleChecked();
- v8::Local<v8::Object> ret = v8::Object::New(isolate);
-
- if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
- v8_str(isolate, "mutable"),
- v8::Boolean::New(isolate, global->is_mutable()))
- .IsJust()) {
- return;
- }
-
- Local<String> type = ToValueTypeString(isolate, global->type());
- if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
- v8_str(isolate, "value"), type)
- .IsJust()) {
- return;
- }
-
- v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
- return_value.Set(ret);
+ auto type = i::wasm::GetTypeForGlobal(i_isolate, global->is_mutable(),
+ global->type());
+ args.GetReturnValue().Set(Utils::ToLocal(type));
}
} // namespace
diff --git a/deps/v8/src/wasm/wasm-module-builder.cc b/deps/v8/src/wasm/wasm-module-builder.cc
index 7dd6b1c7b2..d3874e1a34 100644
--- a/deps/v8/src/wasm/wasm-module-builder.cc
+++ b/deps/v8/src/wasm/wasm-module-builder.cc
@@ -233,6 +233,7 @@ WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
global_imports_(zone),
exports_(zone),
functions_(zone),
+ tables_(zone),
data_segments_(zone),
indirect_functions_(zone),
globals_(zone),
@@ -269,15 +270,29 @@ uint32_t WasmModuleBuilder::AddSignature(FunctionSig* sig) {
}
uint32_t WasmModuleBuilder::AllocateIndirectFunctions(uint32_t count) {
+ DCHECK(allocating_indirect_functions_allowed_);
uint32_t index = static_cast<uint32_t>(indirect_functions_.size());
DCHECK_GE(FLAG_wasm_max_table_size, index);
if (count > FLAG_wasm_max_table_size - index) {
return std::numeric_limits<uint32_t>::max();
}
- DCHECK(max_table_size_ == 0 ||
- indirect_functions_.size() + count <= max_table_size_);
- indirect_functions_.resize(indirect_functions_.size() + count,
- WasmElemSegment::kNullIndex);
+ uint32_t new_size = static_cast<uint32_t>(indirect_functions_.size()) + count;
+ DCHECK(max_table_size_ == 0 || new_size <= max_table_size_);
+ indirect_functions_.resize(new_size, WasmElemSegment::kNullIndex);
+ uint32_t max = max_table_size_ > 0 ? max_table_size_ : new_size;
+ if (tables_.empty()) {
+ // This cannot use {AddTable} because that would flip the
+ // {allocating_indirect_functions_allowed_} flag.
+ tables_.push_back({kWasmFuncRef, new_size, max, true});
+ } else {
+ // There can only be the indirect function table so far, otherwise the
+ // {allocating_indirect_functions_allowed_} flag would have been false.
+ DCHECK_EQ(1u, tables_.size());
+ DCHECK_EQ(kWasmFuncRef, tables_[0].type);
+ DCHECK(tables_[0].has_maximum);
+ tables_[0].min_size = new_size;
+ tables_[0].max_size = max;
+ }
return index;
}
@@ -290,6 +305,27 @@ void WasmModuleBuilder::SetMaxTableSize(uint32_t max) {
DCHECK_GE(FLAG_wasm_max_table_size, max);
DCHECK_GE(max, indirect_functions_.size());
max_table_size_ = max;
+ DCHECK(allocating_indirect_functions_allowed_);
+ if (!tables_.empty()) {
+ tables_[0].max_size = max;
+ }
+}
+
+uint32_t WasmModuleBuilder::AddTable(ValueType type, uint32_t min_size) {
+#if DEBUG
+ allocating_indirect_functions_allowed_ = false;
+#endif
+ tables_.push_back({type, min_size, 0, false});
+ return static_cast<uint32_t>(tables_.size() - 1);
+}
+
+uint32_t WasmModuleBuilder::AddTable(ValueType type, uint32_t min_size,
+ uint32_t max_size) {
+#if DEBUG
+ allocating_indirect_functions_allowed_ = false;
+#endif
+ tables_.push_back({type, min_size, max_size, true});
+ return static_cast<uint32_t>(tables_.size() - 1);
}
uint32_t WasmModuleBuilder::AddImport(Vector<const char> name,
@@ -408,21 +444,20 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
FixupSection(buffer, start);
}
- // == emit function table ====================================================
- if (indirect_functions_.size() > 0) {
+ // == Emit tables ============================================================
+ if (tables_.size() > 0) {
size_t start = EmitSection(kTableSectionCode, buffer);
- buffer->write_u8(1); // table count
- buffer->write_u8(kLocalFuncRef);
- buffer->write_u8(kHasMaximumFlag);
- buffer->write_size(indirect_functions_.size());
- size_t max =
- max_table_size_ > 0 ? max_table_size_ : indirect_functions_.size();
- DCHECK_GE(max, indirect_functions_.size());
- buffer->write_size(max);
+ buffer->write_size(tables_.size());
+ for (const WasmTable& table : tables_) {
+ buffer->write_u8(ValueTypes::ValueTypeCodeFor(table.type));
+ buffer->write_u8(table.has_maximum ? kHasMaximumFlag : kNoMaximumFlag);
+ buffer->write_size(table.min_size);
+ if (table.has_maximum) buffer->write_size(table.max_size);
+ }
FixupSection(buffer, start);
}
- // == emit memory declaration ================================================
+ // == Emit memory declaration ================================================
{
size_t start = EmitSection(kMemorySectionCode, buffer);
buffer->write_u8(1); // memory count
@@ -473,7 +508,13 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
buffer->write_u8(kExprGetGlobal);
buffer->write_u32v(global.init.val.global_index);
break;
- default: {
+ case WasmInitExpr::kRefNullConst:
+ buffer->write_u8(kExprRefNull);
+ break;
+ case WasmInitExpr::kRefFuncConst:
+ UNIMPLEMENTED();
+ break;
+ case WasmInitExpr::kNone: {
// No initializer, emit a default value.
switch (global.type) {
case kWasmI32:
diff --git a/deps/v8/src/wasm/wasm-module-builder.h b/deps/v8/src/wasm/wasm-module-builder.h
index 9e6a8933e2..4c122b8062 100644
--- a/deps/v8/src/wasm/wasm-module-builder.h
+++ b/deps/v8/src/wasm/wasm-module-builder.h
@@ -243,6 +243,8 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
uint32_t AllocateIndirectFunctions(uint32_t count);
void SetIndirectFunction(uint32_t indirect, uint32_t direct);
void SetMaxTableSize(uint32_t max);
+ uint32_t AddTable(ValueType type, uint32_t min_size);
+ uint32_t AddTable(ValueType type, uint32_t min_size, uint32_t max_size);
void MarkStartFunction(WasmFunctionBuilder* builder);
void AddExport(Vector<const char> name, ImportExportKindCode kind,
uint32_t index);
@@ -288,6 +290,13 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
WasmInitExpr init;
};
+ struct WasmTable {
+ ValueType type;
+ uint32_t min_size;
+ uint32_t max_size;
+ bool has_maximum;
+ };
+
struct WasmDataSegment {
ZoneVector<byte> data;
uint32_t dest;
@@ -300,6 +309,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
ZoneVector<WasmGlobalImport> global_imports_;
ZoneVector<WasmExport> exports_;
ZoneVector<WasmFunctionBuilder*> functions_;
+ ZoneVector<WasmTable> tables_;
ZoneVector<WasmDataSegment> data_segments_;
ZoneVector<uint32_t> indirect_functions_;
ZoneVector<WasmGlobal> globals_;
@@ -313,6 +323,8 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
#if DEBUG
// Once AddExportedImport is called, no more imports can be added.
bool adding_imports_allowed_ = true;
+ // Indirect functions must be allocated before adding extra tables.
+ bool allocating_indirect_functions_allowed_ = true;
#endif
};
diff --git a/deps/v8/src/wasm/wasm-module-sourcemap.cc b/deps/v8/src/wasm/wasm-module-sourcemap.cc
new file mode 100644
index 0000000000..cfe54e7c37
--- /dev/null
+++ b/deps/v8/src/wasm/wasm-module-sourcemap.cc
@@ -0,0 +1,161 @@
+// Copyright 2019 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/wasm/wasm-module-sourcemap.h"
+
+#include <algorithm>
+
+#include "include/v8.h"
+#include "src/api/api.h"
+#include "src/base/vlq-base64.h"
+
+namespace v8 {
+namespace internal {
+namespace wasm {
+
+WasmModuleSourceMap::WasmModuleSourceMap(v8::Isolate* v8_isolate,
+ v8::Local<v8::String> src_map_str) {
+ v8::HandleScope scope(v8_isolate);
+ v8::Local<v8::Context> context = v8::Context::New(v8_isolate);
+
+ v8::Local<v8::Value> src_map_value;
+ if (!v8::JSON::Parse(context, src_map_str).ToLocal(&src_map_value)) return;
+ v8::Local<v8::Object> src_map_obj =
+ v8::Local<v8::Object>::Cast(src_map_value);
+
+ v8::Local<v8::Value> version_value, sources_value, mappings_value;
+ bool has_valid_version =
+ src_map_obj
+ ->Get(context,
+ v8::String::NewFromUtf8(v8_isolate, "version").ToLocalChecked())
+ .ToLocal(&version_value) &&
+ version_value->IsUint32();
+ uint32_t version = 0;
+ if (!has_valid_version || !version_value->Uint32Value(context).To(&version) ||
+ version != 3u)
+ return;
+
+ bool has_valid_sources =
+ src_map_obj
+ ->Get(context,
+ v8::String::NewFromUtf8(v8_isolate, "sources").ToLocalChecked())
+ .ToLocal(&sources_value) &&
+ sources_value->IsArray();
+ if (!has_valid_sources) return;
+
+ v8::Local<v8::Object> sources_arr =
+ v8::Local<v8::Object>::Cast(sources_value);
+ v8::Local<v8::Value> sources_len_value;
+ if (!sources_arr
+ ->Get(context,
+ v8::String::NewFromUtf8(v8_isolate, "length").ToLocalChecked())
+ .ToLocal(&sources_len_value))
+ return;
+ uint32_t sources_len = 0;
+ if (!sources_len_value->Uint32Value(context).To(&sources_len)) return;
+
+ for (uint32_t i = 0; i < sources_len; ++i) {
+ v8::Local<v8::Value> file_name_value;
+ if (!sources_arr->Get(context, i).ToLocal(&file_name_value) ||
+ !file_name_value->IsString())
+ return;
+ v8::Local<v8::String> file_name =
+ v8::Local<v8::String>::Cast(file_name_value);
+ auto file_name_sz = file_name->Utf8Length(v8_isolate);
+ std::unique_ptr<char[]> file_name_buf(new char[file_name_sz + 1]);
+ file_name->WriteUtf8(v8_isolate, file_name_buf.get());
+ file_name_buf.get()[file_name_sz] = '\0';
+ filenames.emplace_back(file_name_buf.get());
+ }
+
+ bool has_valid_mappings =
+ src_map_obj
+ ->Get(
+ context,
+ v8::String::NewFromUtf8(v8_isolate, "mappings").ToLocalChecked())
+ .ToLocal(&mappings_value) &&
+ mappings_value->IsString();
+ if (!has_valid_mappings) return;
+
+ v8::Local<v8::String> mappings = v8::Local<v8::String>::Cast(mappings_value);
+ int mappings_sz = mappings->Utf8Length(v8_isolate);
+ std::unique_ptr<char[]> mappings_buf(new char[mappings_sz + 1]);
+ mappings->WriteUtf8(v8_isolate, mappings_buf.get());
+ mappings_buf.get()[mappings_sz] = '\0';
+
+ valid_ = DecodeMapping(mappings_buf.get());
+}
+
+size_t WasmModuleSourceMap::GetSourceLine(size_t wasm_offset) const {
+ std::vector<std::size_t>::const_iterator up =
+ std::upper_bound(offsets.begin(), offsets.end(), wasm_offset);
+ CHECK_NE(offsets.begin(), up);
+ size_t source_idx = up - offsets.begin() - 1;
+ return source_row[source_idx];
+}
+
+std::string WasmModuleSourceMap::GetFilename(size_t wasm_offset) const {
+ std::vector<size_t>::const_iterator up =
+ std::upper_bound(offsets.begin(), offsets.end(), wasm_offset);
+ CHECK_NE(offsets.begin(), up);
+ size_t offset_idx = up - offsets.begin() - 1;
+ size_t filename_idx = file_idxs[offset_idx];
+ return filenames[filename_idx];
+}
+
+bool WasmModuleSourceMap::HasSource(size_t start, size_t end) const {
+ return start <= *(offsets.end() - 1) && end > *offsets.begin();
+}
+
+bool WasmModuleSourceMap::HasValidEntry(size_t start, size_t addr) const {
+ std::vector<size_t>::const_iterator up =
+ std::upper_bound(offsets.begin(), offsets.end(), addr);
+ if (up == offsets.begin()) return false;
+ size_t offset_idx = up - offsets.begin() - 1;
+ size_t entry_offset = offsets[offset_idx];
+ if (entry_offset < start) return false;
+ return true;
+}
+
+bool WasmModuleSourceMap::DecodeMapping(const std::string& s) {
+ size_t pos = 0, gen_col = 0, file_idx = 0, ori_line = 0;
+ int32_t qnt = 0;
+
+ while (pos < s.size()) {
+ // Skip redundant commas.
+ if (s[pos] == ',') {
+ ++pos;
+ continue;
+ }
+ if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
+ std::numeric_limits<int32_t>::min())
+ return false;
+ gen_col += qnt;
+ if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
+ std::numeric_limits<int32_t>::min())
+ return false;
+ file_idx += qnt;
+ if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
+ std::numeric_limits<int32_t>::min())
+ return false;
+ ori_line += qnt;
+ // Column number in source file is always 0 in source map generated by
+ // Emscripten. We just decode this value without further usage of it.
+ if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
+ std::numeric_limits<int32_t>::min())
+ return false;
+
+ if (pos < s.size() && s[pos] != ',') return false;
+ pos++;
+
+ file_idxs.push_back(file_idx);
+ source_row.push_back(ori_line);
+ offsets.push_back(gen_col);
+ }
+ return true;
+}
+
+} // namespace wasm
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/wasm/wasm-module-sourcemap.h b/deps/v8/src/wasm/wasm-module-sourcemap.h
new file mode 100644
index 0000000000..83293ae205
--- /dev/null
+++ b/deps/v8/src/wasm/wasm-module-sourcemap.h
@@ -0,0 +1,83 @@
+// Copyright 2019 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_WASM_WASM_MODULE_SOURCEMAP_H_
+#define V8_WASM_WASM_MODULE_SOURCEMAP_H_
+
+#include <string>
+#include <vector>
+
+#include "include/v8.h"
+#include "src/base/macros.h"
+
+namespace v8 {
+namespace internal {
+namespace wasm {
+// The class is for decoding and managing source map generated by a WebAssembly
+// toolchain (e.g. Emscripten). This implementation mostly complies with the
+// specification (https://sourcemaps.info/spec.html), with the following
+// accommodations:
+// 1. "names" field is an empty array in current source maps of WASM, hence it
+// is not handled;
+// 2. The semicolons divides "mappings" field into groups, each of which
+// represents a line in the generated code. As *.wasm is in binary format, there
+// is one "line" of generated code, and ";" is treated as illegal symbol in
+// "mappings".
+// 3. Though each comma-separated section may contains 1, 4 or 5 fields, we only
+// consider "mappings" with 4 fields, i.e. start line of generated code, index
+// into "sources" fields, start line of source code and start column of source
+// code.
+class V8_EXPORT_PRIVATE WasmModuleSourceMap {
+ public:
+ WasmModuleSourceMap(v8::Isolate* v8_isolate,
+ v8::Local<v8::String> src_map_str);
+
+ // Member valid_ is true only if the source map complies with specification
+ // and can be correctly decoded.
+ bool IsValid() const { return valid_; }
+
+ // Given a function located at [start, end) in WASM Module, this function
+ // checks if this function has its corresponding source code.
+ bool HasSource(size_t start, size_t end) const;
+
+ // Given a function's base address start and an address addr within, this
+ // function checks if the address can be mapped to an offset in this function.
+ // For example, we have the following memory layout for WASM functions, foo
+ // and bar, and O1, O2, O3 and O4 are the decoded offsets of source map:
+ //
+ // O1 --- O2 ----- O3 ----- O4
+ // --->|<-foo->|<--bar->|<-----
+ // --------------A-------------
+ //
+ // Address A of function bar should be mapped to its nearest lower offset, O2.
+ // However, O2 is an address of function foo, thus, this mapping is treated as
+ // invalid.
+ bool HasValidEntry(size_t start, size_t addr) const;
+
+ // This function is responsible for looking up an offset's corresponding line
+ // number in source file. It should only be called when current function is
+ // checked with IsValid, HasSource and HasValidEntry.
+ size_t GetSourceLine(size_t wasm_offset) const;
+
+ // This function is responsible for looking up an offset's corresponding
+ // source file name. It should only be called when current function is checked
+ // with IsValid, HasSource and HasValidEntry.
+ std::string GetFilename(size_t wasm_offset) const;
+
+ private:
+ std::vector<size_t> offsets;
+ std::vector<std::string> filenames;
+ std::vector<size_t> file_idxs;
+ std::vector<size_t> source_row;
+ // As column number in source file is always 0 in source map generated by
+ // WebAssembly toolchain, we will not store this value.
+
+ bool valid_ = false;
+
+ bool DecodeMapping(const std::string& s);
+};
+} // namespace wasm
+} // namespace internal
+} // namespace v8
+#endif // V8_WASM_WASM_MODULE_SOURCEMAP_H_
diff --git a/deps/v8/src/wasm/wasm-module.cc b/deps/v8/src/wasm/wasm-module.cc
index 05057301ed..5a10368a8b 100644
--- a/deps/v8/src/wasm/wasm-module.cc
+++ b/deps/v8/src/wasm/wasm-module.cc
@@ -113,13 +113,156 @@ bool IsWasmCodegenAllowed(Isolate* isolate, Handle<Context> context) {
v8::Utils::ToLocal(isolate->factory()->empty_string()));
}
+namespace {
+
+// Converts the given {type} into a string representation that can be used in
+// reflective functions. Should be kept in sync with the {GetValueType} helper.
+Handle<String> ToValueTypeString(Isolate* isolate, ValueType type) {
+ Factory* factory = isolate->factory();
+ Handle<String> string;
+ switch (type) {
+ case i::wasm::kWasmI32: {
+ string = factory->InternalizeUtf8String("i32");
+ break;
+ }
+ case i::wasm::kWasmI64: {
+ string = factory->InternalizeUtf8String("i64");
+ break;
+ }
+ case i::wasm::kWasmF32: {
+ string = factory->InternalizeUtf8String("f32");
+ break;
+ }
+ case i::wasm::kWasmF64: {
+ string = factory->InternalizeUtf8String("f64");
+ break;
+ }
+ case i::wasm::kWasmAnyRef: {
+ string = factory->InternalizeUtf8String("anyref");
+ break;
+ }
+ case i::wasm::kWasmFuncRef: {
+ string = factory->InternalizeUtf8String("anyfunc");
+ break;
+ }
+ case i::wasm::kWasmExnRef: {
+ string = factory->InternalizeUtf8String("exnref");
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ return string;
+}
+
+} // namespace
+
+Handle<JSObject> GetTypeForFunction(Isolate* isolate, FunctionSig* sig) {
+ Factory* factory = isolate->factory();
+
+ // Extract values for the {ValueType[]} arrays.
+ int param_index = 0;
+ int param_count = static_cast<int>(sig->parameter_count());
+ Handle<FixedArray> param_values = factory->NewFixedArray(param_count);
+ for (ValueType type : sig->parameters()) {
+ Handle<String> type_value = ToValueTypeString(isolate, type);
+ param_values->set(param_index++, *type_value);
+ }
+ int result_index = 0;
+ int result_count = static_cast<int>(sig->return_count());
+ Handle<FixedArray> result_values = factory->NewFixedArray(result_count);
+ for (ValueType type : sig->returns()) {
+ Handle<String> type_value = ToValueTypeString(isolate, type);
+ result_values->set(result_index++, *type_value);
+ }
+
+ // Create the resulting {FunctionType} object.
+ Handle<JSFunction> object_function = isolate->object_function();
+ Handle<JSObject> object = factory->NewJSObject(object_function);
+ Handle<JSArray> params = factory->NewJSArrayWithElements(param_values);
+ Handle<JSArray> results = factory->NewJSArrayWithElements(result_values);
+ Handle<String> params_string = factory->InternalizeUtf8String("parameters");
+ Handle<String> results_string = factory->InternalizeUtf8String("results");
+ JSObject::AddProperty(isolate, object, params_string, params, NONE);
+ JSObject::AddProperty(isolate, object, results_string, results, NONE);
+
+ return object;
+}
+
+Handle<JSObject> GetTypeForGlobal(Isolate* isolate, bool is_mutable,
+ ValueType type) {
+ Factory* factory = isolate->factory();
+
+ Handle<JSFunction> object_function = isolate->object_function();
+ Handle<JSObject> object = factory->NewJSObject(object_function);
+ Handle<String> mutable_string = factory->InternalizeUtf8String("mutable");
+ Handle<String> value_string = factory->InternalizeUtf8String("value");
+ JSObject::AddProperty(isolate, object, mutable_string,
+ factory->ToBoolean(is_mutable), NONE);
+ JSObject::AddProperty(isolate, object, value_string,
+ ToValueTypeString(isolate, type), NONE);
+
+ return object;
+}
+
+Handle<JSObject> GetTypeForMemory(Isolate* isolate, uint32_t min_size,
+ base::Optional<uint32_t> max_size) {
+ Factory* factory = isolate->factory();
+
+ Handle<JSFunction> object_function = isolate->object_function();
+ Handle<JSObject> object = factory->NewJSObject(object_function);
+ Handle<String> minimum_string = factory->InternalizeUtf8String("minimum");
+ Handle<String> maximum_string = factory->InternalizeUtf8String("maximum");
+ JSObject::AddProperty(isolate, object, minimum_string,
+ factory->NewNumberFromUint(min_size), NONE);
+ if (max_size.has_value()) {
+ JSObject::AddProperty(isolate, object, maximum_string,
+ factory->NewNumberFromUint(max_size.value()), NONE);
+ }
+
+ return object;
+}
+
+Handle<JSObject> GetTypeForTable(Isolate* isolate, ValueType type,
+ uint32_t min_size,
+ base::Optional<uint32_t> max_size) {
+ Factory* factory = isolate->factory();
+
+ Handle<String> element;
+ if (type == ValueType::kWasmFuncRef) {
+ // TODO(wasm): We should define the "anyfunc" string in one central place
+ // and then use that constant everywhere.
+ element = factory->InternalizeUtf8String("anyfunc");
+ } else {
+ DCHECK(WasmFeaturesFromFlags().anyref && type == ValueType::kWasmAnyRef);
+ element = factory->InternalizeUtf8String("anyref");
+ }
+
+ Handle<JSFunction> object_function = isolate->object_function();
+ Handle<JSObject> object = factory->NewJSObject(object_function);
+ Handle<String> element_string = factory->InternalizeUtf8String("element");
+ Handle<String> minimum_string = factory->InternalizeUtf8String("minimum");
+ Handle<String> maximum_string = factory->InternalizeUtf8String("maximum");
+ JSObject::AddProperty(isolate, object, element_string, element, NONE);
+ JSObject::AddProperty(isolate, object, minimum_string,
+ factory->NewNumberFromUint(min_size), NONE);
+ if (max_size.has_value()) {
+ JSObject::AddProperty(isolate, object, maximum_string,
+ factory->NewNumberFromUint(max_size.value()), NONE);
+ }
+
+ return object;
+}
+
Handle<JSArray> GetImports(Isolate* isolate,
Handle<WasmModuleObject> module_object) {
+ auto enabled_features = i::wasm::WasmFeaturesFromIsolate(isolate);
Factory* factory = isolate->factory();
Handle<String> module_string = factory->InternalizeUtf8String("module");
Handle<String> name_string = factory->InternalizeUtf8String("name");
Handle<String> kind_string = factory->InternalizeUtf8String("kind");
+ Handle<String> type_string = factory->InternalizeUtf8String("type");
Handle<String> function_string = factory->InternalizeUtf8String("function");
Handle<String> table_string = factory->InternalizeUtf8String("table");
@@ -145,17 +288,43 @@ Handle<JSArray> GetImports(Isolate* isolate,
Handle<JSObject> entry = factory->NewJSObject(object_function);
Handle<String> import_kind;
+ Handle<JSObject> type_value;
switch (import.kind) {
case kExternalFunction:
+ if (enabled_features.type_reflection) {
+ auto& func = module->functions[import.index];
+ type_value = GetTypeForFunction(isolate, func.sig);
+ }
import_kind = function_string;
break;
case kExternalTable:
+ if (enabled_features.type_reflection) {
+ auto& table = module->tables[import.index];
+ base::Optional<uint32_t> maximum_size;
+ if (table.has_maximum_size) maximum_size.emplace(table.maximum_size);
+ type_value = GetTypeForTable(isolate, table.type, table.initial_size,
+ maximum_size);
+ }
import_kind = table_string;
break;
case kExternalMemory:
+ if (enabled_features.type_reflection) {
+ DCHECK_EQ(0, import.index); // Only one memory supported.
+ base::Optional<uint32_t> maximum_size;
+ if (module->has_maximum_pages) {
+ maximum_size.emplace(module->maximum_pages);
+ }
+ type_value =
+ GetTypeForMemory(isolate, module->initial_pages, maximum_size);
+ }
import_kind = memory_string;
break;
case kExternalGlobal:
+ if (enabled_features.type_reflection) {
+ auto& global = module->globals[import.index];
+ type_value =
+ GetTypeForGlobal(isolate, global.mutability, global.type);
+ }
import_kind = global_string;
break;
case kExternalException:
@@ -178,6 +347,9 @@ Handle<JSArray> GetImports(Isolate* isolate,
JSObject::AddProperty(isolate, entry, name_string,
import_name.ToHandleChecked(), NONE);
JSObject::AddProperty(isolate, entry, kind_string, import_kind, NONE);
+ if (!type_value.is_null()) {
+ JSObject::AddProperty(isolate, entry, type_string, type_value, NONE);
+ }
storage->set(index, *entry);
}
@@ -187,10 +359,12 @@ Handle<JSArray> GetImports(Isolate* isolate,
Handle<JSArray> GetExports(Isolate* isolate,
Handle<WasmModuleObject> module_object) {
+ auto enabled_features = i::wasm::WasmFeaturesFromIsolate(isolate);
Factory* factory = isolate->factory();
Handle<String> name_string = factory->InternalizeUtf8String("name");
Handle<String> kind_string = factory->InternalizeUtf8String("kind");
+ Handle<String> type_string = factory->InternalizeUtf8String("type");
Handle<String> function_string = factory->InternalizeUtf8String("function");
Handle<String> table_string = factory->InternalizeUtf8String("table");
@@ -214,17 +388,43 @@ Handle<JSArray> GetExports(Isolate* isolate,
const WasmExport& exp = module->export_table[index];
Handle<String> export_kind;
+ Handle<JSObject> type_value;
switch (exp.kind) {
case kExternalFunction:
+ if (enabled_features.type_reflection) {
+ auto& func = module->functions[exp.index];
+ type_value = GetTypeForFunction(isolate, func.sig);
+ }
export_kind = function_string;
break;
case kExternalTable:
+ if (enabled_features.type_reflection) {
+ auto& table = module->tables[exp.index];
+ base::Optional<uint32_t> maximum_size;
+ if (table.has_maximum_size) maximum_size.emplace(table.maximum_size);
+ type_value = GetTypeForTable(isolate, table.type, table.initial_size,
+ maximum_size);
+ }
export_kind = table_string;
break;
case kExternalMemory:
+ if (enabled_features.type_reflection) {
+ DCHECK_EQ(0, exp.index); // Only one memory supported.
+ base::Optional<uint32_t> maximum_size;
+ if (module->has_maximum_pages) {
+ maximum_size.emplace(module->maximum_pages);
+ }
+ type_value =
+ GetTypeForMemory(isolate, module->initial_pages, maximum_size);
+ }
export_kind = memory_string;
break;
case kExternalGlobal:
+ if (enabled_features.type_reflection) {
+ auto& global = module->globals[exp.index];
+ type_value =
+ GetTypeForGlobal(isolate, global.mutability, global.type);
+ }
export_kind = global_string;
break;
case kExternalException:
@@ -243,6 +443,9 @@ Handle<JSArray> GetExports(Isolate* isolate,
JSObject::AddProperty(isolate, entry, name_string,
export_name.ToHandleChecked(), NONE);
JSObject::AddProperty(isolate, entry, kind_string, export_kind, NONE);
+ if (!type_value.is_null()) {
+ JSObject::AddProperty(isolate, entry, type_string, type_value, NONE);
+ }
storage->set(index, *entry);
}
diff --git a/deps/v8/src/wasm/wasm-module.h b/deps/v8/src/wasm/wasm-module.h
index 7dea208d8e..69c57725de 100644
--- a/deps/v8/src/wasm/wasm-module.h
+++ b/deps/v8/src/wasm/wasm-module.h
@@ -7,6 +7,7 @@
#include <memory>
+#include "src/base/optional.h"
#include "src/common/globals.h"
#include "src/handles/handles.h"
#include "src/utils/vector.h"
@@ -301,13 +302,19 @@ V8_EXPORT_PRIVATE MaybeHandle<WasmModuleObject> CreateModuleObjectFromBytes(
V8_EXPORT_PRIVATE bool IsWasmCodegenAllowed(Isolate* isolate,
Handle<Context> context);
-V8_EXPORT_PRIVATE Handle<JSArray> GetImports(Isolate* isolate,
- Handle<WasmModuleObject> module);
-V8_EXPORT_PRIVATE Handle<JSArray> GetExports(Isolate* isolate,
- Handle<WasmModuleObject> module);
-V8_EXPORT_PRIVATE Handle<JSArray> GetCustomSections(
- Isolate* isolate, Handle<WasmModuleObject> module, Handle<String> name,
- ErrorThrower* thrower);
+Handle<JSObject> GetTypeForFunction(Isolate* isolate, FunctionSig* sig);
+Handle<JSObject> GetTypeForGlobal(Isolate* isolate, bool is_mutable,
+ ValueType type);
+Handle<JSObject> GetTypeForMemory(Isolate* isolate, uint32_t min_size,
+ base::Optional<uint32_t> max_size);
+Handle<JSObject> GetTypeForTable(Isolate* isolate, ValueType type,
+ uint32_t min_size,
+ base::Optional<uint32_t> max_size);
+Handle<JSArray> GetImports(Isolate* isolate, Handle<WasmModuleObject> module);
+Handle<JSArray> GetExports(Isolate* isolate, Handle<WasmModuleObject> module);
+Handle<JSArray> GetCustomSections(Isolate* isolate,
+ Handle<WasmModuleObject> module,
+ Handle<String> name, ErrorThrower* thrower);
// Decode local variable names from the names section. Return FixedArray of
// FixedArray of <undefined|String>. The outer fixed array is indexed by the
diff --git a/deps/v8/src/wasm/wasm-objects-inl.h b/deps/v8/src/wasm/wasm-objects-inl.h
index 7a80b7ea2b..66d3a2716e 100644
--- a/deps/v8/src/wasm/wasm-objects-inl.h
+++ b/deps/v8/src/wasm/wasm-objects-inl.h
@@ -28,7 +28,7 @@ namespace v8 {
namespace internal {
OBJECT_CONSTRUCTORS_IMPL(WasmExceptionObject, JSObject)
-OBJECT_CONSTRUCTORS_IMPL(WasmExceptionTag, Struct)
+TQ_OBJECT_CONSTRUCTORS_IMPL(WasmExceptionTag)
OBJECT_CONSTRUCTORS_IMPL(WasmExportedFunctionData, Struct)
OBJECT_CONSTRUCTORS_IMPL(WasmDebugInfo, Struct)
OBJECT_CONSTRUCTORS_IMPL(WasmGlobalObject, JSObject)
@@ -42,7 +42,6 @@ NEVER_READ_ONLY_SPACE_IMPL(WasmDebugInfo)
CAST_ACCESSOR(WasmDebugInfo)
CAST_ACCESSOR(WasmExceptionObject)
-CAST_ACCESSOR(WasmExceptionTag)
CAST_ACCESSOR(WasmExportedFunctionData)
CAST_ACCESSOR(WasmGlobalObject)
CAST_ACCESSOR(WasmInstanceObject)
@@ -261,9 +260,8 @@ OPTIONAL_ACCESSORS(WasmInstanceObject, managed_native_allocations, Foreign,
kManagedNativeAllocationsOffset)
OPTIONAL_ACCESSORS(WasmInstanceObject, exceptions_table, FixedArray,
kExceptionsTableOffset)
-ACCESSORS(WasmInstanceObject, centry_stub, Code, kCEntryStubOffset)
-OPTIONAL_ACCESSORS(WasmInstanceObject, wasm_exported_functions, FixedArray,
- kWasmExportedFunctionsOffset)
+OPTIONAL_ACCESSORS(WasmInstanceObject, wasm_external_functions, FixedArray,
+ kWasmExternalFunctionsOffset)
void WasmInstanceObject::clear_padding() {
if (FIELD_SIZE(kOptionalPaddingOffset) != 0) {
@@ -325,7 +323,7 @@ SMI_ACCESSORS(WasmExportedFunctionData, jump_table_offset,
kJumpTableOffsetOffset)
SMI_ACCESSORS(WasmExportedFunctionData, function_index, kFunctionIndexOffset)
ACCESSORS(WasmExportedFunctionData, c_wrapper_code, Object, kCWrapperCodeOffset)
-ACCESSORS(WasmExportedFunctionData, wasm_call_target, Smi,
+ACCESSORS(WasmExportedFunctionData, wasm_call_target, Object,
kWasmCallTargetOffset)
SMI_ACCESSORS(WasmExportedFunctionData, packed_args_size, kPackedArgsSizeOffset)
@@ -358,12 +356,17 @@ OBJECT_CONSTRUCTORS_IMPL(WasmCapiFunctionData, Struct)
CAST_ACCESSOR(WasmCapiFunctionData)
PRIMITIVE_ACCESSORS(WasmCapiFunctionData, call_target, Address,
kCallTargetOffset)
-PRIMITIVE_ACCESSORS(WasmCapiFunctionData, embedder_data, void*,
- kEmbedderDataOffset)
+ACCESSORS(WasmCapiFunctionData, embedder_data, Foreign, kEmbedderDataOffset)
ACCESSORS(WasmCapiFunctionData, wrapper_code, Code, kWrapperCodeOffset)
ACCESSORS(WasmCapiFunctionData, serialized_signature, PodArray<wasm::ValueType>,
kSerializedSignatureOffset)
+// WasmExternalFunction
+WasmExternalFunction::WasmExternalFunction(Address ptr) : JSFunction(ptr) {
+ SLOW_DCHECK(IsWasmExternalFunction(*this));
+}
+CAST_ACCESSOR(WasmExternalFunction)
+
// WasmIndirectFunctionTable
OBJECT_CONSTRUCTORS_IMPL(WasmIndirectFunctionTable, Struct)
CAST_ACCESSOR(WasmIndirectFunctionTable)
@@ -399,7 +402,7 @@ wasm::ValueType WasmTableObject::type() {
bool WasmMemoryObject::has_maximum_pages() { return maximum_pages() >= 0; }
// WasmExceptionTag
-SMI_ACCESSORS(WasmExceptionTag, index, kIndexOffset)
+TQ_SMI_ACCESSORS(WasmExceptionTag, index)
// AsmWasmData
ACCESSORS(AsmWasmData, managed_native_module, Managed<wasm::NativeModule>,
diff --git a/deps/v8/src/wasm/wasm-objects.cc b/deps/v8/src/wasm/wasm-objects.cc
index f44f8326ad..d9417943a8 100644
--- a/deps/v8/src/wasm/wasm-objects.cc
+++ b/deps/v8/src/wasm/wasm-objects.cc
@@ -207,36 +207,19 @@ enum DispatchTableElements : int {
// static
Handle<WasmModuleObject> WasmModuleObject::New(
- Isolate* isolate, const wasm::WasmFeatures& enabled,
- std::shared_ptr<const wasm::WasmModule> shared_module,
- OwnedVector<const uint8_t> wire_bytes, Handle<Script> script,
- Handle<ByteArray> asm_js_offset_table) {
- // Create a new {NativeModule} first.
- size_t code_size_estimate =
- wasm::WasmCodeManager::EstimateNativeModuleCodeSize(shared_module.get());
- auto native_module = isolate->wasm_engine()->NewNativeModule(
- isolate, enabled, code_size_estimate,
- wasm::NativeModule::kCanAllocateMoreMemory, std::move(shared_module));
- native_module->SetWireBytes(std::move(wire_bytes));
- native_module->SetRuntimeStubs(isolate);
-
- // Delegate to the shared {WasmModuleObject::New} allocator.
- Handle<WasmModuleObject> module_object =
- New(isolate, std::move(native_module), script, code_size_estimate);
- if (!asm_js_offset_table.is_null()) {
- module_object->set_asm_js_offset_table(*asm_js_offset_table);
- }
- return module_object;
+ Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
+ Handle<Script> script) {
+ Handle<FixedArray> export_wrappers = isolate->factory()->NewFixedArray(0);
+ return New(isolate, std::move(native_module), script, export_wrappers);
}
// static
Handle<WasmModuleObject> WasmModuleObject::New(
Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
- Handle<Script> script, size_t code_size_estimate) {
+ Handle<Script> script, Handle<FixedArray> export_wrappers) {
const WasmModule* module = native_module->module();
- int num_wrappers = MaxNumExportWrappers(module);
- Handle<FixedArray> export_wrappers =
- isolate->factory()->NewFixedArray(num_wrappers, AllocationType::kOld);
+ size_t code_size_estimate =
+ wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module);
return New(isolate, std::move(native_module), script, export_wrappers,
code_size_estimate);
}
@@ -964,6 +947,7 @@ Handle<Object> WasmTableObject::Get(Isolate* isolate,
// Now we handle the funcref case.
if (WasmExportedFunction::IsWasmExportedFunction(*entry) ||
+ WasmJSFunction::IsWasmJSFunction(*entry) ||
WasmCapiFunction::IsWasmCapiFunction(*entry)) {
return entry;
}
@@ -980,7 +964,7 @@ Handle<Object> WasmTableObject::Get(Isolate* isolate,
// Check if we already compiled a wrapper for the function but did not store
// it in the table slot yet.
- entry = WasmInstanceObject::GetOrCreateWasmExportedFunction(isolate, instance,
+ entry = WasmInstanceObject::GetOrCreateWasmExternalFunction(isolate, instance,
function_index);
entries->set(entry_index, *entry);
return entry;
@@ -1726,9 +1710,6 @@ Handle<WasmInstanceObject> WasmInstanceObject::New(
isolate->factory()->NewFixedArray(num_imported_functions);
instance->set_imported_function_refs(*imported_function_refs);
- Handle<Code> centry_stub = CodeFactory::CEntry(isolate);
- instance->set_centry_stub(*centry_stub);
-
instance->SetRawMemory(nullptr, 0);
instance->set_isolate_root(isolate->isolate_root());
instance->set_stack_limit_address(
@@ -1878,27 +1859,27 @@ bool WasmInstanceObject::InitTableEntries(Isolate* isolate,
dst, src, count);
}
-MaybeHandle<WasmExportedFunction> WasmInstanceObject::GetWasmExportedFunction(
+MaybeHandle<WasmExternalFunction> WasmInstanceObject::GetWasmExternalFunction(
Isolate* isolate, Handle<WasmInstanceObject> instance, int index) {
- MaybeHandle<WasmExportedFunction> result;
- if (instance->has_wasm_exported_functions()) {
- Object val = instance->wasm_exported_functions().get(index);
+ MaybeHandle<WasmExternalFunction> result;
+ if (instance->has_wasm_external_functions()) {
+ Object val = instance->wasm_external_functions().get(index);
if (!val.IsUndefined(isolate)) {
- result = Handle<WasmExportedFunction>(WasmExportedFunction::cast(val),
+ result = Handle<WasmExternalFunction>(WasmExternalFunction::cast(val),
isolate);
}
}
return result;
}
-Handle<WasmExportedFunction>
-WasmInstanceObject::GetOrCreateWasmExportedFunction(
+Handle<WasmExternalFunction>
+WasmInstanceObject::GetOrCreateWasmExternalFunction(
Isolate* isolate, Handle<WasmInstanceObject> instance, int function_index) {
- MaybeHandle<WasmExportedFunction> maybe_result =
- WasmInstanceObject::GetWasmExportedFunction(isolate, instance,
+ MaybeHandle<WasmExternalFunction> maybe_result =
+ WasmInstanceObject::GetWasmExternalFunction(isolate, instance,
function_index);
- Handle<WasmExportedFunction> result;
+ Handle<WasmExternalFunction> result;
if (maybe_result.ToHandle(&result)) {
return result;
}
@@ -1923,27 +1904,27 @@ WasmInstanceObject::GetOrCreateWasmExportedFunction(
isolate, function.sig, function.imported);
module_object->export_wrappers().set(wrapper_index, *wrapper);
}
- result = WasmExportedFunction::New(
+ result = Handle<WasmExternalFunction>::cast(WasmExportedFunction::New(
isolate, instance, function_index,
- static_cast<int>(function.sig->parameter_count()), wrapper);
+ static_cast<int>(function.sig->parameter_count()), wrapper));
- WasmInstanceObject::SetWasmExportedFunction(isolate, instance, function_index,
+ WasmInstanceObject::SetWasmExternalFunction(isolate, instance, function_index,
result);
return result;
}
-void WasmInstanceObject::SetWasmExportedFunction(
+void WasmInstanceObject::SetWasmExternalFunction(
Isolate* isolate, Handle<WasmInstanceObject> instance, int index,
- Handle<WasmExportedFunction> val) {
+ Handle<WasmExternalFunction> val) {
Handle<FixedArray> functions;
- if (!instance->has_wasm_exported_functions()) {
- // lazily-allocate the wasm exported functions.
+ if (!instance->has_wasm_external_functions()) {
+ // Lazily allocate the wasm external functions array.
functions = isolate->factory()->NewFixedArray(
static_cast<int>(instance->module()->functions.size()));
- instance->set_wasm_exported_functions(*functions);
+ instance->set_wasm_external_functions(*functions);
} else {
functions =
- Handle<FixedArray>(instance->wasm_exported_functions(), isolate);
+ Handle<FixedArray>(instance->wasm_external_functions(), isolate);
}
functions->set(index, *val);
}
@@ -1968,8 +1949,7 @@ void WasmInstanceObject::ImportWasmJSFunctionIntoTable(
instance->module_object().native_module();
// TODO(mstarzinger): Cache and reuse wrapper code.
const wasm::WasmFeatures enabled = native_module->enabled_features();
- auto resolved =
- compiler::ResolveWasmImportCall(callable, sig, enabled.bigint);
+ auto resolved = compiler::ResolveWasmImportCall(callable, sig, enabled);
compiler::WasmImportCallKind kind = resolved.first;
callable = resolved.second; // Update to ultimate target.
DCHECK_NE(compiler::WasmImportCallKind::kLinkError, kind);
@@ -2183,13 +2163,13 @@ bool WasmCapiFunction::IsWasmCapiFunction(Object object) {
}
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<WasmCapiFunctionData> fun_data =
Handle<WasmCapiFunctionData>::cast(isolate->factory()->NewStruct(
WASM_CAPI_FUNCTION_DATA_TYPE, AllocationType::kOld));
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);
// TODO(jkummerow): Install a JavaScript wrapper. For now, calling
// these functions directly is unsupported; they can only be called
@@ -2301,6 +2281,10 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
if (sig_size > 0) {
serialized_sig->copy_in(0, sig->all().begin(), sig_size);
}
+ // TODO(mstarzinger): Think about caching and sharing the JS-to-JS wrappers
+ // per signature instead of compiling a new one for every instantiation.
+ Handle<Code> wrapper_code =
+ compiler::CompileJSToJSWrapper(isolate, sig).ToHandleChecked();
Handle<WasmJSFunctionData> function_data =
Handle<WasmJSFunctionData>::cast(isolate->factory()->NewStruct(
WASM_JS_FUNCTION_DATA_TYPE, AllocationType::kOld));
@@ -2308,9 +2292,7 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
function_data->set_serialized_parameter_count(parameter_count);
function_data->set_serialized_signature(*serialized_sig);
function_data->set_callable(*callable);
- // TODO(7742): Make this callable by using a proper wrapper code.
- function_data->set_wrapper_code(
- isolate->builtins()->builtin(Builtins::kIllegal));
+ function_data->set_wrapper_code(*wrapper_code);
Handle<String> name = isolate->factory()->Function_string();
if (callable->IsJSFunction()) {
name = JSFunction::GetName(Handle<JSFunction>::cast(callable));
@@ -2319,6 +2301,7 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
NewFunctionArgs args =
NewFunctionArgs::ForWasm(name, function_data, function_map);
Handle<JSFunction> js_function = isolate->factory()->NewFunction(args);
+ js_function->shared().set_internal_formal_parameter_count(parameter_count);
return Handle<WasmJSFunction>::cast(js_function);
}
@@ -2361,6 +2344,11 @@ PodArray<wasm::ValueType> WasmCapiFunction::GetSerializedSignature() const {
return shared().wasm_capi_function_data().serialized_signature();
}
+bool WasmExternalFunction::IsWasmExternalFunction(Object object) {
+ return WasmExportedFunction::IsWasmExportedFunction(object) ||
+ WasmJSFunction::IsWasmJSFunction(object);
+}
+
Handle<WasmExceptionTag> WasmExceptionTag::New(Isolate* isolate, int index) {
Handle<WasmExceptionTag> result =
Handle<WasmExceptionTag>::cast(isolate->factory()->NewStruct(
diff --git a/deps/v8/src/wasm/wasm-objects.h b/deps/v8/src/wasm/wasm-objects.h
index 1200f7040a..c198a9bc63 100644
--- a/deps/v8/src/wasm/wasm-objects.h
+++ b/deps/v8/src/wasm/wasm-objects.h
@@ -41,6 +41,7 @@ class WasmCapiFunction;
class WasmDebugInfo;
class WasmExceptionTag;
class WasmExportedFunction;
+class WasmExternalFunction;
class WasmInstanceObject;
class WasmJSFunction;
class WasmModuleObject;
@@ -139,18 +140,14 @@ class WasmModuleObject : public JSObject {
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
TORQUE_GENERATED_WASM_MODULE_OBJECT_FIELDS)
- // Creates a new {WasmModuleObject} with a new {NativeModule} underneath.
- V8_EXPORT_PRIVATE static Handle<WasmModuleObject> New(
- Isolate* isolate, const wasm::WasmFeatures& enabled,
- std::shared_ptr<const wasm::WasmModule> module,
- OwnedVector<const uint8_t> wire_bytes, Handle<Script> script,
- Handle<ByteArray> asm_js_offset_table);
-
// Creates a new {WasmModuleObject} for an existing {NativeModule} that is
// reference counted and might be shared between multiple Isolates.
V8_EXPORT_PRIVATE static Handle<WasmModuleObject> New(
Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
- Handle<Script> script, size_t code_size_estimate);
+ Handle<Script> script);
+ V8_EXPORT_PRIVATE static Handle<WasmModuleObject> New(
+ Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
+ Handle<Script> script, Handle<FixedArray> export_wrappers);
V8_EXPORT_PRIVATE static Handle<WasmModuleObject> New(
Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
Handle<Script> script, Handle<FixedArray> export_wrappers,
@@ -444,8 +441,7 @@ class WasmInstanceObject : public JSObject {
DECL_OPTIONAL_ACCESSORS(indirect_function_table_refs, FixedArray)
DECL_OPTIONAL_ACCESSORS(managed_native_allocations, Foreign)
DECL_OPTIONAL_ACCESSORS(exceptions_table, FixedArray)
- DECL_ACCESSORS(centry_stub, Code)
- DECL_OPTIONAL_ACCESSORS(wasm_exported_functions, FixedArray)
+ DECL_OPTIONAL_ACCESSORS(wasm_external_functions, FixedArray)
DECL_PRIMITIVE_ACCESSORS(memory_start, byte*)
DECL_PRIMITIVE_ACCESSORS(memory_size, size_t)
DECL_PRIMITIVE_ACCESSORS(memory_mask, size_t)
@@ -504,8 +500,7 @@ class WasmInstanceObject : public JSObject {
V(kIndirectFunctionTablesOffset, kTaggedSize) \
V(kManagedNativeAllocationsOffset, kTaggedSize) \
V(kExceptionsTableOffset, kTaggedSize) \
- V(kCEntryStubOffset, kTaggedSize) \
- V(kWasmExportedFunctionsOffset, kTaggedSize) \
+ V(kWasmExternalFunctionsOffset, kTaggedSize) \
V(kRealStackLimitAddressOffset, kSystemPointerSize) \
V(kDataSegmentStartsOffset, kSystemPointerSize) \
V(kDataSegmentSizesOffset, kSystemPointerSize) \
@@ -544,8 +539,7 @@ class WasmInstanceObject : public JSObject {
kIndirectFunctionTablesOffset,
kManagedNativeAllocationsOffset,
kExceptionsTableOffset,
- kCEntryStubOffset,
- kWasmExportedFunctionsOffset};
+ kWasmExternalFunctionsOffset};
V8_EXPORT_PRIVATE const wasm::WasmModule* module();
@@ -588,22 +582,22 @@ class WasmInstanceObject : public JSObject {
// Iterates all fields in the object except the untagged fields.
class BodyDescriptor;
- static MaybeHandle<WasmExportedFunction> GetWasmExportedFunction(
+ static MaybeHandle<WasmExternalFunction> GetWasmExternalFunction(
Isolate* isolate, Handle<WasmInstanceObject> instance, int index);
- // Acquires the {WasmExportedFunction} for a given {function_index} from the
+ // Acquires the {WasmExternalFunction} for a given {function_index} from the
// cache of the given {instance}, or creates a new {WasmExportedFunction} if
// it does not exist yet. The new {WasmExportedFunction} is added to the
// cache of the {instance} immediately.
- V8_EXPORT_PRIVATE static Handle<WasmExportedFunction>
- GetOrCreateWasmExportedFunction(Isolate* isolate,
+ V8_EXPORT_PRIVATE static Handle<WasmExternalFunction>
+ GetOrCreateWasmExternalFunction(Isolate* isolate,
Handle<WasmInstanceObject> instance,
int function_index);
- static void SetWasmExportedFunction(Isolate* isolate,
+ static void SetWasmExternalFunction(Isolate* isolate,
Handle<WasmInstanceObject> instance,
int index,
- Handle<WasmExportedFunction> val);
+ Handle<WasmExternalFunction> val);
// Imports a constructed {WasmJSFunction} into the indirect function table of
// this instance. Note that this might trigger wrapper compilation, since a
@@ -713,7 +707,7 @@ class WasmCapiFunction : public JSFunction {
static bool IsWasmCapiFunction(Object object);
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);
Address GetHostCallTarget() const;
@@ -726,6 +720,19 @@ class WasmCapiFunction : public JSFunction {
OBJECT_CONSTRUCTORS(WasmCapiFunction, JSFunction);
};
+// Any external function that can be imported/exported in modules. This abstract
+// class just dispatches to the following concrete classes:
+// - {WasmExportedFunction}: A proper Wasm function exported from a module.
+// - {WasmJSFunction}: A function constructed via WebAssembly.Function in JS.
+// // TODO(wasm): Potentially {WasmCapiFunction} will be added here as well.
+class WasmExternalFunction : public JSFunction {
+ public:
+ static bool IsWasmExternalFunction(Object object);
+
+ DECL_CAST(WasmExternalFunction)
+ OBJECT_CONSTRUCTORS(WasmExternalFunction, JSFunction);
+};
+
class WasmIndirectFunctionTable : public Struct {
public:
DECL_PRIMITIVE_ACCESSORS(size, uint32_t)
@@ -757,7 +764,7 @@ class WasmIndirectFunctionTable : public Struct {
class WasmCapiFunctionData : public Struct {
public:
DECL_PRIMITIVE_ACCESSORS(call_target, Address)
- DECL_PRIMITIVE_ACCESSORS(embedder_data, void*)
+ DECL_ACCESSORS(embedder_data, Foreign)
DECL_ACCESSORS(wrapper_code, Code)
DECL_ACCESSORS(serialized_signature, PodArray<wasm::ValueType>)
@@ -769,7 +776,7 @@ class WasmCapiFunctionData : public Struct {
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
TORQUE_GENERATED_WASM_CAPI_FUNCTION_DATA_FIELDS)
- STATIC_ASSERT(kStartOfStrongFieldsOffset == kWrapperCodeOffset);
+ STATIC_ASSERT(kStartOfStrongFieldsOffset == kEmbedderDataOffset);
using BodyDescriptor = FlexibleBodyDescriptor<kStartOfStrongFieldsOffset>;
OBJECT_CONSTRUCTORS(WasmCapiFunctionData, Struct);
@@ -785,7 +792,7 @@ class WasmExportedFunctionData : public Struct {
DECL_INT_ACCESSORS(jump_table_offset)
DECL_INT_ACCESSORS(function_index)
DECL_ACCESSORS(c_wrapper_code, Object)
- DECL_ACCESSORS(wasm_call_target, Smi)
+ DECL_ACCESSORS(wasm_call_target, Object)
DECL_INT_ACCESSORS(packed_args_size)
DECL_CAST(WasmExportedFunctionData)
@@ -914,7 +921,8 @@ class WasmDebugInfo : public Struct {
// header. They are referenced by the following fields:
// - {WasmExceptionObject::exception_tag} : The tag of the exception object.
// - {WasmInstanceObject::exceptions_table}: List of tags used by an instance.
-class WasmExceptionTag : public Struct {
+class WasmExceptionTag
+ : public TorqueGeneratedWasmExceptionTag<WasmExceptionTag, Struct> {
public:
V8_EXPORT_PRIVATE static Handle<WasmExceptionTag> New(Isolate* isolate,
int index);
@@ -924,14 +932,9 @@ class WasmExceptionTag : public Struct {
// least one field, hence this also serves as a padding field for now.
DECL_INT_ACCESSORS(index)
- DECL_CAST(WasmExceptionTag)
DECL_PRINTER(WasmExceptionTag)
- DECL_VERIFIER(WasmExceptionTag)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize,
- TORQUE_GENERATED_WASM_EXCEPTION_TAG_FIELDS)
- OBJECT_CONSTRUCTORS(WasmExceptionTag, Struct);
+ TQ_OBJECT_CONSTRUCTORS(WasmExceptionTag)
};
class AsmWasmData : public Struct {
diff --git a/deps/v8/src/wasm/wasm-opcodes.cc b/deps/v8/src/wasm/wasm-opcodes.cc
index d3fb4c42cf..879da1445b 100644
--- a/deps/v8/src/wasm/wasm-opcodes.cc
+++ b/deps/v8/src/wasm/wasm-opcodes.cc
@@ -10,6 +10,7 @@
#include "src/codegen/signature.h"
#include "src/execution/messages.h"
#include "src/runtime/runtime.h"
+#include "src/wasm/wasm-features.h"
namespace v8 {
namespace internal {
@@ -229,11 +230,16 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_F64x2_OP(Ne, "ne")
CASE_I64x2_OP(Ne, "ne")
CASE_SIMD_OP(Add, "add")
+ CASE_F64x2_OP(Add, "add")
CASE_I64x2_OP(Add, "add")
CASE_SIMD_OP(Sub, "sub")
+ CASE_F64x2_OP(Sub, "sub")
CASE_I64x2_OP(Sub, "sub")
CASE_SIMD_OP(Mul, "mul")
+ CASE_F64x2_OP(Mul, "mul")
CASE_I64x2_OP(Mul, "mul")
+ CASE_F64x2_OP(Div, "div")
+ CASE_F32x4_OP(Div, "div")
CASE_F64x2_OP(Splat, "splat")
CASE_F64x2_OP(Lt, "lt")
CASE_F64x2_OP(Le, "le")
@@ -244,7 +250,9 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_F32x4_OP(AddHoriz, "add_horizontal")
CASE_F32x4_OP(RecipApprox, "recip_approx")
CASE_F32x4_OP(RecipSqrtApprox, "recip_sqrt_approx")
+ CASE_F64x2_OP(Min, "min")
CASE_F32x4_OP(Min, "min")
+ CASE_F64x2_OP(Max, "max")
CASE_F32x4_OP(Max, "max")
CASE_F32x4_OP(Lt, "lt")
CASE_F32x4_OP(Le, "le")
@@ -267,7 +275,9 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_SIMDI_OP(ExtractLane, "extract_lane")
CASE_SIMDI_OP(ReplaceLane, "replace_lane")
CASE_SIGN_OP(SIMDI, Min, "min")
+ CASE_SIGN_OP(I64x2, Min, "min")
CASE_SIGN_OP(SIMDI, Max, "max")
+ CASE_SIGN_OP(I64x2, Max, "max")
CASE_SIGN_OP(SIMDI, Lt, "lt")
CASE_SIGN_OP(I64x2, Lt, "lt")
CASE_SIGN_OP(SIMDI, Le, "le")
@@ -439,12 +449,13 @@ std::ostream& operator<<(std::ostream& os, const FunctionSig& sig) {
return os;
}
-bool IsJSCompatibleSignature(const FunctionSig* sig, bool has_bigint_feature) {
- if (sig->return_count() > 1) {
+bool IsJSCompatibleSignature(const FunctionSig* sig,
+ const WasmFeatures& enabled_features) {
+ if (!enabled_features.mv && sig->return_count() > 1) {
return false;
}
for (auto type : sig->all()) {
- if (!has_bigint_feature && type == kWasmI64) {
+ if (!enabled_features.bigint && type == kWasmI64) {
return false;
}
diff --git a/deps/v8/src/wasm/wasm-opcodes.h b/deps/v8/src/wasm/wasm-opcodes.h
index 22bd47d54b..0b19d7452c 100644
--- a/deps/v8/src/wasm/wasm-opcodes.h
+++ b/deps/v8/src/wasm/wasm-opcodes.h
@@ -15,8 +15,10 @@ namespace internal {
namespace wasm {
+struct WasmFeatures;
+
std::ostream& operator<<(std::ostream& os, const FunctionSig& function);
-bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
+bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&);
// Control expressions and blocks.
#define FOREACH_CONTROL_OPCODE(V) \
@@ -335,6 +337,9 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
V(I8x16Neg, 0xfd51, s_s) \
V(S1x16AnyTrue, 0xfd52, i_s) \
V(S1x16AllTrue, 0xfd53, i_s) \
+ V(I8x16Shl, 0xfd54, s_si) \
+ V(I8x16ShrS, 0xfd55, s_si) \
+ V(I8x16ShrU, 0xfd56, s_si) \
V(I8x16Add, 0xfd57, s_ss) \
V(I8x16AddSaturateS, 0xfd58, s_ss) \
V(I8x16AddSaturateU, 0xfd59, s_ss) \
@@ -349,6 +354,9 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
V(I16x8Neg, 0xfd62, s_s) \
V(S1x8AnyTrue, 0xfd63, i_s) \
V(S1x8AllTrue, 0xfd64, i_s) \
+ V(I16x8Shl, 0xfd65, s_si) \
+ V(I16x8ShrS, 0xfd66, s_si) \
+ V(I16x8ShrU, 0xfd67, s_si) \
V(I16x8Add, 0xfd68, s_ss) \
V(I16x8AddSaturateS, 0xfd69, s_ss) \
V(I16x8AddSaturateU, 0xfd6a, s_ss) \
@@ -363,6 +371,9 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
V(I32x4Neg, 0xfd73, s_s) \
V(S1x4AnyTrue, 0xfd74, i_s) \
V(S1x4AllTrue, 0xfd75, i_s) \
+ V(I32x4Shl, 0xfd76, s_si) \
+ V(I32x4ShrS, 0xfd77, s_si) \
+ V(I32x4ShrU, 0xfd78, s_si) \
V(I32x4Add, 0xfd79, s_ss) \
V(I32x4Sub, 0xfd7c, s_ss) \
V(I32x4Mul, 0xfd7f, s_ss) \
@@ -373,9 +384,16 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
V(I64x2Neg, 0xfd84, s_s) \
V(S1x2AnyTrue, 0xfd85, i_s) \
V(S1x2AllTrue, 0xfd86, i_s) \
+ V(I64x2Shl, 0xfd87, s_si) \
+ V(I64x2ShrS, 0xfd88, s_si) \
+ V(I64x2ShrU, 0xfd89, s_si) \
V(I64x2Add, 0xfd8a, s_ss) \
V(I64x2Sub, 0xfd8d, s_ss) \
V(I64x2Mul, 0xfd8c, s_ss) \
+ V(I64x2MinS, 0xfd8e, s_ss) \
+ V(I64x2MinU, 0xfd8f, s_ss) \
+ V(I64x2MaxS, 0xfd90, s_ss) \
+ V(I64x2MaxU, 0xfd91, s_ss) \
V(F32x4Abs, 0xfd95, s_s) \
V(F32x4Neg, 0xfd96, s_s) \
V(F32x4RecipApprox, 0xfd98, s_s) \
@@ -383,26 +401,33 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
V(F32x4Add, 0xfd9a, s_ss) \
V(F32x4Sub, 0xfd9b, s_ss) \
V(F32x4Mul, 0xfd9c, s_ss) \
+ V(F32x4Div, 0xfd9d, s_ss) \
V(F32x4Min, 0xfd9e, s_ss) \
V(F32x4Max, 0xfd9f, s_ss) \
V(F64x2Abs, 0xfda0, s_s) \
V(F64x2Neg, 0xfda1, s_s) \
+ V(F64x2Add, 0xfda5, s_ss) \
+ V(F64x2Sub, 0xfda6, s_ss) \
+ V(F64x2Mul, 0xfda7, s_ss) \
+ V(F64x2Div, 0xfda8, s_ss) \
+ V(F64x2Min, 0xfda9, s_ss) \
+ V(F64x2Max, 0xfdaa, s_ss) \
V(I32x4SConvertF32x4, 0xfdab, s_s) \
V(I32x4UConvertF32x4, 0xfdac, s_s) \
V(F32x4SConvertI32x4, 0xfdaf, s_s) \
V(F32x4UConvertI32x4, 0xfdb0, s_s) \
- V(I8x16SConvertI16x8, 0xfdb1, s_ss) \
- V(I8x16UConvertI16x8, 0xfdb2, s_ss) \
- V(I16x8SConvertI32x4, 0xfdb3, s_ss) \
- V(I16x8UConvertI32x4, 0xfdb4, s_ss) \
- V(I16x8SConvertI8x16Low, 0xfdb5, s_s) \
- V(I16x8SConvertI8x16High, 0xfdb6, s_s) \
- V(I16x8UConvertI8x16Low, 0xfdb7, s_s) \
- V(I16x8UConvertI8x16High, 0xfdb8, s_s) \
- V(I32x4SConvertI16x8Low, 0xfdb9, s_s) \
- V(I32x4SConvertI16x8High, 0xfdba, s_s) \
- V(I32x4UConvertI16x8Low, 0xfdbb, s_s) \
- V(I32x4UConvertI16x8High, 0xfdbc, s_s) \
+ V(I8x16SConvertI16x8, 0xfdc6, s_ss) \
+ V(I8x16UConvertI16x8, 0xfdc7, s_ss) \
+ V(I16x8SConvertI32x4, 0xfdc8, s_ss) \
+ V(I16x8UConvertI32x4, 0xfdc9, s_ss) \
+ V(I16x8SConvertI8x16Low, 0xfdca, s_s) \
+ V(I16x8SConvertI8x16High, 0xfdcb, s_s) \
+ V(I16x8UConvertI8x16Low, 0xfdcc, s_s) \
+ V(I16x8UConvertI8x16High, 0xfdcd, s_s) \
+ V(I32x4SConvertI16x8Low, 0xfdce, s_s) \
+ V(I32x4SConvertI16x8High, 0xfdcf, s_s) \
+ V(I32x4UConvertI16x8Low, 0xfdd0, s_s) \
+ V(I32x4UConvertI16x8High, 0xfdd1, s_s) \
V(I16x8AddHoriz, 0xfdbd, s_ss) \
V(I32x4AddHoriz, 0xfdbe, s_ss) \
V(F32x4AddHoriz, 0xfdbf, s_ss)
@@ -413,19 +438,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
V(I32x4ExtractLane, 0xfd0d, _) \
V(I64x2ExtractLane, 0xfd10, _) \
V(F32x4ExtractLane, 0xfd13, _) \
- V(F64x2ExtractLane, 0xfd16, _) \
- V(I8x16Shl, 0xfd54, _) \
- V(I8x16ShrS, 0xfd55, _) \
- V(I8x16ShrU, 0xfd56, _) \
- V(I16x8Shl, 0xfd65, _) \
- V(I16x8ShrS, 0xfd66, _) \
- V(I16x8ShrU, 0xfd67, _) \
- V(I32x4Shl, 0xfd76, _) \
- V(I32x4ShrS, 0xfd77, _) \
- V(I32x4ShrU, 0xfd78, _) \
- V(I64x2Shl, 0xfd87, _) \
- V(I64x2ShrS, 0xfd88, _) \
- V(I64x2ShrU, 0xfd89, _)
+ V(F64x2ExtractLane, 0xfd16, _)
#define FOREACH_SIMD_1_OPERAND_2_PARAM_OPCODE(V) \
V(I8x16ReplaceLane, 0xfd07, _) \
@@ -678,6 +691,8 @@ struct WasmInitExpr {
val.global_index = index;
} else if (kind == kRefFuncConst) {
val.function_index = index;
+ } else if (kind == kRefNullConst) {
+ // Nothing to do.
} else {
// For the other types, the other initializers should be used.
UNREACHABLE();
diff --git a/deps/v8/src/wasm/wasm-serialization.cc b/deps/v8/src/wasm/wasm-serialization.cc
index a20b2f115a..81460b9fe2 100644
--- a/deps/v8/src/wasm/wasm-serialization.cc
+++ b/deps/v8/src/wasm/wasm-serialization.cc
@@ -625,12 +625,17 @@ MaybeHandle<WasmModuleObject> DeserializeNativeModule(
Handle<Script> script =
CreateWasmScript(isolate, wire_bytes, module->source_map_url);
- OwnedVector<uint8_t> wire_bytes_copy =
- OwnedVector<uint8_t>::Of(wire_bytes_vec);
+ auto shared_native_module = isolate->wasm_engine()->NewNativeModule(
+ isolate, enabled_features, std::move(decode_result.value()));
+ shared_native_module->SetWireBytes(OwnedVector<uint8_t>::Of(wire_bytes_vec));
+ shared_native_module->SetRuntimeStubs(isolate);
+
+ Handle<FixedArray> export_wrappers;
+ CompileJsToWasmWrappers(isolate, shared_native_module->module(),
+ &export_wrappers);
Handle<WasmModuleObject> module_object = WasmModuleObject::New(
- isolate, enabled_features, std::move(decode_result).value(),
- std::move(wire_bytes_copy), script, Handle<ByteArray>::null());
+ isolate, std::move(shared_native_module), script, export_wrappers);
NativeModule* native_module = module_object->native_module();
NativeModuleDeserializer deserializer(native_module);
@@ -639,9 +644,6 @@ MaybeHandle<WasmModuleObject> DeserializeNativeModule(
Reader reader(data + kVersionSize);
if (!deserializer.Read(&reader)) return {};
- CompileJsToWasmWrappers(isolate, native_module->module(),
- handle(module_object->export_wrappers(), isolate));
-
// Log the code within the generated module for profiling.
native_module->LogWasmCodes(isolate);
diff --git a/deps/v8/src/wasm/wasm-text.cc b/deps/v8/src/wasm/wasm-text.cc
index e17d34e36f..44abd71445 100644
--- a/deps/v8/src/wasm/wasm-text.cc
+++ b/deps/v8/src/wasm/wasm-text.cc
@@ -321,23 +321,6 @@ void PrintWasmText(const WasmModule* module, const ModuleWireBytes& wire_bytes,
break;
}
- case kExprI8x16Shl:
- case kExprI8x16ShrS:
- case kExprI8x16ShrU:
- case kExprI16x8Shl:
- case kExprI16x8ShrS:
- case kExprI16x8ShrU:
- case kExprI32x4Shl:
- case kExprI32x4ShrS:
- case kExprI32x4ShrU:
- case kExprI64x2Shl:
- case kExprI64x2ShrS:
- case kExprI64x2ShrU: {
- SimdShiftImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.shift;
- break;
- }
-
FOREACH_SIMD_0_OPERAND_OPCODE(CASE_OPCODE) {
os << WasmOpcodes::OpcodeName(opcode);
break;