5#ifndef V8_WASM_MODULE_DECODER_IMPL_H_
6#define V8_WASM_MODULE_DECODER_IMPL_H_
8#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
29 if (v8_flags.trace_wasm_decoder) PrintF(__VA_ARGS__); \
67 const char* name,
ITracer* tracer) {
72 uint32_t length = decoder->
consume_u32v(
"length", tracer);
79 const uint8_t* string_start = decoder->
pc();
83 tracer->
Bytes(decoder->
pc(), length);
86 tracer->
Description(
reinterpret_cast<const char*
>(decoder->
pc()), length);
94 case unibrow::Utf8Variant::kUtf8:
96 decoder->
errorf(string_start,
"%s: no valid UTF-8 string", name);
99 case unibrow::Utf8Variant::kWtf8:
100 if (!unibrow::Wtf8::ValidateEncoding(string_start, length)) {
101 decoder->
errorf(string_start,
"%s: no valid WTF-8 string", name);
104 case unibrow::Utf8Variant::kUtf8NoTrap:
120 return consume_string(decoder, unibrow::Utf8Variant::kUtf8, name, tracer);
129 const uint8_t* section_name_start =
132 TRACE(
" +%d section name : \"%.*s\"\n",
133 static_cast<int>(section_name_start - decoder->
start()),
134 string.length() < 20 ?
string.length() : 20, section_name_start);
136 using SpecialSectionPair = std::pair<base::Vector<const char>,
SectionCode>;
137 static constexpr SpecialSectionPair kSpecialSections[]{
152 for (
auto& special_section : kSpecialSections) {
153 if (name_vec == special_section.first)
return special_section.second;
196 void advance(
bool move_to_section_end =
false) {
204 "section was %s than expected size "
205 "(%u bytes expected, %zu decoded)",
247 "section (code %u, \"%s\") extends past end of the module "
248 "(length %u, remaining bytes %u)",
285 if (
v8_flags.dump_wasm_module_path) {
286 path =
v8_flags.dump_wasm_module_path;
295 SNPrintF(buf,
"%08x.%s.wasm", hash, ok ?
"ok" :
"failed");
299 rv = fwrite(module_bytes.
begin(), module_bytes.
length(), 1, file);
304 os <<
"Error while dumping wasm file to " << path << std::endl;
334#define BYTES(x) (x & 0xFF), (x >> 8) & 0xFF, (x >> 16) & 0xFF, (x >> 24) & 0xFF
337 "expected magic word %02x %02x %02x %02x, "
338 "found %02x %02x %02x %02x",
348 "expected version %02x %02x %02x %02x, "
349 "found %02x %02x %02x %02x",
381 errorf(
pc(),
"Multiple %s sections not allowed",
389 auto check_order = [
this, section_code](
SectionCode before,
393 errorf(
pc(),
"The %s section must appear before the %s section",
402 switch (section_code) {
428 TRACE(
"Decode Section %p - %p\n", bytes.begin(), bytes.end());
432 switch (section_code) {
527 "unexpected section <%s> (enable with "
528 "--experimental-wasm-stringref)",
537 if (
pc() != bytes.end()) {
538 const char* msg =
pc() < bytes.end() ?
"shorter" :
"longer";
540 "section was %s than expected size "
541 "(%zu bytes expected, %zu decoded)",
542 msg, bytes.size(),
static_cast<size_t>(
pc() - bytes.begin()));
553 default:
return "unknown";
559 const bool is_final =
true;
560 const bool shared =
false;
569 if (
sig ==
nullptr) {
579 if (type ==
nullptr) {
588 if (type ==
nullptr) {
597 "core stack switching not enabled (enable with "
598 "--experimental-wasm-wasmfx)");
602 const uint8_t*
pos =
pc();
606 error(
pos,
"cont type must refer to a signature index");
625 "descriptor types need --experimental-wasm-custom-descriptors");
630 const uint8_t*
pos =
pc();
632 if (descriptor >=
module_->types.size()) {
633 errorf(
pos,
"descriptor type index %u is out of bounds", descriptor);
639 error(
pos - 1,
"'descriptor' may only be used with structs");
654 "descriptor types need --experimental-wasm-custom-descriptors");
659 const uint8_t*
pos =
pc();
661 if (describes >= current_type_index) {
662 error(
pos,
"types can only describe previously-declared types");
668 error(
pos - 1,
"'describes' may only be used with structs");
681 if (!
v8_flags.experimental_wasm_shared) {
683 "unknown type form: %d, enable with --experimental-wasm-shared",
687 module_->has_shared_part =
true;
690 type.is_shared =
true;
704 consume_bytes(1, is_final ?
" subtype final, " :
" subtype extensible, ",
706 constexpr uint32_t kMaximumSupertypes = 1;
707 uint32_t supertype_count =
710 if (supertype_count == 1) {
712 if (supertype >= current_type_index) {
713 errorf(
"type %u: invalid supertype %u", current_type_index,
724 type.is_final = is_final;
735 for (uint32_t
i = 0;
ok() &&
i < types_count; ++
i) {
736 TRACE(
"DecodeType[%d] module+%d\n",
i,
static_cast<int>(
pc_ -
start_));
738 size_t initial_size =
module_->types.size();
739 uint32_t group_size = 1;
749 errorf(
pc(),
"Type definition count exceeds maximum %zu",
755 module_->types.resize(initial_size + group_size);
756 for (uint32_t j = 0; j < group_size; j++) {
777 uint32_t end_index =
static_cast<uint32_t
>(
module->types.size());
778 uint32_t start_index = end_index - group_size;
779 for (uint32_t
i = start_index;
ok() &&
i < end_index; ++
i) {
782 switch (type_def.
kind) {
785 size_t count = all.size();
787 for (uint32_t j = 0; j <
count; j++) {
793 static_cast<uint32_t
>(type_def.
function_sig->return_count());
794 const char* param_or_return =
795 j < retcount ?
"return" :
"parameter";
796 uint32_t index = j < retcount ? j : j - retcount;
800 "Type %u: shared signature must have shared %s types, "
801 "actual type for %s %d is %s",
802 i, param_or_return, param_or_return, index,
803 type.
name().c_str());
813 for (uint32_t j = 0; j <
count; j++) {
818 "Type %u: shared struct must have shared field types, "
819 "actual type for field %d is %s",
820 i, j, type.
name().c_str());
826 module->type(type_def.descriptor);
830 "Type %u has descriptor %u but %u doesn't describe %u",
i,
836 "Type %u and its descriptor %u must have same sharedness",
845 "Type %u describes %u but %u isn't a descriptor for %u",
i,
860 "Type %u: shared array must have shared element type, "
861 "actual element type is %s",
862 i, type.
name().c_str());
874 "Type %u: cont type must refer to a signature index, "
876 i,
module_->heap_type(contfun_typeid).name().c_str());
881 "Type %u: shared cont type must refer to a shared signature,"
882 " actual type is %s",
883 module_->heap_type(contfun_typeid).name().c_str());
890 module->isorecursive_canonical_type_ids.resize(end_index);
892 for (uint32_t
i = start_index;
ok() &&
i < end_index; ++
i) {
895 if (!explicit_super.
valid())
continue;
897 uint32_t depth =
module->type(explicit_super).subtyping_depth + 1;
901 errorf(
"type %u: subtyping depth is greater than allowed",
i);
906 if (module->
type(explicit_super).is_final) {
907 errorf(
"type %u extends final type %u",
i, explicit_super.
index);
912 errorf(
"type %u has invalid explicit supertype %u",
i,
913 explicit_super.
index);
920 uint32_t import_table_count =
922 module_->import_table.reserve(import_table_count);
923 for (uint32_t
i = 0;
ok() &&
i < import_table_count; ++
i) {
924 TRACE(
"DecodeImportTable[%d] module+%d\n",
i,
940 .module_name = module_name, .field_name = field_name, .kind =
kind});
941 WasmImport*
import = &module_->import_table.back();
945 import->index =
static_cast<uint32_t
>(
module_->functions.size());
946 module_->num_imported_functions++;
948 .func_index =
import->index,
952 function->sig_index =
958 import->index =
static_cast<uint32_t
>(
module_->tables.size());
959 const uint8_t* type_position =
pc();
961 if (!type.is_object_reference()) {
962 errorf(type_position,
"Invalid table type %s", type.name().c_str());
965 module_->num_imported_tables++;
974 if (table->shared &&
v8_flags.experimental_wasm_shared) {
975 module_->has_shared_part =
true;
978 "Shared table %i must have shared element type, actual "
980 i, type.
name().c_str());
989 table->has_maximum_size,
kNoMaximum, &table->maximum_size,
997 errorf(
"At most %u imported memories are supported",
1001 uint32_t mem_index =
static_cast<uint32_t
>(
module_->memories.size());
1002 import->index = mem_index;
1003 module_->memories.emplace_back();
1006 external_memory->
index = mem_index;
1009 uint32_t max_pages = external_memory->
is_memory64()
1013 "memory",
"pages", max_pages, &external_memory->
initial_pages,
1021 import->index =
static_cast<uint32_t
>(
module_->globals.size());
1026 error(
"shared imported global must have shared type");
1031 .mutability = mutability,
1035 module_->num_imported_globals++;
1037 if (shared)
module_->has_shared_part =
true;
1038 if (mutability)
module_->num_imported_mutable_globals++;
1044 import->index =
static_cast<uint32_t
>(
module_->tags.size());
1050 module_->tags.emplace_back(tag_sig, sig_index);
1058 if (
module_->memories.size() > 1) {
1061 error(
"Multiple memories not supported in Wasm jitless mode");
1065 module_->type_feedback.well_known_imports.Initialize(
1066 module_->num_imported_functions);
1071 uint32_t functions_count =
1074 uint32_t total_function_count =
1075 module_->num_imported_functions + functions_count;
1076 module_->functions.resize(total_function_count);
1077 module_->num_declared_functions = functions_count;
1081 module_->validated_functions =
1082 std::make_unique<std::atomic<uint8_t>[]>((functions_count + 7) / 8);
1086 std::fill_n(
module_->validated_functions.get(), (functions_count + 7) / 8,
1090 for (uint32_t func_index =
module_->num_imported_functions;
1091 func_index < total_function_count; ++func_index) {
1093 function->func_index = func_index;
1104 for (uint32_t
i = 0;
ok() &&
i < table_count;
i++) {
1106 module_->tables.emplace_back();
1108 const uint8_t* type_position =
pc();
1110 bool has_initializer =
false;
1112 pc(),
"table-with-initializer byte") == 0x40) {
1114 has_initializer =
true;
1117 if (reserved != 0) {
1118 error(type_position,
"Reserved byte must be 0x00");
1126 error(type_position,
"Only reference types can be used as table types");
1131 "Table of non-defaultable table %s needs initial value",
1132 table_type.
name().c_str());
1135 table->type = table_type;
1139 if (table->shared &&
v8_flags.experimental_wasm_shared) {
1140 module_->has_shared_part =
true;
1144 "Shared table %i must have shared element type, actual type %s",
1145 i +
module_->num_imported_tables, table_type.
name().c_str());
1154 table->has_maximum_size,
kNoMaximum, &table->maximum_size,
1157 if (has_initializer) {
1158 table->initial_value =
1165 const uint8_t* mem_count_pc =
pc();
1171 size_t imported_memories =
module_->memories.size();
1175 "Exceeding maximum number of memories (%u; declared %u, "
1179 module_->memories.resize(imported_memories + memory_count);
1181 for (uint32_t
i = 0;
ok() &&
i < memory_count;
i++) {
1183 memory->index =
static_cast<uint32_t
>(imported_memories +
i);
1186 uint32_t max_pages =
1189 "memory",
"pages", max_pages, &memory->initial_pages,
1190 memory->has_maximum_pages, max_pages, &memory->maximum_pages,
1193 if (
module_->memories.size() > 1) {
1196 error(
"Multiple memories not supported in Wasm jitless mode");
1210 uint32_t imported_globals =
static_cast<uint32_t
>(
module_->globals.size());
1213 module_->globals.reserve(imported_globals + globals_count);
1214 for (uint32_t
i = 0;
ok() &&
i < globals_count; ++
i) {
1215 TRACE(
"DecodeGlobal[%d] module+%d\n",
i,
static_cast<int>(
pc_ -
start_));
1217 const uint8_t*
pos =
pc_;
1223 errorf(
pos,
"Shared global %i must have shared type, actual type %s",
1224 i + imported_globals, type.name().c_str());
1232 .mutability = mutability,
1236 if (shared)
module_->has_shared_part =
true;
1241 uint32_t export_table_count =
1243 module_->export_table.reserve(export_table_count);
1244 for (uint32_t
i = 0;
ok() &&
i < export_table_count; ++
i) {
1245 TRACE(
"DecodeExportTable[%d] module+%d\n",
i,
1255 const uint8_t* kind_pos =
pc();
1275 module_->num_exported_functions++;
1284 if (table) table->exported =
true;
1288 const uint8_t* index_pos =
pc();
1290 size_t num_memories =
module_->memories.size();
1291 if (exp->index >=
module_->memories.size()) {
1293 "invalid exported memory index %u (having %zu memor%s)",
1294 exp->index, num_memories, num_memories == 1 ?
"y" :
"ies");
1297 module_->memories[exp->index].exported =
true;
1314 errorf(kind_pos,
"invalid export kind 0x%02x", exp->kind);
1321 module_->export_table.size() > 1) {
1322 std::vector<WasmExport> sorted_exports(
module_->export_table);
1326 if (a.name.length() != b.name.length()) {
1327 return a.name.length() < b.name.length();
1329 const uint8_t* left =
1331 const uint8_t* right =
1333 return memcmp(left, right, a.name.length()) < 0;
1335 std::stable_sort(sorted_exports.begin(), sorted_exports.end(), cmp_less);
1337 auto it = sorted_exports.begin();
1339 for (
auto end = sorted_exports.end(); it !=
end; last = &*it++) {
1340 DCHECK(!cmp_less(*it, *last));
1341 if (!cmp_less(*last, *it)) {
1345 errorf(
pc,
"Duplicate export name '%.*s' for %s %d and %s %d",
1357 const uint8_t*
pos =
pc_;
1361 (func->
sig->parameter_count() > 0 || func->
sig->return_count() > 0)) {
1362 error(
pos,
"invalid start function: non-zero parameter or return count");
1367 uint32_t segment_count =
1370 for (uint32_t
i = 0;
i < segment_count; ++
i) {
1383 module_->elem_segments.push_back(std::move(segment));
1391 uint32_t code_section_start =
pc_offset();
1400 std::vector<std::pair<uint32_t, uint32_t>> inst_traces;
1402 for (uint32_t
i = 0;
ok() &&
i < functions_count; ++
i) {
1403 int function_index =
module_->num_imported_functions +
i;
1409 const uint8_t*
pos =
pc();
1416 errorf(
pos,
"size %u > maximum function size %zu", size,
1427 std::get<0>(*inst_traces_it) ==
i;
1429 uint32_t trace_offset =
offset + std::get<1>(*inst_traces_it);
1430 uint32_t mark_id = std::get<2>(*inst_traces_it);
1431 std::pair<uint32_t, uint32_t> trace_mark = {trace_offset, mark_id};
1432 inst_traces.push_back(trace_mark);
1439 inst_traces_it == this->inst_traces_.end())) {
1442 inst_traces.push_back({0, 0});
1443 this->
module_->inst_traces = std::move(inst_traces);
1454 module_->code = section_bytes;
1458 if (functions_count !=
module_->num_declared_functions) {
1459 errorf(error_offset,
"function body count %u mismatch (%u expected)",
1460 functions_count,
module_->num_declared_functions);
1469 function->code = {
offset, length};
1470 constexpr uint32_t kSmallFunctionThreshold = 50;
1471 if (length < kSmallFunctionThreshold) {
1472 ++
module_->num_small_functions;
1481 data_segments_count !=
module_->num_declared_data_segments) {
1482 errorf(
pc(),
"data segments count %u mismatch (%u expected)",
1483 data_segments_count,
module_->num_declared_data_segments);
1497 uint32_t data_segments_count =
1501 module_->data_segments.reserve(data_segments_count);
1502 for (uint32_t
i = 0;
i < data_segments_count; ++
i) {
1503 TRACE(
"DecodeDataSegment[%d] module+%d\n",
i,
1524 module_->data_segments.emplace_back(
1545 while (inner.
ok() && inner.
more()) {
1546 uint8_t name_type = inner.
consume_u8(
"name type");
1547 if (name_type & 0x80) inner.
error(
"name type if not varuint7");
1549 uint32_t name_payload_len = inner.
consume_u32v(
"name payload length");
1562 inner.
consume_bytes(name_payload_len,
"name subsection payload");
1608 TRACE(
"DecodeInstTrace module+%d\n",
static_cast<int>(
pc_ -
start_));
1615 std::vector<std::tuple<uint32_t, uint32_t, uint32_t>> inst_traces;
1617 uint32_t func_count = inner.
consume_u32v(
"number of functions");
1619 int64_t last_func_idx = -1;
1620 for (uint32_t
i = 0;
i < func_count;
i++) {
1621 uint32_t func_idx = inner.
consume_u32v(
"function index");
1622 if (int64_t{func_idx} <= last_func_idx) {
1623 inner.
errorf(
"Invalid function index: %d", func_idx);
1626 last_func_idx = func_idx;
1628 uint32_t num_traces = inner.
consume_u32v(
"number of trace marks");
1629 TRACE(
"DecodeInstTrace[%d] module+%d\n", func_idx,
1630 static_cast<int>(inner.
pc() - inner.
start()));
1632 int64_t last_func_off = -1;
1633 for (uint32_t j = 0; j < num_traces; ++j) {
1634 uint32_t func_off = inner.
consume_u32v(
"function offset");
1637 uint32_t trace_mark_id = 0;
1639 for (uint32_t k = 0; k < mark_size; k++) {
1640 trace_mark_id |= inner.
consume_u8(
"trace mark id") << k * 8;
1642 if (int64_t{func_off} <= last_func_off) {
1643 inner.
errorf(
"Invalid branch offset: %d", func_off);
1646 last_func_off = func_off;
1647 TRACE(
"DecodeInstTrace[%d][%d] module+%d\n", func_idx, func_off,
1648 static_cast<int>(inner.
pc() - inner.
start()));
1652 std::tuple<uint32_t, uint32_t, uint32_t> mark_tuple = {
1653 func_idx, func_off, trace_mark_id};
1654 inst_traces.push_back(mark_tuple);
1659 inner.
errorf(
"Unexpected extra bytes: %d\n",
1660 static_cast<int>(inner.
pc() - inner.
start()));
1673 TRACE(
"DecodeCompilationHints module+%d\n",
static_cast<int>(
pc_ -
start_));
1678 const bool before_function_section =
1681 if (before_function_section || after_code_section ||
1694 uint32_t hint_count = decoder.
consume_u32v(
"compilation hint count");
1695 if (hint_count !=
module_->num_declared_functions) {
1696 decoder.
errorf(decoder.
pc(),
"Expected %u compilation hints (%u found)",
1697 module_->num_declared_functions, hint_count);
1702 module_->compilation_hints.reserve(hint_count);
1704 for (uint32_t
i = 0; decoder.
ok() &&
i < hint_count;
i++) {
1705 TRACE(
"DecodeCompilationHints[%d] module+%d\n",
i,
1713 uint8_t hint_byte = decoder.
consume_u8(
"compilation hint");
1714 if (!decoder.
ok())
break;
1723 "The check below assumes that 0x03 is the only invalid 2-bit number "
1724 "for a compilation tier");
1725 if (((hint_byte >> 2) & 0x03) == 0x03 ||
1726 ((hint_byte >> 4) & 0x03) == 0x03) {
1728 "Invalid compilation hint %#04x (invalid tier 0x03)",
1748 "Invalid compilation hint %#04x (forbidden downgrade)",
1754 module_->compilation_hints.push_back(std::move(hint));
1760 module_->compilation_hints.clear();
1769 TRACE(
"DecodeBranchHints module+%d\n",
static_cast<int>(
pc_ -
start_));
1777 uint32_t func_count = inner.
consume_u32v(
"number of functions");
1779 int64_t last_func_idx = -1;
1780 for (uint32_t
i = 0;
i < func_count;
i++) {
1781 uint32_t func_idx = inner.
consume_u32v(
"function index");
1782 if (int64_t{func_idx} <= last_func_idx) {
1783 inner.
errorf(
"Invalid function index: %d", func_idx);
1786 last_func_idx = func_idx;
1787 uint32_t num_hints = inner.
consume_u32v(
"number of hints");
1789 TRACE(
"DecodeBranchHints[%d] module+%d\n", func_idx,
1790 static_cast<int>(inner.
pc() - inner.
start()));
1792 int64_t last_br_off = -1;
1793 for (uint32_t j = 0; j < num_hints; ++j) {
1794 uint32_t br_off = inner.
consume_u32v(
"branch instruction offset");
1795 if (int64_t{br_off} <= last_br_off) {
1796 inner.
errorf(
"Invalid branch offset: %d", br_off);
1799 last_br_off = br_off;
1801 if (data_size != 1) {
1802 inner.
errorf(
"Invalid data size: %#x. Expected 1.", data_size);
1805 uint32_t br_dir = inner.
consume_u8(
"branch direction");
1806 TRACE(
"DecodeBranchHints[%d][%d] module+%d\n", func_idx, br_off,
1807 static_cast<int>(inner.
pc() - inner.
start()));
1818 inner.
errorf(inner.
pc(),
"Invalid branch hint %#x", br_dir);
1824 func_branch_hints.
insert(br_off, hint);
1829 branch_hints.emplace(func_idx, std::move(func_branch_hints));
1833 inner.
errorf(
"Unexpected extra bytes: %d\n",
1834 static_cast<int>(inner.
pc() - inner.
start()));
1838 module_->branch_hints = std::move(branch_hints);
1846 module_->num_declared_data_segments =
1853 for (uint32_t
i = 0;
ok() &&
i < tag_count; ++
i) {
1854 TRACE(
"DecodeTag[%d] module+%d\n",
i,
static_cast<int>(
pc_ -
start_));
1860 module_->tags.emplace_back(tag_sig, sig_index);
1865 uint32_t deferred =
consume_count(
"deferred string literal count",
1868 errorf(
pc(),
"Invalid deferred string literal count %u (expected 0)",
1873 for (uint32_t
i = 0;
ok() &&
i < immediate; ++
i) {
1874 TRACE(
"DecodeStringLiteral[%d] module+%d\n",
i,
1880 module_->stringref_literals.emplace_back(
pos);
1888 if (
module_->num_declared_functions != 0) {
1892 if (!
module_->functions[
module_->num_imported_functions].code.is_set()) {
1893 errorf(
pc(),
"function count is %u, but code section is absent",
1894 module_->num_declared_functions);
1901 static_cast<uint32_t
>(
module_->data_segments.size()))) {
1927 if (wire_bytes.
size() > max_size) {
1929 max_size, wire_bytes.
size()}};
1935 static constexpr uint32_t kWasmHeaderSize = 8;
1942 uint32_t
offset =
static_cast<uint32_t
>(section_iter.
payload().begin() -
1943 wire_bytes.
begin());
1948 if (!section_iter.
more())
break;
1955 if (section_iterator_decoder.
failed()) {
1956 return section_iterator_decoder.
toResult(
nullptr);
1960 if (!
result.failed() && validate_functions) {
1961 std::function<
bool(
int)> kNoFilter;
1983 function.code = {
off(
pc_),
static_cast<uint32_t
>(
end_ -
pc_)};
1987 constexpr bool kShared =
false;
1992 &unused_detected_features, body);
2001 const uint8_t*
start) {
2009 constexpr bool kIsShared =
false;
2036 uint32_t
off(
const uint8_t* ptr) {
2053 uint32_t untagged_offset = 0;
2054 uint32_t tagged_offset = 0;
2055 uint32_t num_imported_mutable_globals = 0;
2058 global.
index = num_imported_mutable_globals++;
2060 global.
offset = tagged_offset;
2065 untagged_offset = (untagged_offset + size - 1) & ~(size - 1);
2066 global.
offset = untagged_offset;
2067 untagged_offset +=
size;
2070 module->untagged_globals_buffer_size = untagged_offset;
2071 module->tagged_globals_buffer_size = tagged_offset;
2076 const uint8_t*
pos =
pc_;
2080 errorf(
pos,
"no signature at index %u (%d types)", sig_index.index,
2081 static_cast<int>(module->
types.size()));
2085 *
sig =
module->signature(sig_index);
2095 const uint8_t*
pos =
pc_;
2099 (*sig)->return_count() != 0) {
2100 errorf(
pos,
"tag signature %u has non-void return", sig_index);
2108 const uint8_t* p =
pc_;
2118 if (
count > maximum) {
2119 errorf(p,
"%s of %u exceeds internal limit of %zu", name,
count, maximum);
2141 template <
typename T>
2143 const uint8_t*
pos =
pc_;
2149 if (index >= vector->size()) {
2150 errorf(
pos,
"%s index %u out of bounds (%d entr%s)", name, index,
2151 static_cast<int>(vector->size()),
2152 vector->size() == 1 ?
"y" :
"ies");
2156 *ptr = &(*vector)[
index];
2176 template <LimitsByteType limits_type>
2180 limits_type ==
kMemory ?
"memory limits flags" :
"table limits flags")};
2181 if (!limits.is_valid()) {
2182 errorf(
pc() - 1,
"invalid %s limits flags 0x%x",
2183 limits_type ==
kMemory ?
"memory" :
"table", limits.flags);
2186 if (limits.is_shared()) {
2187 if constexpr (limits_type ==
kMemory) {
2189 if (!limits.has_maximum()) {
2190 error(
pc() - 1,
"shared memory must have a maximum defined");
2192 if (
v8_flags.experimental_wasm_shared) {
2194 "shared memories are not supported with "
2195 "--experimental-wasm-shared yet.");
2197 }
else if (!
v8_flags.experimental_wasm_shared) {
2199 "invalid table limits flags, enable with "
2200 "--experimental-wasm-shared");
2206 if (limits.is_64bit()) {
2219 table->has_maximum_size = limits.has_maximum();
2220 table->shared = limits.is_shared();
2221 table->address_type = limits.address_type();
2228 memory->has_maximum_pages = limits.has_maximum();
2229 memory->is_shared = limits.is_shared();
2230 memory->address_type = limits.address_type();
2238 if (flags & ~0b11) {
2239 errorf(
pc() - 1,
"invalid global flags 0x%x", flags);
2240 return {
false,
false};
2242 bool mutability = flags & 0b1;
2243 bool shared = flags & 0b10;
2249 if (shared && !
v8_flags.experimental_wasm_shared) {
2252 "invalid global flags 0x%x (enable via --experimental-wasm-shared)",
2254 return {
false,
false};
2256 return {mutability, shared};
2261 const char* name,
const char*
units,
2263 uint32_t max_initial, uint32_t* initial,
bool has_maximum,
2265 const uint8_t*
pos =
pc();
2271 if (initial_64 > max_initial) {
2273 "initial %s size (%" PRIu64
2274 " %s) is larger than implementation limit (%u %s)",
2275 name, initial_64,
units, max_initial,
units);
2277 *initial =
static_cast<uint32_t
>(initial_64);
2287 if (maximum_64 > max_maximum) {
2289 "maximum %s size (%" PRIu64
2290 " %s) is larger than implementation limit (%" PRIu64
" %s)",
2291 name, maximum_64,
units, max_maximum,
units);
2293 if (maximum_64 < *initial) {
2295 "maximum %s size (%" PRIu64
" %s) is less than initial (%u %s)",
2298 *maximum = maximum_64;
2304 *maximum = max_initial;
2310 const uint8_t*
pos =
pc();
2312 if (value != expected) {
2313 errorf(
pos,
"expected %s 0x%02x, got 0x%02x", name, expected, value);
2322#define TYPE_CHECK(found) \
2323 if (V8_UNLIKELY(!IsSubtypeOf(found, expected, module))) { \
2325 "type error in constant expression[0] (expected %s, got %s)", \
2326 expected.name().c_str(), found.name().c_str()); \
2338 error(
"Beyond end of code");
2342 case kExprI32Const: {
2356 case kExprRefFunc: {
2362 errorf(
pc() + 1,
"function index %u out of bounds", index);
2366 bool functype_is_shared =
module->type(functype).is_shared;
2371 error(
pc(),
"ref.func does not have a shared type");
2374 module->functions[index].declared = true;
2383 case kExprRefNull: {
2395 error(
pc(),
"ref.null does not have a shared type");
2426 decoder.DecodeFunctionBody();
2434 static constexpr size_t kInvalidBytesGuess = 4;
2435 const uint8_t*
end =
2436 decoder.ok() ? decoder.end()
2437 : std::min(decoder.end() + kInvalidBytesGuess,
end_);
2440 this->
pc_ = decoder.end();
2442 if (decoder.failed()) {
2443 error(decoder.error().offset(), decoder.error().message().c_str());
2447 if (!decoder.interface().end_found()) {
2448 error(
"constant expression is missing 'end'");
2453 offset,
static_cast<uint32_t
>(decoder.end() - decoder.start()));
2469 : val == 1 ?
" mutable"
2472 if (val > 1)
error(
pc_ - 1,
"invalid mutability");
2496 auto [heap_type,
length] =
2530 uint32_t param_count =
2536 for (uint32_t
i = 0;
i < param_count; ++
i) {
2543 uint32_t return_count =
2550 std::copy_n(params.begin(), param_count, sig_storage + return_count);
2551 for (uint32_t
i = 0;
i < return_count; ++
i) {
2557 return zone->
New<
FunctionSig>(return_count, param_count, sig_storage);
2561 uint32_t field_count =
2563 if (
failed())
return nullptr;
2565 bool* mutabilities = zone->
AllocateArray<
bool>(field_count);
2566 for (uint32_t
i = 0;
ok() &&
i < field_count; ++
i) {
2571 if (
failed())
return nullptr;
2572 uint32_t* offsets = zone->
AllocateArray<uint32_t>(field_count);
2574 mutabilities, is_descriptor);
2583 if (
failed())
return nullptr;
2589 const uint8_t*
pos =
pc_;
2590 uint32_t attribute =
consume_u32v(
"exception attribute");
2593 errorf(
pos,
"exception attribute %u not supported", attribute);
2600 const uint8_t*
pos =
pc();
2604 constexpr uint8_t kNonActiveMask = 1 << 0;
2608 constexpr uint8_t kHasTableIndexOrIsDeclarativeMask = 1 << 1;
2611 constexpr uint8_t kExpressionsAsElementsMask = 1 << 2;
2613 constexpr uint8_t kSharedFlag = 1 << 3;
2614 constexpr uint8_t kFullMask = kNonActiveMask |
2615 kHasTableIndexOrIsDeclarativeMask |
2616 kExpressionsAsElementsMask | kSharedFlag;
2619 if ((flag & kFullMask) != flag) {
2620 errorf(
pos,
"illegal flag value %u", flag);
2627 "illegal flag value %u, enable with --experimental-wasm-shared",
2634 (flag & kNonActiveMask) ? (flag & kHasTableIndexOrIsDeclarativeMask)
2648 flag & kExpressionsAsElementsMask
2652 const bool has_table_index =
2653 is_active && (flag & kHasTableIndexOrIsDeclarativeMask);
2654 uint32_t table_index = 0;
2655 if (has_table_index) {
2662 errorf(
pos,
"out of bounds%s table index %u",
2663 has_table_index ?
"" :
" implicit", table_index);
2685 const bool backwards_compatible_mode =
2686 is_active && !(flag & kHasTableIndexOrIsDeclarativeMask);
2689 if (backwards_compatible_mode) {
2697 if (!backwards_compatible_mode) {
2704 errorf(
pos,
"illegal element kind 0x%x. Must be 0x%x", val,
2715 "Element segment of type %s is not a subtype of referenced "
2716 "table %u (of type %s)",
2717 type.name().c_str(), table_index, table_type.
name().c_str());
2725 "Shared (resp. non-shared) element segments must refer to shared "
2726 "(resp. non-shared) tables");
2742 const uint8_t*
pos =
pc();
2745 if (flag & ~0b1011) {
2746 errorf(
pos,
"illegal flag value %u", flag);
2750 uint32_t status_flag = flag & 0b11;
2764 errorf(
pos,
"illegal flag value %u", flag);
2772 "illegal flag value %u. Enable with --experimental-wasm-shared",
2792 size_t num_memories =
module_->memories.size();
2793 if (mem_index >= num_memories) {
2795 "invalid memory index %u for data section (having %zu memor%s)",
2796 mem_index, num_memories, num_memories == 1 ?
"y" :
"ies");
2809 const uint8_t* initial_pc =
pc();
2819 !
v8_flags.experimental_wasm_shared)) {
2824 "Invalid type in element entry: expected %s, got %s instead.",
2825 expected.
name().c_str(), entry_type.
name().c_str());
static bool ValidateEncoding(const uint8_t *str, size_t length)
static FILE * FOpen(const char *path, const char *mode)
static char DirectorySeparator()
static bool isDirectorySeparator(const char ch)
constexpr size_t size() const
constexpr T * begin() const
static Vector< T > cast(Vector< S > input)
auto Returns(ReturnTypes... return_types) const
T * AllocateArray(size_t length)
ValueType * element_type_writable_ptr()
void insert(uint32_t offset, BranchHint hint)
static constexpr ConstantExpression WireBytes(uint32_t offset, uint32_t length)
constexpr uint32_t index() const
static constexpr ConstantExpression I32Const(int32_t value)
static constexpr ConstantExpression RefFunc(uint32_t index)
static constexpr ConstantExpression RefNull(HeapType type)
const uint8_t * start() const
Result< R > toResult(T &&val)
uint32_t consume_u32(const char *name, ITracer *tracer)
uint32_t available_bytes() const
void V8_NOINLINE V8_PRESERVE_MOST errorf(const char *format, Args... args)
const WasmError & error() const
const uint8_t * pc() const
void Reset(const uint8_t *start, const uint8_t *end, uint32_t buffer_offset=0)
void set_end(const uint8_t *end)
bool checkAvailable(uint32_t size)
bool lookahead(int offset, uint8_t expected)
uint32_t GetBufferRelativeOffset(uint32_t offset) const
uint8_t read_u8(const uint8_t *pc, Name< ValidationTag > msg="expected 1 byte")
uint64_t consume_u64v(const char *name, ITracer *tracer)
std::pair< uint32_t, uint32_t > read_u32v(const uint8_t *pc, Name< ValidationTag > name="LEB32")
void consume_bytes(uint32_t size, const char *name="skip")
uint32_t pc_offset() const
uint32_t consume_u32v(const char *name="var_uint32")
std::pair< int32_t, uint32_t > read_i32v(const uint8_t *pc, Name< ValidationTag > name="signed LEB32")
uint32_t V8_INLINE pc_offset(const uint8_t *pc) const
uint8_t consume_u8(const char *name="uint8_t")
const uint8_t * end() const
void V8_NOINLINE V8_PRESERVE_MOST error(const char *msg)
constexpr bool is_index() const
constexpr ModuleTypeIndex ref_index() const
virtual void StringOffset(uint32_t offset)=0
virtual void InitializerExpression(const uint8_t *start, const uint8_t *end, ValueType expected_type)=0
virtual void NextLineIfNonEmpty()=0
static constexpr ITracer * NoTrace
virtual void RecGroupOffset(uint32_t offset, uint32_t group_size)=0
virtual void GlobalOffset(uint32_t offset)=0
virtual void TypeOffset(uint32_t offset)=0
virtual void ImportOffset(uint32_t offset)=0
virtual void Bytes(const uint8_t *start, uint32_t count)=0
virtual void FunctionBody(const WasmFunction *func, const uint8_t *start)=0
virtual void ImportsDone(const WasmModule *module)=0
virtual void ElementOffset(uint32_t offset)=0
virtual void Description(const char *desc)=0
virtual void TableOffset(uint32_t offset)=0
virtual void MemoryOffset(uint32_t offset)=0
virtual void FunctionName(uint32_t func_index)=0
virtual void DataOffset(uint32_t offset)=0
virtual void TagOffset(uint32_t offset)=0
virtual void StartOffset(uint32_t offset)=0
virtual void NextLine()=0
virtual void NameSection(const uint8_t *start, const uint8_t *end, uint32_t offset)=0
virtual void NextLineIfFull()=0
constexpr IndependentHeapType AsNonNull() const
uint32_t seen_unordered_sections_
const StructType * consume_struct(Zone *zone, bool is_descriptor)
void DecodeDataCountSection()
const uint8_t * module_end_
void DecodeStartSection()
bool CheckFunctionsCount(uint32_t functions_count, uint32_t error_offset)
uint32_t consume_func_index(WasmModule *module, WasmFunction **func)
void onFirstError() override
const WasmEnabledFeatures enabled_features_
bool has_seen_unordered_section(SectionCode section_code)
void DecodeFunctionSection()
void DecodeInstTraceSection()
void consume_memory_flags(WasmMemory *memory)
TypeDefinition consume_subtype_definition(size_t current_type_index)
uint32_t consume_index(const char *name, std::vector< T > *vector, T **ptr)
void DecodeStringRefSection()
const FunctionSig * consume_sig(Zone *zone)
const uint8_t * module_start_
bool CheckSectionOrder(SectionCode section_code)
TypeDefinition consume_describing_type(size_t current_type_index)
bool CheckMismatchedCounts()
bool CheckDataSegmentsCount(uint32_t data_segments_count)
void DecodeBuildIdSection()
uint32_t consume_global_index(WasmModule *module, WasmGlobal **global)
uint32_t consume_tag_index(WasmModule *module, WasmTag **tag)
uint32_t off(const uint8_t *ptr)
void StartCodeSection(WireBytesRef section_bytes)
void consume_resizable_limits(const char *name, const char *units, uint32_t max_initial, uint32_t *initial, bool has_maximum, uint64_t max_maximum, uint64_t *maximum, ResizableLimitsType type)
void DecodeCompilationHintsSection()
DataSegmentHeader consume_data_segment_header()
TypeDefinition consume_described_type(bool is_descriptor)
const FunctionSig * DecodeFunctionSignatureForTesting(Zone *zone, const uint8_t *start)
bool expect_u8(const char *name, uint8_t expected)
ConstantExpression DecodeInitExprForTesting(ValueType expected)
uint32_t consume_table_index(WasmModule *module, WasmTable **table)
ValueType consume_value_type(const WasmModule *module=nullptr)
uint32_t consume_exception_attribute()
void DecodeSourceMappingURLSection()
void consume_table_flags(WasmTable *table)
WasmElemSegment consume_element_segment_header()
bool consume_mutability()
void DecodeElementSection()
const ArrayType * consume_array(Zone *zone)
const std::shared_ptr< WasmModule > module_
void FinalizeRecgroup(uint32_t group_size, TypeCanonicalizer *type_canon)
AccountingAllocator allocator_
void DecodeModuleHeader(base::Vector< const uint8_t > bytes)
void DecodeImportSection()
void CalculateGlobalOffsets(WasmModule *module)
static constexpr const char * TypeKindName(uint8_t kind)
void DecodeMemorySection()
ModuleResult DecodeModule(bool validate_functions)
const std::shared_ptr< WasmModule > & shared_module() const
ModuleTypeIndex consume_tag_sig_index(WasmModule *module, const FunctionSig **sig)
uint32_t consume_element_func_index(WasmModule *module, ValueType expected)
LimitsByte consume_limits_byte()
ConstantExpression consume_element_segment_entry(WasmModule *module, const WasmElemSegment &segment)
ConstantExpression consume_init_expr(WasmModule *module, ValueType expected, bool is_shared)
FunctionResult DecodeSingleFunctionForTesting(Zone *zone, ModuleWireBytes wire_bytes, const WasmModule *module)
ValueType consume_storage_type()
void DecodeBranchHintsSection()
TypeDefinition consume_shared_type(size_t current_type_index)
void DecodeTableSection()
uint8_t next_ordered_section_
HeapType consume_heap_type()
void DecodeSection(SectionCode section_code, base::Vector< const uint8_t > bytes, uint32_t offset)
void UpdateComputedMemoryInformation()
void set_seen_unordered_section(SectionCode section_code)
void DecodeExportSection()
void DecodeFunctionBody(uint32_t func_index, uint32_t length, uint32_t offset)
ModuleTypeIndex consume_sig_index(WasmModule *module, const FunctionSig **sig)
TypeDefinition consume_base_type_definition(bool is_descriptor)
WasmDetectedFeatures *const detected_features_
uint32_t consume_count(const char *name, size_t maximum)
void DecodeExternalDebugInfoSection()
ModuleDecoderImpl(WasmEnabledFeatures enabled_features, base::Vector< const uint8_t > wire_bytes, ModuleOrigin origin, WasmDetectedFeatures *detected_features, ITracer *tracer=ITracer::NoTrace)
ModuleResult FinishDecoding()
void DecodeGlobalSection()
std::vector< std::tuple< uint32_t, uint32_t, uint32_t > > inst_traces_
std::pair< bool, bool > consume_global_flags()
V8_EXPORT_PRIVATE void AddRecursiveGroup(WasmModule *module, uint32_t size)
constexpr int value_kind_size() const
constexpr bool is_reference() const
constexpr bool is_object_reference() const
constexpr bool is_defaultable() const
V8_EXPORT_PRIVATE std::string name() const
static constexpr ValueType RefNull(ModuleTypeIndex index, bool shared, RefTypeKind kind)
static constexpr ValueType Ref(ModuleTypeIndex index, bool shared, RefTypeKind kind)
static constexpr WasmEnabledFeatures None()
SectionCode section_code_
void advance(bool move_to_section_end=false)
uint32_t payload_length() const
const uint8_t * payload_start_
uint32_t section_length() const
const uint8_t * section_end() const
const uint8_t * section_end_
const uint8_t * section_start() const
SectionCode section_code() const
WasmSectionIterator(Decoder *decoder, ITracer *tracer)
const uint8_t * section_start_
base::Vector< const uint8_t > payload() const
const uint8_t * payload_start() const
std::optional< TNode< JSArray > > a
SharedFunctionInfoRef shared
ZoneVector< RpoNumber > & result
std::priority_queue< BigUnit > units[CompilationTier::kNumTiers]
#define TYPE_CHECK(found)
constexpr Vector< const char > StaticCharVector(const char(&array)[N])
constexpr Vector< T > VectorOf(T *start, size_t size)
bool ValidateHeapType(Decoder *decoder, const uint8_t *pc, const WasmModule *module, HeapType type)
static void Populate(HeapType *unfinished_type, const WasmModule *module)
bool ValidateValueType(Decoder *decoder, const uint8_t *pc, const WasmModule *module, ValueType type)
std::pair< ValueType, uint32_t > read_value_type(Decoder *decoder, const uint8_t *pc, WasmEnabledFeatures enabled)
std::pair< HeapType, uint32_t > read_heap_type(Decoder *decoder, const uint8_t *pc, WasmEnabledFeatures enabled)
WireBytesRef consume_utf8_string(Decoder *decoder, const char *name, ITracer *tracer)
const char * ExternalKindName(ImportExportKindCode kind)
constexpr char kNameString[]
constexpr char kInstTraceString[]
const char * SectionName(SectionCode code)
constexpr uint32_t kWasmMagic
constexpr uint8_t kWasmRecursiveTypeGroupCode
V8_EXPORT_PRIVATE bool IsShared(ValueType type, const WasmModule *module)
uint32_t max_table_size()
@ kLastKnownModuleSection
@ kSourceMappingURLSectionCode
@ kExternalDebugInfoSectionCode
@ kBranchHintsSectionCode
@ kCompilationHintsSectionCode
constexpr uint8_t kSharedFlagCode
constexpr uint8_t kWasmDescribesCode
constexpr size_t kSpecMaxMemory32Pages
SectionCode IdentifyUnknownSectionInternal(Decoder *decoder, ITracer *tracer)
constexpr size_t kV8MaxWasmImports
constexpr IndependentValueType kWasmI8
constexpr size_t kV8MaxWasmFunctionSize
constexpr uint8_t kWasmSubtypeCode
constexpr uint8_t kWasmContTypeCode
TypeCanonicalizer * GetTypeCanonicalizer()
bool is_asmjs_module(const WasmModule *module)
size_t GetWireBytesHash(base::Vector< const uint8_t > wire_bytes)
bool IsValidSectionCode(uint8_t byte)
constexpr IndependentValueType kWasmI32
constexpr char kSourceMappingURLString[]
constexpr IndependentHeapType kWasmFuncRef
constexpr size_t kV8MaxWasmTypes
constexpr ModuleTypeIndex kNoSuperType
constexpr char kBuildIdString[]
uint32_t max_table_init_entries()
constexpr size_t kV8MaxWasmExports
bool validate_utf8(Decoder *decoder, WireBytesRef string)
constexpr uint8_t kWasmStructTypeCode
constexpr uint8_t kWasmSubtypeFinalCode
constexpr size_t kV8MaxWasmTables
constexpr uint32_t kV8MaxRttSubtypingDepth
void DumpModule(const base::Vector< const uint8_t > module_bytes, bool ok)
WasmError ValidateFunctions(const WasmModule *module, WasmEnabledFeatures enabled_features, base::Vector< const uint8_t > wire_bytes, std::function< bool(int)> filter, WasmDetectedFeatures *detected_features_out)
DecodeResult ValidateFunctionBody(Zone *zone, WasmEnabledFeatures enabled, const WasmModule *module, WasmDetectedFeatures *detected, const FunctionBody &body)
constexpr size_t kV8MaxWasmMemories
constexpr size_t kV8MaxWasmFunctionReturns
constexpr char kCompilationHintsString[]
bool ValidSubtypeDefinition(ModuleTypeIndex subtype_index, ModuleTypeIndex supertype_index, const WasmModule *sub_module, const WasmModule *super_module)
constexpr uint8_t kWasmFunctionTypeCode
constexpr char kExternalDebugInfoString[]
constexpr size_t kV8MaxWasmDataSegments
void UpdateComputedInformation(WasmMemory *memory, ModuleOrigin origin)
V8_INLINE bool IsSubtypeOf(ValueType subtype, ValueType supertype, const WasmModule *sub_module, const WasmModule *super_module)
constexpr IndependentHeapType kWasmBottom
constexpr uint32_t kWasmVersion
WasmCompilationHintStrategy
constexpr uint8_t kWasmArrayTypeCode
constexpr size_t kSpecMaxMemory64Pages
constexpr size_t kV8MaxWasmGlobals
WireBytesRef consume_string(Decoder *decoder, unibrow::Utf8Variant grammar, const char *name, ITracer *tracer)
std::unordered_map< uint32_t, BranchHintMap > BranchHintInfo
constexpr size_t kV8MaxWasmStringLiterals
constexpr IndependentValueType kWasmI64
constexpr IndependentValueType kWasmI16
constexpr uint32_t kExceptionAttribute
constexpr char kBranchHintsString[]
constexpr size_t kV8MaxWasmFunctionParams
constexpr size_t kV8MaxWasmStructFields
constexpr size_t kV8MaxWasmTags
constexpr char kDebugInfoString[]
constexpr uint8_t kWasmDescriptorCode
constexpr int kBitsPerByte
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
constexpr uint64_t kMaxUInt64
V8_EXPORT_PRIVATE FlagValues v8_flags
JSArrayBuffer::IsDetachableBit is_shared
constexpr uint32_t kMaxUInt32
#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)
AddressType address_type() const
const FunctionSig * function_sig
const ContType * cont_type
ModuleTypeIndex supertype
ModuleTypeIndex describes
const StructType * struct_type
ModuleTypeIndex descriptor
const ArrayType * array_type
constexpr bool valid() const
WasmCompilationHintTier top_tier
WasmCompilationHintStrategy strategy
WasmCompilationHintTier baseline_tier
ModuleTypeIndex sig_index
std::vector< TypeDefinition > types
uint32_t tagged_globals_buffer_size
bool has_signature(ModuleTypeIndex index) const
std::vector< WasmFunction > functions
uint32_t untagged_globals_buffer_size
std::vector< WasmTag > tags
std::vector< WasmGlobal > globals
const TypeDefinition & type(ModuleTypeIndex index) const
std::vector< WasmTable > tables
#define V8_LIKELY(condition)
#define V8_UNLIKELY(condition)