// Copyright 2015 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/wasm/wasm-objects.h" #include "src/utils/utils.h" #include "src/base/iterator.h" #include "src/codegen/assembler-inl.h" #include "src/codegen/code-factory.h" #include "src/compiler/wasm-compiler.h" #include "src/debug/debug-interface.h" #include "src/logging/counters.h" #include "src/objects/debug-objects-inl.h" #include "src/objects/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/utils/vector.h" #include "src/wasm/jump-table-assembler.h" #include "src/wasm/module-compiler.h" #include "src/wasm/module-decoder.h" #include "src/wasm/module-instantiate.h" #include "src/wasm/value-type.h" #include "src/wasm/wasm-code-manager.h" #include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-limits.h" #include "src/wasm/wasm-module.h" #include "src/wasm/wasm-objects-inl.h" #define TRACE(...) \ do { \ if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \ } while (false) #define TRACE_IFT(...) \ do { \ if (false) PrintF(__VA_ARGS__); \ } while (false) namespace v8 { namespace internal { // Import a few often used types from the wasm namespace. using WasmFunction = wasm::WasmFunction; using WasmModule = wasm::WasmModule; namespace { // Manages the natively-allocated memory for a WasmInstanceObject. Since // an instance finalizer is not guaranteed to run upon isolate shutdown, // we must use a Managed to guarantee // it is freed. // Native allocations are the signature ids and targets for indirect call // targets, as well as the call targets for imported functions. class WasmInstanceNativeAllocations { public: // Helper macro to set an internal field and the corresponding field // on an instance. #define SET(instance, field, value) \ { \ auto v = value; \ this->field##_ = v; \ instance->set_##field(v); \ } // Allocates initial native storage for a given instance. WasmInstanceNativeAllocations(Handle instance, size_t num_imported_functions, size_t num_imported_mutable_globals, size_t num_data_segments, size_t num_elem_segments) { SET(instance, imported_function_targets, reinterpret_cast( calloc(num_imported_functions, sizeof(Address)))); SET(instance, imported_mutable_globals, reinterpret_cast( calloc(num_imported_mutable_globals, sizeof(Address)))); SET(instance, data_segment_starts, reinterpret_cast(calloc(num_data_segments, sizeof(Address)))); SET(instance, data_segment_sizes, reinterpret_cast( calloc(num_data_segments, sizeof(uint32_t)))); SET(instance, dropped_data_segments, reinterpret_cast(calloc(num_data_segments, sizeof(uint8_t)))); SET(instance, dropped_elem_segments, reinterpret_cast(calloc(num_elem_segments, sizeof(uint8_t)))); } ~WasmInstanceNativeAllocations() { ::free(indirect_function_table_sig_ids_); indirect_function_table_sig_ids_ = nullptr; ::free(indirect_function_table_targets_); indirect_function_table_targets_ = nullptr; ::free(imported_function_targets_); 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, Handle instance, uint32_t new_size) { uint32_t old_size = instance->indirect_function_table_size(); void* new_sig_ids = nullptr; void* new_targets = nullptr; Handle new_refs; if (indirect_function_table_sig_ids_) { // Reallocate the old storage. new_sig_ids = realloc(indirect_function_table_sig_ids_, new_size * sizeof(uint32_t)); new_targets = realloc(indirect_function_table_targets_, new_size * sizeof(Address)); Handle old(instance->indirect_function_table_refs(), isolate); new_refs = isolate->factory()->CopyFixedArrayAndGrow( old, static_cast(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_refs = isolate->factory()->NewFixedArray(static_cast(new_size)); } // Initialize new entries. instance->set_indirect_function_table_size(new_size); SET(instance, indirect_function_table_sig_ids, reinterpret_cast(new_sig_ids)); SET(instance, indirect_function_table_targets, reinterpret_cast(new_targets)); instance->set_indirect_function_table_refs(*new_refs); for (uint32_t j = old_size; j < new_size; j++) { // {WasmInstanceNativeAllocations} only manages the memory of table 0. // Therefore we pass the {table_index} as a constant here. IndirectFunctionTableEntry(instance, 0, static_cast(j)).clear(); } } uint32_t* indirect_function_table_sig_ids_ = nullptr; 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 * 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 * kSystemPointerSize * table.initial_size; } return estimate; } WasmInstanceNativeAllocations* GetNativeAllocations( WasmInstanceObject instance) { return Managed::cast( instance.managed_native_allocations()) .raw(); } #ifdef DEBUG bool IsBreakablePosition(wasm::NativeModule* native_module, int func_index, int offset_in_func) { AccountingAllocator alloc; Zone tmp(&alloc, ZONE_NAME); wasm::BodyLocalDecls locals(&tmp); const byte* module_start = native_module->wire_bytes().begin(); const WasmFunction& func = native_module->module()->functions[func_index]; wasm::BytecodeIterator iterator(module_start + func.code.offset(), module_start + func.code.end_offset(), &locals); DCHECK_LT(0, locals.encoded_size); for (uint32_t offset : iterator.offsets()) { if (offset > static_cast(offset_in_func)) break; if (offset == static_cast(offset_in_func)) return true; } return false; } #endif // DEBUG enum DispatchTableElements : int { kDispatchTableInstanceOffset, kDispatchTableIndexOffset, kDispatchTableFunctionTableOffset, // Marker: kDispatchTableNumElements }; } // namespace // static Handle WasmModuleObject::New( Isolate* isolate, std::shared_ptr native_module, Handle