diff options
author | Michaƫl Zasso <targos@protonmail.com> | 2018-01-24 20:16:06 +0100 |
---|---|---|
committer | Myles Borins <mylesborins@google.com> | 2018-01-24 15:02:20 -0800 |
commit | 4c4af643e5042d615a60c6bbc05aee9d81b903e5 (patch) | |
tree | 3fb0a97988fe4439ae3ae06f26915d1dcf8cab92 /deps/v8/src/wasm/wasm-objects.cc | |
parent | fa9f31a4fda5a3782c652e56e394465805ebb50f (diff) | |
download | node-new-4c4af643e5042d615a60c6bbc05aee9d81b903e5.tar.gz |
deps: update V8 to 6.4.388.40
PR-URL: https://github.com/nodejs/node/pull/17489
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Myles Borins <myles.borins@gmail.com>
Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Diffstat (limited to 'deps/v8/src/wasm/wasm-objects.cc')
-rw-r--r-- | deps/v8/src/wasm/wasm-objects.cc | 612 |
1 files changed, 439 insertions, 173 deletions
diff --git a/deps/v8/src/wasm/wasm-objects.cc b/deps/v8/src/wasm/wasm-objects.cc index 012aa6644b..565f38a9e7 100644 --- a/deps/v8/src/wasm/wasm-objects.cc +++ b/deps/v8/src/wasm/wasm-objects.cc @@ -11,6 +11,7 @@ #include "src/debug/debug-interface.h" #include "src/objects-inl.h" #include "src/objects/debug-objects-inl.h" +#include "src/trap-handler/trap-handler.h" #include "src/wasm/module-compiler.h" #include "src/wasm/module-decoder.h" #include "src/wasm/wasm-code-specialization.h" @@ -62,25 +63,17 @@ class CompiledModulesIterator void Advance() { DCHECK(!current_.is_null()); if (!is_backwards_) { - if (current_->has_weak_next_instance()) { - WeakCell* weak_next = current_->ptr_to_weak_next_instance(); - if (!weak_next->cleared()) { - current_ = - handle(WasmCompiledModule::cast(weak_next->value()), isolate_); - return; - } + if (current_->has_next_instance()) { + current_ = current_->next_instance(); + return; } // No more modules in next-links, now try the previous-links. is_backwards_ = true; current_ = start_module_; } - if (current_->has_weak_prev_instance()) { - WeakCell* weak_prev = current_->ptr_to_weak_prev_instance(); - if (!weak_prev->cleared()) { - current_ = - handle(WasmCompiledModule::cast(weak_prev->value()), isolate_); - return; - } + if (current_->has_prev_instance()) { + current_ = current_->prev_instance(); + return; } current_ = Handle<WasmCompiledModule>::null(); } @@ -158,6 +151,14 @@ bool IsBreakablePosition(Handle<WasmCompiledModule> compiled_module, } #endif // DEBUG +void CompiledModuleFinalizer(const v8::WeakCallbackInfo<void>& data) { + DisallowHeapAllocation no_gc; + JSObject** p = reinterpret_cast<JSObject**>(data.GetParameter()); + WasmCompiledModule* compiled_module = WasmCompiledModule::cast(*p); + compiled_module->reset_native_module(); + GlobalHandles::Destroy(reinterpret_cast<Object**>(p)); +} + } // namespace Handle<WasmModuleObject> WasmModuleObject::New( @@ -179,8 +180,8 @@ void WasmModuleObject::ValidateStateForTesting( WasmCompiledModule* compiled_module = module_obj->compiled_module(); CHECK(compiled_module->has_weak_wasm_module()); CHECK_EQ(compiled_module->ptr_to_weak_wasm_module()->value(), *module_obj); - CHECK(!compiled_module->has_weak_prev_instance()); - CHECK(!compiled_module->has_weak_next_instance()); + CHECK(!compiled_module->has_prev_instance()); + CHECK(!compiled_module->has_next_instance()); CHECK(!compiled_module->has_weak_owning_instance()); } @@ -233,6 +234,8 @@ Handle<FixedArray> WasmTableObject::AddDispatchTable( } void WasmTableObject::Grow(Isolate* isolate, uint32_t count) { + // TODO(6792): No longer needed once WebAssembly code is off heap. + CodeSpaceMemoryModificationScope modification_scope(isolate->heap()); Handle<FixedArray> dispatch_tables(this->dispatch_tables()); DCHECK_EQ(0, dispatch_tables->length() % 4); uint32_t old_size = functions()->length(); @@ -258,7 +261,27 @@ void WasmTableObject::Grow(Isolate* isolate, uint32_t count) { dispatch_tables->set(i + 3, *new_signature_table); // Patch the code of the respective instance. - { + if (FLAG_wasm_jit_to_native) { + DisallowHeapAllocation no_gc; + wasm::CodeSpecialization code_specialization(isolate, + &specialization_zone); + WasmInstanceObject* instance = + WasmInstanceObject::cast(dispatch_tables->get(i)); + WasmCompiledModule* compiled_module = instance->compiled_module(); + wasm::NativeModule* native_module = compiled_module->GetNativeModule(); + GlobalHandleAddress old_function_table_addr = + native_module->function_tables()[table_index]; + GlobalHandleAddress old_signature_table_addr = + native_module->signature_tables()[table_index]; + code_specialization.PatchTableSize(old_size, old_size + count); + code_specialization.RelocatePointer(old_function_table_addr, + new_function_table_addr); + code_specialization.RelocatePointer(old_signature_table_addr, + new_signature_table_addr); + code_specialization.ApplyToWholeInstance(instance); + native_module->function_tables()[table_index] = new_function_table_addr; + native_module->signature_tables()[table_index] = new_signature_table_addr; + } else { DisallowHeapAllocation no_gc; wasm::CodeSpecialization code_specialization(isolate, &specialization_zone); @@ -294,18 +317,24 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table, Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate); WasmFunction* wasm_function = nullptr; - Handle<Code> code = Handle<Code>::null(); + Handle<Object> code = Handle<Object>::null(); Handle<Object> value = isolate->factory()->null_value(); if (!function.is_null()) { + auto exported_function = Handle<WasmExportedFunction>::cast(function); wasm_function = wasm::GetWasmFunctionForExport(isolate, function); // The verification that {function} is an export was done // by the caller. DCHECK_NOT_NULL(wasm_function); - code = wasm::UnwrapExportWrapper(function); - value = Handle<Object>::cast(function); + value = function; + // TODO(titzer): Make JSToWasm wrappers just call the WASM to WASM wrapper, + // and then we can just reuse the WASM to WASM wrapper. + WasmCodeWrapper wasm_code = exported_function->GetWasmCode(); + CodeSpaceMemoryModificationScope gc_modification_scope(isolate->heap()); + code = wasm::GetOrCreateIndirectCallWrapper( + isolate, handle(exported_function->instance()), wasm_code, + exported_function->function_index(), wasm_function->sig); } - UpdateDispatchTables(isolate, dispatch_tables, index, wasm_function, code); array->set(index, *value); } @@ -361,45 +390,44 @@ Handle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate, // May GC, because SetSpecializationMemInfoFrom may GC void SetInstanceMemory(Isolate* isolate, Handle<WasmInstanceObject> instance, Handle<JSArrayBuffer> buffer) { - instance->set_memory_buffer(*buffer); - if (instance->has_debug_info()) { - instance->debug_info()->UpdateMemory(*buffer); + auto wasm_context = instance->wasm_context()->get(); + wasm_context->SetRawMemory(reinterpret_cast<byte*>(buffer->backing_store()), + buffer->byte_length()->Number()); +#if DEBUG + // To flush out bugs earlier, in DEBUG mode, check that all pages of the + // memory are accessible by reading and writing one byte on each page. + for (uint32_t offset = 0; offset < wasm_context->mem_size; + offset += WasmModule::kPageSize) { + byte val = wasm_context->mem_start[offset]; + wasm_context->mem_start[offset] = val; } -} - -void UpdateWasmContext(WasmContext* wasm_context, - Handle<JSArrayBuffer> buffer) { - uint32_t new_mem_size = buffer->byte_length()->Number(); - Address new_mem_start = static_cast<Address>(buffer->backing_store()); - DCHECK_NOT_NULL(new_mem_start); - wasm_context->mem_start = new_mem_start; - wasm_context->mem_size = new_mem_size; +#endif } } // namespace -Handle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate, - Handle<JSArrayBuffer> buffer, - int32_t maximum) { +Handle<WasmMemoryObject> WasmMemoryObject::New( + Isolate* isolate, MaybeHandle<JSArrayBuffer> maybe_buffer, + int32_t maximum) { Handle<JSFunction> memory_ctor( isolate->native_context()->wasm_memory_constructor()); auto memory_obj = Handle<WasmMemoryObject>::cast( isolate->factory()->NewJSObject(memory_ctor, TENURED)); - auto wasm_context = Managed<WasmContext>::Allocate(isolate); - if (buffer.is_null()) { - const bool enable_guard_regions = trap_handler::UseTrapHandler(); + + Handle<JSArrayBuffer> buffer; + if (maybe_buffer.is_null()) { + // If no buffer was provided, create a 0-length one. buffer = wasm::SetupArrayBuffer(isolate, nullptr, 0, nullptr, 0, false, - enable_guard_regions); - wasm_context->get()->mem_size = 0; - wasm_context->get()->mem_start = nullptr; + trap_handler::UseTrapHandler()); } else { - CHECK(buffer->byte_length()->ToUint32(&wasm_context->get()->mem_size)); - wasm_context->get()->mem_start = - static_cast<Address>(buffer->backing_store()); + buffer = maybe_buffer.ToHandleChecked(); + // Paranoid check that the buffer size makes sense. + uint32_t mem_size = 0; + CHECK(buffer->byte_length()->ToUint32(&mem_size)); } memory_obj->set_array_buffer(*buffer); memory_obj->set_maximum_pages(maximum); - memory_obj->set_wasm_context(*wasm_context); + return memory_obj; } @@ -419,6 +447,8 @@ void WasmMemoryObject::AddInstance(Isolate* isolate, Handle<WeakFixedArray> new_instances = WeakFixedArray::Add(old_instances, instance); memory->set_instances(*new_instances); + Handle<JSArrayBuffer> buffer(memory->array_buffer(), isolate); + SetInstanceMemory(isolate, instance, buffer); } void WasmMemoryObject::RemoveInstance(Isolate* isolate, @@ -463,29 +493,19 @@ int32_t WasmMemoryObject::Grow(Isolate* isolate, if (!old_buffer->is_growable()) return -1; uint32_t old_size = 0; CHECK(old_buffer->byte_length()->ToUint32(&old_size)); + DCHECK_EQ(0, old_size % WasmModule::kPageSize); Handle<JSArrayBuffer> new_buffer; // Return current size if grow by 0. - if (pages == 0) { - DCHECK_EQ(0, old_size % WasmModule::kPageSize); - return old_size / WasmModule::kPageSize; - } + if (pages == 0) return old_size / WasmModule::kPageSize; - uint32_t maximum_pages; + uint32_t maximum_pages = FLAG_wasm_max_mem_pages; if (memory_object->has_maximum_pages()) { maximum_pages = Min(FLAG_wasm_max_mem_pages, static_cast<uint32_t>(memory_object->maximum_pages())); - } else { - maximum_pages = FLAG_wasm_max_mem_pages; } new_buffer = GrowMemoryBuffer(isolate, old_buffer, pages, maximum_pages); if (new_buffer.is_null()) return -1; - // Verify that the values we will change are actually the ones we expect. - DCHECK_EQ(memory_object->wasm_context()->get()->mem_size, old_size); - DCHECK_EQ(memory_object->wasm_context()->get()->mem_start, - static_cast<Address>(old_buffer->backing_store())); - UpdateWasmContext(memory_object->wasm_context()->get(), new_buffer); - if (memory_object->has_instances()) { Handle<WeakFixedArray> instances(memory_object->instances(), isolate); for (int i = 0; i < instances->Length(); i++) { @@ -497,7 +517,6 @@ int32_t WasmMemoryObject::Grow(Isolate* isolate, } } memory_object->set_array_buffer(*new_buffer); - DCHECK_EQ(0, old_size % WasmModule::kPageSize); return old_size / WasmModule::kPageSize; } @@ -505,11 +524,6 @@ WasmModuleObject* WasmInstanceObject::module_object() { return *compiled_module()->wasm_module(); } -WasmContext* WasmInstanceObject::wasm_context() { - DCHECK(has_memory_object()); - return memory_object()->wasm_context()->get(); -} - WasmModule* WasmInstanceObject::module() { return compiled_module()->module(); } Handle<WasmDebugInfo> WasmInstanceObject::GetOrCreateDebugInfo( @@ -530,13 +544,18 @@ Handle<WasmInstanceObject> WasmInstanceObject::New( Handle<WasmInstanceObject> instance( reinterpret_cast<WasmInstanceObject*>(*instance_object), isolate); + auto wasm_context = Managed<WasmContext>::Allocate(isolate); + wasm_context->get()->SetRawMemory(nullptr, 0); + wasm_context->get()->globals_start = nullptr; + instance->set_wasm_context(*wasm_context); + instance->set_compiled_module(*compiled_module); return instance; } int32_t WasmInstanceObject::GetMemorySize() { - if (!has_memory_buffer()) return 0; - uint32_t bytes = memory_buffer()->byte_length()->Number(); + if (!has_memory_object()) return 0; + uint32_t bytes = memory_object()->array_buffer()->byte_length()->Number(); DCHECK_EQ(0, bytes % WasmModule::kPageSize); return bytes / WasmModule::kPageSize; } @@ -567,7 +586,20 @@ uint32_t WasmInstanceObject::GetMaxMemoryPages() { return FLAG_wasm_max_mem_pages; } -WasmInstanceObject* WasmInstanceObject::GetOwningInstance(Code* code) { +WasmInstanceObject* WasmInstanceObject::GetOwningInstance( + const wasm::WasmCode* code) { + DisallowHeapAllocation no_gc; + Object* weak_link = nullptr; + DCHECK(code->kind() == wasm::WasmCode::Function || + code->kind() == wasm::WasmCode::InterpreterStub); + weak_link = code->owner()->compiled_module()->ptr_to_weak_owning_instance(); + DCHECK(weak_link->IsWeakCell()); + WeakCell* cell = WeakCell::cast(weak_link); + if (cell->cleared()) return nullptr; + return WasmInstanceObject::cast(cell->value()); +} + +WasmInstanceObject* WasmInstanceObject::GetOwningInstanceGC(Code* code) { DisallowHeapAllocation no_gc; DCHECK(code->kind() == Code::WASM_FUNCTION || code->kind() == Code::WASM_INTERPRETER_ENTRY); @@ -591,16 +623,16 @@ void WasmInstanceObject::ValidateInstancesChainForTesting( Object* prev = nullptr; int found_instances = compiled_module->has_weak_owning_instance() ? 1 : 0; WasmCompiledModule* current_instance = compiled_module; - while (current_instance->has_weak_next_instance()) { - CHECK((prev == nullptr && !current_instance->has_weak_prev_instance()) || - current_instance->ptr_to_weak_prev_instance()->value() == prev); + while (current_instance->has_next_instance()) { + CHECK((prev == nullptr && !current_instance->has_prev_instance()) || + current_instance->ptr_to_prev_instance() == prev); CHECK_EQ(current_instance->ptr_to_weak_wasm_module()->value(), *module_obj); CHECK(current_instance->ptr_to_weak_owning_instance() ->value() ->IsWasmInstanceObject()); prev = current_instance; - current_instance = WasmCompiledModule::cast( - current_instance->ptr_to_weak_next_instance()->value()); + current_instance = + WasmCompiledModule::cast(current_instance->ptr_to_next_instance()); ++found_instances; CHECK_LE(found_instances, instance_count); } @@ -668,8 +700,9 @@ Handle<WasmExportedFunction> WasmExportedFunction::New( isolate->factory()->NewSharedFunctionInfo(name, export_wrapper, false); shared->set_length(arity); shared->set_internal_formal_parameter_count(arity); - Handle<JSFunction> js_function = isolate->factory()->NewFunction( - isolate->sloppy_function_map(), name, export_wrapper); + NewFunctionArgs args = NewFunctionArgs::ForWasm( + name, export_wrapper, isolate->sloppy_function_map()); + Handle<JSFunction> js_function = isolate->factory()->NewFunction(args); js_function->set_shared(*shared); Handle<Symbol> instance_symbol(isolate->factory()->wasm_instance_symbol()); @@ -683,6 +716,49 @@ Handle<WasmExportedFunction> WasmExportedFunction::New( return Handle<WasmExportedFunction>::cast(js_function); } +WasmCodeWrapper WasmExportedFunction::GetWasmCode() { + DisallowHeapAllocation no_gc; + Handle<Code> export_wrapper_code = handle(this->code()); + DCHECK_EQ(export_wrapper_code->kind(), Code::JS_TO_WASM_FUNCTION); + int mask = + RelocInfo::ModeMask(FLAG_wasm_jit_to_native ? RelocInfo::JS_TO_WASM_CALL + : RelocInfo::CODE_TARGET); + auto IsWasmFunctionCode = [](Code* code) { + return code->kind() == Code::WASM_FUNCTION || + code->kind() == Code::WASM_TO_JS_FUNCTION || + code->kind() == Code::WASM_TO_WASM_FUNCTION || + code->kind() == Code::WASM_INTERPRETER_ENTRY || + code->builtin_index() == Builtins::kWasmCompileLazy; + }; + + for (RelocIterator it(*export_wrapper_code, mask);; it.next()) { + DCHECK(!it.done()); + WasmCodeWrapper target; + if (FLAG_wasm_jit_to_native) { + target = WasmCodeWrapper(GetIsolate()->wasm_code_manager()->LookupCode( + it.rinfo()->js_to_wasm_address())); + } else { + Code* code = Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); + if (!IsWasmFunctionCode(code)) continue; + target = WasmCodeWrapper(handle(code)); + } +// There should only be this one call to wasm code. +#ifdef DEBUG + for (it.next(); !it.done(); it.next()) { + if (FLAG_wasm_jit_to_native) { + UNREACHABLE(); + } else { + Code* code = + Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); + DCHECK(!IsWasmFunctionCode(code)); + } + } +#endif + return target; + } + UNREACHABLE(); +} + bool WasmSharedModuleData::IsWasmSharedModuleData(Object* object) { if (!object->IsFixedArray()) return false; FixedArray* arr = FixedArray::cast(object); @@ -916,8 +992,8 @@ void WasmSharedModuleData::PrepareForLazyCompilation( } Handle<WasmCompiledModule> WasmCompiledModule::New( - Isolate* isolate, Handle<WasmSharedModuleData> shared, - Handle<FixedArray> code_table, Handle<FixedArray> export_wrappers, + Isolate* isolate, WasmModule* module, Handle<FixedArray> code_table, + Handle<FixedArray> export_wrappers, const std::vector<GlobalHandleAddress>& function_tables, const std::vector<GlobalHandleAddress>& signature_tables) { DCHECK_EQ(function_tables.size(), signature_tables.size()); @@ -926,40 +1002,75 @@ Handle<WasmCompiledModule> WasmCompiledModule::New( // WasmCompiledModule::cast would fail since fields are not set yet. Handle<WasmCompiledModule> compiled_module( reinterpret_cast<WasmCompiledModule*>(*ret), isolate); - compiled_module->InitId(); - compiled_module->set_shared(shared); compiled_module->set_native_context(isolate->native_context()); - compiled_module->set_code_table(code_table); - compiled_module->set_export_wrappers(export_wrappers); - // TODO(mtrofin): we copy these because the order of finalization isn't - // reliable, and we need these at Reset (which is called at - // finalization). If the order were reliable, and top-down, we could instead - // just get them from shared(). - compiled_module->set_initial_pages(shared->module()->initial_pages); - compiled_module->set_num_imported_functions( - shared->module()->num_imported_functions); - - int num_function_tables = static_cast<int>(function_tables.size()); - if (num_function_tables > 0) { - Handle<FixedArray> st = - isolate->factory()->NewFixedArray(num_function_tables, TENURED); - Handle<FixedArray> ft = - isolate->factory()->NewFixedArray(num_function_tables, TENURED); - for (int i = 0; i < num_function_tables; ++i) { - size_t index = static_cast<size_t>(i); - SetTableValue(isolate, ft, i, function_tables[index]); - SetTableValue(isolate, st, i, signature_tables[index]); + if (!FLAG_wasm_jit_to_native) { + compiled_module->InitId(); + compiled_module->set_native_context(isolate->native_context()); + compiled_module->set_code_table(code_table); + compiled_module->set_export_wrappers(export_wrappers); + // TODO(mtrofin): we copy these because the order of finalization isn't + // reliable, and we need these at Reset (which is called at + // finalization). If the order were reliable, and top-down, we could instead + // just get them from shared(). + compiled_module->set_initial_pages(module->initial_pages); + compiled_module->set_num_imported_functions(module->num_imported_functions); + + int num_function_tables = static_cast<int>(function_tables.size()); + if (num_function_tables > 0) { + Handle<FixedArray> st = + isolate->factory()->NewFixedArray(num_function_tables, TENURED); + Handle<FixedArray> ft = + isolate->factory()->NewFixedArray(num_function_tables, TENURED); + for (int i = 0; i < num_function_tables; ++i) { + size_t index = static_cast<size_t>(i); + SetTableValue(isolate, ft, i, function_tables[index]); + SetTableValue(isolate, st, i, signature_tables[index]); + } + // TODO(wasm): setting the empty tables here this way is OK under the + // assumption that we compile and then instantiate. It needs rework if we + // do direct instantiation. The empty tables are used as a default when + // resetting the compiled module. + compiled_module->set_signature_tables(st); + compiled_module->set_empty_signature_tables(st); + compiled_module->set_function_tables(ft); + compiled_module->set_empty_function_tables(ft); } - // TODO(wasm): setting the empty tables here this way is OK under the - // assumption that we compile and then instantiate. It needs rework if we do - // direct instantiation. The empty tables are used as a default when - // resetting the compiled module. - compiled_module->set_signature_tables(st); - compiled_module->set_empty_signature_tables(st); - compiled_module->set_function_tables(ft); - compiled_module->set_empty_function_tables(ft); + } else { + if (!export_wrappers.is_null()) { + compiled_module->set_export_wrappers(export_wrappers); + } + wasm::NativeModule* native_module = nullptr; + { + std::unique_ptr<wasm::NativeModule> native_module_ptr = + isolate->wasm_code_manager()->NewNativeModule(*module); + native_module = native_module_ptr.release(); + Handle<Foreign> native_module_wrapper = + Managed<wasm::NativeModule>::From(isolate, native_module); + compiled_module->set_native_module(native_module_wrapper); + Handle<WasmCompiledModule> weak_link = + isolate->global_handles()->Create(*compiled_module); + GlobalHandles::MakeWeak(Handle<Object>::cast(weak_link).location(), + Handle<Object>::cast(weak_link).location(), + &CompiledModuleFinalizer, + v8::WeakCallbackType::kFinalizer); + compiled_module->GetNativeModule()->SetCompiledModule(weak_link); + } + // This is here just because it's easier for APIs that need to work with + // either code_table or native_module. Otherwise we need to check if + // has_code_table and pass undefined. + compiled_module->set_code_table(code_table); + + native_module->function_tables() = function_tables; + native_module->signature_tables() = signature_tables; + native_module->empty_function_tables() = function_tables; + native_module->empty_signature_tables() = signature_tables; + + int function_count = static_cast<int>(module->functions.size()); + compiled_module->set_handler_table( + isolate->factory()->NewFixedArray(function_count, TENURED)); + compiled_module->set_source_positions( + isolate->factory()->NewFixedArray(function_count, TENURED)); } - // TODO(mtrofin): copy the rest of the specialization parameters over. // We're currently OK because we're only using defaults. return compiled_module; @@ -967,19 +1078,41 @@ Handle<WasmCompiledModule> WasmCompiledModule::New( Handle<WasmCompiledModule> WasmCompiledModule::Clone( Isolate* isolate, Handle<WasmCompiledModule> module) { - Handle<FixedArray> code_copy = - isolate->factory()->CopyFixedArray(module->code_table()); + Handle<FixedArray> code_copy; + if (!FLAG_wasm_jit_to_native) { + code_copy = isolate->factory()->CopyFixedArray(module->code_table()); + } Handle<WasmCompiledModule> ret = Handle<WasmCompiledModule>::cast( isolate->factory()->CopyFixedArray(module)); - ret->InitId(); - ret->set_code_table(code_copy); ret->reset_weak_owning_instance(); - ret->reset_weak_next_instance(); - ret->reset_weak_prev_instance(); + ret->reset_next_instance(); + ret->reset_prev_instance(); ret->reset_weak_exported_functions(); - if (ret->has_globals_start()) { - WasmCompiledModule::recreate_globals_start(ret, isolate->factory(), - ret->globals_start()); + if (!FLAG_wasm_jit_to_native) { + ret->InitId(); + ret->set_code_table(code_copy); + return ret; + } + + std::unique_ptr<wasm::NativeModule> native_module = + module->GetNativeModule()->Clone(); + // construct the wrapper in 2 steps, because its construction may trigger GC, + // which would shift the this pointer in set_native_module. + Handle<Foreign> native_module_wrapper = + Managed<wasm::NativeModule>::From(isolate, native_module.release()); + ret->set_native_module(native_module_wrapper); + Handle<WasmCompiledModule> weak_link = + isolate->global_handles()->Create(*ret); + GlobalHandles::MakeWeak(Handle<Object>::cast(weak_link).location(), + Handle<Object>::cast(weak_link).location(), + &CompiledModuleFinalizer, + v8::WeakCallbackType::kFinalizer); + ret->GetNativeModule()->SetCompiledModule(weak_link); + + if (module->has_lazy_compile_data()) { + Handle<FixedArray> lazy_comp_data = isolate->factory()->NewFixedArray( + module->lazy_compile_data()->length(), TENURED); + ret->set_lazy_compile_data(lazy_comp_data); } return ret; } @@ -1005,8 +1138,13 @@ Address WasmCompiledModule::GetTableValue(FixedArray* table, int index) { return reinterpret_cast<Address>(static_cast<size_t>(value)); } -void WasmCompiledModule::Reset(Isolate* isolate, - WasmCompiledModule* compiled_module) { +wasm::NativeModule* WasmCompiledModule::GetNativeModule() const { + if (!has_native_module()) return nullptr; + return Managed<wasm::NativeModule>::cast(ptr_to_native_module())->get(); +} + +void WasmCompiledModule::ResetGCModel(Isolate* isolate, + WasmCompiledModule* compiled_module) { DisallowHeapAllocation no_gc; TRACE("Resetting %d\n", compiled_module->instance_id()); Object* undefined = *isolate->factory()->undefined_value(); @@ -1017,13 +1155,6 @@ void WasmCompiledModule::Reset(Isolate* isolate, Zone specialization_zone(isolate->allocator(), ZONE_NAME); wasm::CodeSpecialization code_specialization(isolate, &specialization_zone); - if (compiled_module->has_globals_start()) { - Address globals_start = - reinterpret_cast<Address>(compiled_module->globals_start()); - code_specialization.RelocateGlobals(globals_start, nullptr); - compiled_module->set_globals_start(0); - } - // Reset function tables. if (compiled_module->has_function_tables()) { FixedArray* function_tables = compiled_module->ptr_to_function_tables(); @@ -1051,6 +1182,8 @@ void WasmCompiledModule::Reset(Isolate* isolate, } } + // TODO(6792): No longer needed once WebAssembly code is off heap. + CodeSpaceMemoryModificationScope modification_scope(isolate->heap()); FixedArray* functions = FixedArray::cast(fct_obj); for (int i = compiled_module->num_imported_functions(), end = functions->length(); @@ -1066,8 +1199,8 @@ void WasmCompiledModule::Reset(Isolate* isolate, } break; } - bool changed = - code_specialization.ApplyToWasmCode(code, SKIP_ICACHE_FLUSH); + bool changed = code_specialization.ApplyToWasmCode( + WasmCodeWrapper(handle(code)), SKIP_ICACHE_FLUSH); // TODO(wasm): Check if this is faster than passing FLUSH_ICACHE_IF_NEEDED // above. if (changed) { @@ -1086,16 +1219,79 @@ void WasmCompiledModule::InitId() { #endif } -void WasmCompiledModule::SetGlobalsStartAddressFrom( - Factory* factory, Handle<WasmCompiledModule> compiled_module, - Handle<JSArrayBuffer> buffer) { - DCHECK(!buffer.is_null()); - size_t start_address = reinterpret_cast<size_t>(buffer->backing_store()); - if (!compiled_module->has_globals_start()) { - WasmCompiledModule::recreate_globals_start(compiled_module, factory, - start_address); - } else { - compiled_module->set_globals_start(start_address); +void WasmCompiledModule::Reset(Isolate* isolate, + WasmCompiledModule* compiled_module) { + DisallowHeapAllocation no_gc; + compiled_module->reset_prev_instance(); + compiled_module->reset_next_instance(); + wasm::NativeModule* native_module = compiled_module->GetNativeModule(); + if (native_module == nullptr) return; + TRACE("Resetting %zu\n", native_module->instance_id); + if (trap_handler::UseTrapHandler()) { + for (uint32_t i = native_module->num_imported_functions(), + e = native_module->FunctionCount(); + i < e; ++i) { + wasm::WasmCode* wasm_code = native_module->GetCode(i); + if (wasm_code->HasTrapHandlerIndex()) { + CHECK_LT(wasm_code->trap_handler_index(), + static_cast<size_t>(std::numeric_limits<int>::max())); + trap_handler::ReleaseHandlerData( + static_cast<int>(wasm_code->trap_handler_index())); + wasm_code->ResetTrapHandlerIndex(); + } + } + } + + // Patch code to update memory references, global references, and function + // table references. + Zone specialization_zone(isolate->allocator(), ZONE_NAME); + wasm::CodeSpecialization code_specialization(isolate, &specialization_zone); + + if (compiled_module->has_lazy_compile_data()) { + for (int i = 0, e = compiled_module->lazy_compile_data()->length(); i < e; + ++i) { + compiled_module->lazy_compile_data()->set( + i, isolate->heap()->undefined_value()); + } + } + // Reset function tables. + if (native_module->function_tables().size() > 0) { + std::vector<GlobalHandleAddress>& function_tables = + native_module->function_tables(); + std::vector<GlobalHandleAddress>& signature_tables = + native_module->signature_tables(); + std::vector<GlobalHandleAddress>& empty_function_tables = + native_module->empty_function_tables(); + std::vector<GlobalHandleAddress>& empty_signature_tables = + native_module->empty_signature_tables(); + + if (function_tables != empty_function_tables) { + DCHECK_EQ(function_tables.size(), empty_function_tables.size()); + for (size_t i = 0, e = function_tables.size(); i < e; ++i) { + code_specialization.RelocatePointer(function_tables[i], + empty_function_tables[i]); + code_specialization.RelocatePointer(signature_tables[i], + empty_signature_tables[i]); + } + native_module->function_tables() = empty_function_tables; + native_module->signature_tables() = empty_signature_tables; + } + } + + for (uint32_t i = native_module->num_imported_functions(), + end = native_module->FunctionCount(); + i < end; ++i) { + wasm::WasmCode* code = native_module->GetCode(i); + // Skip lazy compile stubs. + if (code == nullptr || code->kind() != wasm::WasmCode::Function) continue; + bool changed = code_specialization.ApplyToWasmCode(WasmCodeWrapper(code), + SKIP_ICACHE_FLUSH); + // TODO(wasm): Check if this is faster than passing FLUSH_ICACHE_IF_NEEDED + // above. + if (changed) { + Assembler::FlushICache(isolate, code->instructions().start(), + code->instructions().size()); + } } } @@ -1129,7 +1325,6 @@ bool WasmCompiledModule::IsWasmCompiledModule(Object* obj) { if (!obj->IsFixedArray()) return false; FixedArray* arr = FixedArray::cast(obj); if (arr->length() != PropertyIndices::Count) return false; - Isolate* isolate = arr->GetIsolate(); #define WCM_CHECK_TYPE(NAME, TYPE_CHECK) \ do { \ Object* obj = arr->get(kID_##NAME); \ @@ -1145,16 +1340,13 @@ bool WasmCompiledModule::IsWasmCompiledModule(Object* obj) { #define WCM_CHECK_CONST_OBJECT(TYPE, NAME) \ WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->Is##TYPE()) #define WCM_CHECK_WASM_OBJECT(TYPE, NAME) \ - WCM_CHECK_TYPE(NAME, TYPE::Is##TYPE(obj)) + WCM_CHECK_TYPE(NAME, obj->IsFixedArray() || obj->IsUndefined(isolate)) #define WCM_CHECK_WEAK_LINK(TYPE, NAME) WCM_CHECK_OBJECT(WeakCell, NAME) #define WCM_CHECK_SMALL_NUMBER(TYPE, NAME) \ WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->IsSmi()) #define WCM_CHECK(KIND, TYPE, NAME) WCM_CHECK_##KIND(TYPE, NAME) #define WCM_CHECK_SMALL_CONST_NUMBER(TYPE, NAME) \ WCM_CHECK_TYPE(NAME, obj->IsSmi()) -#define WCM_CHECK_LARGE_NUMBER(TYPE, NAME) \ - WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->IsMutableHeapNumber()) - WCM_PROPERTY_TABLE(WCM_CHECK) #undef WCM_CHECK_TYPE #undef WCM_CHECK_OBJECT #undef WCM_CHECK_CONST_OBJECT @@ -1163,7 +1355,6 @@ bool WasmCompiledModule::IsWasmCompiledModule(Object* obj) { #undef WCM_CHECK_SMALL_NUMBER #undef WCM_CHECK #undef WCM_CHECK_SMALL_CONST_NUMBER -#undef WCM_CHECK_LARGE_NUMBER // All checks passed. return true; @@ -1173,16 +1364,46 @@ void WasmCompiledModule::PrintInstancesChain() { #if DEBUG if (!FLAG_trace_wasm_instances) return; for (WasmCompiledModule* current = this; current != nullptr;) { - PrintF("->%d", current->instance_id()); - if (!current->has_weak_next_instance()) break; - DCHECK(!current->ptr_to_weak_next_instance()->cleared()); - current = - WasmCompiledModule::cast(current->ptr_to_weak_next_instance()->value()); + if (FLAG_wasm_jit_to_native) { + PrintF("->%zu", current->GetNativeModule()->instance_id); + } else { + PrintF("->%d", current->instance_id()); + } + if (!current->has_next_instance()) break; + current = current->ptr_to_next_instance(); } PrintF("\n"); #endif } +void WasmCompiledModule::InsertInChain(WasmModuleObject* module) { + DisallowHeapAllocation no_gc; + WasmCompiledModule* original = module->compiled_module(); + set_ptr_to_next_instance(original); + original->set_ptr_to_prev_instance(this); + set_weak_wasm_module(original->weak_wasm_module()); +} + +void WasmCompiledModule::RemoveFromChain() { + DisallowHeapAllocation no_gc; + Isolate* isolate = GetIsolate(); + + Object* next = get(kID_next_instance); + Object* prev = get(kID_prev_instance); + + if (!prev->IsUndefined(isolate)) { + WasmCompiledModule::cast(prev)->set(kID_next_instance, next); + } + if (!next->IsUndefined(isolate)) { + WasmCompiledModule::cast(next)->set(kID_prev_instance, prev); + } +} + +void WasmCompiledModule::OnWasmModuleDecodingComplete( + Handle<WasmSharedModuleData> shared) { + set_shared(shared); +} + void WasmCompiledModule::ReinitializeAfterDeserialization( Isolate* isolate, Handle<WasmCompiledModule> compiled_module) { // This method must only be called immediately after deserialization. @@ -1191,31 +1412,48 @@ void WasmCompiledModule::ReinitializeAfterDeserialization( Handle<WasmSharedModuleData> shared( static_cast<WasmSharedModuleData*>(compiled_module->get(kID_shared)), isolate); - DCHECK(!WasmSharedModuleData::IsWasmSharedModuleData(*shared)); - WasmSharedModuleData::ReinitializeAfterDeserialization(isolate, shared); - int function_table_count = - static_cast<int>(compiled_module->module()->function_tables.size()); + if (!FLAG_wasm_jit_to_native) { + DCHECK(!WasmSharedModuleData::IsWasmSharedModuleData(*shared)); + WasmSharedModuleData::ReinitializeAfterDeserialization(isolate, shared); + } + size_t function_table_count = + compiled_module->module()->function_tables.size(); + wasm::NativeModule* native_module = compiled_module->GetNativeModule(); + if (function_table_count > 0) { // The tables are of the right size, but contain bogus global handle // addresses. Produce new global handles for the empty tables, then reset, // which will relocate the code. We end up with a WasmCompiledModule as-if // it were just compiled. - DCHECK(compiled_module->has_function_tables()); - DCHECK(compiled_module->has_signature_tables()); - DCHECK(compiled_module->has_empty_signature_tables()); - DCHECK(compiled_module->has_empty_function_tables()); - - for (int i = 0; i < function_table_count; ++i) { + if (!FLAG_wasm_jit_to_native) { + DCHECK(compiled_module->has_function_tables()); + DCHECK(compiled_module->has_signature_tables()); + DCHECK(compiled_module->has_empty_signature_tables()); + DCHECK(compiled_module->has_empty_function_tables()); + } else { + DCHECK_GT(native_module->function_tables().size(), 0); + DCHECK_GT(native_module->signature_tables().size(), 0); + DCHECK_EQ(native_module->empty_signature_tables().size(), + native_module->function_tables().size()); + DCHECK_EQ(native_module->empty_function_tables().size(), + native_module->function_tables().size()); + } + for (size_t i = 0; i < function_table_count; ++i) { Handle<Object> global_func_table_handle = isolate->global_handles()->Create(isolate->heap()->undefined_value()); Handle<Object> global_sig_table_handle = isolate->global_handles()->Create(isolate->heap()->undefined_value()); GlobalHandleAddress new_func_table = global_func_table_handle.address(); GlobalHandleAddress new_sig_table = global_sig_table_handle.address(); - SetTableValue(isolate, compiled_module->empty_function_tables(), i, - new_func_table); - SetTableValue(isolate, compiled_module->empty_signature_tables(), i, - new_sig_table); + if (!FLAG_wasm_jit_to_native) { + SetTableValue(isolate, compiled_module->empty_function_tables(), + static_cast<int>(i), new_func_table); + SetTableValue(isolate, compiled_module->empty_signature_tables(), + static_cast<int>(i), new_sig_table); + } else { + native_module->empty_function_tables()[i] = new_func_table; + native_module->empty_signature_tables()[i] = new_sig_table; + } } } @@ -1575,16 +1813,44 @@ MaybeHandle<FixedArray> WasmCompiledModule::CheckBreakPoints(int position) { return isolate->debug()->GetHitBreakPointObjects(breakpoint_objects); } -Handle<Code> WasmCompiledModule::CompileLazy( - Isolate* isolate, Handle<WasmInstanceObject> instance, Handle<Code> caller, - int offset, int func_index, bool patch_caller) { - isolate->set_context(*instance->compiled_module()->native_context()); - Object* orch_obj = - instance->compiled_module()->shared()->lazy_compilation_orchestrator(); - auto* orch = - Managed<wasm::LazyCompilationOrchestrator>::cast(orch_obj)->get(); - return orch->CompileLazy(isolate, instance, caller, offset, func_index, - patch_caller); +void AttachWasmFunctionInfo(Isolate* isolate, Handle<Code> code, + MaybeHandle<WeakCell> weak_instance, + int func_index) { + DCHECK(weak_instance.is_null() || + weak_instance.ToHandleChecked()->value()->IsWasmInstanceObject()); + Handle<FixedArray> deopt_data = isolate->factory()->NewFixedArray(2, TENURED); + if (!weak_instance.is_null()) { + // TODO(wasm): Introduce constants for the indexes in wasm deopt data. + deopt_data->set(0, *weak_instance.ToHandleChecked()); + } + deopt_data->set(1, Smi::FromInt(func_index)); + + code->set_deoptimization_data(*deopt_data); +} + +void AttachWasmFunctionInfo(Isolate* isolate, Handle<Code> code, + MaybeHandle<WasmInstanceObject> instance, + int func_index) { + MaybeHandle<WeakCell> weak_instance; + if (!instance.is_null()) { + weak_instance = isolate->factory()->NewWeakCell(instance.ToHandleChecked()); + } + AttachWasmFunctionInfo(isolate, code, weak_instance, func_index); +} + +WasmFunctionInfo GetWasmFunctionInfo(Isolate* isolate, Handle<Code> code) { + FixedArray* deopt_data = code->deoptimization_data(); + DCHECK_LE(2, deopt_data->length()); + MaybeHandle<WasmInstanceObject> instance; + Object* maybe_weak_instance = deopt_data->get(0); + if (maybe_weak_instance->IsWeakCell()) { + Object* maybe_instance = WeakCell::cast(maybe_weak_instance)->value(); + if (maybe_instance) { + instance = handle(WasmInstanceObject::cast(maybe_instance), isolate); + } + } + int func_index = Smi::ToInt(deopt_data->get(1)); + return {instance, func_index}; } #undef TRACE |