1// Copyright 2015 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/wasm/wasm-module.h" 6 7#include <functional> 8#include <memory> 9 10#include "src/api/api-inl.h" 11#include "src/base/platform/wrappers.h" 12#include "src/codegen/assembler-inl.h" 13#include "src/compiler/wasm-compiler.h" 14#include "src/debug/interface-types.h" 15#include "src/execution/frames-inl.h" 16#include "src/execution/simulator.h" 17#include "src/init/v8.h" 18#include "src/objects/js-array-inl.h" 19#include "src/objects/objects.h" 20#include "src/objects/property-descriptor.h" 21#include "src/snapshot/snapshot.h" 22#include "src/wasm/module-decoder.h" 23#include "src/wasm/wasm-code-manager.h" 24#include "src/wasm/wasm-init-expr.h" 25#include "src/wasm/wasm-js.h" 26#include "src/wasm/wasm-objects-inl.h" 27#include "src/wasm/wasm-result.h" 28#include "src/wasm/wasm-subtyping.h" 29 30namespace v8 { 31namespace internal { 32namespace wasm { 33 34WireBytesRef LazilyGeneratedNames::LookupFunctionName( 35 const ModuleWireBytes& wire_bytes, uint32_t function_index) const { 36 base::MutexGuard lock(&mutex_); 37 if (!function_names_) { 38 function_names_.reset(new std::unordered_map<uint32_t, WireBytesRef>()); 39 DecodeFunctionNames(wire_bytes.start(), wire_bytes.end(), 40 function_names_.get()); 41 } 42 auto it = function_names_->find(function_index); 43 if (it == function_names_->end()) return WireBytesRef(); 44 return it->second; 45} 46 47// static 48int MaxNumExportWrappers(const WasmModule* module) { 49 // For each signature there may exist a wrapper, both for imported and 50 // internal functions. 51 return static_cast<int>(module->signature_map.size()) * 2; 52} 53 54int GetExportWrapperIndexInternal(const WasmModule* module, 55 int canonical_sig_index, bool is_import) { 56 if (is_import) canonical_sig_index += module->signature_map.size(); 57 return canonical_sig_index; 58} 59 60int GetExportWrapperIndex(const WasmModule* module, const FunctionSig* sig, 61 bool is_import) { 62 int canonical_sig_index = module->signature_map.Find(*sig); 63 CHECK_GE(canonical_sig_index, 0); 64 return GetExportWrapperIndexInternal(module, canonical_sig_index, is_import); 65} 66 67int GetExportWrapperIndex(const WasmModule* module, uint32_t sig_index, 68 bool is_import) { 69 uint32_t canonical_sig_index = module->canonicalized_type_ids[sig_index]; 70 return GetExportWrapperIndexInternal(module, canonical_sig_index, is_import); 71} 72 73// static 74int GetWasmFunctionOffset(const WasmModule* module, uint32_t func_index) { 75 const std::vector<WasmFunction>& functions = module->functions; 76 if (static_cast<uint32_t>(func_index) >= functions.size()) return -1; 77 DCHECK_GE(kMaxInt, functions[func_index].code.offset()); 78 return static_cast<int>(functions[func_index].code.offset()); 79} 80 81// static 82int GetNearestWasmFunction(const WasmModule* module, uint32_t byte_offset) { 83 const std::vector<WasmFunction>& functions = module->functions; 84 85 // Binary search for a function containing the given position. 86 int left = 0; // inclusive 87 int right = static_cast<int>(functions.size()); // exclusive 88 if (right == 0) return -1; 89 while (right - left > 1) { 90 int mid = left + (right - left) / 2; 91 if (functions[mid].code.offset() <= byte_offset) { 92 left = mid; 93 } else { 94 right = mid; 95 } 96 } 97 98 return left; 99} 100 101// static 102int GetContainingWasmFunction(const WasmModule* module, uint32_t byte_offset) { 103 int func_index = GetNearestWasmFunction(module, byte_offset); 104 105 if (func_index >= 0) { 106 // If the found function does not contain the given position, return -1. 107 const WasmFunction& func = module->functions[func_index]; 108 if (byte_offset < func.code.offset() || 109 byte_offset >= func.code.end_offset()) { 110 return -1; 111 } 112 } 113 return func_index; 114} 115 116// TODO(7748): Measure whether this iterative implementation is fast enough. 117// We could cache the result on the module, in yet another vector indexed by 118// type index. 119int GetSubtypingDepth(const WasmModule* module, uint32_t type_index) { 120 uint32_t starting_point = type_index; 121 int depth = 0; 122 while ((type_index = module->supertype(type_index)) != kNoSuperType) { 123 if (type_index == starting_point) return -1; // Cycle detected. 124 depth++; 125 if (depth > static_cast<int>(kV8MaxRttSubtypingDepth)) break; 126 } 127 return depth; 128} 129 130void LazilyGeneratedNames::AddForTesting(int function_index, 131 WireBytesRef name) { 132 base::MutexGuard lock(&mutex_); 133 if (!function_names_) { 134 function_names_.reset(new std::unordered_map<uint32_t, WireBytesRef>()); 135 } 136 function_names_->insert(std::make_pair(function_index, name)); 137} 138 139AsmJsOffsetInformation::AsmJsOffsetInformation( 140 base::Vector<const byte> encoded_offsets) 141 : encoded_offsets_(base::OwnedVector<const uint8_t>::Of(encoded_offsets)) {} 142 143AsmJsOffsetInformation::~AsmJsOffsetInformation() = default; 144 145int AsmJsOffsetInformation::GetSourcePosition(int declared_func_index, 146 int byte_offset, 147 bool is_at_number_conversion) { 148 EnsureDecodedOffsets(); 149 150 DCHECK_LE(0, declared_func_index); 151 DCHECK_GT(decoded_offsets_->functions.size(), declared_func_index); 152 std::vector<AsmJsOffsetEntry>& function_offsets = 153 decoded_offsets_->functions[declared_func_index].entries; 154 155 auto byte_offset_less = [](const AsmJsOffsetEntry& a, 156 const AsmJsOffsetEntry& b) { 157 return a.byte_offset < b.byte_offset; 158 }; 159 SLOW_DCHECK(std::is_sorted(function_offsets.begin(), function_offsets.end(), 160 byte_offset_less)); 161 auto it = 162 std::lower_bound(function_offsets.begin(), function_offsets.end(), 163 AsmJsOffsetEntry{byte_offset, 0, 0}, byte_offset_less); 164 DCHECK_NE(function_offsets.end(), it); 165 DCHECK_EQ(byte_offset, it->byte_offset); 166 return is_at_number_conversion ? it->source_position_number_conversion 167 : it->source_position_call; 168} 169 170std::pair<int, int> AsmJsOffsetInformation::GetFunctionOffsets( 171 int declared_func_index) { 172 EnsureDecodedOffsets(); 173 174 DCHECK_LE(0, declared_func_index); 175 DCHECK_GT(decoded_offsets_->functions.size(), declared_func_index); 176 AsmJsOffsetFunctionEntries& function_info = 177 decoded_offsets_->functions[declared_func_index]; 178 179 return {function_info.start_offset, function_info.end_offset}; 180} 181 182void AsmJsOffsetInformation::EnsureDecodedOffsets() { 183 base::MutexGuard mutex_guard(&mutex_); 184 DCHECK_EQ(encoded_offsets_ == nullptr, decoded_offsets_ != nullptr); 185 186 if (decoded_offsets_) return; 187 AsmJsOffsetsResult result = 188 wasm::DecodeAsmJsOffsets(encoded_offsets_.as_vector()); 189 decoded_offsets_ = std::make_unique<AsmJsOffsets>(std::move(result).value()); 190 encoded_offsets_.ReleaseData(); 191} 192 193// Get a string stored in the module bytes representing a name. 194WasmName ModuleWireBytes::GetNameOrNull(WireBytesRef ref) const { 195 if (!ref.is_set()) return {nullptr, 0}; // no name. 196 DCHECK(BoundsCheck(ref)); 197 return WasmName::cast( 198 module_bytes_.SubVector(ref.offset(), ref.end_offset())); 199} 200 201// Get a string stored in the module bytes representing a function name. 202WasmName ModuleWireBytes::GetNameOrNull(const WasmFunction* function, 203 const WasmModule* module) const { 204 return GetNameOrNull(module->lazily_generated_names.LookupFunctionName( 205 *this, function->func_index)); 206} 207 208std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name) { 209 os << "#" << name.function_->func_index; 210 if (!name.name_.empty()) { 211 if (name.name_.begin()) { 212 os << ":"; 213 os.write(name.name_.begin(), name.name_.length()); 214 } 215 } else { 216 os << "?"; 217 } 218 return os; 219} 220 221WasmModule::WasmModule(std::unique_ptr<Zone> signature_zone) 222 : signature_zone(std::move(signature_zone)) {} 223 224bool IsWasmCodegenAllowed(Isolate* isolate, Handle<Context> context) { 225 // TODO(wasm): Once wasm has its own CSP policy, we should introduce a 226 // separate callback that includes information about the module about to be 227 // compiled. For the time being, pass an empty string as placeholder for the 228 // sources. 229 if (auto wasm_codegen_callback = isolate->allow_wasm_code_gen_callback()) { 230 return wasm_codegen_callback( 231 v8::Utils::ToLocal(context), 232 v8::Utils::ToLocal(isolate->factory()->empty_string())); 233 } 234 auto codegen_callback = isolate->allow_code_gen_callback(); 235 return codegen_callback == nullptr || 236 codegen_callback( 237 v8::Utils::ToLocal(context), 238 v8::Utils::ToLocal(isolate->factory()->empty_string())); 239} 240 241namespace { 242 243// Converts the given {type} into a string representation that can be used in 244// reflective functions. Should be kept in sync with the {GetValueType} helper. 245Handle<String> ToValueTypeString(Isolate* isolate, ValueType type) { 246 return isolate->factory()->InternalizeUtf8String(base::VectorOf(type.name())); 247} 248} // namespace 249 250Handle<JSObject> GetTypeForFunction(Isolate* isolate, const FunctionSig* sig, 251 bool for_exception) { 252 Factory* factory = isolate->factory(); 253 254 // Extract values for the {ValueType[]} arrays. 255 int param_index = 0; 256 int param_count = static_cast<int>(sig->parameter_count()); 257 Handle<FixedArray> param_values = factory->NewFixedArray(param_count); 258 for (ValueType type : sig->parameters()) { 259 Handle<String> type_value = ToValueTypeString(isolate, type); 260 param_values->set(param_index++, *type_value); 261 } 262 263 // Create the resulting {FunctionType} object. 264 Handle<JSFunction> object_function = isolate->object_function(); 265 Handle<JSObject> object = factory->NewJSObject(object_function); 266 Handle<JSArray> params = factory->NewJSArrayWithElements(param_values); 267 Handle<String> params_string = factory->InternalizeUtf8String("parameters"); 268 Handle<String> results_string = factory->InternalizeUtf8String("results"); 269 JSObject::AddProperty(isolate, object, params_string, params, NONE); 270 271 // Now add the result types if needed. 272 if (for_exception) { 273 DCHECK_EQ(sig->returns().size(), 0); 274 } else { 275 int result_index = 0; 276 int result_count = static_cast<int>(sig->return_count()); 277 Handle<FixedArray> result_values = factory->NewFixedArray(result_count); 278 for (ValueType type : sig->returns()) { 279 Handle<String> type_value = ToValueTypeString(isolate, type); 280 result_values->set(result_index++, *type_value); 281 } 282 Handle<JSArray> results = factory->NewJSArrayWithElements(result_values); 283 JSObject::AddProperty(isolate, object, results_string, results, NONE); 284 } 285 286 return object; 287} 288 289Handle<JSObject> GetTypeForGlobal(Isolate* isolate, bool is_mutable, 290 ValueType type) { 291 Factory* factory = isolate->factory(); 292 293 Handle<JSFunction> object_function = isolate->object_function(); 294 Handle<JSObject> object = factory->NewJSObject(object_function); 295 Handle<String> mutable_string = factory->InternalizeUtf8String("mutable"); 296 Handle<String> value_string = factory->InternalizeUtf8String("value"); 297 JSObject::AddProperty(isolate, object, mutable_string, 298 factory->ToBoolean(is_mutable), NONE); 299 JSObject::AddProperty(isolate, object, value_string, 300 ToValueTypeString(isolate, type), NONE); 301 302 return object; 303} 304 305Handle<JSObject> GetTypeForMemory(Isolate* isolate, uint32_t min_size, 306 base::Optional<uint32_t> max_size, 307 bool shared) { 308 Factory* factory = isolate->factory(); 309 310 Handle<JSFunction> object_function = isolate->object_function(); 311 Handle<JSObject> object = factory->NewJSObject(object_function); 312 Handle<String> minimum_string = factory->InternalizeUtf8String("minimum"); 313 Handle<String> maximum_string = factory->InternalizeUtf8String("maximum"); 314 Handle<String> shared_string = factory->InternalizeUtf8String("shared"); 315 JSObject::AddProperty(isolate, object, minimum_string, 316 factory->NewNumberFromUint(min_size), NONE); 317 if (max_size.has_value()) { 318 JSObject::AddProperty(isolate, object, maximum_string, 319 factory->NewNumberFromUint(max_size.value()), NONE); 320 } 321 JSObject::AddProperty(isolate, object, shared_string, 322 factory->ToBoolean(shared), NONE); 323 324 return object; 325} 326 327Handle<JSObject> GetTypeForTable(Isolate* isolate, ValueType type, 328 uint32_t min_size, 329 base::Optional<uint32_t> max_size) { 330 Factory* factory = isolate->factory(); 331 332 Handle<String> element = 333 factory->InternalizeUtf8String(base::VectorOf(type.name())); 334 335 Handle<JSFunction> object_function = isolate->object_function(); 336 Handle<JSObject> object = factory->NewJSObject(object_function); 337 Handle<String> element_string = factory->InternalizeUtf8String("element"); 338 Handle<String> minimum_string = factory->InternalizeUtf8String("minimum"); 339 Handle<String> maximum_string = factory->InternalizeUtf8String("maximum"); 340 JSObject::AddProperty(isolate, object, element_string, element, NONE); 341 JSObject::AddProperty(isolate, object, minimum_string, 342 factory->NewNumberFromUint(min_size), NONE); 343 if (max_size.has_value()) { 344 JSObject::AddProperty(isolate, object, maximum_string, 345 factory->NewNumberFromUint(max_size.value()), NONE); 346 } 347 348 return object; 349} 350 351Handle<JSArray> GetImports(Isolate* isolate, 352 Handle<WasmModuleObject> module_object) { 353 auto enabled_features = i::wasm::WasmFeatures::FromIsolate(isolate); 354 Factory* factory = isolate->factory(); 355 356 Handle<String> module_string = factory->InternalizeUtf8String("module"); 357 Handle<String> name_string = factory->InternalizeUtf8String("name"); 358 Handle<String> kind_string = factory->InternalizeUtf8String("kind"); 359 Handle<String> type_string = factory->InternalizeUtf8String("type"); 360 361 Handle<String> function_string = factory->InternalizeUtf8String("function"); 362 Handle<String> table_string = factory->InternalizeUtf8String("table"); 363 Handle<String> memory_string = factory->InternalizeUtf8String("memory"); 364 Handle<String> global_string = factory->InternalizeUtf8String("global"); 365 Handle<String> tag_string = factory->InternalizeUtf8String("tag"); 366 367 // Create the result array. 368 const WasmModule* module = module_object->module(); 369 int num_imports = static_cast<int>(module->import_table.size()); 370 Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0); 371 Handle<FixedArray> storage = factory->NewFixedArray(num_imports); 372 JSArray::SetContent(array_object, storage); 373 array_object->set_length(Smi::FromInt(num_imports)); 374 375 Handle<JSFunction> object_function = 376 Handle<JSFunction>(isolate->native_context()->object_function(), isolate); 377 378 // Populate the result array. 379 for (int index = 0; index < num_imports; ++index) { 380 const WasmImport& import = module->import_table[index]; 381 382 Handle<JSObject> entry = factory->NewJSObject(object_function); 383 384 Handle<String> import_kind; 385 Handle<JSObject> type_value; 386 switch (import.kind) { 387 case kExternalFunction: 388 if (enabled_features.has_type_reflection()) { 389 auto& func = module->functions[import.index]; 390 type_value = GetTypeForFunction(isolate, func.sig); 391 } 392 import_kind = function_string; 393 break; 394 case kExternalTable: 395 if (enabled_features.has_type_reflection()) { 396 auto& table = module->tables[import.index]; 397 base::Optional<uint32_t> maximum_size; 398 if (table.has_maximum_size) maximum_size.emplace(table.maximum_size); 399 type_value = GetTypeForTable(isolate, table.type, table.initial_size, 400 maximum_size); 401 } 402 import_kind = table_string; 403 break; 404 case kExternalMemory: 405 if (enabled_features.has_type_reflection()) { 406 DCHECK_EQ(0, import.index); // Only one memory supported. 407 base::Optional<uint32_t> maximum_size; 408 if (module->has_maximum_pages) { 409 maximum_size.emplace(module->maximum_pages); 410 } 411 type_value = 412 GetTypeForMemory(isolate, module->initial_pages, maximum_size, 413 module->has_shared_memory); 414 } 415 import_kind = memory_string; 416 break; 417 case kExternalGlobal: 418 if (enabled_features.has_type_reflection()) { 419 auto& global = module->globals[import.index]; 420 type_value = 421 GetTypeForGlobal(isolate, global.mutability, global.type); 422 } 423 import_kind = global_string; 424 break; 425 case kExternalTag: 426 import_kind = tag_string; 427 break; 428 } 429 DCHECK(!import_kind->is_null()); 430 431 Handle<String> import_module = 432 WasmModuleObject::ExtractUtf8StringFromModuleBytes( 433 isolate, module_object, import.module_name, kInternalize); 434 435 Handle<String> import_name = 436 WasmModuleObject::ExtractUtf8StringFromModuleBytes( 437 isolate, module_object, import.field_name, kInternalize); 438 439 JSObject::AddProperty(isolate, entry, module_string, import_module, NONE); 440 JSObject::AddProperty(isolate, entry, name_string, import_name, NONE); 441 JSObject::AddProperty(isolate, entry, kind_string, import_kind, NONE); 442 if (!type_value.is_null()) { 443 JSObject::AddProperty(isolate, entry, type_string, type_value, NONE); 444 } 445 446 storage->set(index, *entry); 447 } 448 449 return array_object; 450} 451 452Handle<JSArray> GetExports(Isolate* isolate, 453 Handle<WasmModuleObject> module_object) { 454 auto enabled_features = i::wasm::WasmFeatures::FromIsolate(isolate); 455 Factory* factory = isolate->factory(); 456 457 Handle<String> name_string = factory->InternalizeUtf8String("name"); 458 Handle<String> kind_string = factory->InternalizeUtf8String("kind"); 459 Handle<String> type_string = factory->InternalizeUtf8String("type"); 460 461 Handle<String> function_string = factory->InternalizeUtf8String("function"); 462 Handle<String> table_string = factory->InternalizeUtf8String("table"); 463 Handle<String> memory_string = factory->InternalizeUtf8String("memory"); 464 Handle<String> global_string = factory->InternalizeUtf8String("global"); 465 Handle<String> tag_string = factory->InternalizeUtf8String("tag"); 466 467 // Create the result array. 468 const WasmModule* module = module_object->module(); 469 int num_exports = static_cast<int>(module->export_table.size()); 470 Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0); 471 Handle<FixedArray> storage = factory->NewFixedArray(num_exports); 472 JSArray::SetContent(array_object, storage); 473 array_object->set_length(Smi::FromInt(num_exports)); 474 475 Handle<JSFunction> object_function = 476 Handle<JSFunction>(isolate->native_context()->object_function(), isolate); 477 478 // Populate the result array. 479 for (int index = 0; index < num_exports; ++index) { 480 const WasmExport& exp = module->export_table[index]; 481 482 Handle<String> export_kind; 483 Handle<JSObject> type_value; 484 switch (exp.kind) { 485 case kExternalFunction: 486 if (enabled_features.has_type_reflection()) { 487 auto& func = module->functions[exp.index]; 488 type_value = GetTypeForFunction(isolate, func.sig); 489 } 490 export_kind = function_string; 491 break; 492 case kExternalTable: 493 if (enabled_features.has_type_reflection()) { 494 auto& table = module->tables[exp.index]; 495 base::Optional<uint32_t> maximum_size; 496 if (table.has_maximum_size) maximum_size.emplace(table.maximum_size); 497 type_value = GetTypeForTable(isolate, table.type, table.initial_size, 498 maximum_size); 499 } 500 export_kind = table_string; 501 break; 502 case kExternalMemory: 503 if (enabled_features.has_type_reflection()) { 504 DCHECK_EQ(0, exp.index); // Only one memory supported. 505 base::Optional<uint32_t> maximum_size; 506 if (module->has_maximum_pages) { 507 maximum_size.emplace(module->maximum_pages); 508 } 509 type_value = 510 GetTypeForMemory(isolate, module->initial_pages, maximum_size, 511 module->has_shared_memory); 512 } 513 export_kind = memory_string; 514 break; 515 case kExternalGlobal: 516 if (enabled_features.has_type_reflection()) { 517 auto& global = module->globals[exp.index]; 518 type_value = 519 GetTypeForGlobal(isolate, global.mutability, global.type); 520 } 521 export_kind = global_string; 522 break; 523 case kExternalTag: 524 export_kind = tag_string; 525 break; 526 default: 527 UNREACHABLE(); 528 } 529 530 Handle<JSObject> entry = factory->NewJSObject(object_function); 531 532 Handle<String> export_name = 533 WasmModuleObject::ExtractUtf8StringFromModuleBytes( 534 isolate, module_object, exp.name, kNoInternalize); 535 536 JSObject::AddProperty(isolate, entry, name_string, export_name, NONE); 537 JSObject::AddProperty(isolate, entry, kind_string, export_kind, NONE); 538 if (!type_value.is_null()) { 539 JSObject::AddProperty(isolate, entry, type_string, type_value, NONE); 540 } 541 542 storage->set(index, *entry); 543 } 544 545 return array_object; 546} 547 548Handle<JSArray> GetCustomSections(Isolate* isolate, 549 Handle<WasmModuleObject> module_object, 550 Handle<String> name, ErrorThrower* thrower) { 551 Factory* factory = isolate->factory(); 552 553 base::Vector<const uint8_t> wire_bytes = 554 module_object->native_module()->wire_bytes(); 555 std::vector<CustomSectionOffset> custom_sections = 556 DecodeCustomSections(wire_bytes.begin(), wire_bytes.end()); 557 558 std::vector<Handle<Object>> matching_sections; 559 560 // Gather matching sections. 561 for (auto& section : custom_sections) { 562 Handle<String> section_name = 563 WasmModuleObject::ExtractUtf8StringFromModuleBytes( 564 isolate, module_object, section.name, kNoInternalize); 565 566 if (!name->Equals(*section_name)) continue; 567 568 // Make a copy of the payload data in the section. 569 size_t size = section.payload.length(); 570 MaybeHandle<JSArrayBuffer> result = 571 isolate->factory()->NewJSArrayBufferAndBackingStore( 572 size, InitializedFlag::kUninitialized); 573 Handle<JSArrayBuffer> array_buffer; 574 if (!result.ToHandle(&array_buffer)) { 575 thrower->RangeError("out of memory allocating custom section data"); 576 return Handle<JSArray>(); 577 } 578 memcpy(array_buffer->backing_store(), 579 wire_bytes.begin() + section.payload.offset(), 580 section.payload.length()); 581 582 matching_sections.push_back(array_buffer); 583 } 584 585 int num_custom_sections = static_cast<int>(matching_sections.size()); 586 Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0); 587 Handle<FixedArray> storage = factory->NewFixedArray(num_custom_sections); 588 JSArray::SetContent(array_object, storage); 589 array_object->set_length(Smi::FromInt(num_custom_sections)); 590 591 for (int i = 0; i < num_custom_sections; i++) { 592 storage->set(i, *matching_sections[i]); 593 } 594 595 return array_object; 596} 597 598// Get the source position from a given function index and byte offset, 599// for either asm.js or pure Wasm modules. 600int GetSourcePosition(const WasmModule* module, uint32_t func_index, 601 uint32_t byte_offset, bool is_at_number_conversion) { 602 DCHECK_EQ(is_asmjs_module(module), 603 module->asm_js_offset_information != nullptr); 604 if (!is_asmjs_module(module)) { 605 // For non-asm.js modules, we just add the function's start offset 606 // to make a module-relative position. 607 return byte_offset + GetWasmFunctionOffset(module, func_index); 608 } 609 610 // asm.js modules have an additional offset table that must be searched. 611 return module->asm_js_offset_information->GetSourcePosition( 612 declared_function_index(module, func_index), byte_offset, 613 is_at_number_conversion); 614} 615 616namespace { 617template <typename T> 618inline size_t VectorSize(const std::vector<T>& vector) { 619 return sizeof(T) * vector.size(); 620} 621} // namespace 622 623size_t EstimateStoredSize(const WasmModule* module) { 624 return sizeof(WasmModule) + VectorSize(module->globals) + 625 (module->signature_zone ? module->signature_zone->allocation_size() 626 : 0) + 627 VectorSize(module->types) + 628 VectorSize(module->canonicalized_type_ids) + 629 VectorSize(module->functions) + VectorSize(module->data_segments) + 630 VectorSize(module->tables) + VectorSize(module->import_table) + 631 VectorSize(module->export_table) + VectorSize(module->tags) + 632 VectorSize(module->elem_segments); 633} 634 635size_t PrintSignature(base::Vector<char> buffer, const wasm::FunctionSig* sig, 636 char delimiter) { 637 if (buffer.empty()) return 0; 638 size_t old_size = buffer.size(); 639 auto append_char = [&buffer](char c) { 640 if (buffer.size() == 1) return; // Keep last character for '\0'. 641 buffer[0] = c; 642 buffer += 1; 643 }; 644 for (wasm::ValueType t : sig->parameters()) { 645 append_char(t.short_name()); 646 } 647 append_char(delimiter); 648 for (wasm::ValueType t : sig->returns()) { 649 append_char(t.short_name()); 650 } 651 buffer[0] = '\0'; 652 return old_size - buffer.size(); 653} 654 655} // namespace wasm 656} // namespace internal 657} // namespace v8 658