diff options
Diffstat (limited to 'deps/v8/src/wasm/module-instantiate.cc')
-rw-r--r-- | deps/v8/src/wasm/module-instantiate.cc | 240 |
1 files changed, 118 insertions, 122 deletions
diff --git a/deps/v8/src/wasm/module-instantiate.cc b/deps/v8/src/wasm/module-instantiate.cc index 976c3cde00..95d892ab50 100644 --- a/deps/v8/src/wasm/module-instantiate.cc +++ b/deps/v8/src/wasm/module-instantiate.cc @@ -93,7 +93,7 @@ class InstanceBuilder { InstanceBuilder(Isolate* isolate, ErrorThrower* thrower, Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> ffi, - MaybeHandle<JSArrayBuffer> memory); + MaybeHandle<JSArrayBuffer> memory_buffer); // Build an instance, in all of its glory. MaybeHandle<WasmInstanceObject> Build(); @@ -114,7 +114,8 @@ class InstanceBuilder { ErrorThrower* thrower_; Handle<WasmModuleObject> module_object_; MaybeHandle<JSReceiver> ffi_; - MaybeHandle<JSArrayBuffer> memory_; + MaybeHandle<JSArrayBuffer> memory_buffer_; + Handle<WasmMemoryObject> memory_object_; Handle<JSArrayBuffer> untagged_globals_; Handle<FixedArray> tagged_globals_; std::vector<Handle<WasmExceptionObject>> exception_wrappers_; @@ -165,9 +166,11 @@ class InstanceBuilder { void SanitizeImports(); - // Find the imported memory buffer if there is one. This is used to see if we - // need to recompile with bounds checks before creating the instance. - MaybeHandle<JSArrayBuffer> FindImportedMemoryBuffer() const; + // Find the imported memory if there is one. + bool FindImportedMemory(); + + // Allocate the memory. + bool AllocateMemory(); // Processes a single imported function. bool ProcessImportedFunction(Handle<WasmInstanceObject> instance, @@ -221,9 +224,6 @@ class InstanceBuilder { // Process initialization of globals. void InitGlobals(Handle<WasmInstanceObject> instance); - // Allocate memory for a module instance as a new JSArrayBuffer. - Handle<JSArrayBuffer> AllocateMemory(uint32_t initial_pages, - uint32_t maximum_pages); bool NeedsWrappers() const; @@ -243,8 +243,9 @@ class InstanceBuilder { MaybeHandle<WasmInstanceObject> InstantiateToInstanceObject( Isolate* isolate, ErrorThrower* thrower, Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports, - MaybeHandle<JSArrayBuffer> memory) { - InstanceBuilder builder(isolate, thrower, module_object, imports, memory); + MaybeHandle<JSArrayBuffer> memory_buffer) { + InstanceBuilder builder(isolate, thrower, module_object, imports, + memory_buffer); auto instance = builder.Build(); if (!instance.is_null() && builder.ExecuteStartFunction()) { return instance; @@ -256,14 +257,14 @@ MaybeHandle<WasmInstanceObject> InstantiateToInstanceObject( InstanceBuilder::InstanceBuilder(Isolate* isolate, ErrorThrower* thrower, Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> ffi, - MaybeHandle<JSArrayBuffer> memory) + MaybeHandle<JSArrayBuffer> memory_buffer) : isolate_(isolate), enabled_(module_object->native_module()->enabled_features()), module_(module_object->module()), thrower_(thrower), module_object_(module_object), ffi_(ffi), - memory_(memory) { + memory_buffer_(memory_buffer) { sanitized_imports_.reserve(module_->import_table.size()); } @@ -289,7 +290,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() { NativeModule* native_module = module_object_->native_module(); //-------------------------------------------------------------------------- - // Allocate the memory array buffer. + // Set up the memory buffer and memory objects. //-------------------------------------------------------------------------- uint32_t initial_pages = module_->initial_pages; auto initial_pages_counter = SELECT_WASM_COUNTER( @@ -301,29 +302,41 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() { isolate_->counters()->wasm_wasm_max_mem_pages_count(); max_pages_counter->AddSample(module_->maximum_pages); } - // Asm.js has memory_ already set at this point, so we don't want to - // overwrite it. - if (memory_.is_null()) { - memory_ = FindImportedMemoryBuffer(); - } - if (!memory_.is_null()) { - // Set externally passed ArrayBuffer non detachable. - Handle<JSArrayBuffer> memory = memory_.ToHandleChecked(); - memory->set_is_detachable(false); - - DCHECK_IMPLIES(native_module->use_trap_handler(), - is_asmjs_module(module_) || memory->is_wasm_memory() || - memory->backing_store() == nullptr); - } else if (initial_pages > 0 || native_module->use_trap_handler()) { - // We need to unconditionally create a guard region if using trap handlers, - // even when the size is zero to prevent null-dereference issues - // (e.g. https://crbug.com/769637). - // Allocate memory if the initial size is more than 0 pages. - memory_ = AllocateMemory(initial_pages, module_->maximum_pages); - if (memory_.is_null()) { - // failed to allocate memory - DCHECK(isolate_->has_pending_exception() || thrower_->error()); - return {}; + + if (is_asmjs_module(module_)) { + Handle<JSArrayBuffer> buffer; + if (memory_buffer_.ToHandle(&buffer)) { + // asm.js instantiation should have changed the state of the buffer. + CHECK(!buffer->is_detachable()); + CHECK(buffer->is_asmjs_memory()); + } else { + // Use an empty JSArrayBuffer for degenerate asm.js modules. + memory_buffer_ = isolate_->factory()->NewJSArrayBufferAndBackingStore( + 0, InitializedFlag::kUninitialized); + if (!memory_buffer_.ToHandle(&buffer)) { + thrower_->RangeError("Out of memory: asm.js memory"); + return {}; + } + buffer->set_is_asmjs_memory(true); + buffer->set_is_detachable(false); + } + + // The maximum number of pages isn't strictly necessary for memory + // objects used for asm.js, as they are never visible, but we might + // as well make it accurate. + auto maximum_pages = static_cast<uint32_t>( + RoundUp(buffer->byte_length(), wasm::kWasmPageSize) / + wasm::kWasmPageSize); + memory_object_ = + WasmMemoryObject::New(isolate_, memory_buffer_, maximum_pages); + } else { + // Actual wasm module must have either imported or created memory. + CHECK(memory_buffer_.is_null()); + if (!FindImportedMemory()) { + if (module_->has_memory && !AllocateMemory()) { + DCHECK(isolate_->has_pending_exception() || thrower_->error()); + return {}; + } } } @@ -333,33 +346,42 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() { TRACE("New module instantiation for %p\n", native_module); Handle<WasmInstanceObject> instance = WasmInstanceObject::New(isolate_, module_object_); - NativeModuleModificationScope native_modification_scope(native_module); + + //-------------------------------------------------------------------------- + // Attach the memory to the instance. + //-------------------------------------------------------------------------- + if (module_->has_memory) { + DCHECK(!memory_object_.is_null()); + if (!instance->has_memory_object()) { + instance->set_memory_object(*memory_object_); + } + // Add the instance object to the list of instances for this memory. + WasmMemoryObject::AddInstance(isolate_, memory_object_, instance); + + // Double-check the {memory} array buffer matches the instance. + Handle<JSArrayBuffer> memory = memory_buffer_.ToHandleChecked(); + CHECK_EQ(instance->memory_size(), memory->byte_length()); + CHECK_EQ(instance->memory_start(), memory->backing_store()); + } //-------------------------------------------------------------------------- // Set up the globals for the new instance. //-------------------------------------------------------------------------- uint32_t untagged_globals_buffer_size = module_->untagged_globals_buffer_size; if (untagged_globals_buffer_size > 0) { - void* backing_store = isolate_->array_buffer_allocator()->Allocate( - untagged_globals_buffer_size); - if (backing_store == nullptr) { - thrower_->RangeError("Out of memory: wasm globals"); - return {}; - } - untagged_globals_ = isolate_->factory()->NewJSArrayBuffer( - SharedFlag::kNotShared, AllocationType::kOld); - constexpr bool is_external = false; - constexpr bool is_wasm_memory = false; - JSArrayBuffer::Setup(untagged_globals_, isolate_, is_external, - backing_store, untagged_globals_buffer_size, - SharedFlag::kNotShared, is_wasm_memory); - if (untagged_globals_.is_null()) { + MaybeHandle<JSArrayBuffer> result = + isolate_->factory()->NewJSArrayBufferAndBackingStore( + untagged_globals_buffer_size, InitializedFlag::kZeroInitialized, + AllocationType::kOld); + + if (!result.ToHandle(&untagged_globals_)) { thrower_->RangeError("Out of memory: wasm globals"); return {}; } + + instance->set_untagged_globals_buffer(*untagged_globals_); instance->set_globals_start( reinterpret_cast<byte*>(untagged_globals_->backing_store())); - instance->set_untagged_globals_buffer(*untagged_globals_); } uint32_t tagged_globals_buffer_size = module_->tagged_globals_buffer_size; @@ -425,6 +447,8 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() { instance->set_indirect_function_tables(*tables); } + NativeModuleModificationScope native_modification_scope(native_module); + //-------------------------------------------------------------------------- // Process the imports for the module. //-------------------------------------------------------------------------- @@ -450,30 +474,6 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() { InitializeExceptions(instance); } - //-------------------------------------------------------------------------- - // Create the WebAssembly.Memory object. - //-------------------------------------------------------------------------- - if (module_->has_memory) { - if (!instance->has_memory_object()) { - // No memory object exists. Create one. - Handle<WasmMemoryObject> memory_object = WasmMemoryObject::New( - isolate_, memory_, - module_->maximum_pages != 0 ? module_->maximum_pages : -1); - instance->set_memory_object(*memory_object); - } - - // Add the instance object to the list of instances for this memory. - Handle<WasmMemoryObject> memory_object(instance->memory_object(), isolate_); - WasmMemoryObject::AddInstance(isolate_, memory_object, instance); - - if (!memory_.is_null()) { - // Double-check the {memory} array buffer matches the instance. - Handle<JSArrayBuffer> memory = memory_.ToHandleChecked(); - CHECK_EQ(instance->memory_size(), memory->byte_length()); - CHECK_EQ(instance->memory_start(), memory->backing_store()); - } - } - // The bulk memory proposal changes the MVP behavior here; the segments are // written as if `memory.init` and `table.init` are executed directly, and // not bounds checked ahead of time. @@ -536,7 +536,8 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() { // Debugging support. //-------------------------------------------------------------------------- // Set all breakpoints that were set on the shared module. - WasmModuleObject::SetBreakpointsOnNewInstance(module_object_, instance); + WasmModuleObject::SetBreakpointsOnNewInstance( + handle(module_object_->script(), isolate_), instance); //-------------------------------------------------------------------------- // Create a wrapper for the start function. @@ -547,7 +548,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() { Handle<Code> wrapper_code = JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper( isolate_, function.sig, function.imported); - // TODO(clemensh): Don't generate an exported function for the start + // TODO(clemensb): Don't generate an exported function for the start // function. Use CWasmEntry instead. start_function_ = WasmExportedFunction::New( isolate_, instance, start_index, @@ -807,22 +808,21 @@ void InstanceBuilder::SanitizeImports() { } } -MaybeHandle<JSArrayBuffer> InstanceBuilder::FindImportedMemoryBuffer() const { +bool InstanceBuilder::FindImportedMemory() { DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size()); for (size_t index = 0; index < module_->import_table.size(); index++) { - const WasmImport& import = module_->import_table[index]; + WasmImport import = module_->import_table[index]; if (import.kind == kExternalMemory) { - const auto& value = sanitized_imports_[index].value; - if (!value->IsWasmMemoryObject()) { - return {}; - } - auto memory = Handle<WasmMemoryObject>::cast(value); - Handle<JSArrayBuffer> buffer(memory->array_buffer(), isolate_); - return buffer; + auto& value = sanitized_imports_[index].value; + if (!value->IsWasmMemoryObject()) return false; + memory_object_ = Handle<WasmMemoryObject>::cast(value); + memory_buffer_ = + Handle<JSArrayBuffer>(memory_object_->array_buffer(), isolate_); + return true; } } - return {}; + return false; } bool InstanceBuilder::ProcessImportedFunction( @@ -1016,19 +1016,19 @@ bool InstanceBuilder::ProcessImportedMemory(Handle<WasmInstanceObject> instance, Handle<String> module_name, Handle<String> import_name, Handle<Object> value) { - // Validation should have failed if more than one memory object was - // provided. - DCHECK(!instance->has_memory_object()); if (!value->IsWasmMemoryObject()) { ReportLinkError("memory import must be a WebAssembly.Memory object", import_index, module_name, import_name); return false; } - auto memory = Handle<WasmMemoryObject>::cast(value); - instance->set_memory_object(*memory); - Handle<JSArrayBuffer> buffer(memory->array_buffer(), isolate_); + auto memory_object = Handle<WasmMemoryObject>::cast(value); + + // The imported memory should have been already set up early. + CHECK_EQ(instance->memory_object(), *memory_object); + + Handle<JSArrayBuffer> buffer(memory_object_->array_buffer(), isolate_); // memory_ should have already been assigned in Build(). - DCHECK_EQ(*memory_.ToHandleChecked(), *buffer); + DCHECK_EQ(*memory_buffer_.ToHandleChecked(), *buffer); uint32_t imported_cur_pages = static_cast<uint32_t>(buffer->byte_length() / kWasmPageSize); if (imported_cur_pages < module_->initial_pages) { @@ -1037,7 +1037,7 @@ bool InstanceBuilder::ProcessImportedMemory(Handle<WasmInstanceObject> instance, imported_cur_pages); return false; } - int32_t imported_maximum_pages = memory->maximum_pages(); + int32_t imported_maximum_pages = memory_object_->maximum_pages(); if (module_->has_maximum_pages) { if (imported_maximum_pages < 0) { thrower_->LinkError( @@ -1186,13 +1186,8 @@ bool InstanceBuilder::ProcessImportedGlobal(Handle<WasmInstanceObject> instance, return true; } - if (enabled_.bigint && global.type == kWasmI64) { - Handle<BigInt> bigint; - - if (!BigInt::FromObject(isolate_, value).ToHandle(&bigint)) { - return false; - } - WriteGlobalValue(global, bigint->AsInt64()); + if (enabled_.bigint && global.type == kWasmI64 && value->IsBigInt()) { + WriteGlobalValue(global, BigInt::cast(*value).AsInt64()); return true; } @@ -1241,7 +1236,7 @@ void InstanceBuilder::CompileImportWrappers( CancelableTaskManager task_manager; const int max_background_tasks = GetMaxBackgroundTasks(); for (int i = 0; i < max_background_tasks; ++i) { - auto task = base::make_unique<CompileImportWrapperTask>( + auto task = std::make_unique<CompileImportWrapperTask>( &task_manager, isolate_->wasm_engine(), isolate_->counters(), native_module, &import_wrapper_queue, &cache_scope); V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task)); @@ -1411,27 +1406,28 @@ void InstanceBuilder::InitGlobals(Handle<WasmInstanceObject> instance) { } // Allocate memory for a module instance as a new JSArrayBuffer. -Handle<JSArrayBuffer> InstanceBuilder::AllocateMemory(uint32_t initial_pages, - uint32_t maximum_pages) { +bool InstanceBuilder::AllocateMemory() { + auto initial_pages = module_->initial_pages; + auto maximum_pages = module_->has_maximum_pages ? module_->maximum_pages + : wasm::max_mem_pages(); if (initial_pages > max_mem_pages()) { thrower_->RangeError("Out of memory: wasm memory too large"); - return Handle<JSArrayBuffer>::null(); - } - const bool is_shared_memory = module_->has_shared_memory && enabled_.threads; - Handle<JSArrayBuffer> mem_buffer; - if (is_shared_memory) { - if (!NewSharedArrayBuffer(isolate_, initial_pages * kWasmPageSize, - maximum_pages * kWasmPageSize) - .ToHandle(&mem_buffer)) { - thrower_->RangeError("Out of memory: wasm shared memory"); - } - } else { - if (!NewArrayBuffer(isolate_, initial_pages * kWasmPageSize) - .ToHandle(&mem_buffer)) { - thrower_->RangeError("Out of memory: wasm memory"); - } + return false; } - return mem_buffer; + auto shared = (module_->has_shared_memory && enabled_.threads) + ? SharedFlag::kShared + : SharedFlag::kNotShared; + + MaybeHandle<WasmMemoryObject> result = + WasmMemoryObject::New(isolate_, initial_pages, maximum_pages, shared); + + if (!result.ToHandle(&memory_object_)) { + thrower_->RangeError("Out of memory: wasm memory"); + return false; + } + memory_buffer_ = + Handle<JSArrayBuffer>(memory_object_->array_buffer(), isolate_); + return true; } bool InstanceBuilder::NeedsWrappers() const { |