aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/wasm/module-instantiate.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/wasm/module-instantiate.cc')
-rw-r--r--deps/v8/src/wasm/module-instantiate.cc445
1 files changed, 315 insertions, 130 deletions
diff --git a/deps/v8/src/wasm/module-instantiate.cc b/deps/v8/src/wasm/module-instantiate.cc
index 4dc61a91bf..8293674826 100644
--- a/deps/v8/src/wasm/module-instantiate.cc
+++ b/deps/v8/src/wasm/module-instantiate.cc
@@ -5,11 +5,11 @@
#include "src/wasm/module-instantiate.h"
#include "src/asmjs/asm-js.h"
-#include "src/conversions-inl.h"
-#include "src/counters.h"
-#include "src/property-descriptor.h"
+#include "src/logging/counters.h"
+#include "src/numbers/conversions-inl.h"
+#include "src/objects/property-descriptor.h"
#include "src/tracing/trace-event.h"
-#include "src/utils.h"
+#include "src/utils/utils.h"
#include "src/wasm/module-compiler.h"
#include "src/wasm/wasm-external-refs.h"
#include "src/wasm/wasm-import-wrapper-cache.h"
@@ -38,16 +38,76 @@ uint32_t EvalUint32InitExpr(Handle<WasmInstanceObject> instance,
case WasmInitExpr::kGlobalIndex: {
uint32_t offset =
instance->module()->globals[expr.val.global_index].offset;
- auto raw_addr =
- reinterpret_cast<Address>(
- instance->untagged_globals_buffer()->backing_store()) +
- offset;
+ auto raw_addr = reinterpret_cast<Address>(
+ instance->untagged_globals_buffer().backing_store()) +
+ offset;
return ReadLittleEndianValue<uint32_t>(raw_addr);
}
default:
UNREACHABLE();
}
}
+
+// Queue of import wrapper keys to compile for an instance.
+class ImportWrapperQueue {
+ public:
+ // Removes an arbitrary cache key from the queue and returns it.
+ // If the queue is empty, returns nullopt.
+ // Thread-safe.
+ base::Optional<WasmImportWrapperCache::CacheKey> pop() {
+ base::Optional<WasmImportWrapperCache::CacheKey> key = base::nullopt;
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ auto it = queue_.begin();
+ if (it != queue_.end()) {
+ key = *it;
+ queue_.erase(it);
+ }
+ return key;
+ }
+
+ // Add the given key to the queue.
+ // Not thread-safe.
+ void insert(const WasmImportWrapperCache::CacheKey& key) {
+ queue_.insert(key);
+ }
+
+ private:
+ base::Mutex mutex_;
+ std::unordered_set<WasmImportWrapperCache::CacheKey,
+ WasmImportWrapperCache::CacheKeyHash>
+ queue_;
+};
+
+class CompileImportWrapperTask final : public CancelableTask {
+ public:
+ CompileImportWrapperTask(
+ CancelableTaskManager* task_manager, WasmEngine* engine,
+ Counters* counters, NativeModule* native_module,
+ ImportWrapperQueue* queue,
+ WasmImportWrapperCache::ModificationScope* cache_scope)
+ : CancelableTask(task_manager),
+ engine_(engine),
+ counters_(counters),
+ native_module_(native_module),
+ queue_(queue),
+ cache_scope_(cache_scope) {}
+
+ void RunInternal() override {
+ while (base::Optional<WasmImportWrapperCache::CacheKey> key =
+ queue_->pop()) {
+ CompileImportWrapper(engine_, native_module_, counters_, key->first,
+ key->second, cache_scope_);
+ }
+ }
+
+ private:
+ WasmEngine* const engine_;
+ Counters* const counters_;
+ NativeModule* const native_module_;
+ ImportWrapperQueue* const queue_;
+ WasmImportWrapperCache::ModificationScope* const cache_scope_;
+};
+
} // namespace
// A helper class to simplify instantiating a module from a module object.
@@ -140,6 +200,11 @@ class InstanceBuilder {
Handle<String> import_name,
Handle<Object> value);
+ // Initialize imported tables of type anyfunc.
+ bool InitializeImportedIndirectFunctionTable(
+ Handle<WasmInstanceObject> instance, int import_index,
+ Handle<WasmTableObject> table_object);
+
// Process a single imported table.
bool ProcessImportedTable(Handle<WasmInstanceObject> instance,
int import_index, int table_index,
@@ -165,6 +230,10 @@ class InstanceBuilder {
const WasmGlobal& global,
Handle<WasmGlobalObject> global_object);
+ // Compile import wrappers in parallel. The result goes into the native
+ // module's import_wrapper_cache.
+ void CompileImportWrappers(Handle<WasmInstanceObject> instance);
+
// Process the imports, including functions, tables, globals, and memory, in
// order, loading them from the {ffi_} object. Returns the number of imported
// functions.
@@ -174,7 +243,7 @@ class InstanceBuilder {
T* GetRawGlobalPtr(const WasmGlobal& global);
// Process initialization of globals.
- void InitGlobals();
+ void InitGlobals(Handle<WasmInstanceObject> instance);
// Allocate memory for a module instance as a new JSArrayBuffer.
Handle<JSArrayBuffer> AllocateMemory(uint32_t initial_pages,
@@ -371,7 +440,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
//--------------------------------------------------------------------------
// Process the initialization for the module's globals.
//--------------------------------------------------------------------------
- InitGlobals();
+ InitGlobals(instance);
//--------------------------------------------------------------------------
// Initialize the indirect tables.
@@ -424,10 +493,10 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
uint32_t base = EvalUint32InitExpr(instance, elem_segment.offset);
// Because of imported tables, {table_size} has to come from the table
// object itself.
- auto table_object = handle(WasmTableObject::cast(instance->tables()->get(
+ auto table_object = handle(WasmTableObject::cast(instance->tables().get(
elem_segment.table_index)),
isolate_);
- size_t table_size = table_object->elements()->length();
+ size_t table_size = table_object->entries().length();
if (!IsInBounds(base, elem_segment.entries.size(), table_size)) {
thrower_->LinkError("table initializer is out of bounds");
return {};
@@ -487,7 +556,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
// TODO(clemensh): Don't generate an exported function for the start
// function. Use CWasmEntry instead.
start_function_ = WasmExportedFunction::New(
- isolate_, instance, MaybeHandle<String>(), start_index,
+ isolate_, instance, start_index,
static_cast<int>(function.sig->parameter_count()), wrapper_code);
}
@@ -601,7 +670,7 @@ void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
static_cast<uint32_t>(instance->memory_size()));
Address dest_addr =
reinterpret_cast<Address>(instance->memory_start()) + dest_offset;
- Address src_addr = reinterpret_cast<Address>(wire_bytes.start()) +
+ Address src_addr = reinterpret_cast<Address>(wire_bytes.begin()) +
segment.source.offset();
memory_copy_wrapper(dest_addr, src_addr, size);
if (!ok) {
@@ -616,7 +685,7 @@ void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
uint32_t dest_offset = EvalUint32InitExpr(instance, segment.dest_addr);
DCHECK(IsInBounds(dest_offset, size, instance->memory_size()));
byte* dest = instance->memory_start() + dest_offset;
- const byte* src = wire_bytes.start() + segment.source.offset();
+ const byte* src = wire_bytes.begin() + segment.source.offset();
memcpy(dest, src, size);
}
}
@@ -624,8 +693,8 @@ void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global, double num) {
TRACE("init [globals_start=%p + %u] = %lf, type = %s\n",
- reinterpret_cast<void*>(raw_buffer_ptr(untagged_globals_, 0)),
- global.offset, num, ValueTypes::TypeName(global.type));
+ raw_buffer_ptr(untagged_globals_, 0), global.offset, num,
+ ValueTypes::TypeName(global.type));
switch (global.type) {
case kWasmI32:
WriteLittleEndianValue<int32_t>(GetRawGlobalPtr<int32_t>(global),
@@ -636,7 +705,6 @@ void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global, double num) {
// only be initialized with BigInts. See:
// https://github.com/WebAssembly/JS-BigInt-integration/issues/12
UNREACHABLE();
- break;
case kWasmF32:
WriteLittleEndianValue<float>(GetRawGlobalPtr<float>(global),
DoubleToFloat32(num));
@@ -651,16 +719,15 @@ void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global, double num) {
void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global, int64_t num) {
TRACE("init [globals_start=%p + %u] = %" PRId64 ", type = %s\n",
- reinterpret_cast<void*>(raw_buffer_ptr(untagged_globals_, 0)),
- global.offset, num, ValueTypes::TypeName(global.type));
+ raw_buffer_ptr(untagged_globals_, 0), global.offset, num,
+ ValueTypes::TypeName(global.type));
DCHECK_EQ(kWasmI64, global.type);
WriteLittleEndianValue<int64_t>(GetRawGlobalPtr<int64_t>(global), num);
}
void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global,
Handle<WasmGlobalObject> value) {
- TRACE("init [globals_start=%p + %u] = ",
- reinterpret_cast<void*>(raw_buffer_ptr(untagged_globals_, 0)),
+ TRACE("init [globals_start=%p + %u] = ", raw_buffer_ptr(untagged_globals_, 0),
global.offset);
switch (global.type) {
case kWasmI32: {
@@ -687,6 +754,12 @@ void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global,
TRACE("%lf", num);
break;
}
+ case kWasmAnyRef:
+ case kWasmAnyFunc:
+ case kWasmExceptRef: {
+ tagged_globals_->set(global.offset, *value->GetRef());
+ break;
+ }
default:
UNREACHABLE();
}
@@ -785,13 +858,35 @@ 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: {
+ NativeModule* native_module = instance->module_object().native_module();
+ Address host_address = WasmCapiFunction::cast(*value).GetHostCallTarget();
+ WasmCodeRefScope code_ref_scope;
+ WasmCode* wasm_code = compiler::CompileWasmCapiCallWrapper(
+ isolate_->wasm_engine(), native_module, expected_sig, host_address);
+ isolate_->counters()->wasm_generated_code_size()->Increment(
+ wasm_code->instructions().length());
+ isolate_->counters()->wasm_reloc_size()->Increment(
+ wasm_code->reloc_info().length());
+
+ ImportedFunctionEntry entry(instance, func_index);
+ // We re-use the SetWasmToJs infrastructure because it passes the
+ // callable to the wrapper, which we need to get the function data.
+ entry.SetWasmToJs(isolate_, js_receiver, wasm_code);
break;
}
default: {
// The imported function is a callable.
- NativeModule* native_module = instance->module_object()->native_module();
- WasmCode* wasm_code = native_module->import_wrapper_cache()->GetOrCompile(
- isolate_->wasm_engine(), isolate_->counters(), kind, expected_sig);
+ NativeModule* native_module = instance->module_object().native_module();
+ WasmCode* wasm_code =
+ native_module->import_wrapper_cache()->Get(kind, expected_sig);
+ DCHECK_NOT_NULL(wasm_code);
ImportedFunctionEntry entry(instance, func_index);
if (wasm_code->kind() == WasmCode::kWasmToJsWrapper) {
// Wasm to JS wrappers are treated specially in the import table.
@@ -808,6 +903,49 @@ bool InstanceBuilder::ProcessImportedFunction(
return true;
}
+bool InstanceBuilder::InitializeImportedIndirectFunctionTable(
+ Handle<WasmInstanceObject> instance, int import_index,
+ Handle<WasmTableObject> table_object) {
+ int imported_table_size = table_object->entries().length();
+ // Allocate a new dispatch table.
+ if (!instance->has_indirect_function_table()) {
+ WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
+ instance, imported_table_size);
+ }
+ // Initialize the dispatch table with the (foreign) JS functions
+ // that are already in the table.
+ for (int i = 0; i < imported_table_size; ++i) {
+ bool is_valid;
+ bool is_null;
+ MaybeHandle<WasmInstanceObject> maybe_target_instance;
+ int function_index;
+ WasmTableObject::GetFunctionTableEntry(isolate_, table_object, i, &is_valid,
+ &is_null, &maybe_target_instance,
+ &function_index);
+ if (!is_valid) {
+ thrower_->LinkError("table import %d[%d] is not a wasm function",
+ import_index, i);
+ return false;
+ }
+ if (is_null) continue;
+
+ Handle<WasmInstanceObject> target_instance =
+ maybe_target_instance.ToHandleChecked();
+ FunctionSig* sig = target_instance->module_object()
+ .module()
+ ->functions[function_index]
+ .sig;
+
+ // Look up the signature's canonical id. If there is no canonical
+ // id, then the signature does not appear at all in this module,
+ // so putting {-1} in the table will cause checks to always fail.
+ IndirectFunctionTableEntry(instance, i)
+ .Set(module_->signature_map.Find(*sig), target_instance,
+ function_index);
+ }
+ return true;
+}
+
bool InstanceBuilder::ProcessImportedTable(Handle<WasmInstanceObject> instance,
int import_index, int table_index,
Handle<String> module_name,
@@ -820,10 +958,10 @@ bool InstanceBuilder::ProcessImportedTable(Handle<WasmInstanceObject> instance,
}
const WasmTable& table = module_->tables[table_index];
- instance->tables()->set(table_index, *value);
+ instance->tables().set(table_index, *value);
auto table_object = Handle<WasmTableObject>::cast(value);
- int imported_table_size = table_object->elements().length();
+ int imported_table_size = table_object->entries().length();
if (imported_table_size < static_cast<int>(table.initial_size)) {
thrower_->LinkError("table import %d is smaller than initial %d, got %u",
import_index, table.initial_size, imported_table_size);
@@ -831,12 +969,12 @@ bool InstanceBuilder::ProcessImportedTable(Handle<WasmInstanceObject> instance,
}
if (table.has_maximum_size) {
- if (table_object->maximum_length()->IsUndefined(isolate_)) {
+ if (table_object->maximum_length().IsUndefined(isolate_)) {
thrower_->LinkError("table import %d has no maximum length, expected %d",
import_index, table.maximum_size);
return false;
}
- int64_t imported_maximum_size = table_object->maximum_length()->Number();
+ int64_t imported_maximum_size = table_object->maximum_length().Number();
if (imported_maximum_size < 0) {
thrower_->LinkError("table import %d has no maximum length, expected %d",
import_index, table.maximum_size);
@@ -851,42 +989,19 @@ bool InstanceBuilder::ProcessImportedTable(Handle<WasmInstanceObject> instance,
}
}
- // Allocate a new dispatch table.
- if (!instance->has_indirect_function_table()) {
- WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
- instance, imported_table_size);
+ if (table.type != table_object->type()) {
+ ReportLinkError("imported table does not match the expected type",
+ import_index, module_name, import_name);
+ return false;
}
- // Initialize the dispatch table with the (foreign) JS functions
- // that are already in the table.
- for (int i = 0; i < imported_table_size; ++i) {
- bool is_valid;
- bool is_null;
- MaybeHandle<WasmInstanceObject> maybe_target_instance;
- int function_index;
- WasmTableObject::GetFunctionTableEntry(isolate_, table_object, i, &is_valid,
- &is_null, &maybe_target_instance,
- &function_index);
- if (!is_valid) {
- thrower_->LinkError("table import %d[%d] is not a wasm function",
- import_index, i);
- return false;
- }
- if (is_null) continue;
- Handle<WasmInstanceObject> target_instance =
- maybe_target_instance.ToHandleChecked();
- FunctionSig* sig = target_instance->module_object()
- ->module()
- ->functions[function_index]
- .sig;
-
- // Look up the signature's canonical id. If there is no canonical
- // id, then the signature does not appear at all in this module,
- // so putting {-1} in the table will cause checks to always fail.
- IndirectFunctionTableEntry(instance, i)
- .Set(module_->signature_map.Find(*sig), target_instance,
- function_index);
+ // The indirect function table only exists for table 0.
+ if (table.type == kWasmAnyFunc && table_index == 0 &&
+ !InitializeImportedIndirectFunctionTable(instance, import_index,
+ table_object)) {
+ return false;
}
+
return true;
}
@@ -947,13 +1062,18 @@ bool InstanceBuilder::ProcessImportedWasmGlobalObject(
Handle<WasmInstanceObject> instance, int import_index,
Handle<String> module_name, Handle<String> import_name,
const WasmGlobal& global, Handle<WasmGlobalObject> global_object) {
- if (global_object->type() != global.type) {
- ReportLinkError("imported global does not match the expected type",
+ if (global_object->is_mutable() != global.mutability) {
+ ReportLinkError("imported global does not match the expected mutability",
import_index, module_name, import_name);
return false;
}
- if (global_object->is_mutable() != global.mutability) {
- ReportLinkError("imported global does not match the expected mutability",
+
+ bool is_sub_type = ValueTypes::IsSubType(global.type, global_object->type());
+ bool is_same_type = global_object->type() == global.type;
+ bool valid_type = global.mutability ? is_same_type : is_sub_type;
+
+ if (!valid_type) {
+ ReportLinkError("imported global does not match the expected type",
import_index, module_name, import_name);
return false;
}
@@ -976,7 +1096,7 @@ bool InstanceBuilder::ProcessImportedWasmGlobalObject(
address_or_offset = reinterpret_cast<Address>(raw_buffer_ptr(
Handle<JSArrayBuffer>::cast(buffer), global_object->offset()));
}
- instance->imported_mutable_globals_buffers()->set(global.index, *buffer);
+ instance->imported_mutable_globals_buffers().set(global.index, *buffer);
instance->imported_mutable_globals()[global.index] = address_or_offset;
return true;
}
@@ -1075,6 +1195,62 @@ bool InstanceBuilder::ProcessImportedGlobal(Handle<WasmInstanceObject> instance,
return false;
}
+void InstanceBuilder::CompileImportWrappers(
+ Handle<WasmInstanceObject> instance) {
+ int num_imports = static_cast<int>(module_->import_table.size());
+ NativeModule* native_module = instance->module_object().native_module();
+ WasmImportWrapperCache::ModificationScope cache_scope(
+ native_module->import_wrapper_cache());
+
+ // Compilation is done in two steps:
+ // 1) Insert nullptr entries in the cache for wrappers that need to be
+ // compiled. 2) Compile wrappers in background tasks using the
+ // ImportWrapperQueue. This way the cache won't invalidate other iterators
+ // when inserting a new WasmCode, since the key will already be there.
+ ImportWrapperQueue import_wrapper_queue;
+ for (int index = 0; index < num_imports; ++index) {
+ Handle<Object> value = sanitized_imports_[index].value;
+ if (module_->import_table[index].kind != kExternalFunction ||
+ !value->IsCallable()) {
+ continue;
+ }
+ auto js_receiver = Handle<JSReceiver>::cast(value);
+ uint32_t func_index = module_->import_table[index].index;
+ FunctionSig* sig = module_->functions[func_index].sig;
+ auto kind =
+ compiler::GetWasmImportCallKind(js_receiver, sig, enabled_.bigint);
+ if (kind == compiler::WasmImportCallKind::kWasmToWasm ||
+ kind == compiler::WasmImportCallKind::kLinkError ||
+ kind == compiler::WasmImportCallKind::kWasmToCapi) {
+ continue;
+ }
+ WasmImportWrapperCache::CacheKey key(kind, sig);
+ if (cache_scope[key] != nullptr) {
+ // Cache entry already exists, no need to compile it again.
+ continue;
+ }
+ import_wrapper_queue.insert(key);
+ }
+
+ CancelableTaskManager task_manager;
+ const int max_background_tasks = GetMaxBackgroundTasks();
+ for (int i = 0; i < max_background_tasks; ++i) {
+ auto task = base::make_unique<CompileImportWrapperTask>(
+ &task_manager, isolate_->wasm_engine(), isolate_->counters(),
+ native_module, &import_wrapper_queue, &cache_scope);
+ V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task));
+ }
+
+ // Also compile in the current thread, in case there are no worker threads.
+ while (base::Optional<WasmImportWrapperCache::CacheKey> key =
+ import_wrapper_queue.pop()) {
+ CompileImportWrapper(isolate_->wasm_engine(), native_module,
+ isolate_->counters(), key->first, key->second,
+ &cache_scope);
+ }
+ task_manager.CancelAndWait();
+}
+
// Process the imports, including functions, tables, globals, and memory, in
// order, loading them from the {ffi_} object. Returns the number of imported
// functions.
@@ -1083,6 +1259,8 @@ int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
int num_imported_tables = 0;
DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size());
+
+ CompileImportWrappers(instance);
int num_imports = static_cast<int>(module_->import_table.size());
for (int index = 0; index < num_imports; ++index) {
const WasmImport& import = module_->import_table[index];
@@ -1141,8 +1319,8 @@ int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
return -1;
}
Object exception_tag = imported_exception->exception_tag();
- DCHECK(instance->exceptions_table()->get(import.index)->IsUndefined());
- instance->exceptions_table()->set(import.index, exception_tag);
+ DCHECK(instance->exceptions_table().get(import.index).IsUndefined());
+ instance->exceptions_table().set(import.index, exception_tag);
exception_wrappers_[import.index] = imported_exception;
break;
}
@@ -1160,7 +1338,7 @@ T* InstanceBuilder::GetRawGlobalPtr(const WasmGlobal& global) {
}
// Process initialization of globals.
-void InstanceBuilder::InitGlobals() {
+void InstanceBuilder::InitGlobals(Handle<WasmInstanceObject> instance) {
for (auto global : module_->globals) {
if (global.mutability && global.imported) {
continue;
@@ -1191,6 +1369,13 @@ void InstanceBuilder::InitGlobals() {
ReadOnlyRoots(isolate_).null_value(),
SKIP_WRITE_BARRIER);
break;
+ case WasmInitExpr::kRefFuncConst: {
+ DCHECK(enabled_.anyref);
+ auto function = WasmInstanceObject::GetOrCreateWasmExportedFunction(
+ isolate_, instance, global.init.val.function_index);
+ tagged_globals_->set(global.offset, *function);
+ break;
+ }
case WasmInitExpr::kGlobalIndex: {
// Initialize with another global.
uint32_t new_offset = global.offset;
@@ -1254,8 +1439,6 @@ bool InstanceBuilder::NeedsWrappers() const {
// Process the exports, creating wrappers for functions, tables, memories,
// globals, and exceptions.
void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
- Handle<FixedArray> export_wrappers(module_object_->export_wrappers(),
- isolate_);
if (NeedsWrappers()) {
// If an imported WebAssembly function gets exported, the exported function
// has to be identical to to imported function. Therefore we cache all
@@ -1303,7 +1486,6 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
desc.set_configurable(is_asm_js);
// Process each export in the export table.
- int export_index = 0; // Index into {export_wrappers}.
for (const WasmExport& exp : module_->export_table) {
Handle<String> name = WasmModuleObject::ExtractUtf8StringFromModuleBytes(
isolate_, module_object_, exp.name)
@@ -1320,37 +1502,15 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
case kExternalFunction: {
// Wrap and export the code as a JSFunction.
// TODO(wasm): reduce duplication with LoadElemSegment() further below
- const WasmFunction& function = module_->functions[exp.index];
MaybeHandle<WasmExportedFunction> wasm_exported_function =
- WasmInstanceObject::GetWasmExportedFunction(isolate_, instance,
- exp.index);
- if (wasm_exported_function.is_null()) {
- // Wrap the exported code as a JSFunction.
- Handle<Code> export_code =
- export_wrappers->GetValueChecked<Code>(isolate_, export_index);
- MaybeHandle<String> func_name;
- if (is_asm_js) {
- // For modules arising from asm.js, honor the names section.
- WireBytesRef func_name_ref = module_->LookupFunctionName(
- ModuleWireBytes(module_object_->native_module()->wire_bytes()),
- function.func_index);
- func_name = WasmModuleObject::ExtractUtf8StringFromModuleBytes(
- isolate_, module_object_, func_name_ref)
- .ToHandleChecked();
- }
- wasm_exported_function = WasmExportedFunction::New(
- isolate_, instance, func_name, function.func_index,
- static_cast<int>(function.sig->parameter_count()), export_code);
- WasmInstanceObject::SetWasmExportedFunction(
- isolate_, instance, exp.index,
- wasm_exported_function.ToHandleChecked());
- }
+ WasmInstanceObject::GetOrCreateWasmExportedFunction(
+ isolate_, instance, exp.index);
+
desc.set_value(wasm_exported_function.ToHandleChecked());
- export_index++;
break;
}
case kExternalTable: {
- desc.set_value(handle(instance->tables()->get(exp.index), isolate_));
+ desc.set_value(handle(instance->tables().get(exp.index), isolate_));
break;
}
case kExternalMemory: {
@@ -1372,8 +1532,8 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
Handle<FixedArray> buffers_array(
instance->imported_mutable_globals_buffers(), isolate_);
if (ValueTypes::IsReferenceType(global.type)) {
- tagged_buffer = buffers_array->GetValueChecked<FixedArray>(
- isolate_, global.index);
+ tagged_buffer = handle(
+ FixedArray::cast(buffers_array->get(global.index)), isolate_);
// For anyref globals we store the relative offset in the
// imported_mutable_globals array instead of an absolute address.
Address addr = instance->imported_mutable_globals()[global.index];
@@ -1381,8 +1541,9 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
std::numeric_limits<uint32_t>::max()));
offset = static_cast<uint32_t>(addr);
} else {
- untagged_buffer = buffers_array->GetValueChecked<JSArrayBuffer>(
- isolate_, global.index);
+ untagged_buffer =
+ handle(JSArrayBuffer::cast(buffers_array->get(global.index)),
+ isolate_);
Address global_addr =
instance->imported_mutable_globals()[global.index];
@@ -1417,7 +1578,7 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
Handle<WasmExceptionObject> wrapper = exception_wrappers_[exp.index];
if (wrapper.is_null()) {
Handle<HeapObject> exception_tag(
- HeapObject::cast(instance->exceptions_table()->get(exp.index)),
+ HeapObject::cast(instance->exceptions_table().get(exp.index)),
isolate_);
wrapper =
WasmExceptionObject::New(isolate_, exception.sig, exception_tag);
@@ -1441,7 +1602,6 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
return;
}
}
- DCHECK_EQ(export_index, export_wrappers->length());
if (module_->origin == kWasmOrigin) {
v8::Maybe<bool> success =
@@ -1472,7 +1632,7 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
// for both instantiation and in the implementation of the table.init
// instruction.
bool ok =
- ClampToBounds<size_t>(dst, &count, table_object->elements()->length());
+ ClampToBounds<size_t>(dst, &count, table_object->entries().length());
// Use & instead of && so the clamp is not short-circuited.
ok &= ClampToBounds<size_t>(src, &count, elem_segment.entries.size());
@@ -1482,7 +1642,9 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
int entry_index = static_cast<int>(dst + i);
if (func_index == WasmElemSegment::kNullIndex) {
- IndirectFunctionTableEntry(instance, entry_index).clear();
+ if (table_object->type() == kWasmAnyFunc) {
+ IndirectFunctionTableEntry(instance, entry_index).clear();
+ }
WasmTableObject::Set(isolate, table_object, entry_index,
isolate->factory()->null_value());
continue;
@@ -1490,28 +1652,44 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
const WasmFunction* function = &module->functions[func_index];
- // Update the local dispatch table first.
- uint32_t sig_id = module->signature_ids[function->sig_index];
- IndirectFunctionTableEntry(instance, entry_index)
- .Set(sig_id, instance, func_index);
-
- // Update the table object's other dispatch tables.
- MaybeHandle<WasmExportedFunction> wasm_exported_function =
- WasmInstanceObject::GetWasmExportedFunction(isolate, instance,
- func_index);
- if (wasm_exported_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);
+ // Update the local dispatch table first if necessary. We only have to
+ // update the dispatch table if the first table of the instance is changed.
+ // For all other tables, function calls do not use a dispatch table at
+ // the moment.
+ if (elem_segment.table_index == 0 && table_object->type() == kWasmAnyFunc) {
+ uint32_t sig_id = module->signature_ids[function->sig_index];
+ IndirectFunctionTableEntry(instance, entry_index)
+ .Set(sig_id, instance, func_index);
+ }
+
+ // For AnyRef tables, we have to generate the WasmExportedFunction 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,
+ func_index);
+ WasmTableObject::Set(isolate, table_object, entry_index,
+ wasm_exported_function);
} else {
- table_object->elements()->set(entry_index,
+ // Update the table object's other dispatch tables.
+ MaybeHandle<WasmExportedFunction> wasm_exported_function =
+ WasmInstanceObject::GetWasmExportedFunction(isolate, instance,
+ func_index);
+ if (wasm_exported_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());
+ }
+ // UpdateDispatchTables() updates all other dispatch tables, since
+ // we have not yet added the dispatch table we are currently building.
+ WasmTableObject::UpdateDispatchTables(isolate, table_object, entry_index,
+ function->sig, instance,
+ func_index);
}
- // UpdateDispatchTables() updates all other dispatch tables, since
- // we have not yet added the dispatch table we are currently building.
- WasmTableObject::UpdateDispatchTables(isolate, table_object, entry_index,
- function->sig, instance, func_index);
}
return ok;
}
@@ -1528,7 +1706,7 @@ void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
bool success = LoadElemSegmentImpl(
isolate_, instance,
handle(WasmTableObject::cast(
- instance->tables()->get(elem_segment.table_index)),
+ instance->tables().get(elem_segment.table_index)),
isolate_),
elem_segment, dst, src, count);
if (enabled_.bulk_memory) {
@@ -1548,7 +1726,7 @@ void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
for (int index = 0; index < table_count; ++index) {
if (module_->tables[index].type == kWasmAnyFunc) {
auto table_object = handle(
- WasmTableObject::cast(instance->tables()->get(index)), isolate_);
+ WasmTableObject::cast(instance->tables().get(index)), isolate_);
// Add the new dispatch table at the end to avoid redundant lookups.
WasmTableObject::AddDispatchTable(isolate_, table_object, instance,
@@ -1561,7 +1739,7 @@ void InstanceBuilder::InitializeExceptions(
Handle<WasmInstanceObject> instance) {
Handle<FixedArray> exceptions_table(instance->exceptions_table(), isolate_);
for (int index = 0; index < exceptions_table->length(); ++index) {
- if (!exceptions_table->get(index)->IsUndefined(isolate_)) continue;
+ if (!exceptions_table->get(index).IsUndefined(isolate_)) continue;
Handle<WasmExceptionTag> exception_tag =
WasmExceptionTag::New(isolate_, index);
exceptions_table->set(index, *exception_tag);
@@ -1571,10 +1749,17 @@ void InstanceBuilder::InitializeExceptions(
bool LoadElemSegment(Isolate* isolate, Handle<WasmInstanceObject> instance,
uint32_t table_index, uint32_t segment_index, uint32_t dst,
uint32_t src, uint32_t count) {
+ // This code path is only used for passive element segments with the
+ // table.init instruction. This instruction was introduced in the
+ // bulk-memory-operations proposal. At the moment, table.init can only operate
+ // on table-0. If table.init should work for tables with higher indices, then
+ // we have to adjust the code in {LoadElemSegmentImpl}. The code there uses
+ // {IndirectFunctionTableEntry} at the moment, which only works for table-0.
+ CHECK_EQ(table_index, 0);
auto& elem_segment = instance->module()->elem_segments[segment_index];
return LoadElemSegmentImpl(
isolate, instance,
- handle(WasmTableObject::cast(instance->tables()->get(table_index)),
+ handle(WasmTableObject::cast(instance->tables().get(table_index)),
isolate),
elem_segment, dst, src, count);
}