diff options
Diffstat (limited to 'deps/v8/src/wasm/module-instantiate.cc')
-rw-r--r-- | deps/v8/src/wasm/module-instantiate.cc | 445 |
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); } |