diff options
author | Michaël Zasso <targos@protonmail.com> | 2019-03-12 09:01:49 +0100 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2019-03-14 18:49:21 +0100 |
commit | 7b48713334469818661fe276cf571de9c7899f2d (patch) | |
tree | 4dbda49ac88db76ce09dc330a0cb587e68e139ba /deps/v8/src/wasm/wasm-objects.cc | |
parent | 8549ac09b256666cf5275224ec58fab9939ff32e (diff) | |
download | android-node-v8-7b48713334469818661fe276cf571de9c7899f2d.tar.gz android-node-v8-7b48713334469818661fe276cf571de9c7899f2d.tar.bz2 android-node-v8-7b48713334469818661fe276cf571de9c7899f2d.zip |
deps: update V8 to 7.3.492.25
PR-URL: https://github.com/nodejs/node/pull/25852
Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@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 | 542 |
1 files changed, 369 insertions, 173 deletions
diff --git a/deps/v8/src/wasm/wasm-objects.cc b/deps/v8/src/wasm/wasm-objects.cc index 9d0e20ab2b..392ddd4ca8 100644 --- a/deps/v8/src/wasm/wasm-objects.cc +++ b/deps/v8/src/wasm/wasm-objects.cc @@ -9,10 +9,12 @@ #include "src/base/iterator.h" #include "src/code-factory.h" #include "src/compiler/wasm-compiler.h" +#include "src/counters.h" #include "src/debug/debug-interface.h" #include "src/objects-inl.h" #include "src/objects/debug-objects-inl.h" #include "src/objects/shared-function-info.h" +#include "src/objects/struct-inl.h" #include "src/trap-handler/trap-handler.h" #include "src/wasm/jump-table-assembler.h" #include "src/wasm/module-compiler.h" @@ -64,13 +66,24 @@ class WasmInstanceNativeAllocations { // Allocates initial native storage for a given instance. WasmInstanceNativeAllocations(Handle<WasmInstanceObject> instance, size_t num_imported_functions, - size_t num_imported_mutable_globals) { + size_t num_imported_mutable_globals, + size_t num_data_segments, + size_t num_elem_segments) { SET(instance, imported_function_targets, reinterpret_cast<Address*>( calloc(num_imported_functions, sizeof(Address)))); SET(instance, imported_mutable_globals, reinterpret_cast<Address*>( calloc(num_imported_mutable_globals, sizeof(Address)))); + SET(instance, data_segment_starts, + reinterpret_cast<Address*>(calloc(num_data_segments, sizeof(Address)))); + SET(instance, data_segment_sizes, + reinterpret_cast<uint32_t*>( + calloc(num_data_segments, sizeof(uint32_t)))); + SET(instance, dropped_data_segments, + reinterpret_cast<uint8_t*>(calloc(num_data_segments, sizeof(uint8_t)))); + SET(instance, dropped_elem_segments, + reinterpret_cast<uint8_t*>(calloc(num_elem_segments, sizeof(uint8_t)))); } ~WasmInstanceNativeAllocations() { ::free(indirect_function_table_sig_ids_); @@ -81,6 +94,14 @@ class WasmInstanceNativeAllocations { imported_function_targets_ = nullptr; ::free(imported_mutable_globals_); imported_mutable_globals_ = nullptr; + ::free(data_segment_starts_); + data_segment_starts_ = nullptr; + ::free(data_segment_sizes_); + data_segment_sizes_ = nullptr; + ::free(dropped_data_segments_); + dropped_data_segments_ = nullptr; + ::free(dropped_elem_segments_); + dropped_elem_segments_ = nullptr; } // Resizes the indirect function table. void resize_indirect_function_table(Isolate* isolate, @@ -89,7 +110,7 @@ class WasmInstanceNativeAllocations { uint32_t old_size = instance->indirect_function_table_size(); void* new_sig_ids = nullptr; void* new_targets = nullptr; - Handle<FixedArray> new_instances; + Handle<FixedArray> new_refs; if (indirect_function_table_sig_ids_) { // Reallocate the old storage. new_sig_ids = realloc(indirect_function_table_sig_ids_, @@ -97,16 +118,14 @@ class WasmInstanceNativeAllocations { new_targets = realloc(indirect_function_table_targets_, new_size * sizeof(Address)); - Handle<FixedArray> old(instance->indirect_function_table_instances(), - isolate); - new_instances = isolate->factory()->CopyFixedArrayAndGrow( + Handle<FixedArray> old(instance->indirect_function_table_refs(), isolate); + new_refs = isolate->factory()->CopyFixedArrayAndGrow( old, static_cast<int>(new_size - old_size)); } else { // Allocate new storage. new_sig_ids = malloc(new_size * sizeof(uint32_t)); new_targets = malloc(new_size * sizeof(Address)); - new_instances = - isolate->factory()->NewFixedArray(static_cast<int>(new_size)); + new_refs = isolate->factory()->NewFixedArray(static_cast<int>(new_size)); } // Initialize new entries. instance->set_indirect_function_table_size(new_size); @@ -115,7 +134,7 @@ class WasmInstanceNativeAllocations { SET(instance, indirect_function_table_targets, reinterpret_cast<Address*>(new_targets)); - instance->set_indirect_function_table_instances(*new_instances); + instance->set_indirect_function_table_refs(*new_refs); for (uint32_t j = old_size; j < new_size; j++) { IndirectFunctionTableEntry(instance, static_cast<int>(j)).clear(); } @@ -124,22 +143,29 @@ class WasmInstanceNativeAllocations { Address* indirect_function_table_targets_ = nullptr; Address* imported_function_targets_ = nullptr; Address* imported_mutable_globals_ = nullptr; + Address* data_segment_starts_ = nullptr; + uint32_t* data_segment_sizes_ = nullptr; + uint8_t* dropped_data_segments_ = nullptr; + uint8_t* dropped_elem_segments_ = nullptr; #undef SET }; size_t EstimateNativeAllocationsSize(const WasmModule* module) { - size_t estimate = sizeof(WasmInstanceNativeAllocations) + - (1 * kPointerSize * module->num_imported_mutable_globals) + - (2 * kPointerSize * module->num_imported_functions); + size_t estimate = + sizeof(WasmInstanceNativeAllocations) + + (1 * kSystemPointerSize * module->num_imported_mutable_globals) + + (2 * kSystemPointerSize * module->num_imported_functions) + + ((kSystemPointerSize + sizeof(uint32_t) + sizeof(uint8_t)) * + module->num_declared_data_segments); for (auto& table : module->tables) { - estimate += 3 * kPointerSize * table.initial_size; + estimate += 3 * kSystemPointerSize * table.initial_size; } return estimate; } WasmInstanceNativeAllocations* GetNativeAllocations( - WasmInstanceObject* instance) { - return reinterpret_cast<Managed<WasmInstanceNativeAllocations>*>( + WasmInstanceObject instance) { + return Managed<WasmInstanceNativeAllocations>::cast( instance->managed_native_allocations()) ->raw(); } @@ -177,25 +203,21 @@ enum DispatchTableElements : int { // static Handle<WasmModuleObject> WasmModuleObject::New( Isolate* isolate, const wasm::WasmFeatures& enabled, - std::shared_ptr<const wasm::WasmModule> shared_module, wasm::ModuleEnv& env, + std::shared_ptr<const wasm::WasmModule> shared_module, OwnedVector<const uint8_t> wire_bytes, Handle<Script> script, Handle<ByteArray> asm_js_offset_table) { - DCHECK_EQ(shared_module.get(), env.module); - // Create a new {NativeModule} first. - size_t native_memory_estimate = - isolate->wasm_engine()->code_manager()->EstimateNativeModuleSize( - env.module); + size_t code_size_estimate = + wasm::WasmCodeManager::EstimateNativeModuleCodeSize(shared_module.get()); auto native_module = isolate->wasm_engine()->code_manager()->NewNativeModule( - isolate, enabled, native_memory_estimate, - wasm::NativeModule::kCanAllocateMoreMemory, std::move(shared_module), - env); - native_module->set_wire_bytes(std::move(wire_bytes)); + isolate, enabled, code_size_estimate, + wasm::NativeModule::kCanAllocateMoreMemory, std::move(shared_module)); + native_module->SetWireBytes(std::move(wire_bytes)); native_module->SetRuntimeStubs(isolate); // Delegate to the shared {WasmModuleObject::New} allocator. Handle<WasmModuleObject> module_object = - New(isolate, std::move(native_module), script); + New(isolate, std::move(native_module), script, code_size_estimate); if (!asm_js_offset_table.is_null()) { module_object->set_asm_js_offset_table(*asm_js_offset_table); } @@ -205,19 +227,27 @@ Handle<WasmModuleObject> WasmModuleObject::New( // static Handle<WasmModuleObject> WasmModuleObject::New( Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module, - Handle<Script> script) { - int export_wrapper_size = - static_cast<int>(native_module->module()->num_exported_functions); + Handle<Script> script, size_t code_size_estimate) { + const WasmModule* module = native_module->module(); + int export_wrapper_size = static_cast<int>(module->num_exported_functions); Handle<FixedArray> export_wrappers = isolate->factory()->NewFixedArray(export_wrapper_size, TENURED); + return New(isolate, std::move(native_module), script, export_wrappers, + code_size_estimate); +} + +// static +Handle<WasmModuleObject> WasmModuleObject::New( + Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module, + Handle<Script> script, Handle<FixedArray> export_wrappers, + size_t code_size_estimate) { + const WasmModule* module = native_module->module(); // Use the given shared {NativeModule}, but increase its reference count by // allocating a new {Managed<T>} that the {WasmModuleObject} references. - size_t native_memory_estimate = - isolate->wasm_engine()->code_manager()->EstimateNativeModuleSize( - native_module->module()); size_t memory_estimate = - EstimateWasmModuleSize(native_module->module()) + native_memory_estimate; + code_size_estimate + + wasm::WasmCodeManager::EstimateNativeModuleNonCodeSize(module); Handle<Managed<wasm::NativeModule>> managed_native_module = Managed<wasm::NativeModule>::FromSharedPtr(isolate, memory_estimate, std::move(native_module)); @@ -259,7 +289,7 @@ bool WasmModuleObject::SetBreakPoint(Handle<WasmModuleObject> module_object, Handle<WeakArrayList> weak_instance_list(module_object->weak_instance_list(), isolate); for (int i = 0; i < weak_instance_list->length(); ++i) { - MaybeObject* maybe_instance = weak_instance_list->Get(i); + MaybeObject maybe_instance = weak_instance_list->Get(i); if (maybe_instance->IsWeak()) { Handle<WasmInstanceObject> instance( WasmInstanceObject::cast(maybe_instance->GetHeapObjectAssumeWeak()), @@ -275,7 +305,7 @@ bool WasmModuleObject::SetBreakPoint(Handle<WasmModuleObject> module_object, namespace { -int GetBreakpointPos(Isolate* isolate, Object* break_point_info_or_undef) { +int GetBreakpointPos(Isolate* isolate, Object break_point_info_or_undef) { if (break_point_info_or_undef->IsUndefined(isolate)) return kMaxInt; return BreakPointInfo::cast(break_point_info_or_undef)->source_position(); } @@ -291,7 +321,7 @@ int FindBreakpointInfoInsertPos(Isolate* isolate, int right = breakpoint_infos->length(); // exclusive while (right - left > 1) { int mid = left + (right - left) / 2; - Object* mid_obj = breakpoint_infos->get(mid); + Object mid_obj = breakpoint_infos->get(mid); if (GetBreakpointPos(isolate, mid_obj) <= position) { left = mid; } else { @@ -346,7 +376,7 @@ void WasmModuleObject::AddBreakpoint(Handle<WasmModuleObject> module_object, // Move elements [insert_pos, ...] up by one. for (int i = breakpoint_infos->length() - 1; i >= insert_pos; --i) { - Object* entry = breakpoint_infos->get(i); + Object entry = breakpoint_infos->get(i); if (entry->IsUndefined(isolate)) continue; new_breakpoint_infos->set(i + 1, entry); } @@ -414,25 +444,24 @@ Handle<ByteArray> GetDecodedAsmJsOffsetTable( DCHECK(table_type == Encoded || table_type == Decoded); if (table_type == Decoded) return offset_table; - wasm::AsmJsOffsetsResult asm_offsets; + wasm::AsmJsOffsets asm_offsets; { DisallowHeapAllocation no_gc; byte* bytes_start = offset_table->GetDataStartAddress(); byte* bytes_end = reinterpret_cast<byte*>( reinterpret_cast<Address>(bytes_start) + offset_table->length() - 1); - asm_offsets = wasm::DecodeAsmJsOffsets(bytes_start, bytes_end); + asm_offsets = wasm::DecodeAsmJsOffsets(bytes_start, bytes_end).value(); } // Wasm bytes must be valid and must contain asm.js offset table. - DCHECK(asm_offsets.ok()); - DCHECK_GE(kMaxInt, asm_offsets.val.size()); - int num_functions = static_cast<int>(asm_offsets.val.size()); + DCHECK_GE(kMaxInt, asm_offsets.size()); + int num_functions = static_cast<int>(asm_offsets.size()); int num_imported_functions = static_cast<int>(module_object->module()->num_imported_functions); DCHECK_EQ(module_object->module()->functions.size(), static_cast<size_t>(num_functions) + num_imported_functions); int num_entries = 0; for (int func = 0; func < num_functions; ++func) { - size_t new_size = asm_offsets.val[func].size(); + size_t new_size = asm_offsets[func].size(); DCHECK_LE(new_size, static_cast<size_t>(kMaxInt) - num_entries); num_entries += static_cast<int>(new_size); } @@ -449,8 +478,7 @@ Handle<ByteArray> GetDecodedAsmJsOffsetTable( const std::vector<WasmFunction>& wasm_funs = module_object->module()->functions; for (int func = 0; func < num_functions; ++func) { - std::vector<wasm::AsmJsOffsetEntry>& func_asm_offsets = - asm_offsets.val[func]; + std::vector<wasm::AsmJsOffsetEntry>& func_asm_offsets = asm_offsets[func]; if (func_asm_offsets.empty()) continue; int func_offset = wasm_funs[num_imported_functions + func].code.offset(); for (wasm::AsmJsOffsetEntry& e : func_asm_offsets) { @@ -520,7 +548,7 @@ v8::debug::WasmDisassembly WasmModuleObject::DisassembleFunction( static_cast<uint32_t>(func_index) >= module()->functions.size()) return {}; - Vector<const byte> wire_bytes = native_module()->wire_bytes(); + wasm::ModuleWireBytes wire_bytes(native_module()->wire_bytes()); std::ostringstream disassembly_os; v8::debug::WasmDisassembly::OffsetTable offset_table; @@ -747,7 +775,7 @@ bool WasmModuleObject::GetPositionInfo(uint32_t position, } Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial, - int64_t maximum, + uint32_t maximum, Handle<FixedArray>* js_functions) { Handle<JSFunction> table_ctor( isolate->native_context()->wasm_table_constructor(), isolate); @@ -755,13 +783,12 @@ Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial, isolate->factory()->NewJSObject(table_ctor)); *js_functions = isolate->factory()->NewFixedArray(initial); - Object* null = ReadOnlyRoots(isolate).null_value(); + Object null = ReadOnlyRoots(isolate).null_value(); for (int i = 0; i < static_cast<int>(initial); ++i) { (*js_functions)->set(i, null); } table_obj->set_functions(**js_functions); - DCHECK_EQ(maximum, static_cast<int>(maximum)); - Handle<Object> max = isolate->factory()->NewNumber(maximum); + Handle<Object> max = isolate->factory()->NewNumberFromUint(maximum); table_obj->set_maximum_length(*max); table_obj->set_dispatch_tables(ReadOnlyRoots(isolate).empty_fixed_array()); @@ -817,7 +844,7 @@ void WasmTableObject::Grow(Isolate* isolate, uint32_t count) { } void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table, - int32_t table_index, Handle<JSFunction> function) { + uint32_t table_index, Handle<JSFunction> function) { Handle<FixedArray> array(table->functions(), isolate); if (function.is_null()) { ClearDispatchTables(isolate, table, table_index); // Degenerate case. @@ -825,26 +852,23 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table, return; } - // TODO(titzer): Change this to MaybeHandle<WasmExportedFunction> - DCHECK(WasmExportedFunction::IsWasmExportedFunction(*function)); auto exported_function = Handle<WasmExportedFunction>::cast(function); - Handle<WasmInstanceObject> other_instance(exported_function->instance(), - isolate); + Handle<WasmInstanceObject> target_instance(exported_function->instance(), + isolate); int func_index = exported_function->function_index(); - auto* wasm_function = &other_instance->module()->functions[func_index]; + auto* wasm_function = &target_instance->module()->functions[func_index]; DCHECK_NOT_NULL(wasm_function); DCHECK_NOT_NULL(wasm_function->sig); - Address call_target = exported_function->GetWasmCallTarget(); UpdateDispatchTables(isolate, table, table_index, wasm_function->sig, handle(exported_function->instance(), isolate), - call_target); + func_index); array->set(table_index, *function); } void WasmTableObject::UpdateDispatchTables( Isolate* isolate, Handle<WasmTableObject> table, int table_index, - wasm::FunctionSig* sig, Handle<WasmInstanceObject> from_instance, - Address call_target) { + wasm::FunctionSig* sig, Handle<WasmInstanceObject> target_instance, + int target_func_index) { // We simply need to update the IFTs for each instance that imports // this table. Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate); @@ -852,15 +876,15 @@ void WasmTableObject::UpdateDispatchTables( for (int i = 0; i < dispatch_tables->length(); i += kDispatchTableNumElements) { - Handle<WasmInstanceObject> to_instance( + Handle<WasmInstanceObject> instance( WasmInstanceObject::cast( dispatch_tables->get(i + kDispatchTableInstanceOffset)), isolate); // Note that {SignatureMap::Find} may return {-1} if the signature is // not found; it will simply never match any check. - auto sig_id = to_instance->module()->signature_map.Find(*sig); - IndirectFunctionTableEntry(to_instance, table_index) - .set(sig_id, *from_instance, call_target); + auto sig_id = instance->module()->signature_map.Find(*sig); + IndirectFunctionTableEntry(instance, table_index) + .Set(sig_id, target_instance, target_func_index); } } @@ -881,25 +905,12 @@ void WasmTableObject::ClearDispatchTables(Isolate* isolate, } namespace { -MaybeHandle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate, +MaybeHandle<JSArrayBuffer> MemoryGrowBuffer(Isolate* isolate, Handle<JSArrayBuffer> old_buffer, - uint32_t pages, - uint32_t maximum_pages) { - if (!old_buffer->is_growable()) return {}; - void* old_mem_start = old_buffer->backing_store(); + size_t new_size) { + CHECK_EQ(0, new_size % wasm::kWasmPageSize); size_t old_size = old_buffer->byte_length(); - CHECK_GE(wasm::kV8MaxWasmMemoryBytes, old_size); - CHECK_EQ(0, old_size % wasm::kWasmPageSize); - size_t old_pages = old_size / wasm::kWasmPageSize; - if (old_pages > maximum_pages || // already reached maximum - (pages > maximum_pages - old_pages) || // exceeds remaining - (pages > FLAG_wasm_max_mem_pages - old_pages)) { // exceeds limit - return {}; - } - size_t new_size = - static_cast<size_t>(old_pages + pages) * wasm::kWasmPageSize; - CHECK_GE(wasm::kV8MaxWasmMemoryBytes, new_size); - + void* old_mem_start = old_buffer->backing_store(); // Reusing the backing store from externalized buffers causes problems with // Blink's array buffers. The connection between the two is lost, which can // lead to Blink not knowing about the other reference to the buffer and @@ -914,8 +925,9 @@ MaybeHandle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate, new_size, PageAllocator::kReadWrite)) { return {}; } + DCHECK_GE(new_size, old_size); reinterpret_cast<v8::Isolate*>(isolate) - ->AdjustAmountOfExternalAllocatedMemory(pages * wasm::kWasmPageSize); + ->AdjustAmountOfExternalAllocatedMemory(new_size - old_size); } // NOTE: We must allocate a new array buffer here because the spec // assumes that ArrayBuffers do not change size. @@ -976,7 +988,7 @@ void SetInstanceMemory(Handle<WasmInstanceObject> instance, Handle<WasmMemoryObject> WasmMemoryObject::New( Isolate* isolate, MaybeHandle<JSArrayBuffer> maybe_buffer, - int32_t maximum) { + uint32_t maximum) { // TODO(kschimpf): Do we need to add an argument that defines the // style of memory the user prefers (with/without trap handling), so // that the memory will match the style of the compiled wasm module. @@ -997,11 +1009,6 @@ Handle<WasmMemoryObject> WasmMemoryObject::New( return memory_obj; } -uint32_t WasmMemoryObject::current_pages() { - return static_cast<uint32_t>(array_buffer()->byte_length() / - wasm::kWasmPageSize); -} - bool WasmMemoryObject::has_full_guard_region(Isolate* isolate) { const wasm::WasmMemoryTracker::AllocationData* allocation = isolate->wasm_engine()->memory_tracker()->FindAllocationData( @@ -1041,38 +1048,44 @@ void WasmMemoryObject::AddInstance(Isolate* isolate, SetInstanceMemory(instance, buffer); } -void WasmMemoryObject::RemoveInstance(Handle<WasmMemoryObject> memory, - Handle<WasmInstanceObject> instance) { - if (memory->has_instances()) { - memory->instances()->RemoveOne(MaybeObjectHandle::Weak(instance)); - } -} - // static int32_t WasmMemoryObject::Grow(Isolate* isolate, Handle<WasmMemoryObject> memory_object, uint32_t pages) { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "GrowMemory"); Handle<JSArrayBuffer> old_buffer(memory_object->array_buffer(), isolate); if (!old_buffer->is_growable()) return -1; - size_t old_size = old_buffer->byte_length(); - DCHECK_EQ(0, old_size % wasm::kWasmPageSize); - Handle<JSArrayBuffer> new_buffer; - uint32_t maximum_pages = FLAG_wasm_max_mem_pages; + // Checks for maximum memory size, compute new size. + uint32_t maximum_pages = 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())); + maximum_pages = std::min( + maximum_pages, static_cast<uint32_t>(memory_object->maximum_pages())); + } + CHECK_GE(wasm::max_mem_pages(), maximum_pages); + size_t old_size = old_buffer->byte_length(); + CHECK_EQ(0, old_size % wasm::kWasmPageSize); + size_t old_pages = old_size / wasm::kWasmPageSize; + CHECK_GE(wasm::max_mem_pages(), old_pages); + if ((pages > maximum_pages - old_pages) || // exceeds remaining + (pages > wasm::max_mem_pages() - old_pages)) { // exceeds limit + return -1; } - if (!GrowMemoryBuffer(isolate, old_buffer, pages, maximum_pages) - .ToHandle(&new_buffer)) { + size_t new_size = + static_cast<size_t>(old_pages + pages) * wasm::kWasmPageSize; + + // Grow the buffer. + Handle<JSArrayBuffer> new_buffer; + if (!MemoryGrowBuffer(isolate, old_buffer, new_size).ToHandle(&new_buffer)) { return -1; } + // Update instances if any. if (memory_object->has_instances()) { Handle<WeakArrayList> instances(memory_object->instances(), isolate); for (int i = 0; i < instances->length(); i++) { - MaybeObject* elem = instances->Get(i); - HeapObject* heap_object; + MaybeObject elem = instances->Get(i); + HeapObject heap_object; if (elem->GetHeapObjectIfWeak(&heap_object)) { Handle<WasmInstanceObject> instance( WasmInstanceObject::cast(heap_object), isolate); @@ -1088,32 +1101,44 @@ int32_t WasmMemoryObject::Grow(Isolate* isolate, // static MaybeHandle<WasmGlobalObject> WasmGlobalObject::New( - Isolate* isolate, MaybeHandle<JSArrayBuffer> maybe_buffer, - wasm::ValueType type, int32_t offset, bool is_mutable) { + Isolate* isolate, MaybeHandle<JSArrayBuffer> maybe_untagged_buffer, + MaybeHandle<FixedArray> maybe_tagged_buffer, wasm::ValueType type, + int32_t offset, bool is_mutable) { Handle<JSFunction> global_ctor( isolate->native_context()->wasm_global_constructor(), isolate); auto global_obj = Handle<WasmGlobalObject>::cast( isolate->factory()->NewJSObject(global_ctor)); - uint32_t type_size = wasm::ValueTypes::ElementSizeInBytes(type); - - Handle<JSArrayBuffer> buffer; - if (!maybe_buffer.ToHandle(&buffer)) { - // If no buffer was provided, create one long enough for the given type. - buffer = - isolate->factory()->NewJSArrayBuffer(SharedFlag::kNotShared, TENURED); - - const bool initialize = true; - if (!JSArrayBuffer::SetupAllocatingData(buffer, isolate, type_size, - initialize)) { - return {}; + if (type == wasm::kWasmAnyRef) { + DCHECK(maybe_untagged_buffer.is_null()); + Handle<FixedArray> tagged_buffer; + if (!maybe_tagged_buffer.ToHandle(&tagged_buffer)) { + // If no buffer was provided, create one. + tagged_buffer = isolate->factory()->NewFixedArray(1, TENURED); + CHECK_EQ(offset, 0); + } + global_obj->set_tagged_buffer(*tagged_buffer); + } else { + DCHECK(maybe_tagged_buffer.is_null()); + Handle<JSArrayBuffer> untagged_buffer; + uint32_t type_size = wasm::ValueTypes::ElementSizeInBytes(type); + if (!maybe_untagged_buffer.ToHandle(&untagged_buffer)) { + // If no buffer was provided, create one long enough for the given type. + untagged_buffer = + isolate->factory()->NewJSArrayBuffer(SharedFlag::kNotShared, TENURED); + + const bool initialize = true; + if (!JSArrayBuffer::SetupAllocatingData(untagged_buffer, isolate, + type_size, initialize)) { + return {}; + } } - } - // Check that the offset is in bounds. - CHECK_LE(offset + type_size, buffer->byte_length()); + // Check that the offset is in bounds. + CHECK_LE(offset + type_size, untagged_buffer->byte_length()); - global_obj->set_array_buffer(*buffer); + global_obj->set_untagged_buffer(*untagged_buffer); + } global_obj->set_flags(0); global_obj->set_type(type); global_obj->set_offset(offset); @@ -1125,23 +1150,42 @@ MaybeHandle<WasmGlobalObject> WasmGlobalObject::New( void IndirectFunctionTableEntry::clear() { instance_->indirect_function_table_sig_ids()[index_] = -1; instance_->indirect_function_table_targets()[index_] = 0; - instance_->indirect_function_table_instances()->set( + instance_->indirect_function_table_refs()->set( index_, ReadOnlyRoots(instance_->GetIsolate()).undefined_value()); } -void IndirectFunctionTableEntry::set(int sig_id, WasmInstanceObject* instance, - Address call_target) { - TRACE_IFT("IFT entry %p[%d] = {sig_id=%d, instance=%p, target=%" PRIuPTR - "}\n", - *instance_, index_, sig_id, instance, call_target); +void IndirectFunctionTableEntry::Set(int sig_id, + Handle<WasmInstanceObject> target_instance, + int target_func_index) { + TRACE_IFT( + "IFT entry %p[%d] = {sig_id=%d, target_instance=%p, " + "target_func_index=%d}\n", + reinterpret_cast<void*>(instance_->ptr()), index_, sig_id, + reinterpret_cast<void*>(target_instance->ptr()), target_func_index); + + Object ref; + Address call_target = 0; + if (target_func_index < + static_cast<int>(target_instance->module()->num_imported_functions)) { + // The function in the target instance was imported. Use its imports table, + // which contains a tuple needed by the import wrapper. + ImportedFunctionEntry entry(target_instance, target_func_index); + ref = entry.object_ref(); + call_target = entry.target(); + } else { + // The function in the target instance was not imported. + ref = *target_instance; + call_target = target_instance->GetCallTarget(target_func_index); + } + + // Set the signature id, the target, and the receiver ref. instance_->indirect_function_table_sig_ids()[index_] = sig_id; instance_->indirect_function_table_targets()[index_] = call_target; - instance_->indirect_function_table_instances()->set(index_, instance); + instance_->indirect_function_table_refs()->set(index_, ref); } -WasmInstanceObject* IndirectFunctionTableEntry::instance() { - return WasmInstanceObject::cast( - instance_->indirect_function_table_instances()->get(index_)); +Object IndirectFunctionTableEntry::object_ref() { + return instance_->indirect_function_table_refs()->get(index_); } int IndirectFunctionTableEntry::sig_id() { @@ -1152,43 +1196,61 @@ Address IndirectFunctionTableEntry::target() { return instance_->indirect_function_table_targets()[index_]; } -void ImportedFunctionEntry::set_wasm_to_js( - JSReceiver* callable, const wasm::WasmCode* wasm_to_js_wrapper) { - TRACE_IFT("Import callable %p[%d] = {callable=%p, target=%p}\n", *instance_, - index_, callable, wasm_to_js_wrapper->instructions().start()); +void IndirectFunctionTableEntry::CopyFrom( + const IndirectFunctionTableEntry& that) { + instance_->indirect_function_table_sig_ids()[index_] = + that.instance_->indirect_function_table_sig_ids()[that.index_]; + instance_->indirect_function_table_targets()[index_] = + that.instance_->indirect_function_table_targets()[that.index_]; + instance_->indirect_function_table_refs()->set( + index_, that.instance_->indirect_function_table_refs()->get(that.index_)); +} + +void ImportedFunctionEntry::SetWasmToJs( + Isolate* isolate, Handle<JSReceiver> callable, + const wasm::WasmCode* wasm_to_js_wrapper) { + TRACE_IFT("Import callable %p[%d] = {callable=%p, target=%p}\n", + reinterpret_cast<void*>(instance_->ptr()), index_, + reinterpret_cast<void*>(callable->ptr()), + wasm_to_js_wrapper->instructions().start()); DCHECK_EQ(wasm::WasmCode::kWasmToJsWrapper, wasm_to_js_wrapper->kind()); - instance_->imported_function_instances()->set(index_, *instance_); - instance_->imported_function_callables()->set(index_, callable); + Handle<Tuple2> tuple = + isolate->factory()->NewTuple2(instance_, callable, TENURED); + instance_->imported_function_refs()->set(index_, *tuple); instance_->imported_function_targets()[index_] = wasm_to_js_wrapper->instruction_start(); } -void ImportedFunctionEntry::set_wasm_to_wasm(WasmInstanceObject* instance, - Address call_target) { +void ImportedFunctionEntry::SetWasmToWasm(WasmInstanceObject instance, + Address call_target) { TRACE_IFT("Import WASM %p[%d] = {instance=%p, target=%" PRIuPTR "}\n", - *instance_, index_, instance, call_target); - instance_->imported_function_instances()->set(index_, instance); - instance_->imported_function_callables()->set( - index_, instance_->GetReadOnlyRoots().undefined_value()); + reinterpret_cast<void*>(instance_->ptr()), index_, + reinterpret_cast<void*>(instance->ptr()), call_target); + instance_->imported_function_refs()->set(index_, instance); instance_->imported_function_targets()[index_] = call_target; } -WasmInstanceObject* ImportedFunctionEntry::instance() { - return WasmInstanceObject::cast( - instance_->imported_function_instances()->get(index_)); +WasmInstanceObject ImportedFunctionEntry::instance() { + // The imported reference entry is either a target instance or a tuple + // of this instance and the target callable. + Object value = instance_->imported_function_refs()->get(index_); + if (value->IsWasmInstanceObject()) { + return WasmInstanceObject::cast(value); + } + Tuple2 tuple = Tuple2::cast(value); + return WasmInstanceObject::cast(tuple->value1()); } -JSReceiver* ImportedFunctionEntry::callable() { - return JSReceiver::cast( - instance_->imported_function_callables()->get(index_)); +JSReceiver ImportedFunctionEntry::callable() { + return JSReceiver::cast(Tuple2::cast(object_ref())->value2()); } -Address ImportedFunctionEntry::target() { - return instance_->imported_function_targets()[index_]; +Object ImportedFunctionEntry::object_ref() { + return instance_->imported_function_refs()->get(index_); } -bool ImportedFunctionEntry::is_js_receiver_entry() { - return instance_->imported_function_callables()->get(index_)->IsJSReceiver(); +Address ImportedFunctionEntry::target() { + return instance_->imported_function_targets()[index_]; } bool WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize( @@ -1205,7 +1267,7 @@ bool WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize( } void WasmInstanceObject::SetRawMemory(byte* mem_start, size_t mem_size) { - CHECK_LE(mem_size, wasm::kV8MaxWasmMemoryBytes); + CHECK_LE(mem_size, wasm::max_mem_bytes()); #if V8_HOST_ARCH_64_BIT uint64_t mem_mask64 = base::bits::RoundUpToPowerOfTwo64(mem_size) - 1; set_memory_start(mem_start); @@ -1247,32 +1309,30 @@ Handle<WasmInstanceObject> WasmInstanceObject::New( isolate->factory()->NewJSObject(instance_cons, TENURED); Handle<WasmInstanceObject> instance( - reinterpret_cast<WasmInstanceObject*>(*instance_object), isolate); + WasmInstanceObject::cast(*instance_object), isolate); + instance->clear_padding(); // Initialize the imported function arrays. auto module = module_object->module(); auto num_imported_functions = module->num_imported_functions; auto num_imported_mutable_globals = module->num_imported_mutable_globals; + auto num_data_segments = module->num_declared_data_segments; size_t native_allocations_size = EstimateNativeAllocationsSize(module); auto native_allocations = Managed<WasmInstanceNativeAllocations>::Allocate( isolate, native_allocations_size, instance, num_imported_functions, - num_imported_mutable_globals); + num_imported_mutable_globals, num_data_segments, + module->elem_segments.size()); instance->set_managed_native_allocations(*native_allocations); - Handle<FixedArray> imported_function_instances = - isolate->factory()->NewFixedArray(num_imported_functions); - instance->set_imported_function_instances(*imported_function_instances); - - Handle<FixedArray> imported_function_callables = + Handle<FixedArray> imported_function_refs = isolate->factory()->NewFixedArray(num_imported_functions); - instance->set_imported_function_callables(*imported_function_callables); + instance->set_imported_function_refs(*imported_function_refs); Handle<Code> centry_stub = CodeFactory::CEntry(isolate); instance->set_centry_stub(*centry_stub); instance->SetRawMemory(nullptr, 0); - instance->set_roots_array_address( - reinterpret_cast<Address>(isolate->heap()->roots_array_start())); + instance->set_isolate_root(isolate->isolate_root()); instance->set_stack_limit_address( isolate->stack_guard()->address_of_jslimit()); instance->set_real_stack_limit_address( @@ -1296,9 +1356,54 @@ Handle<WasmInstanceObject> WasmInstanceObject::New( isolate, weak_instance_list, MaybeObjectHandle::Weak(instance)); module_object->set_weak_instance_list(*weak_instance_list); + InitDataSegmentArrays(instance, module_object); + InitElemSegmentArrays(instance, module_object); + return instance; } +// static +void WasmInstanceObject::InitDataSegmentArrays( + Handle<WasmInstanceObject> instance, + Handle<WasmModuleObject> module_object) { + auto module = module_object->module(); + auto wire_bytes = module_object->native_module()->wire_bytes(); + auto num_data_segments = module->num_declared_data_segments; + // The number of declared data segments will be zero if there is no DataCount + // section. These arrays will not be allocated nor initialized in that case, + // since they cannot be used (since the validator checks that number of + // declared data segments when validating the memory.init and memory.drop + // instructions). + DCHECK(num_data_segments == 0 || + num_data_segments == module->data_segments.size()); + for (size_t i = 0; i < num_data_segments; ++i) { + const wasm::WasmDataSegment& segment = module->data_segments[i]; + // Set the active segments to being already dropped, since memory.init on + // a dropped passive segment and an active segment have the same + // behavior. + instance->dropped_data_segments()[i] = segment.active ? 1 : 0; + + // Initialize the pointer and size of passive segments. + instance->data_segment_starts()[i] = + reinterpret_cast<Address>(&wire_bytes[segment.source.offset()]); + instance->data_segment_sizes()[i] = segment.source.length(); + } +} + +void WasmInstanceObject::InitElemSegmentArrays( + Handle<WasmInstanceObject> instance, + Handle<WasmModuleObject> module_object) { + auto module = module_object->module(); + auto num_elem_segments = module->elem_segments.size(); + for (size_t i = 0; i < num_elem_segments; ++i) { + const wasm::WasmElemSegment& segment = module->elem_segments[i]; + // Set the active segments to being already dropped, since table.init on + // a dropped passive segment and an active segment have the same + // behavior. + instance->dropped_elem_segments()[i] = segment.active ? 1 : 0; + } +} + Address WasmInstanceObject::GetCallTarget(uint32_t func_index) { wasm::NativeModule* native_module = module_object()->native_module(); if (func_index < native_module->num_imported_functions()) { @@ -1307,6 +1412,71 @@ Address WasmInstanceObject::GetCallTarget(uint32_t func_index) { return native_module->GetCallTargetForFunction(func_index); } +namespace { +void CopyTableEntriesImpl(Handle<WasmInstanceObject> instance, uint32_t dst, + uint32_t src, uint32_t count) { + DCHECK(IsInBounds(dst, count, instance->indirect_function_table_size())); + if (src < dst) { + for (uint32_t i = count; i > 0; i--) { + auto to_entry = IndirectFunctionTableEntry(instance, dst + i - 1); + auto from_entry = IndirectFunctionTableEntry(instance, src + i - 1); + to_entry.CopyFrom(from_entry); + } + } else { + for (uint32_t i = 0; i < count; i++) { + auto to_entry = IndirectFunctionTableEntry(instance, dst + i); + auto from_entry = IndirectFunctionTableEntry(instance, src + i); + to_entry.CopyFrom(from_entry); + } + } +} +} // namespace + +// static +bool WasmInstanceObject::CopyTableEntries(Isolate* isolate, + Handle<WasmInstanceObject> instance, + uint32_t table_index, uint32_t dst, + uint32_t src, uint32_t count) { + CHECK_EQ(0, table_index); // TODO(titzer): multiple tables in TableCopy + if (count == 0) return true; // no-op + auto max = instance->indirect_function_table_size(); + if (!IsInBounds(dst, count, max)) return false; + if (!IsInBounds(src, count, max)) return false; + if (dst == src) return true; // no-op + + if (!instance->has_table_object()) { + // No table object, only need to update this instance. + CopyTableEntriesImpl(instance, dst, src, count); + return true; + } + + Handle<WasmTableObject> table = + Handle<WasmTableObject>(instance->table_object(), isolate); + // Broadcast table copy operation to all instances that import this table. + Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate); + for (int i = 0; i < dispatch_tables->length(); + i += kDispatchTableNumElements) { + Handle<WasmInstanceObject> target_instance( + WasmInstanceObject::cast( + dispatch_tables->get(i + kDispatchTableInstanceOffset)), + isolate); + CopyTableEntriesImpl(target_instance, dst, src, count); + } + + // Copy the function entries. + Handle<FixedArray> functions(table->functions(), isolate); + if (src < dst) { + for (uint32_t i = count; i > 0; i--) { + functions->set(dst + i - 1, functions->get(src + i - 1)); + } + } else { + for (uint32_t i = 0; i < count; i++) { + functions->set(dst + i, functions->get(src + i)); + } + } + return true; +} + // static Handle<WasmExceptionObject> WasmExceptionObject::New( Isolate* isolate, const wasm::FunctionSig* sig, @@ -1347,20 +1517,15 @@ bool WasmExceptionObject::IsSignatureEqual(const wasm::FunctionSig* sig) { return true; } -bool WasmExportedFunction::IsWasmExportedFunction(Object* object) { +bool WasmExportedFunction::IsWasmExportedFunction(Object object) { if (!object->IsJSFunction()) return false; - JSFunction* js_function = JSFunction::cast(object); + JSFunction js_function = JSFunction::cast(object); if (Code::JS_TO_WASM_FUNCTION != js_function->code()->kind()) return false; DCHECK(js_function->shared()->HasWasmExportedFunctionData()); return true; } -WasmExportedFunction* WasmExportedFunction::cast(Object* object) { - DCHECK(IsWasmExportedFunction(object)); - return reinterpret_cast<WasmExportedFunction*>(object); -} - -WasmInstanceObject* WasmExportedFunction::instance() { +WasmInstanceObject WasmExportedFunction::instance() { return shared()->wasm_exported_function_data()->instance(); } @@ -1413,6 +1578,37 @@ Address WasmExportedFunction::GetWasmCallTarget() { return instance()->GetCallTarget(function_index()); } +wasm::FunctionSig* WasmExportedFunction::sig() { + return instance()->module()->functions[function_index()].sig; +} + +Handle<WasmExceptionTag> WasmExceptionTag::New(Isolate* isolate, int index) { + Handle<WasmExceptionTag> result = Handle<WasmExceptionTag>::cast( + isolate->factory()->NewStruct(WASM_EXCEPTION_TAG_TYPE, TENURED)); + result->set_index(index); + return result; +} + +Handle<AsmWasmData> AsmWasmData::New( + Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module, + Handle<FixedArray> export_wrappers, Handle<ByteArray> asm_js_offset_table, + Handle<HeapNumber> uses_bitset) { + const WasmModule* module = native_module->module(); + size_t memory_estimate = + wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module) + + wasm::WasmCodeManager::EstimateNativeModuleNonCodeSize(module); + Handle<Managed<wasm::NativeModule>> managed_native_module = + Managed<wasm::NativeModule>::FromSharedPtr(isolate, memory_estimate, + std::move(native_module)); + Handle<AsmWasmData> result = Handle<AsmWasmData>::cast( + isolate->factory()->NewStruct(ASM_WASM_DATA_TYPE, TENURED)); + result->set_managed_native_module(*managed_native_module); + result->set_export_wrappers(*export_wrappers); + result->set_asm_js_offset_table(*asm_js_offset_table); + result->set_uses_bitset(*uses_bitset); + return result; +} + #undef TRACE #undef TRACE_IFT } // namespace internal |