5#ifndef V8_WASM_WASM_MODULE_H_
6#define V8_WASM_WASM_MODULE_H_
8#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
31class WasmModuleObject;
36using WasmName = base::Vector<const char>;
40#if V8_ENABLE_DRUMBRAKE
41class WasmInterpreterRuntime;
43class WellKnownImportsList;
44class TypeCanonicalizer;
164 const uintptr_t platform_max_pages =
166 memory->min_memory_size =
static_cast<uintptr_t
>(std::min<uint64_t>(
167 platform_max_pages, memory->initial_pages)) *
169 memory->max_memory_size =
static_cast<uintptr_t
>(std::min<uint64_t>(
170 platform_max_pages, memory->maximum_pages)) *
175 }
else if (
v8_flags.wasm_enforce_bounds_checks) {
181 }
else if (memory->is_memory64() && !
v8_flags.wasm_memory64_trap_handling) {
317#define SELECT_WASM_COUNTER(counters, origin, prefix, suffix) \
318 ((origin) == kWasmOrigin ? (counters)->prefix##_wasm_##suffix() \
319 : (counters)->prefix##_asm_##suffix())
324template <
class Value>
330 static constexpr uint32_t kMaxKey = 10'000'000;
331 static_assert(kMaxKey < std::numeric_limits<uint32_t>::max());
343 map_.swap(other.map_);
347 void FinishInitialization();
354 map_->insert(std::make_pair(
key, value));
360 map_->insert(std::make_pair(
key, std::move(value)));
364 if (
mode_ == kDense) {
371 if (it ==
map_->end())
return nullptr;
377 if (
mode_ == kDense) {
385 size_t EstimateCurrentMemoryConsumption()
const;
388 static constexpr uint32_t kLoadFactor = 4;
404 uint32_t function_index);
406 void AddForTesting(
int function_index,
WireBytesRef name);
407 bool Has(uint32_t function_index);
409 size_t EstimateCurrentMemoryConsumption()
const;
415 bool has_functions_{
false};
428 bool is_at_number_conversion);
430 std::pair<int, int> GetFunctionOffsets(
int func_index);
433 void EnsureDecodedOffsets();
453 kFunction =
static_cast<int8_t
>(RefTypeKind::kFunction),
454 kStruct =
static_cast<int8_t
>(RefTypeKind::kStruct),
455 kArray =
static_cast<int8_t
>(RefTypeKind::kArray),
456 kCont =
static_cast<int8_t
>(RefTypeKind::kCont),
460 bool is_final,
bool is_shared)
462 supertype{supertype},
468 bool is_final,
bool is_shared)
470 supertype{supertype},
476 bool is_final,
bool is_shared)
478 supertype{supertype},
484 bool is_final,
bool is_shared)
486 supertype{supertype},
494 if (supertype != other.supertype)
return false;
495 if (
kind != other.kind)
return false;
496 if (is_final != other.is_final)
return false;
497 if (
is_shared != other.is_shared)
return false;
498 if (descriptor != other.descriptor)
return false;
499 if (describes != other.describes)
return false;
500 if (
kind == kFunction)
return *function_sig == *other.function_sig;
501 if (
kind == kStruct)
return *struct_type == *other.struct_type;
503 return *array_type == *other.array_type;
519 bool is_final =
false;
521 uint8_t subtyping_depth = 0;
541 DCHECK(!feedback.is_invalid());
542 DCHECK(!feedback.is_monomorphic());
543 DCHECK(!feedback.is_polymorphic());
544 DCHECK(feedback.is_megamorphic());
552 : index_or_count_(function_index), frequency_or_ool_(call_count) {}
554 : index_or_count_(-num_cases),
555 frequency_or_ool_(reinterpret_cast<intptr_t>(polymorphic_cases)) {}
563 index_or_count_ = other.index_or_count_;
564 if (other.is_polymorphic()) {
565 int num_cases = other.num_cases();
567 for (
int i = 0;
i < num_cases;
i++) {
568 polymorphic[
i].function_index = other.function_index(
i);
569 polymorphic[
i].absolute_call_frequency = other.call_count(
i);
571 frequency_or_ool_ =
reinterpret_cast<intptr_t
>(polymorphic);
573 frequency_or_ool_ = other.frequency_or_ool_;
575 has_non_inlineable_targets_ = other.has_non_inlineable_targets_;
576 is_megamorphic_ = other.is_megamorphic_;
580 if (
this != &other) {
581 index_or_count_ = other.index_or_count_;
582 frequency_or_ool_ = other.frequency_or_ool_;
583 other.frequency_or_ool_ = 0;
585 has_non_inlineable_targets_ = other.has_non_inlineable_targets_;
586 is_megamorphic_ = other.is_megamorphic_;
591 if (is_polymorphic())
delete[] polymorphic_storage();
595 if (is_monomorphic())
return 1;
596 if (is_invalid() || is_megamorphic())
return 0;
597 return -index_or_count_;
600 DCHECK(!is_invalid() && !is_megamorphic());
601 if (is_monomorphic())
return index_or_count_;
602 return polymorphic_storage()[
i].function_index;
605 DCHECK(!is_invalid() && !is_megamorphic());
606 if (is_monomorphic())
return static_cast<int>(frequency_or_ool_);
607 return polymorphic_storage()[
i].absolute_call_frequency;
610 return has_non_inlineable_targets_;
613 has_non_inlineable_targets_ = has_non_inlineable_targets;
621 bool is_invalid()
const {
return index_or_count_ == -1 && !is_megamorphic_; }
628 bool has_non_inlineable_targets_ =
false;
629 bool is_megamorphic_ =
false;
646 int tierup_priority = 0;
648 static constexpr uint32_t kUninitializedLiftoffFrameSize = 1;
660 static constexpr uint32_t kCallRef = 0xFFFFFFFF;
661 static constexpr uint32_t kCallIndirect = kCallRef - 1;
685 size_t EstimateCurrentMemoryConsumption()
const;
690 uint32_t initial_size = 0;
693 uint64_t maximum_size = 0;
694 bool has_maximum_size =
false;
697 bool imported =
false;
698 bool exported =
false;
701 bool is_table64()
const {
return address_type == AddressType::kI64; }
712 int start_function_index = -1;
716 uint32_t untagged_globals_buffer_size = 0;
717 uint32_t tagged_globals_buffer_size = 0;
718 uint32_t num_imported_globals = 0;
719 uint32_t num_imported_mutable_globals = 0;
720 uint32_t num_imported_functions = 0;
721 uint32_t num_imported_tables = 0;
722 uint32_t num_imported_tags = 0;
723 uint32_t num_declared_functions = 0;
730 std::atomic<uint32_t> num_small_functions = 0;
731 uint32_t num_exported_functions = 0;
732 uint32_t num_declared_data_segments = 0;
741 mutable std::atomic<bool> canonical_typenames_decoded =
false;
743 bool is_wasm_gc =
false;
745 bool has_shared_part =
false;
773 std::array<WasmDebugSymbols, WasmDebugSymbols::kNumTypes> debug_symbols{};
782 static_assert(
sizeof(std::atomic<uint8_t>) == 1);
783 static_assert(
alignof(std::atomic<uint8_t>) == 1);
795 types.push_back(type);
796 if (type.supertype.valid()) {
800 DCHECK_LT(type.supertype.index, types.size() - 1);
801 types.back().subtyping_depth =
809 bool is_final,
bool is_shared) {
822 bool is_final,
bool is_shared) {
828 bool is_final,
bool is_shared) {
835 return index.index < types.size();
839 size_t num_types = types.size();
841 return types[index.index];
846 return HeapType::Index(index, t.is_shared,
851 size_t num_types = isorecursive_canonical_type_ids.size();
854 return isorecursive_canonical_type_ids[index.index];
858 if (!type.has_index()) {
861 return type.Canonicalize(canonical_type_id(type.ref_index()));
865 return index.index < types.size() &&
866 types[index.index].kind == TypeDefinition::kFunction;
869 DCHECK(has_signature(index));
870 size_t num_types = types.size();
872 return types[index.index].function_sig;
876 return index.index < types.size() &&
877 types[index.index].kind == TypeDefinition::kCont;
881 DCHECK(has_cont_type(index));
882 size_t num_types = types.size();
884 return types[index.index].cont_type;
888 DCHECK(has_signature(index));
889 size_t num_types = isorecursive_canonical_type_ids.size();
891 return isorecursive_canonical_type_ids[index.index];
895 uint32_t function_index)
const;
898 return index.index < types.size() &&
899 types[index.index].kind == TypeDefinition::kStruct;
903 DCHECK(has_struct(index));
904 size_t num_types = types.size();
906 return types[index.index].struct_type;
910 return index.index < types.size() &&
911 types[index.index].kind == TypeDefinition::kArray;
915 size_t num_types = types.size();
917 return types[index.index].array_type;
921 size_t num_types = types.size();
923 return types[index.index].supertype;
926 return supertype(index).valid();
931 if (isorecursive_canonical_type_ids.empty()) {
932 return CanonicalTypeIndex::Invalid();
934 return *std::max_element(isorecursive_canonical_type_ids.begin(),
935 isorecursive_canonical_type_ids.end());
939 return type(functions[func_index].sig_index).is_shared;
944 static_assert(
sizeof(validated_functions[0]) == 1);
945 DCHECK_LE(num_imported_functions, func_index);
946 int pos = func_index - num_imported_functions;
949 validated_functions[
pos >> 3].load(std::memory_order_relaxed);
951 return byte & (1 << (
pos & 7));
957 DCHECK_LE(num_imported_functions, func_index);
958 int pos = func_index - num_imported_functions;
960 std::atomic<uint8_t>* atomic_byte = &validated_functions[
pos >> 3];
961 uint8_t old_byte = atomic_byte->load(std::memory_order_relaxed);
962 uint8_t new_bit = 1 << (
pos & 7);
963 while ((old_byte & new_bit) == 0 &&
964 !atomic_byte->compare_exchange_weak(old_byte, old_byte | new_bit,
965 std::memory_order_relaxed)) {
972 if (num_declared_functions == 0)
return;
974 size_t num_words = (num_declared_functions + 7) / 8;
975 for (
size_t i = 0;
i < num_words; ++
i) {
976 validated_functions[
i].store(0xff, std::memory_order_relaxed);
981 return base::VectorOf(functions) + num_imported_functions;
984#if V8_ENABLE_DRUMBRAKE
985 void SetWasmInterpreter(
986 std::shared_ptr<WasmInterpreterRuntime> interpreter)
const {
988 interpreter_ = interpreter;
990 mutable std::weak_ptr<WasmInterpreterRuntime> interpreter_;
994 size_t EstimateStoredSize()
const;
995 size_t EstimateCurrentMemoryConsumption()
const;
999 return module->origin != kWasmOrigin;
1022 ModuleTypeIndex type_index);
1032 : module_bytes_(module_bytes) {}
1048 uint32_t size =
static_cast<uint32_t
>(module_bytes_.length());
1054 return module_bytes_.
SubVector(function->code.offset(),
1055 function->code.end_offset());
1059 const uint8_t*
start()
const {
return module_bytes_.begin(); }
1060 const uint8_t*
end()
const {
return module_bytes_.end(); }
1061 size_t length()
const {
return module_bytes_.length(); }
1087 bool for_exception =
false);
1091 std::optional<uint64_t> max_size,
1095 std::optional<uint64_t> max_size,
1109 uint32_t byte_offset,
bool is_at_number_conversion);
1117 return declared_idx;
1128template <
int kMaxLen = 50>
1130 static_assert(kMaxLen >= 4,
"minimum length is 4 (length of '...' plus one)");
1133 template <
typename T>
1142 if (len >
static_cast<size_t>(kMaxLen)) {
1144 memset(
buffer_ + kMaxLen - 3,
'.', 3);
1164 char delimiter =
':');
Vector< T > SubVector(size_t from, size_t to) const
AdaptiveMap & operator=(AdaptiveMap &&other) V8_NOEXCEPT
std::map< uint32_t, Value > MapType
void Put(uint32_t key, const Value &value)
AdaptiveMap(AdaptiveMap &&other) V8_NOEXCEPT
const Value * Get(uint32_t key) const
std::unique_ptr< MapType > map_
bool Has(uint32_t key) const
AdaptiveMap & operator=(const AdaptiveMap &)=delete
void Put(uint32_t key, Value &&value)
AdaptiveMap(const AdaptiveMap &)=delete
std::vector< Value > vector_
bool is_polymorphic() const
CallSiteFeedback(const CallSiteFeedback &other) V8_NOEXCEPT
bool is_monomorphic() const
CallSiteFeedback & operator=(CallSiteFeedback &&other) V8_NOEXCEPT
intptr_t frequency_or_ool_
static CallSiteFeedback CreateMegamorphic()
CallSiteFeedback(PolymorphicCase *polymorphic_cases, int num_cases)
bool is_megamorphic() const
const PolymorphicCase * polymorphic_storage() const
CallSiteFeedback(CallSiteFeedback &&other) V8_NOEXCEPT
int call_count(int i) const
bool has_non_inlineable_targets() const
CallSiteFeedback(int function_index, int call_count)
void set_has_non_inlineable_targets(bool has_non_inlineable_targets)
int function_index(int i) const
CallSiteFeedback & operator=(const CallSiteFeedback &other) V8_NOEXCEPT
const char * start() const
TruncatedUserString(const char *start, size_t len)
TruncatedUserString(const uint8_t *start, size_t len)
TruncatedUserString(base::Vector< T > name)
uint32_t end_offset() const
constexpr WireBytesRef(uint32_t offset, uint32_t length)
constexpr WireBytesRef()=default
RecordWriteMode const mode_
base::OwnedVector< uint8_t > buffer_
bool IsTrapHandlerEnabled()
DirectHandle< JSObject > GetTypeForTable(Isolate *isolate, ValueType type, uint32_t min_size, std::optional< uint64_t > max_size, AddressType address_type)
size_t PrintSignature(base::Vector< char > buffer, const CanonicalSig *sig, char delimiter)
int GetSubtypingDepth(const WasmModule *module, ModuleTypeIndex type_index)
uint32_t max_mem32_pages()
DirectHandle< JSObject > GetTypeForMemory(Isolate *isolate, uint32_t min_size, std::optional< uint64_t > max_size, bool shared, AddressType address_type)
uint32_t max_mem64_pages()
int GetWasmFunctionOffset(const WasmModule *module, uint32_t func_index)
int JumpTableOffset(const WasmModule *module, int func_index)
int GetContainingWasmFunction(const WasmModule *module, uint32_t byte_offset)
bool is_asmjs_module(const WasmModule *module)
size_t GetWireBytesHash(base::Vector< const uint8_t > wire_bytes)
DirectHandle< JSArray > GetImports(Isolate *isolate, DirectHandle< WasmModuleObject > module_object)
constexpr const char * AddressTypeToStr(AddressType address_type)
int GetSourcePosition(const WasmModule *module, uint32_t func_index, uint32_t byte_offset, bool is_at_number_conversion)
base::Vector< const char > WasmName
constexpr ModuleTypeIndex kNoType
constexpr ModuleTypeIndex kNoSuperType
int GetNearestWasmFunction(const WasmModule *module, uint32_t byte_offset)
constexpr IndependentHeapType kWasmVoid
int declared_function_index(const WasmModule *module, int func_index)
DirectHandle< JSArray > GetExports(Isolate *isolate, DirectHandle< WasmModuleObject > module_object)
constexpr size_t kWasmPageSize
void UpdateComputedInformation(WasmMemory *memory, ModuleOrigin origin)
DirectHandle< JSArray > GetCustomSections(Isolate *isolate, DirectHandle< WasmModuleObject > module_object, DirectHandle< String > name, ErrorThrower *thrower)
constexpr IndependentHeapType kWasmBottom
std::ostream & operator<<(std::ostream &os, LiftoffVarState slot)
WasmCompilationHintStrategy
@ kLazyBaselineEagerTopTier
DirectHandle< JSObject > GetTypeForFunction(Isolate *isolate, const FunctionSig *sig, bool for_exception)
constexpr size_t kV8MaxWasmTotalFunctions
std::unordered_map< uint32_t, BranchHintMap > BranchHintInfo
Signature< ValueType > FunctionSig
DirectHandle< String > ErrorStringForCodegen(Isolate *isolate, DirectHandle< Context > context)
bool IsWasmCodegenAllowed(Isolate *isolate, DirectHandle< NativeContext > context)
int NumFeedbackSlots(const WasmModule *module, int func_index)
DirectHandle< JSObject > GetTypeForGlobal(Isolate *isolate, bool is_mutable, ValueType type)
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
constexpr int kSystemPointerSize
V8_EXPORT_PRIVATE FlagValues v8_flags
JSArrayBuffer::IsDetachableBit is_shared
#define DCHECK_LE(v1, v2)
#define DCHECK_NOT_NULL(val)
#define DCHECK_IMPLIES(v1, v2)
#define DCHECK_NE(v1, v2)
#define DCHECK_GE(v1, v2)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
#define DCHECK_GT(v1, v2)
#define ASSERT_TRIVIALLY_COPYABLE(T)
#define V8_EXPORT_PRIVATE
int absolute_call_frequency
bool needs_reprocessing_after_deopt
uint32_t liftoff_frame_size
base::OwnedVector< uint32_t > call_targets
base::OwnedVector< CallSiteFeedback > feedback_vector
static constexpr ModuleTypeIndex Invalid()
bool BoundsCheck(WireBytesRef ref) const
base::Vector< const uint8_t > module_bytes_
bool operator==(const ModuleWireBytes &other) const =default
base::Vector< const uint8_t > GetFunctionBytes(const WasmFunction *function) const
const uint8_t * end() const
constexpr ModuleWireBytes(const uint8_t *start, const uint8_t *end)
ModuleWireBytes(base::Vector< const uint8_t > module_bytes)
const uint8_t * start() const
base::Vector< const uint8_t > module_bytes() const
bool has_descriptor() const
const ContType * cont_type
constexpr TypeDefinition(const StructType *type, ModuleTypeIndex supertype, bool is_final, bool is_shared)
constexpr TypeDefinition()=default
bool operator==(const TypeDefinition &other) const
bool is_descriptor() const
ModuleTypeIndex supertype
const StructType * struct_type
constexpr TypeDefinition(const FunctionSig *sig, ModuleTypeIndex supertype, bool is_final, bool is_shared)
const ArrayType * array_type
constexpr TypeDefinition(const ArrayType *type, ModuleTypeIndex supertype, bool is_final, bool is_shared)
constexpr TypeDefinition(const ContType *type, ModuleTypeIndex supertype, bool is_final, bool is_shared)
WellKnownImportsList well_known_imports
std::unordered_map< uint32_t, FunctionTypeFeedback > feedback_for_function
std::unordered_map< uint32_t, uint32_t > deopt_count_for_function
WasmCompilationHintTier top_tier
WasmCompilationHintStrategy strategy
WasmCompilationHintTier baseline_tier
ConstantExpression dest_addr
WasmDataSegment(bool is_active, bool is_shared, uint32_t memory_index, ConstantExpression dest_addr, WireBytesRef source)
static WasmDataSegment PassiveForTesting()
WireBytesRef external_url
uint32_t elements_wire_bytes_offset
WasmElemSegment(Status status, bool shared, ValueType type, ElementType element_type, uint32_t element_count, uint32_t elements_wire_bytes_offset)
WasmElemSegment(WasmElemSegment &&) V8_NOEXCEPT=default
ConstantExpression offset
WasmElemSegment(const WasmElemSegment &)=delete
WasmElemSegment(bool shared, ValueType type, uint32_t table_index, ConstantExpression offset, ElementType element_type, uint32_t element_count, uint32_t elements_wire_bytes_offset)
ImportExportKindCode kind
WasmFunctionName(int func_index, WasmName name)
ModuleTypeIndex sig_index
ImportExportKindCode kind
BoundsCheckStrategy bounds_checks
uintptr_t min_memory_size
uintptr_t max_memory_size
const StructType * struct_type(ModuleTypeIndex index) const
base::Vector< const WasmFunction > declared_functions() const
LazilyGeneratedNames lazily_generated_names
void AddContTypeForTesting(const ContType *type, ModuleTypeIndex supertype, bool is_final, bool is_shared)
std::vector< TypeDefinition > types
WasmModule(const WasmModule &)=delete
void set_function_validated(int func_index) const
std::vector< CanonicalTypeIndex > isorecursive_canonical_type_ids
CanonicalTypeIndex canonical_type_id(ModuleTypeIndex index) const
const ContType * cont_type(ModuleTypeIndex index) const
std::vector< WasmMemory > memories
std::unique_ptr< AsmJsOffsetInformation > asm_js_offset_information
bool has_cont_type(ModuleTypeIndex index) const
void AddTypeForTesting(TypeDefinition type)
const ArrayType * array_type(ModuleTypeIndex index) const
std::unique_ptr< std::atomic< uint8_t >[]> validated_functions
bool has_signature(ModuleTypeIndex index) const
bool has_array(ModuleTypeIndex index) const
std::vector< WasmExport > export_table
std::vector< WasmElemSegment > elem_segments
std::vector< WasmImport > import_table
std::vector< WasmStringRefLiteral > stringref_literals
uint32_t num_declared_functions
HeapType heap_type(ModuleTypeIndex index) const
void AddSignatureForTesting(const FunctionSig *sig, ModuleTypeIndex supertype, bool is_final, bool is_shared)
CanonicalValueType canonical_type(ValueType type) const
bool function_is_shared(int func_index) const
const ModuleOrigin origin
std::vector< WasmFunction > functions
bool has_supertype(ModuleTypeIndex index) const
CanonicalTypeIndex canonical_sig_id(ModuleTypeIndex index) const
uint32_t num_imported_functions
std::vector< WasmCompilationHint > compilation_hints
const FunctionSig * signature(ModuleTypeIndex index) const
bool has_struct(ModuleTypeIndex index) const
std::vector< std::pair< uint32_t, uint32_t > > inst_traces
std::vector< WasmTag > tags
void AddStructTypeForTesting(const StructType *type, ModuleTypeIndex supertype, bool is_final, bool is_shared)
WasmModule & operator=(const WasmModule &)=delete
std::vector< WasmGlobal > globals
TypeFeedbackStorage type_feedback
bool function_was_validated(int func_index) const
BranchHintInfo branch_hints
void AddArrayTypeForTesting(const ArrayType *type, ModuleTypeIndex supertype, bool is_final, bool is_shared)
const TypeDefinition & type(ModuleTypeIndex index) const
std::vector< WasmDataSegment > data_segments
ModuleTypeIndex supertype(ModuleTypeIndex index) const
bool has_type(ModuleTypeIndex index) const
void set_all_functions_validated() const
std::vector< WasmTable > tables
CanonicalTypeIndex MaxCanonicalTypeIndex() const
WasmStringRefLiteral(const WireBytesRef &source)
ModuleTypeIndex sig_index
WasmTag(const WasmTagSig *sig, ModuleTypeIndex sig_index)
const FunctionSig * ToFunctionSig() const
std::unique_ptr< ValueMirror > key