// 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.h" #include "src/assembler-inl.h" #include "src/base/iterator.h" #include "src/code-factory.h" #include "src/compiler/wasm-compiler.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/trap-handler/trap-handler.h" #include "src/wasm/jump-table-assembler.h" #include "src/wasm/module-compiler.h" #include "src/wasm/module-decoder.h" #include "src/wasm/wasm-code-manager.h" #include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-limits.h" #include "src/wasm/wasm-memory.h" #include "src/wasm/wasm-module.h" #include "src/wasm/wasm-objects-inl.h" #include "src/wasm/wasm-text.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) { 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)))); } ~WasmInstanceNativeAllocations() { free(); } // Frees natively-allocated storage. void free() { ::free(indirect_function_table_sig_ids_); ::free(indirect_function_table_targets_); ::free(imported_function_targets_); ::free(imported_mutable_globals_); indirect_function_table_sig_ids_ = nullptr; indirect_function_table_targets_ = nullptr; imported_function_targets_ = nullptr; imported_mutable_globals_ = 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_instances; 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_instances(), isolate); new_instances = 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_instances = 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_instances(*new_instances); for (uint32_t j = old_size; j < new_size; j++) { IndirectFunctionTableEntry(instance, 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; #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); for (auto& table : module->tables) { estimate += 3 * kPointerSize * table.initial_size; } return estimate; } WasmInstanceNativeAllocations* GetNativeAllocations( WasmInstanceObject* instance) { return reinterpret_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().start(); 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, const wasm::WasmFeatures& enabled, std::shared_ptr shared_module, wasm::ModuleEnv& env, OwnedVector wire_bytes, Handle