/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/wasm/wasm-module.cc
879 строк
34 KB
Michaël Zasso
deps: update V8 to 14.6.202.33
24 апр 2026, 19:01
Не верифицирован
24 апр 2026, 19:01
f1e0b83
Код
Авторство
О чём код?
// 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-module.h" #include <memory> #include "src/api/api-inl.h" #include "src/compiler/wasm-compiler.h" #include "src/objects/js-array-inl.h" #include "src/objects/objects.h" #include "src/wasm/jump-table-assembler.h" #include "src/wasm/module-decoder.h" #include "src/wasm/std-object-sizes.h" #include "src/wasm/wasm-code-manager.h" #include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-init-expr.h" #include "src/wasm/wasm-js.h" #include "src/wasm/wasm-module-builder.h" // For {ZoneBuffer}. #include "src/wasm/wasm-objects-inl.h" #include "src/wasm/wasm-result.h" #include "src/wasm/wasm-subtyping.h" namespace v8::internal::wasm { void UpdateComputedInformation(WasmMemory* memory, ModuleOrigin origin) { const uintptr_t platform_max_pages = memory->is_memory64() ? wasm::max_mem64_pages() : wasm::max_mem32_pages(); memory->min_memory_size = static_cast<uintptr_t>(std::min<uint64_t>( platform_max_pages, memory->initial_pages)) * kWasmPageSize; memory->max_memory_size = static_cast<uintptr_t>(std::min<uint64_t>( platform_max_pages, memory->maximum_pages)) * kWasmPageSize; if (!v8_flags.wasm_bounds_checks) { memory->bounds_checks = kNoBoundsChecks; } else if (v8_flags.wasm_enforce_bounds_checks) { // Explicit bounds checks requested via flag (for testing). memory->bounds_checks = kExplicitBoundsChecks; } else if (origin != kWasmOrigin) { // Asm.js modules can't use trap handling. memory->bounds_checks = kExplicitBoundsChecks; } else if (memory->is_memory64() && !v8_flags.wasm_memory64_trap_handling) { memory->bounds_checks = kExplicitBoundsChecks; } else if (trap_handler::IsTrapHandlerEnabled()) { if constexpr (kSystemPointerSize == 4) UNREACHABLE(); memory->bounds_checks = kTrapHandler; } else { // If the trap handler is not enabled, fall back to explicit bounds checks. memory->bounds_checks = kExplicitBoundsChecks; } } // Ensure that the max subtyping depth can be stored in the TypeDefinition. static_assert( kV8MaxRttSubtypingDepth <= std::numeric_limits<decltype(TypeDefinition().subtyping_depth)>::max()); template <class Value> void AdaptiveMap<Value>::FinishInitialization() { uint32_t count = 0; uint32_t max = 0; DCHECK_EQ(mode_, kInitializing); for (const auto& entry : *map_) { count++; max = std::max(max, entry.first); } if (count >= (max + 1) / kLoadFactor) { mode_ = kDense; vector_.resize(max + 1); for (auto& entry : *map_) { vector_[entry.first] = std::move(entry.second); } map_.reset(); } else { mode_ = kSparse; } } template void NameMap::FinishInitialization(); template void IndirectNameMap::FinishInitialization(); WireBytesRef LazilyGeneratedNames::LookupFunctionName( ModuleWireBytes wire_bytes, uint32_t function_index) { base::MutexGuard lock(&mutex_); if (!has_functions_) { has_functions_ = true; DecodeFunctionNames(wire_bytes.module_bytes(), function_names_); } const WireBytesRef* result = function_names_.Get(function_index); if (!result) return WireBytesRef(); return *result; } bool LazilyGeneratedNames::Has(uint32_t function_index) { DCHECK(has_functions_); base::MutexGuard lock(&mutex_); return function_names_.Get(function_index) != nullptr; } // static int GetWasmFunctionOffset(const WasmModule* module, uint32_t func_index) { const std::vector<WasmFunction>& functions = module->functions; if (static_cast<uint32_t>(func_index) >= functions.size()) return -1; DCHECK_GE(kMaxInt, functions[func_index].code.offset()); return static_cast<int>(functions[func_index].code.offset()); } // static int GetNearestWasmFunction(const WasmModule* module, uint32_t byte_offset) { const std::vector<WasmFunction>& functions = module->functions; // Binary search for a function containing the given position. int left = 0; // inclusive int right = static_cast<int>(functions.size()); // exclusive if (right == 0) return -1; while (right - left > 1) { int mid = left + (right - left) / 2; if (functions[mid].code.offset() <= byte_offset) { left = mid; } else { right = mid; } } return left; } // static int GetContainingWasmFunction(const WasmModule* module, uint32_t byte_offset) { int func_index = GetNearestWasmFunction(module, byte_offset); if (func_index >= 0) { // If the found function does not contain the given position, return -1. const WasmFunction& func = module->functions[func_index]; if (byte_offset < func.code.offset() || byte_offset >= func.code.end_offset()) { return -1; } } return func_index; } int GetSubtypingDepth(const WasmModule* module, ModuleTypeIndex type_index) { DCHECK_LT(type_index.index, module->types.size()); int depth = module->type(type_index).subtyping_depth; DCHECK_LE(depth, kV8MaxRttSubtypingDepth); return depth; } void LazilyGeneratedNames::AddForTesting(int function_index, WireBytesRef name) { base::MutexGuard lock(&mutex_); function_names_.Put(function_index, name); } AsmJsOffsetInformation::AsmJsOffsetInformation( base::Vector<const uint8_t> encoded_offsets) : encoded_offsets_(base::OwnedCopyOf(encoded_offsets)) {} AsmJsOffsetInformation::~AsmJsOffsetInformation() = default; int AsmJsOffsetInformation::GetSourcePosition(int declared_func_index, int byte_offset, bool is_at_number_conversion) { EnsureDecodedOffsets(); DCHECK_LE(0, declared_func_index); DCHECK_GT(decoded_offsets_->functions.size(), declared_func_index); std::vector<AsmJsOffsetEntry>& function_offsets = decoded_offsets_->functions[declared_func_index].entries; auto byte_offset_less = [](const AsmJsOffsetEntry& a, const AsmJsOffsetEntry& b) { return a.byte_offset < b.byte_offset; }; SLOW_DCHECK(std::is_sorted(function_offsets.begin(), function_offsets.end(), byte_offset_less)); // If there are no positions recorded, map offset 0 (for function entry) to // position 0. if (function_offsets.empty() && byte_offset == 0) return 0; auto it = std::lower_bound(function_offsets.begin(), function_offsets.end(), AsmJsOffsetEntry{byte_offset, 0, 0}, byte_offset_less); DCHECK_NE(function_offsets.end(), it); DCHECK_EQ(byte_offset, it->byte_offset); return is_at_number_conversion ? it->source_position_number_conversion : it->source_position_call; } std::pair<int, int> AsmJsOffsetInformation::GetFunctionOffsets( int declared_func_index) { EnsureDecodedOffsets(); DCHECK_LE(0, declared_func_index); DCHECK_GT(decoded_offsets_->functions.size(), declared_func_index); AsmJsOffsetFunctionEntries& function_info = decoded_offsets_->functions[declared_func_index]; return {function_info.start_offset, function_info.end_offset}; } void AsmJsOffsetInformation::EnsureDecodedOffsets() { base::MutexGuard mutex_guard(&mutex_); DCHECK_EQ(encoded_offsets_ == nullptr, decoded_offsets_ != nullptr); if (decoded_offsets_) return; AsmJsOffsetsResult result = wasm::DecodeAsmJsOffsets(encoded_offsets_.as_vector()); decoded_offsets_ = std::make_unique<AsmJsOffsets>(std::move(result).value()); encoded_offsets_.ReleaseData(); } // Get a string stored in the module bytes representing a name. WasmName ModuleWireBytes::GetNameOrNull(WireBytesRef ref) const { if (!ref.is_set()) return {nullptr, 0}; // no name. DCHECK(BoundsCheck(ref)); return WasmName::cast( module_bytes_.SubVector(ref.offset(), ref.end_offset())); } // Get a string stored in the module bytes representing a function name. WasmName ModuleWireBytes::GetNameOrNull(int func_index, const WasmModule* module) const { return GetNameOrNull( module->lazily_generated_names.LookupFunctionName(*this, func_index)); } std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name) { os << "#" << name.func_index_; if (!name.name_.empty()) { if (name.name_.begin()) { os << ":"; os.write(name.name_.begin(), name.name_.size()); } } else { os << "?"; } return os; } WasmModule::WasmModule(ModuleOrigin origin) : origin(origin) {} uint64_t WasmModule::signature_hash(const TypeCanonicalizer* type_canonicalizer, uint32_t function_index) const { if (function_index >= functions.size()) { return kInvalidWasmSignatureHash; } CanonicalTypeIndex canonical_type_id = canonical_sig_id(functions[function_index].sig_index); return type_canonicalizer->LookupFunctionSignature(canonical_type_id) ->signature_hash(); } bool IsWasmCodegenAllowed(Isolate* isolate, DirectHandle<NativeContext> context) { // TODO(wasm): Once wasm has its own CSP policy, we should introduce a // separate callback that includes information about the module about to be // compiled. For the time being, pass an empty string as placeholder for the // sources. if (auto wasm_codegen_callback = isolate->allow_wasm_code_gen_callback()) { return wasm_codegen_callback( v8::Utils::ToLocal(context), v8::Utils::ToLocal(isolate->factory()->empty_string())); } return true; } DirectHandle<String> ErrorStringForCodegen(Isolate* isolate, DirectHandle<Context> context) { DirectHandle<Object> error = context->ErrorMessageForWasmCodeGeneration(); DCHECK(!error.is_null()); return Object::NoSideEffectsToString(isolate, error); } namespace { // Converts the given {type} into a string representation that can be used in // reflective functions. Should be kept in sync with the {GetValueType} helper. DirectHandle<String> ToValueTypeString(Isolate* isolate, ValueType type) { return isolate->factory()->InternalizeUtf8String(base::VectorOf(type.name())); } } // namespace DirectHandle<JSObject> GetTypeForFunction(Isolate* isolate, const FunctionSig* sig, bool for_exception) { Factory* factory = isolate->factory(); // Extract values for the {ValueType[]} arrays. int param_index = 0; int param_count = static_cast<int>(sig->parameter_count()); DirectHandle<FixedArray> param_values = factory->NewFixedArray(param_count); for (ValueType type : sig->parameters()) { DirectHandle<String> type_value = ToValueTypeString(isolate, type); param_values->set(param_index++, *type_value); } // Create the resulting {FunctionType} object. DirectHandle<JSFunction> object_function = isolate->object_function(); DirectHandle<JSObject> object = factory->NewJSObject(object_function); DirectHandle<JSArray> params = factory->NewJSArrayWithElements(param_values); DirectHandle<String> params_string = factory->InternalizeUtf8String("parameters"); DirectHandle<String> results_string = factory->InternalizeUtf8String("results"); JSObject::AddProperty(isolate, object, params_string, params, NONE); // Now add the result types if needed. if (for_exception) { DCHECK_EQ(sig->returns().size(), 0); } else { int result_index = 0; int result_count = static_cast<int>(sig->return_count()); DirectHandle<FixedArray> result_values = factory->NewFixedArray(result_count); for (ValueType type : sig->returns()) { DirectHandle<String> type_value = ToValueTypeString(isolate, type); result_values->set(result_index++, *type_value); } DirectHandle<JSArray> results = factory->NewJSArrayWithElements(result_values); JSObject::AddProperty(isolate, object, results_string, results, NONE); } return object; } DirectHandle<JSObject> GetTypeForGlobal(Isolate* isolate, bool is_mutable, ValueType unsafe_type) { Factory* factory = isolate->factory(); DirectHandle<JSFunction> object_function = isolate->object_function(); DirectHandle<JSObject> object = factory->NewJSObject(object_function); DirectHandle<String> mutable_string = factory->InternalizeUtf8String("mutable"); DirectHandle<String> value_string = factory->value_string(); JSObject::AddProperty(isolate, object, mutable_string, factory->ToBoolean(is_mutable), NONE); JSObject::AddProperty(isolate, object, value_string, ToValueTypeString(isolate, unsafe_type), NONE); return object; } DirectHandle<JSObject> GetTypeForMemory(Isolate* isolate, uint32_t min_size, std::optional<uint64_t> max_size, bool shared, AddressType address_type) { Factory* factory = isolate->factory(); DirectHandle<JSFunction> object_function = isolate->object_function(); DirectHandle<JSObject> object = factory->NewJSObject(object_function); DirectHandle<String> minimum_string = factory->InternalizeUtf8String("minimum"); DirectHandle<String> maximum_string = factory->InternalizeUtf8String("maximum"); DirectHandle<String> shared_string = factory->InternalizeUtf8String("shared"); DirectHandle<String> address_string = factory->InternalizeUtf8String("address"); JSObject::AddProperty(isolate, object, minimum_string, factory->NewNumberFromUint(min_size), NONE); if (max_size.has_value()) { DirectHandle<UnionOf<Smi, HeapNumber, BigInt>> max; if (address_type == AddressType::kI32) { DCHECK_GE(kMaxUInt32, *max_size); max = factory->NewNumberFromUint(static_cast<uint32_t>(*max_size)); } else { max = BigInt::FromUint64(isolate, *max_size); } JSObject::AddProperty(isolate, object, maximum_string, max, NONE); } JSObject::AddProperty(isolate, object, shared_string, factory->ToBoolean(shared), NONE); JSObject::AddProperty( isolate, object, address_string, factory->InternalizeUtf8String(AddressTypeToStr(address_type)), NONE); return object; } DirectHandle<JSObject> GetTypeForTable(Isolate* isolate, ValueType type, uint32_t min_size, std::optional<uint64_t> max_size, AddressType address_type) { Factory* factory = isolate->factory(); DirectHandle<String> element = factory->InternalizeUtf8String(base::VectorOf(type.name())); DirectHandle<JSFunction> object_function = isolate->object_function(); DirectHandle<JSObject> object = factory->NewJSObject(object_function); DirectHandle<String> element_string = factory->element_string(); DirectHandle<String> minimum_string = factory->InternalizeUtf8String("minimum"); DirectHandle<String> maximum_string = factory->InternalizeUtf8String("maximum"); DirectHandle<String> address_string = factory->InternalizeUtf8String("address"); JSObject::AddProperty(isolate, object, element_string, element, NONE); JSObject::AddProperty(isolate, object, minimum_string, factory->NewNumberFromUint(min_size), NONE); if (max_size.has_value()) { DirectHandle<UnionOf<Smi, HeapNumber, BigInt>> max; if (address_type == AddressType::kI32) { DCHECK_GE(kMaxUInt32, *max_size); max = factory->NewNumberFromUint(static_cast<uint32_t>(*max_size)); } else { max = BigInt::FromUint64(isolate, *max_size); } JSObject::AddProperty(isolate, object, maximum_string, max, NONE); } JSObject::AddProperty( isolate, object, address_string, factory->InternalizeUtf8String(AddressTypeToStr(address_type)), NONE); return object; } DirectHandle<JSArray> GetImports(Isolate* isolate, DirectHandle<WasmModuleObject> module_object) { auto enabled_features = i::wasm::WasmEnabledFeatures::FromIsolate(isolate); Factory* factory = isolate->factory(); DirectHandle<String> module_string = factory->InternalizeUtf8String("module"); DirectHandle<String> name_string = factory->name_string(); DirectHandle<String> kind_string = factory->InternalizeUtf8String("kind"); DirectHandle<String> type_string = factory->InternalizeUtf8String("type"); DirectHandle<String> function_string = factory->function_string(); DirectHandle<String> table_string = factory->InternalizeUtf8String("table"); DirectHandle<String> memory_string = factory->InternalizeUtf8String("memory"); DirectHandle<String> global_string = factory->global_string(); DirectHandle<String> tag_string = factory->InternalizeUtf8String("tag"); // Create the result array. NativeModule* native_module = module_object->native_module(); const WasmModule* module = native_module->module(); base::Vector<const uint8_t> wire_bytes = native_module->wire_bytes(); int num_imports = static_cast<int>(module->import_table.size()); DirectHandle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0); DirectHandle<FixedArray> storage = factory->NewFixedArray(num_imports); JSArray::SetContent(isolate, array_object, storage); DirectHandle<JSFunction> object_function = DirectHandle<JSFunction>( isolate->native_context()->object_function(), isolate); // Populate the result array. const WellKnownImportsList& well_known_imports = module->type_feedback.well_known_imports; const std::string& magic_string_constants = native_module->compile_imports().constants_module(); const bool has_magic_string_constants = native_module->compile_imports().contains( CompileTimeImport::kStringConstants); int cursor = 0; for (int index = 0; index < num_imports; ++index) { const WasmImport& import = module->import_table[index]; DirectHandle<JSObject> entry = factory->NewJSObject(object_function); DirectHandle<String> import_kind; DirectHandle<JSObject> type_value; switch (import.kind) { case kExternalFunction: case kExternalExactFunction: if (IsCompileTimeImport(well_known_imports.get(import.index))) { continue; } if (enabled_features.has_type_reflection()) { auto& func = module->functions[import.index]; type_value = GetTypeForFunction(isolate, func.sig); } // Since {kExternalExactFunction} is still a function import, it // uses the string "function" here. import_kind = function_string; break; case kExternalTable: if (enabled_features.has_type_reflection()) { auto& table = module->tables[import.index]; std::optional<uint32_t> maximum_size; if (table.has_maximum_size) maximum_size.emplace(table.maximum_size); type_value = GetTypeForTable(isolate, table.type, table.initial_size, maximum_size, table.address_type); } import_kind = table_string; break; case kExternalMemory: if (enabled_features.has_type_reflection()) { auto& memory = module->memories[import.index]; std::optional<uint32_t> maximum_size; if (memory.has_maximum_pages) { maximum_size.emplace(memory.maximum_pages); } type_value = GetTypeForMemory(isolate, memory.initial_pages, maximum_size, memory.is_shared, memory.address_type); } import_kind = memory_string; break; case kExternalGlobal: if (has_magic_string_constants && import.module_name.length() == magic_string_constants.size() && std::equal(magic_string_constants.begin(), magic_string_constants.end(), wire_bytes.begin() + import.module_name.offset())) { continue; } if (enabled_features.has_type_reflection()) { auto& global = module->globals[import.index]; type_value = GetTypeForGlobal(isolate, global.mutability, global.type); } import_kind = global_string; break; case kExternalTag: import_kind = tag_string; break; } DCHECK(!import_kind.is_null()); DirectHandle<String> import_module = WasmModuleObject::ExtractUtf8StringFromModuleBytes( isolate, wire_bytes, import.module_name, kInternalize); DirectHandle<String> import_name = WasmModuleObject::ExtractUtf8StringFromModuleBytes( isolate, wire_bytes, import.field_name, kInternalize); JSObject::AddProperty(isolate, entry, module_string, import_module, NONE); JSObject::AddProperty(isolate, entry, name_string, import_name, NONE); JSObject::AddProperty(isolate, entry, kind_string, import_kind, NONE); if (!type_value.is_null()) { JSObject::AddProperty(isolate, entry, type_string, type_value, NONE); } storage->set(cursor++, *entry); } array_object->set_length(Smi::FromInt(cursor)); // Make sure that values after the cursor are holes. for (int index = cursor; index < num_imports; ++index) { storage->set_the_hole(isolate, cursor++); } JSObject::ValidateElements(isolate, *array_object); return array_object; } DirectHandle<JSArray> GetExports(Isolate* isolate, DirectHandle<WasmModuleObject> module_object) { auto enabled_features = i::wasm::WasmEnabledFeatures::FromIsolate(isolate); Factory* factory = isolate->factory(); DirectHandle<String> name_string = factory->name_string(); DirectHandle<String> kind_string = factory->InternalizeUtf8String("kind"); DirectHandle<String> type_string = factory->InternalizeUtf8String("type"); DirectHandle<String> function_string = factory->function_string(); DirectHandle<String> table_string = factory->InternalizeUtf8String("table"); DirectHandle<String> memory_string = factory->InternalizeUtf8String("memory"); DirectHandle<String> global_string = factory->global_string(); DirectHandle<String> tag_string = factory->InternalizeUtf8String("tag"); // Create the result array. NativeModule* native_module = module_object->native_module(); const WasmModule* module = native_module->module(); int num_exports = static_cast<int>(module->export_table.size()); DirectHandle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0); DirectHandle<FixedArray> storage = factory->NewFixedArray(num_exports); JSArray::SetContent(isolate, array_object, storage); DCHECK_EQ(array_object->length(), Smi::FromInt(num_exports)); DirectHandle<JSFunction> object_function = DirectHandle<JSFunction>( isolate->native_context()->object_function(), isolate); // Populate the result array. for (int index = 0; index < num_exports; ++index) { const WasmExport& exp = module->export_table[index]; DirectHandle<String> export_kind; DirectHandle<JSObject> type_value; switch (exp.kind) { case kExternalFunction: if (enabled_features.has_type_reflection()) { auto& func = module->functions[exp.index]; type_value = GetTypeForFunction(isolate, func.sig); } export_kind = function_string; break; case kExternalTable: if (enabled_features.has_type_reflection()) { auto& table = module->tables[exp.index]; std::optional<uint32_t> maximum_size; if (table.has_maximum_size) maximum_size.emplace(table.maximum_size); type_value = GetTypeForTable(isolate, table.type, table.initial_size, maximum_size, table.address_type); } export_kind = table_string; break; case kExternalMemory: if (enabled_features.has_type_reflection()) { auto& memory = module->memories[exp.index]; std::optional<uint32_t> maximum_size; if (memory.has_maximum_pages) { maximum_size.emplace(memory.maximum_pages); } type_value = GetTypeForMemory(isolate, memory.initial_pages, maximum_size, memory.is_shared, memory.address_type); } export_kind = memory_string; break; case kExternalGlobal: if (enabled_features.has_type_reflection()) { auto& global = module->globals[exp.index]; type_value = GetTypeForGlobal(isolate, global.mutability, global.type); } export_kind = global_string; break; case kExternalTag: export_kind = tag_string; break; case kExternalExactFunction: default: UNREACHABLE(); } DirectHandle<JSObject> entry = factory->NewJSObject(object_function); DirectHandle<String> export_name = WasmModuleObject::ExtractUtf8StringFromModuleBytes( isolate, native_module->wire_bytes(), exp.name, kNoInternalize); JSObject::AddProperty(isolate, entry, name_string, export_name, NONE); JSObject::AddProperty(isolate, entry, kind_string, export_kind, NONE); if (!type_value.is_null()) { JSObject::AddProperty(isolate, entry, type_string, type_value, NONE); } storage->set(index, *entry); } JSObject::ValidateElements(isolate, *array_object); return array_object; } DirectHandle<JSArray> GetCustomSections( Isolate* isolate, DirectHandle<WasmModuleObject> module_object, DirectHandle<String> name, ErrorThrower* thrower) { Factory* factory = isolate->factory(); base::Vector<const uint8_t> wire_bytes = module_object->native_module()->wire_bytes(); std::vector<CustomSectionOffset> custom_sections = DecodeCustomSections(wire_bytes); DirectHandleVector<Object> matching_sections(isolate); // Gather matching sections. for (auto& section : custom_sections) { DirectHandle<String> section_name = WasmModuleObject::ExtractUtf8StringFromModuleBytes( isolate, wire_bytes, section.name, kNoInternalize); if (!name->Equals(*section_name)) continue; // Make a copy of the payload data in the section. size_t size = section.payload.length(); MaybeDirectHandle<JSArrayBuffer> result = isolate->factory()->NewJSArrayBufferAndBackingStore( size, InitializedFlag::kUninitialized); DirectHandle<JSArrayBuffer> array_buffer; if (!result.ToHandle(&array_buffer)) { thrower->RangeError("out of memory allocating custom section data"); return DirectHandle<JSArray>(); } memcpy(array_buffer->backing_store(), wire_bytes.begin() + section.payload.offset(), section.payload.length()); matching_sections.push_back(array_buffer); } int num_custom_sections = static_cast<int>(matching_sections.size()); DirectHandle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0); DirectHandle<FixedArray> storage = factory->NewFixedArray(num_custom_sections); JSArray::SetContent(isolate, array_object, storage); DCHECK_EQ(array_object->length(), Smi::FromInt(num_custom_sections)); for (int i = 0; i < num_custom_sections; i++) { storage->set(i, *matching_sections[i]); } JSObject::ValidateElements(isolate, *array_object); return array_object; } // Get the source position from a given function index and wire bytes offset // (relative to the function entry), for either asm.js or pure Wasm modules. int GetSourcePosition(const WasmModule* module, uint32_t func_index, uint32_t byte_offset, bool is_at_number_conversion) { DCHECK_EQ(is_asmjs_module(module), module->asm_js_offset_information != nullptr); if (!is_asmjs_module(module)) { // For non-asm.js modules, we just add the function's start offset // to make a module-relative position. return byte_offset + GetWasmFunctionOffset(module, func_index); } // asm.js modules have an additional offset table that must be searched. return module->asm_js_offset_information->GetSourcePosition( declared_function_index(module, func_index), byte_offset, is_at_number_conversion); } size_t WasmModule::EstimateStoredSize() const { UPDATE_WHEN_CLASS_CHANGES(WasmModule, #if V8_ENABLE_DRUMBRAKE 912 #else // V8_ENABLE_DRUMBRAKE 880 #endif // V8_ENABLE_DRUMBRAKE ); return sizeof(WasmModule) + // -- signature_storage.TotalReservedSize() + // -- ContentSize(types) + // -- ContentSize(isorecursive_canonical_type_ids) + // -- ContentSize(functions) + // -- ContentSize(globals) + // -- ContentSize(data_segments) + // -- ContentSize(tables) + // -- ContentSize(memories) + // -- ContentSize(import_table) + // -- ContentSize(export_table) + // -- ContentSize(tags) + // -- ContentSize(stringref_literals) + // -- ContentSize(elem_segments) + // -- ContentSize(branch_hints) + // -- ContentSize(compilation_priorities) + // -- ContentSize(instruction_frequencies) + // -- ContentSize(call_targets) + // -- ContentSize(inst_traces) + // -- (num_declared_functions + 7) / 8; // validated_functions } template <class Value> size_t AdaptiveMap<Value>::EstimateCurrentMemoryConsumption() const { UNREACHABLE(); // Explicit implementations below. } template <> size_t NameMap::EstimateCurrentMemoryConsumption() const { size_t result = ContentSize(vector_); if (map_) result += ContentSize(*map_); return result; } size_t LazilyGeneratedNames::EstimateCurrentMemoryConsumption() const { base::MutexGuard lock(&mutex_); return function_names_.EstimateCurrentMemoryConsumption(); } template <> size_t IndirectNameMap::EstimateCurrentMemoryConsumption() const { size_t result = ContentSize(vector_); for (const auto& inner_map : vector_) { result += inner_map.EstimateCurrentMemoryConsumption(); } if (map_) { result += ContentSize(*map_); for (const auto& [outer_index, inner_map] : *map_) { result += inner_map.EstimateCurrentMemoryConsumption(); } } return result; } size_t TypeFeedbackStorage::EstimateCurrentMemoryConsumption() const { UPDATE_WHEN_CLASS_CHANGES(TypeFeedbackStorage, 112); UPDATE_WHEN_CLASS_CHANGES(FunctionTypeFeedback, 48); // Not including sizeof(TFS) because that's contained in sizeof(WasmModule). base::MutexGuard guard(&mutex); size_t result = ContentSize(feedback_for_function); for (const auto& [func_idx, feedback] : feedback_for_function) { result += ContentSize(feedback.feedback_vector); result += feedback.call_targets.size() * sizeof(uint32_t); } result += ContentSize(deopt_count_for_function); // The size of {well_known_imports} can only be estimated at the WasmModule // level. if (v8_flags.trace_wasm_offheap_memory) { PrintF("TypeFeedback: %zu\n", result); } return result; } size_t WasmModule::EstimateCurrentMemoryConsumption() const { UPDATE_WHEN_CLASS_CHANGES(WasmModule, #if V8_ENABLE_DRUMBRAKE 912 #else // V8_ENABLE_DRUMBRAKE 880 #endif // V8_ENABLE_DRUMBRAKE ); size_t result = EstimateStoredSize(); result += type_feedback.EstimateCurrentMemoryConsumption(); // For type_feedback.well_known_imports: result += num_imported_functions * sizeof(WellKnownImport); result += lazily_generated_names.EstimateCurrentMemoryConsumption(); result += ContentSize(marked_for_tierup); result += ContentSize(feedback_slots_to_wire_byte_offsets); if (v8_flags.trace_wasm_offheap_memory) { PrintF("WasmModule: %zu\n", result); } return result; } size_t PrintSignature(base::Vector<char> buffer, const CanonicalSig* sig, char delimiter) { if (buffer.empty()) return 0; size_t old_size = buffer.size(); auto append_char = [&buffer](char c) { if (buffer.size() == 1) return; // Keep last character for '\0'. buffer[0] = c; buffer += 1; }; for (CanonicalValueType t : sig->parameters()) { append_char(t.short_name()); } append_char(delimiter); for (CanonicalValueType t : sig->returns()) { append_char(t.short_name()); } buffer[0] = '\0'; return old_size - buffer.size(); } int JumpTableOffset(const WasmModule* module, int func_index) { return JumpTableAssembler::JumpSlotIndexToOffset( declared_function_index(module, func_index)); } size_t GetWireBytesHash(base::Vector<const uint8_t> wire_bytes) { return StringHasher::HashSequentialString( reinterpret_cast<const char*>(wire_bytes.begin()), static_cast<uint32_t>(wire_bytes.size()), HashSeed::Default()); } int NumFeedbackSlots(const WasmModule* module, int func_index) { base::MutexGuard mutex_guard{&module->type_feedback.mutex}; auto it = module->type_feedback.feedback_for_function.find(func_index); if (it == module->type_feedback.feedback_for_function.end()) { // The first slot is reserved for total invocation count. return FeedbackConstants::kHeaderSlots; } // The number of call instructions is capped by max function size. static_assert(kV8MaxWasmFunctionSize * FeedbackConstants::kSlotsPerInstruction + FeedbackConstants::kHeaderSlots < static_cast<size_t>(std::numeric_limits<int>::max())); // The first slot is reserved for total invocation count. return static_cast<int>(FeedbackConstants::kSlotsPerInstruction * it->second.call_targets.size() + FeedbackConstants::kHeaderSlots); } } // namespace v8::internal::wasm