5#ifndef V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_
6#define V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_
8#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
41 if (v8_flags.trace_wasm_decoder) PrintF(__VA_ARGS__); \
44#define TRACE_INST_FORMAT " @%-8d #%-30s|"
51#define VALIDATE(condition) \
52 (ValidationTag::validate ? V8_LIKELY(condition) \
53 : ValidateAssumeTrue(condition, #condition))
60#define VALIDATE(condition) (!ValidationTag::validate || V8_LIKELY(condition))
63#define CHECK_PROTOTYPE_OPCODE(feat) \
64 DCHECK(this->module_->origin == kWasmOrigin); \
65 if (!VALIDATE(this->enabled_.has_##feat())) { \
67 "Invalid opcode 0x%02x (enable with --experimental-wasm-" #feat ")", \
71 this->detected_->add_##feat()
76 static_assert(
sizeof(
LoadType) ==
sizeof(uint8_t),
"LoadType is compact");
77 constexpr uint8_t kMinOpcode = kExprI32LoadMem;
78 constexpr uint8_t kMaxOpcode = kExprI64LoadMem32U;
80 LoadType::kI32Load, LoadType::kI64Load, LoadType::kF32Load,
81 LoadType::kF64Load, LoadType::kI32Load8S, LoadType::kI32Load8U,
82 LoadType::kI32Load16S, LoadType::kI32Load16U, LoadType::kI64Load8S,
83 LoadType::kI64Load8U, LoadType::kI64Load16S, LoadType::kI64Load16U,
84 LoadType::kI64Load32S, LoadType::kI64Load32U};
85 static_assert(
arraysize(kLoadTypes) == kMaxOpcode - kMinOpcode + 1);
88 return kLoadTypes[opcode - kMinOpcode];
94 static_assert(
sizeof(
StoreType) ==
sizeof(uint8_t),
"StoreType is compact");
95 constexpr uint8_t kMinOpcode = kExprI32StoreMem;
96 constexpr uint8_t kMaxOpcode = kExprI64StoreMem32;
98 StoreType::kI32Store, StoreType::kI64Store, StoreType::kF32Store,
99 StoreType::kF64Store, StoreType::kI32Store8, StoreType::kI32Store16,
100 StoreType::kI64Store8, StoreType::kI64Store16, StoreType::kI64Store32};
101 static_assert(
arraysize(kStoreTypes) == kMaxOpcode - kMinOpcode + 1);
104 return kStoreTypes[opcode - kMinOpcode];
107#define ATOMIC_OP_LIST(V) \
108 V(AtomicNotify, Uint32) \
109 V(I32AtomicWait, Uint32) \
110 V(I64AtomicWait, Uint64) \
111 V(I32AtomicLoad, Uint32) \
112 V(I64AtomicLoad, Uint64) \
113 V(I32AtomicLoad8U, Uint8) \
114 V(I32AtomicLoad16U, Uint16) \
115 V(I64AtomicLoad8U, Uint8) \
116 V(I64AtomicLoad16U, Uint16) \
117 V(I64AtomicLoad32U, Uint32) \
118 V(I32AtomicAdd, Uint32) \
119 V(I32AtomicAdd8U, Uint8) \
120 V(I32AtomicAdd16U, Uint16) \
121 V(I64AtomicAdd, Uint64) \
122 V(I64AtomicAdd8U, Uint8) \
123 V(I64AtomicAdd16U, Uint16) \
124 V(I64AtomicAdd32U, Uint32) \
125 V(I32AtomicSub, Uint32) \
126 V(I64AtomicSub, Uint64) \
127 V(I32AtomicSub8U, Uint8) \
128 V(I32AtomicSub16U, Uint16) \
129 V(I64AtomicSub8U, Uint8) \
130 V(I64AtomicSub16U, Uint16) \
131 V(I64AtomicSub32U, Uint32) \
132 V(I32AtomicAnd, Uint32) \
133 V(I64AtomicAnd, Uint64) \
134 V(I32AtomicAnd8U, Uint8) \
135 V(I32AtomicAnd16U, Uint16) \
136 V(I64AtomicAnd8U, Uint8) \
137 V(I64AtomicAnd16U, Uint16) \
138 V(I64AtomicAnd32U, Uint32) \
139 V(I32AtomicOr, Uint32) \
140 V(I64AtomicOr, Uint64) \
141 V(I32AtomicOr8U, Uint8) \
142 V(I32AtomicOr16U, Uint16) \
143 V(I64AtomicOr8U, Uint8) \
144 V(I64AtomicOr16U, Uint16) \
145 V(I64AtomicOr32U, Uint32) \
146 V(I32AtomicXor, Uint32) \
147 V(I64AtomicXor, Uint64) \
148 V(I32AtomicXor8U, Uint8) \
149 V(I32AtomicXor16U, Uint16) \
150 V(I64AtomicXor8U, Uint8) \
151 V(I64AtomicXor16U, Uint16) \
152 V(I64AtomicXor32U, Uint32) \
153 V(I32AtomicExchange, Uint32) \
154 V(I64AtomicExchange, Uint64) \
155 V(I32AtomicExchange8U, Uint8) \
156 V(I32AtomicExchange16U, Uint16) \
157 V(I64AtomicExchange8U, Uint8) \
158 V(I64AtomicExchange16U, Uint16) \
159 V(I64AtomicExchange32U, Uint32) \
160 V(I32AtomicCompareExchange, Uint32) \
161 V(I64AtomicCompareExchange, Uint64) \
162 V(I32AtomicCompareExchange8U, Uint8) \
163 V(I32AtomicCompareExchange16U, Uint16) \
164 V(I64AtomicCompareExchange8U, Uint8) \
165 V(I64AtomicCompareExchange16U, Uint16) \
166 V(I64AtomicCompareExchange32U, Uint32)
168#define ATOMIC_STORE_OP_LIST(V) \
169 V(I32AtomicStore, Uint32) \
170 V(I64AtomicStore, Uint64) \
171 V(I32AtomicStore8U, Uint8) \
172 V(I32AtomicStore16U, Uint16) \
173 V(I64AtomicStore8U, Uint8) \
174 V(I64AtomicStore16U, Uint16) \
175 V(I64AtomicStore32U, Uint32)
180template <
typename ValidationTag,
typename... Args>
187 if constexpr (
sizeof...(Args) == 0) {
197template <
typename ValidationTag,
typename... Args>
203 if constexpr (
sizeof...(Args) == 0) {
206 decoder->
errorf(str, std::forward<Args>(
args)...);
210namespace value_type_reader {
212template <
typename Val
idationTag>
216 auto [heap_index,
length] =
217 decoder->
read_i33v<ValidationTag>(
pc,
"heap type");
220 if (heap_index < 0) {
221 int64_t min_1_byte_leb128 = -64;
222 if (!
VALIDATE(heap_index >= min_1_byte_leb128)) {
227 uint8_t uint_7_mask = 0x7F;
228 uint8_t code =
static_cast<ValueTypeCode>(heap_index) & uint_7_mask;
231 if (!
VALIDATE(enabled.has_shared())) {
234 "invalid heap type 0x%hhx, enable with --experimental-wasm-shared",
256 if (!
VALIDATE(enabled.has_exnref())) {
259 "invalid heap type '%s', enable with --experimental-wasm-exnref",
268 if (!
VALIDATE(enabled.has_stringref())) {
271 "invalid heap type '%s', enable with "
272 "--experimental-wasm-stringref",
279 if (!
VALIDATE(enabled.has_wasmfx())) {
282 "invalid heap type '%s', enable with "
283 "--experimental-wasm-wasmfx",
289 if (!
VALIDATE(enabled.has_custom_descriptors())) {
291 "invalid heap type 'exact', enable with "
292 "--experimental-wasm-custom-descriptors");
295 auto [nested_index, index_length] =
296 decoder->
read_u32v<ValidationTag>(
pc + 1,
"type index");
297 type_index = nested_index;
299 length += index_length;
308 type_index =
static_cast<uint32_t
>(heap_index);
313 "Type index %u is greater than the maximum number %zu "
314 "of type definitions supported by V8",
319 bool kDefaultShared =
false;
322 kDefaultKind, exactness),
329template <
typename Val
idationTag>
333 uint8_t val = decoder->
read_u8<ValidationTag>(
pc,
"value type opcode");
352 if (!
VALIDATE(enabled.has_exnref())) {
355 "invalid value type '%s', enable with --experimental-wasm-exnref",
364 if (!
VALIDATE(enabled.has_stringref())) {
367 "invalid value type '%sref', enable with "
368 "--experimental-wasm-stringref",
380 if (!
VALIDATE(enabled.has_wasmfx())) {
383 "invalid value type '%s', enable with --experimental-wasm-wasmfx",
399 auto [heap_type,
length] =
401 if (!
VALIDATE(!heap_type.is_string_view() ||
404 "nullable string views don't exist");
410 return {
type, length + 1};
414 if (
v8_flags.correctness_fuzzer_suppressions) {
415 FATAL(
"Aborting on missing Wasm SIMD support");
434 if constexpr (!ValidationTag::validate)
UNREACHABLE();
439template <
typename Val
idationTag>
442 if (!
VALIDATE(!type.is_bottom()))
return false;
443 if (!type.is_index())
return true;
446 if (!ValidationTag::validate && module ==
nullptr)
return true;
447 if (!
VALIDATE(type.ref_index().index < module->
types.size())) {
449 type.ref_index().index);
455template <
typename Val
idationTag>
458 if (!
VALIDATE(!type.is_bottom()))
return false;
459 if (
V8_LIKELY(!type.is_object_reference()))
return true;
465 if (!unfinished_type->
has_index())
return;
467 const TypeDefinition& type_def =
module->type(unfinished_type->ref_index());
474 if (!unfinished_type->
has_index())
return;
476 const TypeDefinition& type_def =
module->type(unfinished_type->ref_index());
490 template <
typename Val
idationTag>
492 std::tie(value, length) = decoder->
read_i32v<ValidationTag>(
pc,
"immi32");
500 template <
typename Val
idationTag>
502 std::tie(value, length) = decoder->
read_i64v<ValidationTag>(
pc,
"immi64");
510 template <
typename Val
idationTag>
515 uint32_t tmp = decoder->
read_u32<ValidationTag>(
pc,
"immf32");
516 memcpy(&value, &tmp,
sizeof(value));
524 template <
typename Val
idationTag>
528 uint64_t tmp = decoder->
read_u64<ValidationTag>(
pc,
"immf64");
529 memcpy(&value, &tmp,
sizeof(value));
555 template <
typename Val
idationTag>
572 template <
typename Val
idationTag>
574 ValidationTag = {}) {
582 template <
typename Val
idationTag>
584 ValidationTag validate = {})
591 template <
typename Val
idationTag>
593 ValidationTag validate = {})
600 template <
typename Val
idationTag>
602 ValidationTag validate = {})
609 template <
typename Val
idationTag>
611 ValidationTag validate = {})
619 template <
typename Val
idationTag>
621 ValidationTag = {}) {
623 std::tie(raw_index, length) = decoder->
read_u32v<ValidationTag>(
pc,
name);
632 template <
typename Val
idationTag>
634 ValidationTag validate = {})
646 template <
typename Val
idationTag>
648 ValidationTag validate = {})
660 template <
typename Val
idationTag>
662 ValidationTag validate = {})
674 template <
typename Val
idationTag>
676 ValidationTag validate = {})
687 template <
typename Val
idationTag>
689 ValidationTag validate = {})
697 template <
typename Val
idationTag>
699 const uint8_t*
pc, ValidationTag = {}) {
701 std::tie(num_types, length) =
702 decoder->
read_u32v<ValidationTag>(
pc,
"number of select types");
706 "Invalid number of types. Select accepts exactly one type");
709 uint32_t type_length;
710 std::tie(type, type_length) =
713 length += type_length;
733 template <
typename Val
idationTag>
735 const uint8_t*
pc, ValidationTag = {}) {
737 std::tie(block_type, length) =
738 decoder->
read_i33v<ValidationTag>(
pc,
"block type");
739 if (block_type < 0) {
742 constexpr int64_t min_1_byte_leb128 = -64;
743 if (!
VALIDATE(block_type >= min_1_byte_leb128)) {
756 sig_index = ModuleTypeIndex{
static_cast<uint32_t
>(block_type)};
774 template <
typename Val
idationTag>
776 ValidationTag = {}) {
777 std::tie(
depth, length) =
778 decoder->
read_u32v<ValidationTag>(
pc,
"branch depth");
787 template <
typename Val
idationTag>
789 ValidationTag validate = {})
801 template <
typename Val
idationTag>
803 ValidationTag validate = {})
814 template <
typename Val
idationTag>
816 ValidationTag = {}) {
820 decoder->
read_u32v<ValidationTag>(
pc,
"table count");
828template <
typename Val
idationTag>
848 return static_cast<uint32_t
>(
pc_ -
start_);
850 const uint8_t*
pc()
const {
return pc_; }
878template <
typename Val
idationTag>
893 pc_ += maybe_tag.tag_imm.length;
896 pc_ += br_imm.length;
906 return static_cast<uint32_t
>(
pc_ -
start_);
908 const uint8_t*
pc()
const {
return pc_; }
936template <
typename Val
idationTag>
955 pc_ += maybe_depth.br.length;
967 return static_cast<uint32_t
>(
pc_ -
start_);
969 const uint8_t*
pc()
const {
return pc_; }
994 template <
typename Val
idationTag>
996 uint32_t max_alignment, ValidationTag = {}) {
998 const bool two_bytes = !ValidationTag::validate || decoder->
end() -
pc >= 2;
999 const bool use_fast_path = two_bytes && !(
pc[0] & 0xc0) && !(
pc[1] & 0x80);
1011 "invalid alignment; expected maximum alignment is %u, "
1012 "actual alignment is %u",
1018 template <
typename Val
idationTag>
1021 uint32_t max_alignment) {
1022 uint32_t alignment_length;
1024 decoder->
read_u32v<ValidationTag>(
pc,
"alignment");
1025 length = alignment_length;
1028 uint32_t mem_index_length;
1031 length += mem_index_length;
1035 uint32_t offset_length;
1036 std::tie(
offset, offset_length) =
1038 length += offset_length;
1045 uint32_t length = 1;
1047 template <
typename Val
idationTag>
1057 template <
typename Val
idationTag>
1060 value[
i] = decoder->
read_u8<ValidationTag>(
pc +
i,
"value");
1070 template <
typename Val
idationTag>
1072 ValidationTag validate = {})
1083 template <
typename Val
idationTag>
1085 ValidationTag validate = {})
1096 template <
typename Val
idationTag>
1098 ValidationTag validate = {})
1109 template <
typename Val
idationTag>
1111 ValidationTag validate = {})
1121 template <
typename Val
idationTag>
1123 const uint8_t*
pc, ValidationTag = {}) {
1124 std::tie(type, length) =
1133 template <
typename Val
idationTag>
1135 ValidationTag = {}) {
1136 std::tie(index, length) =
1137 decoder->
read_u32v<ValidationTag>(
pc,
"stringref literal index");
1141template <
bool val
idate>
1143 static_assert(validate ==
false);
1146 const uint8_t*
pc()
const {
return nullptr; }
1151 const uint8_t* pc_for_errors =
nullptr;
1155 const uint8_t*
pc()
const {
return pc_for_errors; }
1159template <
typename Val
idationTag>
1167template <
typename Value>
1208template <
typename Value,
typename Val
idationTag>
1275#define INTERFACE_FUNCTIONS(F) \
1276 INTERFACE_META_FUNCTIONS(F) \
1277 INTERFACE_CONSTANT_FUNCTIONS(F) \
1278 INTERFACE_NON_CONSTANT_FUNCTIONS(F)
1280#define INTERFACE_META_FUNCTIONS(F) \
1281 F(TraceInstruction, uint32_t value) \
1283 F(StartFunctionBody, Control* block) \
1286 F(NextInstruction, WasmOpcode)
1288#define INTERFACE_CONSTANT_FUNCTIONS(F) \
1289 F(I32Const, Value* result, int32_t value) \
1290 F(I64Const, Value* result, int64_t value) \
1291 F(F32Const, Value* result, float value) \
1292 F(F64Const, Value* result, double value) \
1293 F(S128Const, const Simd128Immediate& imm, Value* result) \
1294 F(GlobalGet, Value* result, const GlobalIndexImmediate& imm) \
1295 F(DoReturn, uint32_t drop_values) \
1296 F(UnOp, WasmOpcode opcode, const Value& value, Value* result) \
1297 F(BinOp, WasmOpcode opcode, const Value& lhs, const Value& rhs, \
1299 F(RefNull, ValueType type, Value* result) \
1300 F(RefFunc, uint32_t function_index, Value* result) \
1301 F(StructNew, const StructIndexImmediate& imm, const Value& descriptor, \
1302 const Value args[], Value* result) \
1303 F(StructNewDefault, const StructIndexImmediate& imm, \
1304 const Value& descriptor, Value* result) \
1305 F(ArrayNew, const ArrayIndexImmediate& imm, const Value& length, \
1306 const Value& initial_value, Value* result) \
1307 F(ArrayNewDefault, const ArrayIndexImmediate& imm, const Value& length, \
1309 F(ArrayNewFixed, const ArrayIndexImmediate& imm, \
1310 const IndexImmediate& length_imm, const Value elements[], Value* result) \
1311 F(ArrayNewSegment, const ArrayIndexImmediate& array_imm, \
1312 const IndexImmediate& data_segment, const Value& offset, \
1313 const Value& length, Value* result) \
1314 F(RefI31, const Value& input, Value* result) \
1315 F(StringConst, const StringConstImmediate& imm, Value* result)
1317#define INTERFACE_NON_CONSTANT_FUNCTIONS(F) \
1319 F(Block, Control* block) \
1320 F(Loop, Control* block) \
1321 F(Try, Control* block) \
1322 F(TryTable, Control* block) \
1323 F(CatchCase, Control* block, const CatchCase& catch_case, \
1324 base::Vector<Value> caught_values) \
1325 F(If, const Value& cond, Control* if_block) \
1326 F(FallThruTo, Control* c) \
1327 F(PopControl, Control* block) \
1329 F(RefAsNonNull, const Value& arg, Value* result) \
1331 F(LocalGet, Value* result, const IndexImmediate& imm) \
1332 F(LocalSet, const Value& value, const IndexImmediate& imm) \
1333 F(LocalTee, const Value& value, Value* result, const IndexImmediate& imm) \
1334 F(GlobalSet, const Value& value, const GlobalIndexImmediate& imm) \
1335 F(TableGet, const Value& index, Value* result, const IndexImmediate& imm) \
1336 F(TableSet, const Value& index, const Value& value, \
1337 const IndexImmediate& imm) \
1338 F(Trap, TrapReason reason) \
1339 F(NopForTestingUnsupportedInLiftoff) \
1340 F(Forward, const Value& from, Value* to) \
1341 F(Select, const Value& cond, const Value& fval, const Value& tval, \
1343 F(BrOrRet, uint32_t depth) \
1344 F(BrIf, const Value& cond, uint32_t depth) \
1345 F(BrTable, const BranchTableImmediate& imm, const Value& key) \
1346 F(Else, Control* if_block) \
1347 F(LoadMem, LoadType type, const MemoryAccessImmediate& imm, \
1348 const Value& index, Value* result) \
1349 F(LoadTransform, LoadType type, LoadTransformationKind transform, \
1350 const MemoryAccessImmediate& imm, const Value& index, Value* result) \
1351 F(LoadLane, LoadType type, const Value& value, const Value& index, \
1352 const MemoryAccessImmediate& imm, const uint8_t laneidx, Value* result) \
1353 F(StoreMem, StoreType type, const MemoryAccessImmediate& imm, \
1354 const Value& index, const Value& value) \
1355 F(StoreLane, StoreType type, const MemoryAccessImmediate& imm, \
1356 const Value& index, const Value& value, const uint8_t laneidx) \
1357 F(CurrentMemoryPages, const MemoryIndexImmediate& imm, Value* result) \
1358 F(MemoryGrow, const MemoryIndexImmediate& imm, const Value& value, \
1360 F(CallDirect, const CallFunctionImmediate& imm, const Value args[], \
1362 F(CallIndirect, const Value& index, const CallIndirectImmediate& imm, \
1363 const Value args[], Value returns[]) \
1364 F(CallRef, const Value& func_ref, const FunctionSig* sig, \
1365 const Value args[], const Value returns[]) \
1366 F(ReturnCallRef, const Value& func_ref, const FunctionSig* sig, \
1367 const Value args[]) \
1368 F(ReturnCall, const CallFunctionImmediate& imm, const Value args[]) \
1369 F(ReturnCallIndirect, const Value& index, const CallIndirectImmediate& imm, \
1370 const Value args[]) \
1371 F(BrOnNull, const Value& ref_object, uint32_t depth, \
1372 bool pass_null_along_branch, Value* result_on_fallthrough) \
1373 F(BrOnNonNull, const Value& ref_object, Value* result, uint32_t depth, \
1374 bool drop_null_on_fallthrough) \
1375 F(SimdOp, WasmOpcode opcode, const Value args[], Value* result) \
1376 F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate& imm, \
1377 base::Vector<const Value> inputs, Value* result) \
1378 F(Simd8x16ShuffleOp, const Simd128Immediate& imm, const Value& input0, \
1379 const Value& input1, Value* result) \
1380 F(Throw, const TagIndexImmediate& imm, const Value args[]) \
1381 F(ThrowRef, Value* value) \
1382 F(Rethrow, Control* block) \
1383 F(CatchException, const TagIndexImmediate& imm, Control* block, \
1384 base::Vector<Value> caught_values) \
1385 F(Delegate, uint32_t depth, Control* block) \
1386 F(CatchAll, Control* block) \
1387 F(ContNew, const Value& func_ref, const ContIndexImmediate* imm, \
1389 F(Resume, const ContIndexImmediate* imm, base::Vector<HandlerCase> handlers, \
1390 const Value args[], const Value returns[]) \
1391 F(Suspend, const TagIndexImmediate& imm, const Value args[], \
1392 const Value returns[]) \
1393 F(AtomicOp, WasmOpcode opcode, const Value args[], const size_t argc, \
1394 const MemoryAccessImmediate& imm, Value* result) \
1396 F(MemoryInit, const MemoryInitImmediate& imm, const Value& dst, \
1397 const Value& src, const Value& size) \
1398 F(DataDrop, const IndexImmediate& imm) \
1399 F(MemoryCopy, const MemoryCopyImmediate& imm, const Value& dst, \
1400 const Value& src, const Value& size) \
1401 F(MemoryFill, const MemoryIndexImmediate& imm, const Value& dst, \
1402 const Value& value, const Value& size) \
1403 F(TableInit, const TableInitImmediate& imm, const Value& dst, \
1404 const Value& src, const Value& size) \
1405 F(ElemDrop, const IndexImmediate& imm) \
1406 F(TableCopy, const TableCopyImmediate& imm, const Value& dst, \
1407 const Value& src, const Value& size) \
1408 F(TableGrow, const IndexImmediate& imm, const Value& value, \
1409 const Value& delta, Value* result) \
1410 F(TableSize, const IndexImmediate& imm, Value* result) \
1411 F(TableFill, const IndexImmediate& imm, const Value& start, \
1412 const Value& value, const Value& count) \
1413 F(StructGet, const Value& struct_object, const FieldImmediate& field, \
1414 bool is_signed, Value* result) \
1415 F(StructSet, const Value& struct_object, const FieldImmediate& field, \
1416 const Value& field_value) \
1417 F(ArrayGet, const Value& array_obj, const ArrayIndexImmediate& imm, \
1418 const Value& index, bool is_signed, Value* result) \
1419 F(ArraySet, const Value& array_obj, const ArrayIndexImmediate& imm, \
1420 const Value& index, const Value& value) \
1421 F(ArrayLen, const Value& array_obj, Value* result) \
1422 F(ArrayCopy, const Value& dst, const Value& dst_index, const Value& src, \
1423 const Value& src_index, const ArrayIndexImmediate& src_imm, \
1424 const Value& length) \
1425 F(ArrayFill, const ArrayIndexImmediate& imm, const Value& array, \
1426 const Value& index, const Value& value, const Value& length) \
1427 F(ArrayInitSegment, const ArrayIndexImmediate& array_imm, \
1428 const IndexImmediate& segment_imm, const Value& array, \
1429 const Value& array_index, const Value& segment_offset, \
1430 const Value& length) \
1431 F(I31GetS, const Value& input, Value* result) \
1432 F(I31GetU, const Value& input, Value* result) \
1433 F(RefGetDesc, const Value& ref, Value* desc) \
1434 F(RefTest, HeapType target_type, const Value& obj, Value* result, \
1435 bool null_succeeds) \
1436 F(RefTestAbstract, const Value& obj, HeapType type, Value* result, \
1437 bool null_succeeds) \
1438 F(RefCast, const Value& obj, Value* result) \
1439 F(RefCastDesc, const Value& obj, const Value& desc, Value* result) \
1440 F(RefCastAbstract, const Value& obj, HeapType type, Value* result, \
1441 bool null_succeeds) \
1442 F(AssertNullTypecheck, const Value& obj, Value* result) \
1443 F(AssertNotNullTypecheck, const Value& obj, Value* result) \
1444 F(BrOnCast, HeapType target_type, const Value& obj, Value* result_on_branch, \
1445 uint32_t depth, bool null_succeeds) \
1446 F(BrOnCastFail, HeapType target_type, const Value& obj, \
1447 Value* result_on_fallthrough, uint32_t depth, bool null_succeeds) \
1448 F(BrOnCastDesc, HeapType target_type, const Value& obj, const Value& desc, \
1449 Value* result_on_branch, uint32_t depth, bool null_succeeds) \
1450 F(BrOnCastDescFail, HeapType target_type, const Value& obj, \
1451 const Value& desc, Value* result_on_fallthrough, uint32_t depth, \
1452 bool null_succeeds) \
1453 F(BrOnCastAbstract, const Value& obj, HeapType type, \
1454 Value* result_on_branch, uint32_t depth, bool null_succeeds) \
1455 F(BrOnCastFailAbstract, const Value& obj, HeapType type, \
1456 Value* result_on_fallthrough, uint32_t depth, bool null_succeeds) \
1457 F(StringNewWtf8, const MemoryIndexImmediate& memory, \
1458 const unibrow::Utf8Variant variant, const Value& offset, \
1459 const Value& size, Value* result) \
1460 F(StringNewWtf8Array, const unibrow::Utf8Variant variant, \
1461 const Value& array, const Value& start, const Value& end, Value* result) \
1462 F(StringNewWtf16, const MemoryIndexImmediate& memory, const Value& offset, \
1463 const Value& size, Value* result) \
1464 F(StringNewWtf16Array, const Value& array, const Value& start, \
1465 const Value& end, Value* result) \
1466 F(StringMeasureWtf8, const unibrow::Utf8Variant variant, const Value& str, \
1468 F(StringMeasureWtf16, const Value& str, Value* result) \
1469 F(StringEncodeWtf8, const MemoryIndexImmediate& memory, \
1470 const unibrow::Utf8Variant variant, const Value& str, \
1471 const Value& address, Value* result) \
1472 F(StringEncodeWtf8Array, const unibrow::Utf8Variant variant, \
1473 const Value& str, const Value& array, const Value& start, Value* result) \
1474 F(StringEncodeWtf16, const MemoryIndexImmediate& memory, const Value& str, \
1475 const Value& address, Value* result) \
1476 F(StringEncodeWtf16Array, const Value& str, const Value& array, \
1477 const Value& start, Value* result) \
1478 F(StringConcat, const Value& head, const Value& tail, Value* result) \
1479 F(StringEq, const Value& a, const Value& b, Value* result) \
1480 F(StringIsUSVSequence, const Value& str, Value* result) \
1481 F(StringAsWtf8, const Value& str, Value* result) \
1482 F(StringViewWtf8Advance, const Value& view, const Value& pos, \
1483 const Value& bytes, Value* result) \
1484 F(StringViewWtf8Encode, const MemoryIndexImmediate& memory, \
1485 const unibrow::Utf8Variant variant, const Value& view, const Value& addr, \
1486 const Value& pos, const Value& bytes, Value* next_pos, \
1487 Value* bytes_written) \
1488 F(StringViewWtf8Slice, const Value& view, const Value& start, \
1489 const Value& end, Value* result) \
1490 F(StringAsWtf16, const Value& str, Value* result) \
1491 F(StringViewWtf16GetCodeUnit, const Value& view, const Value& pos, \
1493 F(StringViewWtf16Encode, const MemoryIndexImmediate& memory, \
1494 const Value& view, const Value& addr, const Value& pos, \
1495 const Value& codeunits, Value* result) \
1496 F(StringViewWtf16Slice, const Value& view, const Value& start, \
1497 const Value& end, Value* result) \
1498 F(StringAsIter, const Value& str, Value* result) \
1499 F(StringViewIterNext, const Value& view, Value* result) \
1500 F(StringViewIterAdvance, const Value& view, const Value& codepoints, \
1502 F(StringViewIterRewind, const Value& view, const Value& codepoints, \
1504 F(StringViewIterSlice, const Value& view, const Value& codepoints, \
1506 F(StringCompare, const Value& lhs, const Value& rhs, Value* result) \
1507 F(StringFromCodePoint, const Value& code_point, Value* result) \
1508 F(StringHash, const Value& string, Value* result)
1516template <
typename T>
1521 Grow(initial_size, zone);
1532 if (
begin_ ==
nullptr)
return;
1533 if constexpr (!std::is_trivially_destructible_v<T>) {
1567 static_assert(std::is_trivially_destructible_v<T>);
1574 for (T* new_end =
end_ - num;
end_ != new_end;) {
1582 *
end_ = std::move(value);
1586 template <
typename... Args>
1589 new (
end_) T{std::forward<Args>(
args)...};
1595 Grow(slots_needed, zone);
1600 size_t new_capacity = std::max(
1604 T* new_begin = zone->template AllocateArray<T>(new_capacity);
1606 for (T *ptr =
begin_, *new_ptr = new_begin; ptr !=
end_;
1608 new (new_ptr) T{std::move(*ptr)};
1626template <
typename Val
idationTag, DecodingMode decoding_mode = kFunctionBody>
1642 auto last_trace = module_->inst_traces.end() - 1;
1643 auto first_inst_trace =
1644 std::lower_bound(module_->inst_traces.begin(), last_trace,
1645 std::make_pair(buffer_offset, 0),
1646 [](const std::pair<uint32_t, uint32_t>& a,
1647 const std::pair<uint32_t, uint32_t>& b) {
1648 return a.first < b.first;
1650 if (
V8_UNLIKELY(first_inst_trace != last_trace)) {
1665 return local_types_[
index];
1678 num_locals_ =
static_cast<uint32_t
>(this->sig_->parameter_count());
1681 auto [
entries, entries_length] =
1682 read_u32v<ValidationTag>(
pc,
"local decls count");
1693 if (available_bytes() / 2 <
entries) {
1694 DecodeError(
pc,
"local decls count bigger than remaining function size");
1698 struct DecodedLocalEntry {
1703 uint32_t total_length = entries_length;
1704 for (uint32_t entry = 0; entry <
entries; ++entry) {
1707 "expected more local decls but reached end of input");
1711 auto [
count, count_length] =
1712 read_u32v<ValidationTag>(
pc + total_length,
"local count");
1722 total_length += count_length;
1724 auto [
type, type_length] =
1727 ValidateValueType(
pc + total_length, type);
1732 DCHECK(!ValidationTag::validate);
1734 if (!
VALIDATE(!is_shared_ || type.is_shared())) {
1735 DecodeError(
pc + total_length,
"local must have shared type");
1738 total_length += type_length;
1741 decoded_locals[entry] = DecodedLocalEntry{
count, type};
1750 if (sig_->parameter_count() > 0) {
1751 std::copy(sig_->parameters().begin(), sig_->parameters().end(),
1753 locals_ptr += sig_->parameter_count();
1756 for (
auto& entry : decoded_locals) {
1757 std::fill_n(locals_ptr, entry.count, entry.type);
1758 locals_ptr += entry.count;
1762 return total_length;
1767 template <
typename... Args>
1778 uint32_t locals_count,
Zone* zone,
1779 bool* loop_is_innermost =
nullptr) {
1780 if (
pc >= decoder->
end())
return nullptr;
1781 if (*
pc != kExprLoop)
return nullptr;
1787 if (loop_is_innermost) *loop_is_innermost =
true;
1793 if (loop_is_innermost && depth >= 0) *loop_is_innermost =
false;
1802 case kExprLocalTee: {
1808 case kExprMemoryGrow:
1809 case kExprCallFunction:
1810 case kExprCallIndirect:
1813 assigned->
Add(locals_count);
1821 if (depth < 0)
break;
1824 return VALIDATE(decoder->
ok()) ? assigned :
nullptr;
1828 size_t num_tags =
module_->tags.size();
1841 size_t num_globals =
module_->globals.size();
1849 DecodeError(
pc,
"Cannot access non-shared global %d in a shared %s",
1859 "mutable globals cannot be used in constant "
1910 if (sig_->return_count() != target_sig->
return_count())
return false;
1911 auto target_sig_it = target_sig->
returns().begin();
1912 for (
ValueType ret_type : sig_->returns()) {
1919 size_t num_functions =
module_->functions.size();
1924 if (is_shared_ && !
module_->function_is_shared(imm.
index)) {
1934 if (!Validate(
pc, imm.
sig_imm))
return false;
1939 pc,
"call_indirect: immediate table #%u is not of a function type",
1952 size_t control_depth) {
1962 DecodeError(
pc,
"invalid table count (> max br_table size): %u",
1970 uint8_t num_lanes = 0;
1972 case kExprF64x2ExtractLane:
1973 case kExprF64x2ReplaceLane:
1974 case kExprI64x2ExtractLane:
1975 case kExprI64x2ReplaceLane:
1976 case kExprS128Load64Lane:
1977 case kExprS128Store64Lane:
1980 case kExprF32x4ExtractLane:
1981 case kExprF32x4ReplaceLane:
1982 case kExprI32x4ExtractLane:
1983 case kExprI32x4ReplaceLane:
1984 case kExprS128Load32Lane:
1985 case kExprS128Store32Lane:
1988 case kExprF16x8ExtractLane:
1989 case kExprF16x8ReplaceLane:
1990 case kExprI16x8ExtractLaneS:
1991 case kExprI16x8ExtractLaneU:
1992 case kExprI16x8ReplaceLane:
1993 case kExprS128Load16Lane:
1994 case kExprS128Store16Lane:
1997 case kExprI8x16ExtractLaneS:
1998 case kExprI8x16ExtractLaneU:
1999 case kExprI8x16ReplaceLane:
2000 case kExprS128Load8Lane:
2001 case kExprS128Store8Lane:
2017 uint8_t max_lane = 0;
2019 max_lane = std::max(max_lane, imm.
value[
i]);
2030 if (imm.
sig.
all().begin() ==
nullptr) {
2033 DecodeError(
pc,
"block type index %u is not a signature definition",
2052 size_t num_memories =
module_->memories.size();
2054 this->detected_->add_multi_memory();
2056 DecodeError(
pc,
"Multiple memories not supported in Wasm jitless mode");
2063 "memory index %u exceeds number of declared memories (%zu)",
2064 imm.
index, num_memories);
2075 size_t num_memories =
module_->memories.size();
2078 "memory index %u exceeds number of declared memories (%zu)",
2084 this->
DecodeError(pc,
"memory offset outside 32-bit range: %" PRIu64,
2114 elem_type.
name().c_str());
2126 src_type.
name().c_str());
2142 this->detected_->add_reftypes();
2144 size_t num_tables =
module_->tables.size();
2146 DecodeError(
pc,
"table index %u exceeds number of tables (%zu)",
2147 imm.
index, num_tables);
2154 "cannot reference non-shared table %u from shared function",
2165 size_t num_elem_segments =
module_->elem_segments.size();
2174 "cannot reference non-shared element segment %u from shared function",
2190 size_t num_functions =
module_->functions.size();
2224 pc,
"cannot refer to non-shared segment %u from a shared function",
2254 template <
typename... ImmediateObservers>
2256 ImmediateObservers&... ios) {
2260 case kExprUnreachable:
2262 case kExprNopForTestingUnsupportedInLiftoff:
2273 (ios.BlockType(imm), ...);
2280 case kExprBrOnNonNull:
2281 case kExprDelegate: {
2283 (ios.BranchDepth(imm), ...);
2286 case kExprBrTable: {
2288 (ios.BranchTable(imm), ...);
2290 return 1 + iterator.
length();
2292 case kExprTryTable: {
2295 (ios.BlockType(block_type_imm), ...);
2298 (ios.TryTable(try_table_imm), ...);
2305 (ios.TagIndex(imm), ...);
2312 case kExprContNew: {
2314 (ios.TypeIndex(imm), ...);
2317 case kExprContBind: {
2319 (ios.TypeIndex(src), ...);
2321 (ios.TypeIndex(dst), ...);
2322 return 1 + src.length + dst.
length;
2324 case kExprSuspend: {
2326 (ios.TagIndex(imm), ...);
2331 (ios.TypeIndex(src), ...);
2334 (ios.EffectHandlerTable(handler_table), ...);
2337 return 1 + src.length + iterator.
length();
2339 case kExprResumeThrow: {
2341 (ios.TypeIndex(src), ...);
2343 (ios.TagIndex(event), ...);
2345 decoder,
pc + 1 + src.length + event.
length, validate);
2346 (ios.EffectHandlerTable(handler_table), ...);
2349 return 1 + src.length +
event.length + iterator.
length();
2353 (ios.TypeIndex(src), ...);
2355 (ios.TagIndex(tag), ...);
2356 return 1 + src.length + tag.
length;
2360 case kExprCallFunction:
2361 case kExprReturnCall: {
2363 (ios.FunctionIndex(imm), ...);
2366 case kExprCallIndirect:
2367 case kExprReturnCallIndirect: {
2369 (ios.CallIndirect(imm), ...);
2373 case kExprReturnCallRef: {
2375 (ios.TypeIndex(imm), ...);
2383 case kExprSelectWithType: {
2386 (ios.SelectType(imm), ...);
2392 case kExprLocalTee: {
2394 (ios.LocalIndex(imm), ...);
2397 case kExprGlobalGet:
2398 case kExprGlobalSet: {
2400 (ios.GlobalIndex(imm), ...);
2404 case kExprTableSet: {
2406 (ios.TableIndex(imm), ...);
2409 case kExprI32Const: {
2411 (ios.I32Const(imm), ...);
2414 case kExprI64Const: {
2416 (ios.I64Const(imm), ...);
2420 if (
sizeof...(ios) > 0) {
2422 (ios.F32Const(imm), ...);
2426 if (
sizeof...(ios) > 0) {
2428 (ios.F64Const(imm), ...);
2431 case kExprRefNull: {
2434 (ios.HeapType(imm), ...);
2437 case kExprRefIsNull:
2438 case kExprRefAsNonNull:
2440 case kExprRefFunc: {
2442 (ios.FunctionIndex(imm), ...);
2446#define DECLARE_OPCODE_CASE(name, ...) case kExpr##name:
2456 (ios.MemoryAccess(imm), ...);
2460 case kExprMemoryGrow:
2461 case kExprMemorySize: {
2463 (ios.MemoryIndex(imm), ...);
2468 case kNumericPrefix: {
2470 std::tie(opcode, length) =
2473 case kExprI32SConvertSatF32:
2474 case kExprI32UConvertSatF32:
2475 case kExprI32SConvertSatF64:
2476 case kExprI32UConvertSatF64:
2477 case kExprI64SConvertSatF32:
2478 case kExprI64UConvertSatF32:
2479 case kExprI64SConvertSatF64:
2480 case kExprI64UConvertSatF64:
2482 case kExprMemoryInit: {
2484 (ios.MemoryInit(imm), ...);
2485 return length + imm.
length;
2487 case kExprDataDrop: {
2490 (ios.DataSegmentIndex(imm), ...);
2491 return length + imm.
length;
2493 case kExprMemoryCopy: {
2495 (ios.MemoryCopy(imm), ...);
2496 return length + imm.
length;
2498 case kExprMemoryFill: {
2500 (ios.MemoryIndex(imm), ...);
2501 return length + imm.
length;
2503 case kExprTableInit: {
2505 (ios.TableInit(imm), ...);
2506 return length + imm.
length;
2508 case kExprElemDrop: {
2511 (ios.ElemSegmentIndex(imm), ...);
2512 return length + imm.
length;
2514 case kExprTableCopy: {
2516 (ios.TableCopy(imm), ...);
2517 return length + imm.
length;
2519 case kExprTableGrow:
2520 case kExprTableSize:
2521 case kExprTableFill: {
2523 (ios.TableIndex(imm), ...);
2524 return length + imm.
length;
2526 case kExprF32LoadMemF16:
2527 case kExprF32StoreMemF16: {
2530 (ios.MemoryAccess(imm), ...);
2531 return length + imm.
length;
2540 case kAsmJsPrefix: {
2542 std::tie(opcode, length) =
2556 std::tie(opcode, length) =
2563 if (
sizeof...(ios) > 0) {
2565 (ios.SimdLane(lane_imm), ...);
2571 (ios.MemoryAccess(imm), ...);
2572 return length + imm.
length;
2576 decoder,
pc + length, UINT32_MAX,
2578 if (
sizeof...(ios) > 0) {
2580 pc + length + imm.
length, validate);
2581 (ios.MemoryAccess(imm), ...);
2582 (ios.SimdLane(lane_imm), ...);
2585 return length + imm.
length + 1;
2589 case kExprS128Const:
2590 case kExprI8x16Shuffle:
2591 if (
sizeof...(ios) > 0) {
2593 (ios.S128Const(imm), ...);
2603 case kAtomicPrefix: {
2605 std::tie(opcode, length) =
2611 (ios.MemoryAccess(imm), ...);
2612 return length + imm.
length;
2627 std::tie(opcode, length) =
2630 case kExprStructNew:
2631 case kExprStructNewDefault:
2632 case kExprRefGetDesc: {
2634 (ios.TypeIndex(imm), ...);
2635 return length + imm.
length;
2637 case kExprStructGet:
2638 case kExprStructGetS:
2639 case kExprStructGetU:
2640 case kExprStructSet: {
2642 (ios.Field(imm), ...);
2643 return length + imm.
length;
2646 case kExprArrayNewDefault:
2648 case kExprArrayGetS:
2649 case kExprArrayGetU:
2650 case kExprArraySet: {
2652 (ios.TypeIndex(imm), ...);
2653 return length + imm.
length;
2655 case kExprArrayNewFixed: {
2658 "array length", validate);
2659 (ios.TypeIndex(array_imm), ...);
2660 (ios.Length(length_imm), ...);
2663 case kExprArrayCopy: {
2667 (ios.ArrayCopy(dst_imm, src_imm), ...);
2670 case kExprArrayFill: {
2672 (ios.TypeIndex(imm), ...);
2673 return length + imm.
length;
2675 case kExprArrayNewData:
2676 case kExprArrayNewElem:
2677 case kExprArrayInitData:
2678 case kExprArrayInitElem: {
2681 "segment index", validate);
2682 (ios.TypeIndex(array_imm), ...);
2683 (ios.DataSegmentIndex(data_imm), ...);
2687 case kExprRefCastNull:
2688 case kExprRefCastNop:
2689 case kExprRefCastDesc:
2690 case kExprRefCastDescNull:
2692 case kExprRefTestNull: {
2694 pc + length, validate);
2695 (ios.HeapType(imm), ...);
2696 return length + imm.
length;
2699 case kExprBrOnCastFail:
2700 case kExprBrOnCastDesc:
2701 case kExprBrOnCastDescFail: {
2712 (ios.BrOnCastFlags(flags_imm), ...);
2713 (ios.BranchDepth(branch), ...);
2733 case kExprAnyConvertExtern:
2734 case kExprExternConvertAny:
2737 case kExprStringNewUtf8:
2738 case kExprStringNewUtf8Try:
2739 case kExprStringNewLossyUtf8:
2740 case kExprStringNewWtf8:
2741 case kExprStringEncodeUtf8:
2742 case kExprStringEncodeLossyUtf8:
2743 case kExprStringEncodeWtf8:
2744 case kExprStringViewWtf8EncodeUtf8:
2745 case kExprStringViewWtf8EncodeLossyUtf8:
2746 case kExprStringViewWtf8EncodeWtf8:
2747 case kExprStringNewWtf16:
2748 case kExprStringEncodeWtf16:
2749 case kExprStringViewWtf16Encode: {
2751 (ios.MemoryIndex(imm), ...);
2752 return length + imm.
length;
2754 case kExprStringConst: {
2756 (ios.StringConst(imm), ...);
2757 return length + imm.
length;
2759 case kExprStringMeasureUtf8:
2760 case kExprStringMeasureWtf8:
2761 case kExprStringNewUtf8Array:
2762 case kExprStringNewUtf8ArrayTry:
2763 case kExprStringNewLossyUtf8Array:
2764 case kExprStringNewWtf8Array:
2765 case kExprStringEncodeUtf8Array:
2766 case kExprStringEncodeLossyUtf8Array:
2767 case kExprStringEncodeWtf8Array:
2768 case kExprStringMeasureWtf16:
2769 case kExprStringConcat:
2771 case kExprStringIsUSVSequence:
2772 case kExprStringAsWtf8:
2773 case kExprStringViewWtf8Advance:
2774 case kExprStringViewWtf8Slice:
2775 case kExprStringAsWtf16:
2776 case kExprStringViewWtf16Length:
2777 case kExprStringViewWtf16GetCodeunit:
2778 case kExprStringViewWtf16Slice:
2779 case kExprStringAsIter:
2780 case kExprStringViewIterNext:
2781 case kExprStringViewIterAdvance:
2782 case kExprStringViewIterRewind:
2783 case kExprStringViewIterSlice:
2784 case kExprStringNewWtf16Array:
2785 case kExprStringEncodeWtf16Array:
2786 case kExprStringCompare:
2787 case kExprStringFromCodePoint:
2788 case kExprStringHash:
2809#undef DECLARE_OPCODE_CASE
2812 if (ValidationTag::validate) {
2818 static constexpr ValidationTag validate = {};
2835#define CALL_INTERFACE(name, ...) \
2837 DCHECK(!control_.empty()); \
2838 DCHECK(current_code_reachable_and_ok_); \
2839 DCHECK_EQ(current_code_reachable_and_ok_, \
2840 this->ok() && control_.back().reachable()); \
2841 interface_.name(this, ##__VA_ARGS__); \
2843#define CALL_INTERFACE_IF_OK_AND_REACHABLE(name, ...) \
2845 DCHECK(!control_.empty()); \
2846 DCHECK_EQ(current_code_reachable_and_ok_, \
2847 this->ok() && control_.back().reachable()); \
2848 if (V8_LIKELY(current_code_reachable_and_ok_)) { \
2849 interface_.name(this, ##__VA_ARGS__); \
2852#define CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(name, ...) \
2854 DCHECK(!control_.empty()); \
2855 if (VALIDATE(this->ok()) && \
2856 (control_.size() == 1 || control_at(1)->reachable())) { \
2857 interface_.name(this, ##__VA_ARGS__); \
2867 template <
typename... Ts>
2870 constexpr std::nullptr_t
data()
const {
return nullptr; }
2873template <
typename ValidationTag,
typename Interface,
2874 DecodingMode decoding_mode = kFunctionBody>
2876 using Value =
typename Interface::Value;
2880 std::conditional_t<Interface::kUsesPoppedArgs,
2889 template <
typename... InterfaceArgs>
2892 const FunctionBody& body, InterfaceArgs&&... interface_args)
2894 zone, module, enabled, detected, body.
sig, body.
is_shared,
2896 interface_(
std::forward<InterfaceArgs>(interface_args)...),
2902 stack_.Reset(this->
zone_);
2903 locals_initializers_stack_.Reset(this->
zone_);
2915 uint32_t locals_length = this->DecodeLocals(this->
pc());
2916 if (!
VALIDATE(this->ok()))
return TraceFailed();
2917 this->consume_bytes(locals_length);
2918 int non_defaultable = 0;
2919 uint32_t params_count =
2920 static_cast<uint32_t
>(this->sig_->parameter_count());
2921 for (uint32_t index = params_count; index < this->num_locals(); index++) {
2922 if (!this->local_type(index).is_defaultable()) non_defaultable++;
2926 this->detected_->add_reftypes();
2929 this->InitializeInitializedLocalsTracking(non_defaultable);
2932 interface().StartFunction(
this);
2933 DecodeFunctionBody();
2936 if (this->failed())
return TraceFailed();
2941 "unterminated control structure");
2943 this->
DecodeError(
"function body must end with \"end\" opcode");
2945 return TraceFailed();
2948 interface().FinishFunction(
this);
2949 if (this->failed())
return TraceFailed();
2952 TRACE(
"wasm-decode ok\n\n");
2956 if (this->
error_.offset()) {
2957 TRACE(
"wasm-error module+%-6d func+%d: %s\n\n", this->
error_.offset(),
2958 this->GetBufferRelativeOffset(this->error_.offset()),
2959 this->error_.message().c_str());
2961 TRACE(
"wasm-error: %s\n\n", this->
error_.message().c_str());
2966 if (!
pc)
return "<null>";
2967 if (
pc >= this->
end_)
return "<end>";
2969 if (!WasmOpcodes::IsPrefixOpcode(opcode)) {
2970 return WasmOpcodes::OpcodeName(
static_cast<WasmOpcode>(opcode));
2972 opcode = this->
template read_prefixed_opcode<Decoder::FullValidationTag>(
pc)
2974 return WasmOpcodes::OpcodeName(opcode);
2984 return static_cast<uint32_t
>(
control_.size());
2997 return stack_.end() - depth;
3003 return control_depth() - 1 - current_catch();
3007 return this->
pc_offset() - locals_offset_;
3012 if (!has_nondefaultable_locals_)
return true;
3013 return initialized_locals_[local_index];
3018 if (!has_nondefaultable_locals_)
return;
3021 if (is_local_initialized(local_index))
return;
3022 initialized_locals_[local_index] =
true;
3023 locals_initializers_stack_.push(local_index);
3027 return static_cast<uint32_t
>(locals_initializers_stack_.size());
3031 if (!has_nondefaultable_locals_)
return;
3032 uint32_t previous_stack_height = c->init_stack_depth;
3033 while (locals_initializers_stack_.size() > previous_stack_height) {
3034 uint32_t local_index = locals_initializers_stack_.back();
3035 locals_initializers_stack_.pop();
3036 initialized_locals_[local_index] =
false;
3041 has_nondefaultable_locals_ = non_defaultable_locals > 0;
3042 if (!has_nondefaultable_locals_)
return;
3043 initialized_locals_ =
3046 const size_t num_params = this->sig_->parameter_count();
3047 std::fill_n(initialized_locals_, num_params,
true);
3050 initialized_locals_[
i] = this->local_types_[
i].is_defaultable();
3052 DCHECK(locals_initializers_stack_.empty());
3053 locals_initializers_stack_.EnsureMoreCapacity(non_defaultable_locals,
3058 TRACE(
"wasm-decode %p...%p (module+%u, %d bytes)\n", this->
start(),
3060 static_cast<int>(this->
end() - this->
start()));
3065 constexpr uint32_t kStackDepth = 0;
3066 constexpr uint32_t kInitStackDepth = 0;
3072 InitMerge(&c->start_merge, 0,
nullptr);
3073 InitMerge(&c->end_merge,
3074 static_cast<uint32_t
>(this->sig_->return_count()),
3075 [
this](uint32_t
i) {
3076 return Value{this->pc_, this->sig_->GetReturn(i)};
3079 DCHECK_EQ(this->sig_->parameter_count(), 0);
3080 DCHECK_EQ(this->sig_->return_count(), 1);
3081 c->start_merge.arity = 0;
3082 c->end_merge.arity = 1;
3083 c->end_merge.vals.first =
Value{this->
pc_, this->sig_->GetReturn(0)};
3088 if (
V8_LIKELY(this->current_inst_trace_->first == 0)) {
3095 stack_.EnsureMoreCapacity(1, this->
zone_);
3096 uint8_t first_byte = *this->
pc_;
3104 if (opcode == kExprLocalGet) {
3105 len = WasmFullDecoder::DecodeLocalGet(
this, opcode);
3106 }
else if (opcode == kExprI32Const) {
3107 len = WasmFullDecoder::DecodeI32Const(
this, opcode);
3109 OpcodeHandler handler = GetOpcodeHandler(first_byte);
3110 len = (*handler)(
this, opcode);
3118 DCHECK(this->current_inst_trace_->first == 0 ||
3119 this->current_inst_trace_->first >= this->pc_offset());
3120 if (
V8_UNLIKELY(this->current_inst_trace_->first ==
3121 this->pc_offset())) {
3123 this->current_inst_trace_->second);
3125 this->current_inst_trace_->second);
3126 this->current_inst_trace_++;
3133 stack_.EnsureMoreCapacity(1, this->
zone_);
3134 uint8_t first_byte = *this->
pc_;
3137 OpcodeHandler handler = GetOpcodeHandler(first_byte);
3138 int len = (*handler)(
this, opcode);
3146 if (this->
pc_ != this->end_) {
3148 if constexpr (ValidationTag::validate) {
3155 DCHECK(block->is_try_table());
3156 return std::any_of(block->catch_cases.begin(), block->catch_cases.end(),
3157 [](
const struct CatchCase& catch_case) {
3158 return catch_case.kind == kCatchAll ||
3159 catch_case.kind == kCatchAllRef;
3164 uint32_t locals_offset_ = 0;
3186 bool current_code_reachable_and_ok_ =
true;
3190 bool has_nondefaultable_locals_ =
true;
3193 int32_t current_catch_ = -1;
3201 if (current->reachable()) {
3203 current_code_reachable_and_ok_ =
false;
3210 if (!current_code_reachable_and_ok_ || current_catch() == -1)
return;
3211 control_at(control_depth_of_current_catch())->might_throw =
true;
3233 if (!WasmOpcodes::IsPrefixOpcode(opcode)) AppendOpcode(opcode);
3237 DCHECK(!WasmOpcodes::IsPrefixOpcode(opcode));
3239 WasmOpcodes::OpcodeName(opcode));
3243 if (!v8_flags.trace_wasm_decoder)
return;
3245 PrintF(
"%.*s\n", len_,
buffer_);
3250 void Append(const
char* format, ...) {
3251 if (!v8_flags.trace_wasm_decoder)
return;
3253 va_start(va_args, format);
3254 size_t remaining_len = kMaxLen - len_;
3255 base::Vector<char> remaining_msg_space(
buffer_ + len_, remaining_len);
3256 int len = base::VSNPrintF(remaining_msg_space, format, va_args);
3258 len_ += len < 0 ? remaining_len : len;
3262 void AppendStackState() {
3265 for (Control& c : decoder_->control_) {
3292 if (c.start_merge.arity) Append(
"%u-", c.start_merge.arity);
3293 Append(
"%u", c.end_merge.arity);
3294 if (!c.reachable()) Append(
"%c", c.unreachable() ?
'*' :
'#');
3297 for (uint32_t
i = 0;
i < decoder_->stack_.
size(); ++
i) {
3298 Value& val = decoder_->stack_[
i];
3299 Append(
" %c", val.type.short_name());
3303 static constexpr int kMaxLen = 512;
3307 WasmFullDecoder*
const decoder_;
3317 void Append(const
char* format, ...) {}
3321#define DECODE(name) \
3322 static int Decode##name(WasmFullDecoder* decoder, WasmOpcode opcode) { \
3323 TraceLine trace_msg(decoder); \
3324 return decoder->Decode##name##Impl(&trace_msg, opcode); \
3326 V8_INLINE int Decode##name##Impl(TraceLine* trace_msg, WasmOpcode opcode)
3337 if (this->failed()) {
3344#define BUILD_SIMPLE_OPCODE(op, _, sig, ...) \
3345 DECODE(op) { return BuildSimpleOperator_##sig(kExpr##op); }
3347#undef BUILD_SIMPLE_OPCODE
3349#define BUILD_SIMPLE_OPCODE(op, _, sig, ...) \
3351 if constexpr (decoding_mode == kConstantExpression) { \
3352 this->detected_->add_extended_const(); \
3354 return BuildSimpleOperator_##sig(kExpr##op); \
3357#undef BUILD_SIMPLE_OPCODE
3361 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
3370 if (!this->Validate(this->
pc_ + 1, imm,
control_.size()))
return 0;
3372 if (!
VALIDATE(c->is_try_catchall() || c->is_try_catch())) {
3373 this->error(
"rethrow not targeting catch or catch-all");
3386 this->detected_->Add(this->
enabled_.has_exnref()
3387 ? WasmDetectedFeature::exnref
3388 : WasmDetectedFeature::legacy_eh);
3390 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
3391 if (imm.
tag->sig->return_count() != 0) {
3405 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
3407 try_block->previous_catch = current_catch_;
3408 current_catch_ =
static_cast<int>(control_depth() - 1);
3416 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
3423 if (!
VALIDATE(!c->is_try_catchall())) {
3424 this->
DecodeError(
"catch after catch-all for try");
3430 c->reachability = control_at(1)->innerReachability();
3431 current_code_reachable_and_ok_ =
VALIDATE(this->ok()) && c->reachable();
3432 RollbackLocalsInitialization(c);
3436 if (
sig->return_count() != 0) {
3445 sig->parameter_count());
3446 current_catch_ = c->previous_catch;
3449 if (c->might_throw) {
3452 SetSucceedingCodeDynamicallyUnreachable();
3461 if (!this->Validate(this->
pc_ + 1, imm, control_depth() - 1))
return 0;
3463 if (!
VALIDATE(c->is_incomplete_try())) {
3464 this->
DecodeError(
"delegate does not match a try");
3468 uint32_t target_depth = imm.
depth + 1;
3469 while (target_depth < control_depth() - 1 &&
3470 (!control_at(target_depth)->is_try() ||
3471 control_at(target_depth)->is_try_catch() ||
3472 control_at(target_depth)->is_try_catchall())) {
3476 if (c->might_throw) {
3479 if (control_at(1)->reachable() && target_depth != control_depth() - 1) {
3480 control_at(target_depth)->might_throw =
true;
3483 current_catch_ = c->previous_catch;
3494 this->
DecodeError(
"catch-all does not match a try");
3497 if (!
VALIDATE(!c->is_try_catchall())) {
3498 this->error(
"catch-all already present for try");
3503 c->reachability = control_at(1)->innerReachability();
3504 current_code_reachable_and_ok_ =
VALIDATE(this->ok()) && c->reachable();
3505 RollbackLocalsInitialization(c);
3506 current_catch_ = c->previous_catch;
3509 if (c->might_throw) {
3512 SetSucceedingCodeDynamicallyUnreachable();
3521 if (!this->Validate(this->
pc_ + 1, block_imm))
return 0;
3526 try_block->previous_catch = current_catch_;
3527 current_catch_ =
static_cast<int>(control_depth() - 1);
3529 if (!this->Validate(this->
pc_ + 2, try_table_imm))
return 0;
3531 try_block->catch_cases = this->
zone_->template AllocateVector<CatchCase>(
3534 while (try_table_iterator.
has_next()) {
3537 this->
DecodeError(
"invalid catch kind in try table");
3545 if (
sig->return_count() != 0) {
3547 this->
DecodeError(
"tag signature %u has non-void return",
3557 uint32_t stack_size = stack_.
size();
3558 uint32_t push_count = 0;
3564 push_count +=
sig->parameter_count();
3572 if (!
VALIDATE(push_count == target->br_merge()->arity)) {
3574 "catch kind generates %d operand%s, target block expects %d",
3575 push_count, push_count != 1 ?
"s" :
"", target->br_merge()->arity);
3579 (TypeCheckBranch<PushBranchValues::kYes, RewriteStackTypes::kNo>(
3585 try_block->catch_cases[
i] = catch_case;
3589 return 1 + block_imm.
length + try_table_iterator.
length();
3602 this->detected_->add_typed_funcref();
3604 if (!this->Validate(this->
pc_ + 1, imm,
control_.size()))
return 0;
3605 Value ref_object = Pop();
3608 (TypeCheckBranch<PushBranchValues::kYes, RewriteStackTypes::kYes>(
3612 switch (ref_object.type.kind()) {
3615 DCHECK(!current_code_reachable_and_ok_);
3623 Value*
result = Push(ValueType::Ref(ref_object.type.heap_type()));
3626 if (
V8_LIKELY(current_code_reachable_and_ok_)) {
3628 c->br_merge()->reached =
true;
3633 PopTypeError(0, ref_object,
"object reference");
3640 this->detected_->add_typed_funcref();
3642 if (!this->Validate(this->
pc_ + 1, imm,
control_.size()))
return 0;
3643 Value ref_object = Pop();
3644 if (!
VALIDATE(ref_object.type.is_object_reference() ||
3645 ref_object.type.is_bottom())) {
3648 "subtype of ((ref null any), (ref null extern) or (ref null func))");
3653 Value* value_on_branch = Push(ref_object.type.AsNonNull());
3656 (TypeCheckBranch<PushBranchValues::kYes, RewriteStackTypes::kYes>(
3660 switch (ref_object.type.kind()) {
3663 DCHECK(!current_code_reachable_and_ok_);
3667 if (
V8_LIKELY(current_code_reachable_and_ok_)) {
3672 SetSucceedingCodeDynamicallyUnreachable();
3673 c->br_merge()->reached =
true;
3677 if (
V8_LIKELY(current_code_reachable_and_ok_)) {
3680 c->br_merge()->reached =
true;
3685 PopTypeError(0, ref_object,
"object reference");
3688 Drop(*value_on_branch);
3694 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
3701 PushMergeValues(block, &block->start_merge);
3707 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
3721 if (!
VALIDATE(c->is_onearmed_if())) {
3725 if (!
VALIDATE(TypeCheckFallThru()))
return 0;
3728 if (c->reachable()) c->end_merge.reached =
true;
3729 RollbackLocalsInitialization(c);
3730 PushMergeValues(c, &c->start_merge);
3731 c->reachability = control_at(1)->innerReachability();
3732 current_code_reachable_and_ok_ =
VALIDATE(this->ok()) && c->reachable();
3740 if (c->is_incomplete_try()) {
3743 current_catch_ = c->previous_catch;
3745 if (c->is_try_catch()) {
3748 c->reachability = control_at(1)->innerReachability();
3749 current_code_reachable_and_ok_ =
VALIDATE(this->ok()) && c->reachable();
3752 bool might_throw = c->might_throw;
3762 if (might_throw && current_catch() != -1) {
3763 control_at(control_depth_of_current_catch())->might_throw =
true;
3767 if (c->is_onearmed_if()) {
3768 if (!
VALIDATE(TypeCheckOneArmedIf(c)))
return 0;
3770 if (c->is_try_table()) {
3773 if (c->catch_cases.size() > 0) {
3774 current_catch_ = c->previous_catch;
3780 c->reachability = control_at(1)->innerReachability();
3781 current_code_reachable_and_ok_ =
VALIDATE(this->ok()) && c->reachable();
3782 for (
CatchCase& catch_case : c->catch_cases) {
3783 uint32_t stack_size = stack_.
size();
3784 size_t push_count = 0;
3790 push_count =
sig->parameter_count();
3798 stack_.
begin() + stack_.
size() - push_count, push_count);
3799 if (c->might_throw) {
3803 if (current_code_reachable_and_ok_) {
3805 target->br_merge()->reached =
true;
3813 c->reachability = reachability_at_end;
3817 if (c->might_throw && !HasCatchAll(c) && current_catch() != -1) {
3818 control_at(control_depth_of_current_catch())->might_throw =
true;
3831 : kInitExprMerge>();
3834 this->
DecodeError(this->
pc_ + 1,
"trailing code after function end");
3839 "(implicit) return");
3844 if (!
VALIDATE(TypeCheckFallThru()))
return 0;
3853 result_type = fval.type;
3855 ValidateStackValue(1, fval, result_type);
3859 "select without type is only valid for value type inputs");
3868 this->detected_->add_reftypes();
3870 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
3879 if (!this->Validate(this->
pc_ + 1, imm,
control_.size()))
return 0;
3882 (TypeCheckBranch<PushBranchValues::kNo, RewriteStackTypes::kNo>(
3886 if (
V8_LIKELY(current_code_reachable_and_ok_)) {
3888 c->br_merge()->reached =
true;
3896 if (!this->Validate(this->
pc_ + 1, imm,
control_.size()))
return 0;
3900 (TypeCheckBranch<PushBranchValues::kYes, RewriteStackTypes::kYes>(
3904 if (
V8_LIKELY(current_code_reachable_and_ok_)) {
3906 c->br_merge()->reached =
true;
3915 if (!
VALIDATE(this->ok()))
return 0;
3916 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
3921 std::uninitialized_fill(br_targets.
begin(), br_targets.
end(),
false);
3926 const uint32_t index = iterator.
cur_index();
3927 const uint8_t*
pos = iterator.
pc();
3928 const uint32_t target = iterator.
next();
3929 if (!
VALIDATE(target < control_depth())) {
3934 if (br_targets[target])
continue;
3935 br_targets[
target] =
true;
3937 if (ValidationTag::validate) {
3939 arity = control_at(target)->br_merge()->arity;
3940 }
else if (!
VALIDATE(control_at(target)->br_merge()->arity == arity)) {
3942 pos,
"br_table: label arity inconsistent with previous arity %d",
3947 (TypeCheckBranch<PushBranchValues::kNo, RewriteStackTypes::kNo>(
3948 control_at(target))))) {
3954 if (
V8_LIKELY(current_code_reachable_and_ok_)) {
3957 for (uint32_t
i = 0;
i < control_depth(); ++
i) {
3958 control_at(
i)->br_merge()->reached |= br_targets[
i];
3962 return 1 + iterator.
length();
3966 return DoReturn<kNonStrictCounting, kReturnMerge>() ? 1 : 0;
4004 this->detected_->add_reftypes();
4006 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
4009 this->
DecodeError(this->
pc_ + 1,
"cannot create null string view");
4013 Value* value = Push(type);
4019 this->detected_->add_reftypes();
4020 Value value = Pop();
4022 switch (value.type.kind()) {
4034 if constexpr (!ValidationTag::validate)
UNREACHABLE();
4035 PopTypeError(0, value,
"reference type");
4041 this->detected_->add_reftypes();
4043 if (!this->ValidateFunction(this->
pc_ + 1, imm))
return 0;
4047 Push(ValueType::Ref(index, type_def.
is_shared, RefTypeKind::kFunction)
4048 .AsExactIfProposalEnabled());
4054 this->detected_->add_typed_funcref();
4055 Value value = Pop();
4056 switch (value.type.kind()) {
4064 Value*
result = Push(ValueType::Ref(value.type.heap_type()));
4069 if constexpr (!ValidationTag::validate)
UNREACHABLE();
4070 PopTypeError(0, value,
"reference type");
4077 if (!this->ValidateLocal(this->
pc_ + 1, imm))
return 0;
4079 this->
DecodeError(this->
pc_,
"uninitialized non-defaultable local: %u",
4083 Value* value = Push(this->local_type(imm.
index));
4090 if (!this->ValidateLocal(this->
pc_ + 1, imm))
return 0;
4091 Value value = Pop(this->local_type(imm.
index));
4093 this->set_local_initialized(imm.
index);
4099 if (!this->ValidateLocal(this->
pc_ + 1, imm))
return 0;
4101 Value value = Pop(local_type);
4104 this->set_local_initialized(imm.
index);
4116 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
4124 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
4135 this->detected_->add_reftypes();
4137 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
4138 Value index = Pop(TableAddressType(imm.
table));
4145 this->detected_->add_reftypes();
4147 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
4162 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
4164 Value value = Pop(mem_type);
4172 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
4181 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
4183 Value* returns = PushReturns(imm.
sig);
4191 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
4194 Value* returns = PushReturns(imm.
sig);
4200 this->detected_->add_gc();
4206 this->detected_->add_return_call();
4208 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
4210 this->
DecodeError(
"%s: %s", WasmOpcodes::OpcodeName(kExprReturnCall),
4211 "tail call type error");
4221 this->detected_->add_return_call();
4223 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
4226 WasmOpcodes::OpcodeName(kExprReturnCallIndirect),
4227 "tail call return types mismatch");
4237 this->detected_->add_gc();
4243 this->detected_->add_typed_funcref();
4245 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
4248 Value* returns = PushReturns(imm.
sig);
4256 this->detected_->add_typed_funcref();
4257 this->detected_->add_return_call();
4259 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
4261 this->
DecodeError(
"%s: %s", WasmOpcodes::OpcodeName(kExprReturnCallRef),
4262 "tail call return types mismatch");
4274 this->detected_->add_gc();
4281 "ref.eq[0] expected either eqref or (ref null shared "
4282 "eq), found %s of type %s",
4283 SafeOpcodeNameAt(lhs.pc()), lhs.type.name().c_str());
4290 "ref.eq[1] expected either eqref or (ref null shared "
4291 "eq), found %s of type %s",
4292 SafeOpcodeNameAt(rhs.pc()), rhs.type.name().c_str());
4295 if (!
VALIDATE(lhs.type.is_shared() == rhs.type.is_shared() ||
4298 "ref.eq: sharedness of both operands must match");
4308 this->detected_->add_wasmfx();
4310 if (!this->ValidateCont(this->
pc_ + 1, imm))
return 0;
4314 Pop(ValueType::RefNull(imm.
cont_type->contfun_typeindex(), imm.
shared,
4315 RefTypeKind::kFunction));
4328 this->detected_->add_wasmfx();
4331 if (!this->ValidateCont(this->
pc_ + 1, imm))
return 0;
4333 Pop(ValueType::RefNull(imm.
heap_type()));
4336 this, this->
pc_ + 1 + imm.
length, validate);
4338 if (!this->Validate(this->
pc_ + imm.
length + 1, handler_table_imm))
4341 this, handler_table_imm);
4343 this->
zone_->template AllocateVector<HandlerCase>(
4346 while (handle_iterator.
has_next()) {
4349 if (!this->Validate(this->
pc_, handler.
tag)) {
4354 uint32_t stack_size = stack_.
size();
4355 uint32_t push_count = 0;
4361 push_count +=
sig->parameter_count();
4364 control_depth())))) {
4368 Control* target = control_at(handler.maybe_depth.br.depth);
4369 if (!
VALIDATE(push_count == target->br_merge()->arity)) {
4371 "handler generates %d operand%s, target block returns %d",
4372 push_count, push_count != 1 ?
"s" :
"",
4373 target->br_merge()->arity);
4378 TypeCheckBranch<PushBranchValues::kYes, RewriteStackTypes::kNo>(
4384 }
else if (handler.kind !=
kSwitch) {
4385 this->
DecodeError(
"invalid handler kind %d", handler.kind);
4396 PopArgs(contFunSig);
4398 PushReturns(contFunSig);
4406 this->detected_->add_wasmfx();
4409 if (!this->Validate(this->
pc_ + 1, imm))
return 0;
4426 auto [full_opcode, opcode_length] =
4427 this->
template read_prefixed_opcode<ValidationTag>(this->
pc_,
4429 if (full_opcode == kExprTableGrow || full_opcode == kExprTableSize ||
4430 full_opcode == kExprTableFill) {
4431 this->detected_->add_reftypes();
4433 trace_msg->AppendOpcode(full_opcode);
4434 return DecodeNumericOpcode(full_opcode, opcode_length);
4438 auto [full_opcode, opcode_length] =
4439 this->
template read_prefixed_opcode<ValidationTag>(this->
pc_,
4441 trace_msg->AppendOpcode(full_opcode);
4442 return DecodeAsmJsOpcode(full_opcode, opcode_length);
4446 this->detected_->add_simd();
4448 if (
v8_flags.correctness_fuzzer_suppressions) {
4449 FATAL(
"Aborting on missing Wasm SIMD support");
4454 auto [full_opcode, opcode_length] =
4455 this->
template read_prefixed_opcode<ValidationTag>(this->
pc_);
4456 if (!
VALIDATE(this->ok()))
return 0;
4457 trace_msg->AppendOpcode(full_opcode);
4458 if (WasmOpcodes::IsFP16SimdOpcode(full_opcode)) {
4459 this->detected_->add_fp16();
4460 }
else if (WasmOpcodes::IsRelaxedSimdOpcode(full_opcode)) {
4461 this->detected_->add_relaxed_simd();
4463 return DecodeSimdOpcode(full_opcode, opcode_length);
4467 this->detected_->add_threads();
4468 auto [full_opcode, opcode_length] =
4469 this->
template read_prefixed_opcode<ValidationTag>(this->
pc_,
4471 trace_msg->AppendOpcode(full_opcode);
4472 return DecodeAtomicOpcode(full_opcode, opcode_length);
4476 auto [full_opcode, opcode_length] =
4477 this->
template read_prefixed_opcode<ValidationTag>(this->
pc_,
4479 trace_msg->AppendOpcode(full_opcode);
4485 }
else if (full_opcode >= kExprStringNewUtf8) {
4487 return DecodeStringRefOpcode(full_opcode, opcode_length);
4489 this->detected_->add_gc();
4490 return DecodeGCOpcode(full_opcode, opcode_length);
4494#define SIMPLE_PROTOTYPE_CASE(name, ...) \
4495 DECODE(name) { return BuildSimplePrototypeOperator(opcode); }
4497#undef SIMPLE_PROTOTYPE_CASE
4502 decoder->
DecodeError(
"opcode %s is not allowed in constant expressions",
4503 WasmOpcodes::OpcodeName(opcode));
4508 decoder->
DecodeError(
"Invalid opcode 0x%x", opcode);
4520#define DECODE_IMPL(opcode) DECODE_IMPL2(kExpr##opcode, opcode)
4521#define DECODE_IMPL2(opcode, name) \
4522 if (idx == opcode) { \
4523 if constexpr (decoding_mode == kConstantExpression) { \
4524 return &WasmFullDecoder::NonConstError; \
4526 return &WasmFullDecoder::Decode##name; \
4529#define DECODE_IMPL_CONST(opcode) DECODE_IMPL_CONST2(kExpr##opcode, opcode)
4530#define DECODE_IMPL_CONST2(opcode, name) \
4531 if (idx == opcode) return &WasmFullDecoder::Decode##name
4535#define BUILD_SIMPLE_OPCODE(op, ...) DECODE_IMPL(op);
4537#undef BUILD_SIMPLE_OPCODE
4538#define BUILD_SIMPLE_EXTENDED_CONST_OPCODE(op, ...) DECODE_IMPL_CONST(op);
4540#undef BUILD_SIMPLE_EXTENDED_CONST_OPCODE
4584#define DECODE_LOAD_MEM(op, ...) DECODE_IMPL2(kExpr##op, LoadMem);
4586#undef DECODE_LOAD_MEM
4587#define DECODE_STORE_MEM(op, ...) DECODE_IMPL2(kExpr##op, StoreMem);
4589#undef DECODE_LOAD_MEM
4603#define SIMPLE_PROTOTYPE_CASE(name, ...) DECODE_IMPL(name);
4605#undef SIMPLE_PROTOTYPE_CASE
4606 return &WasmFullDecoder::UnknownOpcodeError;
4613 static constexpr std::array<OpcodeHandler, 256> kOpcodeHandlers =
4614 base::make_array<256>(GetOpcodeHandlerTableEntry);
4615 return kOpcodeHandlers[opcode];
4623 current_code_reachable_and_ok_ =
false;
4626 template <
typename func>
4628 merge->
arity = arity;
4629 if constexpr (std::is_null_pointer_v<func>) {
4631 }
else if (arity == 1) {
4633 }
else if (arity > 1) {
4634 merge->
vals.
array = this->zone()->template AllocateArray<Value>(arity);
4635 for (uint32_t
i = 0;
i < arity;
i++) {
4646 uint32_t limit =
control_.back().stack_depth;
4648 return EnsureStackArguments_Slow(
count);
4652 uint32_t limit =
control_.back().stack_depth;
4654 NotEnoughArgumentsError(
count, stack_.
size() - limit);
4660 int current_values = stack_.
size() - limit;
4661 int additional_values =
count - current_values;
4667 Value unreachable_value = UnreachableValue(this->
pc_);
4668 for (
int i = 0;
i < additional_values; ++
i) stack_.
push(unreachable_value);
4669 if (current_values > 0) {
4672 Value* stack_base = stack_value(current_values + additional_values);
4673 for (
int i = current_values - 1;
i >= 0;
i--) {
4674 stack_base[additional_values +
i] = stack_base[
i];
4676 for (
int i = 0;
i < additional_values;
i++) {
4677 stack_base[
i] = UnreachableValue(this->
pc_);
4680 return additional_values;
4684 int num_params =
static_cast<int>(
sig->parameter_count());
4685 EnsureStackArguments(num_params);
4686 Value* param_base = stack_.
end() - num_params;
4687 for (
int i = 0;
i < num_params;
i++) {
4688 ValidateStackValue(
i, param_base[
i],
sig->GetParam(
i));
4695 int count =
static_cast<int>(
sig->parameter_count());
4700 int count =
static_cast<int>(type->field_count());
4701 EnsureStackArguments(
count);
4706 ValidateStackValue(
i, args_base[
i], type->field(
i).Unpacked());
4716 Drop(
static_cast<int>(type->field_count()));
4722 int count =
static_cast<int>(
sig->parameter_count());
4723 EnsureStackArguments(
count);
4728 ValidateStackValue(
i, args_base[
i],
sig->GetParam(
i));
4738 ValidateParameters(&imm.
sig);
4740 uint32_t stack_depth = stack_.
size();
4741 DCHECK_LE(consumed_values, stack_depth);
4742 uint32_t inner_stack_depth = stack_depth - consumed_values;
4745 uint32_t init_stack_depth = this->locals_initialization_stack_depth();
4749 init_stack_depth, this->
pc_, reachability);
4752 Value* arg_base = stack_.
end() - consumed_values;
4756 for (uint32_t
i = 0;
i < consumed_values; ++
i) {
4765 const uint8_t*
pc = this->
pc_;
4766 InitMerge(&new_block->end_merge, imm.
out_arity(), [
pc, &imm](uint32_t
i) {
4767 return Value{pc, imm.out_type(i)};
4769 InitMerge(&new_block->start_merge, imm.in_arity(),
4770 [arg_base](uint32_t
i) { return arg_base[i]; });
4787 if (!c->is_loop() || c->unreachable()) {
4788 PushMergeValues(c, &c->end_merge);
4790 RollbackLocalsInitialization(c);
4792 bool parent_reached =
4793 c->reachable() || c->end_merge.reached || c->is_onearmed_if();
4797 if (!parent_reached) SetSucceedingCodeDynamicallyUnreachable();
4798 current_code_reachable_and_ok_ =
4804 MakeMemoryAccessImmediate(prefix_len, type.size_log_2());
4805 if (!this->Validate(this->
pc_ + prefix_len, imm))
return 0;
4807 Value index = Pop(address_type);
4810 !CheckStaticallyOutOfBounds(imm.
memory, type.size(), imm.
offset))) {
4813 return prefix_len + imm.
length;
4817 uint32_t opcode_length) {
4819 uint32_t max_alignment =
4820 transform == LoadTransformationKind::kExtend ? 3 : type.size_log_2();
4822 MakeMemoryAccessImmediate(opcode_length, max_alignment);
4823 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
4825 Value index = Pop(address_type);
4828 transform == LoadTransformationKind::kExtend ? 8 : type.size();
4830 !CheckStaticallyOutOfBounds(imm.
memory, op_size, imm.
offset))) {
4834 return opcode_length + imm.
length;
4839 MakeMemoryAccessImmediate(opcode_length, type.size_log_2());
4840 if (!this->Validate(this->
pc_ + opcode_length, mem_imm))
return 0;
4843 if (!this->Validate(this->
pc_ + opcode_length, opcode, lane_imm))
return 0;
4848 if (
V8_LIKELY(!CheckStaticallyOutOfBounds(mem_imm.
memory, type.size(),
4853 return opcode_length + mem_imm.
length + lane_imm.
length;
4857 uint32_t opcode_length) {
4859 MakeMemoryAccessImmediate(opcode_length, type.size_log_2());
4860 if (!this->Validate(this->
pc_ + opcode_length, mem_imm))
return 0;
4863 if (!this->Validate(this->
pc_ + opcode_length, opcode, lane_imm))
return 0;
4867 if (
V8_LIKELY(!CheckStaticallyOutOfBounds(mem_imm.
memory, type.size(),
4872 return opcode_length + mem_imm.
length + lane_imm.
length;
4877 const bool statically_oob =
4878 !base::IsInBounds<uint64_t>(
offset, size, memory->max_memory_size);
4881 SetSucceedingCodeDynamicallyUnreachable();
4883 return statically_oob;
4888 MakeMemoryAccessImmediate(prefix_len, store.size_log_2());
4889 if (!this->Validate(this->
pc_ + prefix_len, imm))
return 0;
4891 auto [
index,
value] = Pop(address_type, store.value_type());
4896 return prefix_len + imm.
length;
4907 uint32_t opcode_length) {
4909 if (!this->Validate(this->
pc_ + opcode_length, opcode, imm))
return 0;
4913 base::VectorOf({input}),
result);
4914 return opcode_length + imm.
length;
4918 uint32_t opcode_length) {
4920 if (!this->Validate(this->
pc_ + opcode_length, opcode, imm))
return 0;
4921 auto [v128, lane_val] = Pop(
kWasmS128, type);
4924 SimdLaneOp, opcode, imm, base::VectorOf({v128, lane_val}),
result);
4925 return opcode_length + imm.
length;
4930 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
4935 return opcode_length + 16;
4941 if (opcode != kExprS128Const) {
4942 this->
DecodeError(
"opcode %s is not allowed in constant expressions",
4943 this->SafeOpcodeNameAt(this->
pc()));
4946 return SimdConstOp(opcode_length);
4951 case kExprF64x2ExtractLane:
4952 return SimdExtractLane(opcode,
kWasmF64, opcode_length);
4953 case kExprF16x8ExtractLane: {
4954 if (!
v8_flags.experimental_wasm_fp16) {
4956 "invalid simd opcode: 0x%x, "
4957 "enable with --experimental-wasm-fp16",
4963 case kExprF32x4ExtractLane:
4964 return SimdExtractLane(opcode,
kWasmF32, opcode_length);
4965 case kExprI64x2ExtractLane:
4966 return SimdExtractLane(opcode,
kWasmI64, opcode_length);
4967 case kExprI32x4ExtractLane:
4968 case kExprI16x8ExtractLaneS:
4969 case kExprI16x8ExtractLaneU:
4970 case kExprI8x16ExtractLaneS:
4971 case kExprI8x16ExtractLaneU:
4972 return SimdExtractLane(opcode,
kWasmI32, opcode_length);
4973 case kExprF64x2ReplaceLane:
4974 return SimdReplaceLane(opcode,
kWasmF64, opcode_length);
4975 case kExprF16x8ReplaceLane: {
4976 if (!
v8_flags.experimental_wasm_fp16) {
4978 "invalid simd opcode: 0x%x, "
4979 "enable with --experimental-wasm-fp16",
4985 case kExprF32x4ReplaceLane:
4986 return SimdReplaceLane(opcode,
kWasmF32, opcode_length);
4987 case kExprI64x2ReplaceLane:
4988 return SimdReplaceLane(opcode,
kWasmI64, opcode_length);
4989 case kExprI32x4ReplaceLane:
4990 case kExprI16x8ReplaceLane:
4991 case kExprI8x16ReplaceLane:
4992 return SimdReplaceLane(opcode,
kWasmI32, opcode_length);
4993 case kExprI8x16Shuffle:
4994 return Simd8x16ShuffleOp(opcode_length);
4995 case kExprS128LoadMem:
4996 return DecodeLoadMem(LoadType::kS128Load, opcode_length);
4997 case kExprS128StoreMem:
4998 return DecodeStoreMem(StoreType::kS128Store, opcode_length);
4999 case kExprS128Load32Zero:
5000 return DecodeLoadTransformMem(LoadType::kI32Load,
5001 LoadTransformationKind::kZeroExtend,
5003 case kExprS128Load64Zero:
5004 return DecodeLoadTransformMem(LoadType::kI64Load,
5005 LoadTransformationKind::kZeroExtend,
5007 case kExprS128Load8Splat:
5008 return DecodeLoadTransformMem(LoadType::kI32Load8S,
5009 LoadTransformationKind::kSplat,
5011 case kExprS128Load16Splat:
5012 return DecodeLoadTransformMem(LoadType::kI32Load16S,
5013 LoadTransformationKind::kSplat,
5015 case kExprS128Load32Splat:
5016 return DecodeLoadTransformMem(
5017 LoadType::kI32Load, LoadTransformationKind::kSplat, opcode_length);
5018 case kExprS128Load64Splat:
5019 return DecodeLoadTransformMem(
5020 LoadType::kI64Load, LoadTransformationKind::kSplat, opcode_length);
5021 case kExprS128Load8x8S:
5022 return DecodeLoadTransformMem(LoadType::kI32Load8S,
5023 LoadTransformationKind::kExtend,
5025 case kExprS128Load8x8U:
5026 return DecodeLoadTransformMem(LoadType::kI32Load8U,
5027 LoadTransformationKind::kExtend,
5029 case kExprS128Load16x4S:
5030 return DecodeLoadTransformMem(LoadType::kI32Load16S,
5031 LoadTransformationKind::kExtend,
5033 case kExprS128Load16x4U:
5034 return DecodeLoadTransformMem(LoadType::kI32Load16U,
5035 LoadTransformationKind::kExtend,
5037 case kExprS128Load32x2S:
5038 return DecodeLoadTransformMem(LoadType::kI64Load32S,
5039 LoadTransformationKind::kExtend,
5041 case kExprS128Load32x2U:
5042 return DecodeLoadTransformMem(LoadType::kI64Load32U,
5043 LoadTransformationKind::kExtend,
5045 case kExprS128Load8Lane: {
5046 return DecodeLoadLane(opcode, LoadType::kI32Load8S, opcode_length);
5048 case kExprS128Load16Lane: {
5049 return DecodeLoadLane(opcode, LoadType::kI32Load16S, opcode_length);
5051 case kExprS128Load32Lane: {
5052 return DecodeLoadLane(opcode, LoadType::kI32Load, opcode_length);
5054 case kExprS128Load64Lane: {
5055 return DecodeLoadLane(opcode, LoadType::kI64Load, opcode_length);
5057 case kExprS128Store8Lane: {
5058 return DecodeStoreLane(opcode, StoreType::kI32Store8, opcode_length);
5060 case kExprS128Store16Lane: {
5061 return DecodeStoreLane(opcode, StoreType::kI32Store16, opcode_length);
5063 case kExprS128Store32Lane: {
5064 return DecodeStoreLane(opcode, StoreType::kI32Store, opcode_length);
5066 case kExprS128Store64Lane: {
5067 return DecodeStoreLane(opcode, StoreType::kI64Store, opcode_length);
5069 case kExprS128Const:
5070 return SimdConstOp(opcode_length);
5071 case kExprF16x8Splat:
5074 case kExprF16x8Sqrt:
5075 case kExprF16x8Ceil:
5076 case kExprF16x8Floor:
5077 case kExprF16x8Trunc:
5078 case kExprF16x8NearestInt:
5091 case kExprF16x8Pmin:
5092 case kExprF16x8Pmax:
5093 case kExprI16x8SConvertF16x8:
5094 case kExprI16x8UConvertF16x8:
5095 case kExprF16x8SConvertI16x8:
5096 case kExprF16x8UConvertI16x8:
5097 case kExprF16x8DemoteF32x4Zero:
5098 case kExprF16x8DemoteF64x2Zero:
5099 case kExprF32x4PromoteLowF16x8:
5100 case kExprF16x8Qfma:
5101 case kExprF16x8Qfms: {
5102 if (!
v8_flags.experimental_wasm_fp16) {
5104 "invalid simd opcode: 0x%x, "
5105 "enable with --experimental-wasm-fp16",
5121 return opcode_length;
5131 bool types_unrelated =
5132 !
IsSubtypeOf(ValueType::Ref(expected_type), obj.type, this->module_) &&
5133 !
IsSubtypeOf(obj.type, ValueType::RefNull(expected_type),
5140 return (types_unrelated &&
5153 return IsSubtypeOf(obj.type, ValueType::RefNull(type), this->module_);
5156#define NON_CONST_ONLY \
5157 if constexpr (decoding_mode == kConstantExpression) { \
5158 this->DecodeError("opcode %s is not allowed in constant expressions", \
5159 this->SafeOpcodeNameAt(this->pc())); \
5169 return Pop(desc_type);
5178 case kExprStructNew: {
5180 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
5184 Push(ValueType::Ref(imm.
heap_type()).AsExactIfProposalEnabled());
5186 args.data(), value);
5187 return opcode_length + imm.
length;
5189 case kExprStructNewDefault: {
5191 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
5192 if (ValidationTag::validate) {
5197 "%s: struct type %d has field %d of non-defaultable type %s",
5198 WasmOpcodes::OpcodeName(opcode), imm.
index.
index,
i,
5199 ftype.
name().c_str());
5206 Push(ValueType::Ref(imm.
heap_type()).AsExactIfProposalEnabled());
5209 return opcode_length + imm.
length;
5211 case kExprStructGet: {
5214 if (!this->Validate(this->
pc_ + opcode_length, field))
return 0;
5216 field.struct_imm.struct_type->field(field.field_imm.index);
5219 "struct.get: Immediate field %d of type %d has packed type %s. "
5220 "Use struct.get_s or struct.get_u instead.",
5221 field.field_imm.index, field.struct_imm.index.index,
5222 field_type.
name().c_str());
5226 Pop(ValueType::RefNull(field.struct_imm.heap_type()));
5227 Value* value = Push(field_type);
5230 return opcode_length + field.length;
5232 case kExprStructGetU:
5233 case kExprStructGetS: {
5236 if (!this->Validate(this->
pc_ + opcode_length, field))
return 0;
5238 field.struct_imm.struct_type->field(field.field_imm.index);
5241 "%s: Immediate field %d of type %d has non-packed type %s. Use "
5242 "struct.get instead.",
5243 WasmOpcodes::OpcodeName(opcode), field.field_imm.index,
5244 field.struct_imm.index, field_type.
name().c_str());
5248 Pop(ValueType::RefNull(field.struct_imm.heap_type()));
5251 opcode == kExprStructGetS, value);
5252 return opcode_length + field.length;
5254 case kExprStructSet: {
5257 if (!this->Validate(this->
pc_ + opcode_length, field))
return 0;
5258 const StructType* struct_type = field.struct_imm.struct_type;
5260 this->
DecodeError(
"struct.set: Field %d of type %d is immutable.",
5261 field.field_imm.index,
5262 field.struct_imm.index.index);
5265 auto [struct_obj, field_value] =
5266 Pop(ValueType::RefNull(field.struct_imm.heap_type()),
5270 return opcode_length + field.length;
5272 case kExprArrayNew: {
5274 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
5275 auto [initial_value,
length] =
5278 Push(ValueType::Ref(imm.
heap_type()).AsExactIfProposalEnabled());
5281 return opcode_length + imm.
length;
5283 case kExprArrayNewDefault: {
5285 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
5288 "%s: array type %d has non-defaultable element type %s",
5289 WasmOpcodes::OpcodeName(opcode), imm.
index.
index,
5290 imm.
array_type->element_type().name().c_str());
5295 Push(ValueType::Ref(imm.
heap_type()).AsExactIfProposalEnabled());
5297 return opcode_length + imm.
length;
5299 case kExprArrayNewData: {
5304 if (!this->Validate(this->
pc_ + opcode_length, array_imm))
return 0;
5305 ValueType element_type = array_imm.array_type->element_type();
5308 "array.new_data can only be used with numeric-type arrays, found "
5309 "array type #%d instead",
5313 const uint8_t* data_index_pc =
5314 this->
pc_ + opcode_length + array_imm.length;
5317 if (!this->ValidateDataSegment(data_index_pc, data_segment))
return 0;
5321 Value* array = Push(
5322 ValueType::Ref(array_imm.heap_type()).AsExactIfProposalEnabled());
5324 data_segment,
offset, length, array);
5325 return opcode_length + array_imm.length + data_segment.
length;
5327 case kExprArrayNewElem: {
5332 if (!this->Validate(this->
pc_ + opcode_length, array_imm))
return 0;
5333 ValueType element_type = array_imm.array_type->element_type();
5336 "array.new_elem can only be used with reference-type arrays, "
5337 "found array type #%d instead",
5341 const uint8_t* elem_index_pc =
5342 this->
pc_ + opcode_length + array_imm.length;
5343 IndexImmediate elem_segment(
this, elem_index_pc,
"element segment",
5345 if (!this->ValidateElementSegment(elem_index_pc, elem_segment)) {
5354 "array.new_elem: segment type %s is not a subtype of array "
5356 elem_segment_type.
name().c_str(), element_type.
name().c_str());
5361 Value* array = Push(
5362 ValueType::Ref(array_imm.heap_type()).AsExactIfProposalEnabled());
5364 elem_segment,
offset, length, array);
5365 return opcode_length + array_imm.length + elem_segment.
length;
5367 case kExprArrayInitData: {
5372 if (!this->Validate(this->
pc_ + opcode_length, array_imm))
return 0;
5373 if (!array_imm.array_type->mutability()) {
5375 "array.init_data can only be used with mutable arrays, found "
5376 "array type #%d instead",
5380 ValueType element_type = array_imm.array_type->element_type();
5383 "array.init_data can only be used with numeric-type arrays, "
5384 "found array type #%d instead",
5388 const uint8_t* data_index_pc =
5389 this->
pc_ + opcode_length + array_imm.length;
5392 if (!this->ValidateDataSegment(data_index_pc, data_segment))
return 0;
5394 auto [array, array_index, data_offset,
length] =
5398 data_segment, array, array_index,
5399 data_offset, length);
5400 return opcode_length + array_imm.length + data_segment.
length;
5402 case kExprArrayInitElem: {
5407 if (!this->Validate(this->
pc_ + opcode_length, array_imm))
return 0;
5408 if (!array_imm.array_type->mutability()) {
5410 "array.init_elem can only be used with mutable arrays, found "
5411 "array type #%d instead",
5415 ValueType element_type = array_imm.array_type->element_type();
5418 "array.init_elem can only be used with reference-type arrays, "
5419 "found array type #%d instead",
5423 const uint8_t* elem_index_pc =
5424 this->
pc_ + opcode_length + array_imm.length;
5425 IndexImmediate elem_segment(
this, elem_index_pc,
"element segment",
5427 if (!this->ValidateElementSegment(elem_index_pc, elem_segment)) {
5434 "array.init_elem: segment type %s is not a subtype of array "
5436 segment_type.
name().c_str(), element_type.
name().c_str());
5440 auto [array, array_index, elem_offset,
length] =
5444 elem_segment, array, array_index,
5445 elem_offset, length);
5446 return opcode_length + array_imm.length + elem_segment.
length;
5448 case kExprArrayGetS:
5449 case kExprArrayGetU: {
5452 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
5453 if (!
VALIDATE(imm.array_type->element_type().is_packed())) {
5455 "%s: Immediate array type %d has non-packed type %s. Use "
5456 "array.get instead.",
5457 WasmOpcodes::OpcodeName(opcode), imm.index,
5458 imm.array_type->element_type().name().c_str());
5461 auto [array_obj,
index] =
5462 Pop(ValueType::RefNull(imm.heap_type()),
kWasmI32);
5463 Value* value = Push(imm.array_type->element_type().Unpacked());
5465 opcode == kExprArrayGetS, value);
5466 return opcode_length + imm.length;
5468 case kExprArrayGet: {
5471 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
5472 if (!
VALIDATE(!imm.array_type->element_type().is_packed())) {
5474 "array.get: Immediate array type %d has packed type %s. Use "
5475 "array.get_s or array.get_u instead.",
5476 imm.index, imm.array_type->element_type().name().c_str());
5479 auto [array_obj,
index] =
5480 Pop(ValueType::RefNull(imm.heap_type()),
kWasmI32);
5481 Value* value = Push(imm.array_type->element_type());
5484 return opcode_length + imm.length;
5486 case kExprArraySet: {
5489 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
5490 if (!
VALIDATE(imm.array_type->mutability())) {
5491 this->
DecodeError(
"array.set: immediate array type %d is immutable",
5496 Pop(ValueType::RefNull(imm.heap_type()),
kWasmI32,
5497 imm.array_type->element_type().Unpacked());
5500 return opcode_length + imm.length;
5502 case kExprArrayLen: {
5507 return opcode_length;
5509 case kExprArrayCopy: {
5512 if (!this->Validate(this->
pc_ + opcode_length, dst_imm))
return 0;
5513 if (!
VALIDATE(dst_imm.array_type->mutability())) {
5515 "array.copy: immediate destination array type #%d is immutable",
5516 dst_imm.index.index);
5520 this, this->
pc_ + opcode_length + dst_imm.length, validate);
5521 if (!this->Validate(this->
pc_ + opcode_length + dst_imm.length,
5526 dst_imm.array_type->element_type(), this->module_)) {
5528 "array.copy: source array's #%d element type is not a subtype of "
5529 "destination array's #%d element type",
5533 auto [dst, dst_index, src, src_index,
length] =
5534 Pop(ValueType::RefNull(dst_imm.heap_type()),
kWasmI32,
5537 src_index, src_imm, length);
5538 return opcode_length + dst_imm.length + src_imm.
length;
5540 case kExprArrayFill: {
5544 if (!this->Validate(this->
pc_ + opcode_length, array_imm))
return 0;
5545 if (!
VALIDATE(array_imm.array_type->mutability())) {
5546 this->
DecodeError(
"array.init: immediate array type #%d is immutable",
5547 array_imm.index.index);
5552 Pop(ValueType::RefNull(array_imm.heap_type()),
kWasmI32,
5553 array_imm.array_type->element_type().Unpacked(),
kWasmI32);
5556 return opcode_length + array_imm.length;
5558 case kExprArrayNewFixed: {
5561 if (!this->Validate(this->
pc_ + opcode_length, array_imm))
return 0;
5563 this->
pc_ + opcode_length + array_imm.
length,
5564 "array.new_fixed length", validate);
5565 uint32_t elem_count = length_imm.
index;
5568 "Requested length %u for array.new_fixed too large, maximum is "
5574 std::vector<ValueType> element_types(elem_count,
5576 FunctionSig element_sig(0, elem_count, element_types.data());
5579 ValueType::Ref(array_imm.
heap_type()).AsExactIfProposalEnabled());
5581 elements.data(),
result);
5582 return opcode_length + array_imm.
length + length_imm.
length;
5588 return opcode_length;
5590 case kExprI31GetS: {
5595 return opcode_length;
5597 case kExprI31GetU: {
5602 return opcode_length;
5604 case kExprRefGetDesc: {
5610 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
5612 if (!
VALIDATE(type.has_descriptor())) {
5614 this->
pc_ + opcode_length,
5615 "Invalid type for ref.get_desc: type %s has no custom descriptor",
5622 .AsExact(ref.type.exactness()));
5624 return opcode_length + imm.
length;
5626 case kExprRefCastDesc:
5627 case kExprRefCastDescNull: {
5632 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
5635 this->
pc_ + opcode_length,
5636 "ref.cast_desc: immediate type must have an index, but was %s",
5644 this->
pc_ + opcode_length,
5645 "ref.cast_desc: immediate type %s must have a descriptor",
5650 ValueType::RefNull(this->
module_->heap_type(expected_desc_index))
5652 Value desc = Pop(expected_desc_type);
5657 ValueType expected_obj_type = ValueType::Generic(
5659 Value obj = Pop(expected_obj_type);
5662 ValueType target_type = ValueType::RefMaybeNull(
5664 Value* value = Push(target_type);
5671 return opcode_length + imm.
length;
5674 case kExprRefCastNull: {
5678 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
5679 opcode_length += imm.length;
5685 if (!
VALIDATE((obj.type.is_object_reference() &&
5688 obj.type.is_bottom())) {
5690 "Invalid types for %s: %s of type %s has to "
5691 "be in the same reference type hierarchy as %s",
5692 WasmOpcodes::OpcodeName(opcode),
5693 SafeOpcodeNameAt(obj.pc()), obj.type.name().c_str(),
5694 ValueType::Ref(target_type).name().c_str());
5706 "Invalid type for %s: string views are not classifiable",
5707 WasmOpcodes::OpcodeName(opcode));
5712 Value* value = Push(ValueType::RefMaybeNull(
5714 if (current_code_reachable_and_ok_) {
5717 if (
V8_UNLIKELY(TypeCheckAlwaysSucceeds(obj, target_type))) {
5723 }
else if (
V8_UNLIKELY(TypeCheckAlwaysFails(obj, target_type,
5733 SetSucceedingCodeDynamicallyUnreachable();
5744 return opcode_length;
5746 case kExprRefTestNull:
5747 case kExprRefTest: {
5751 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
5752 opcode_length += imm.length;
5758 if (!
VALIDATE((obj.type.is_object_reference() &&
5761 obj.type.is_bottom())) {
5763 "Invalid types for %s: %s of type %s has to "
5764 "be in the same reference type hierarchy as %s",
5765 WasmOpcodes::OpcodeName(opcode),
5766 SafeOpcodeNameAt(obj.pc()), obj.type.name().c_str(),
5767 ValueType::Ref(target_type).name().c_str());
5779 "Invalid type for %s: string views are not classifiable",
5780 WasmOpcodes::OpcodeName(opcode));
5784 if (
V8_LIKELY(current_code_reachable_and_ok_)) {
5787 if (
V8_UNLIKELY(TypeCheckAlwaysSucceeds(obj, target_type))) {
5797 }
else if (
V8_UNLIKELY(TypeCheckAlwaysFails(obj, target_type,
5802 if (imm.type.is_index()) {
5810 return opcode_length;
5812 case kExprRefCastNop: {
5817 "Invalid opcode 0xfb4c (enable with "
5818 "--experimental-wasm-ref-cast-nop)");
5823 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
5824 opcode_length += imm.
length;
5827 if (!
VALIDATE((obj.type.is_object_reference() &&
5830 obj.type.is_bottom())) {
5832 "Invalid types for %s: %s of type %s has to "
5833 "be in the same reference type hierarchy as %s",
5834 WasmOpcodes::OpcodeName(opcode),
5835 SafeOpcodeNameAt(obj.pc()), obj.type.name().c_str(),
5836 ValueType::Ref(target_type).name().c_str());
5839 Value* value = Push(ValueType::Ref(target_type));
5841 return opcode_length;
5844 case kExprBrOnCastFail: {
5846 return ParseBrOnCast(opcode, opcode_length);
5848 case kExprBrOnCastDesc:
5849 case kExprBrOnCastDescFail: {
5852 return ParseBrOnCast(opcode, opcode_length);
5854 case kExprAnyConvertExtern: {
5856 ValueType intern_type = ValueType::RefMaybeNull(
5858 Value* intern_val = Push(intern_type);
5860 extern_val, intern_val);
5861 return opcode_length;
5863 case kExprExternConvertAny: {
5865 ValueType extern_type = ValueType::RefMaybeNull(
5867 Value* extern_val = Push(extern_type);
5870 return opcode_length;
5873 this->
DecodeError(
"invalid gc opcode: %x", opcode);
5886 if (!this->Validate(this->
pc_ + pc_offset, branch_depth,
control_.size())) {
5893 if (!this->Validate(this->
pc_ + pc_offset, src_imm))
return 0;
5895 ValueType src_type = ValueType::RefMaybeNull(
5900 if (!this->Validate(target_imm_pc, target_imm))
return 0;
5903 ValueType target_type = ValueType::RefMaybeNull(
5907 this->
DecodeError(
"invalid types for %s: %s is not a subtype of %s",
5908 WasmOpcodes::OpcodeName(opcode),
5909 target_type.
name().c_str(), src_type.
name().c_str());
5914 if (opcode == kExprBrOnCastDesc || opcode == kExprBrOnCastDescFail) {
5917 target_imm_pc,
"%s: target type must have an index, but was %s",
5918 WasmOpcodes::OpcodeName(opcode), target_imm.
type.
name().c_str());
5925 target_imm_pc,
"%s: target type %s must have a descriptor",
5926 WasmOpcodes::OpcodeName(opcode), target_imm.
type.
name().c_str());
5930 ValueType::RefNull(this->
module_->heap_type(target_desc_index))
5932 descriptor = Pop(desc_type);
5935 Value obj = Pop(src_type);
5938 (obj.type.is_object_reference() &&
5941 obj.type.is_bottom())) {
5943 "invalid types for %s: %s of type %s has to "
5944 "be in the same reference type hierarchy as %s",
5945 WasmOpcodes::OpcodeName(opcode),
5946 SafeOpcodeNameAt(obj.pc()), obj.type.name().c_str(),
5947 target_type.
name().c_str());
5952 if (c->br_merge()->arity == 0) {
5953 this->
DecodeError(
"%s must target a branch of arity at least 1",
5954 WasmOpcodes::OpcodeName(opcode));
5958 if (opcode == kExprBrOnCast || opcode == kExprBrOnCastDesc) {
5959 Value* value_on_branch = Push(target_type);
5961 (TypeCheckBranch<PushBranchValues::kYes, RewriteStackTypes::kYes>(
5965 if (
V8_LIKELY(current_code_reachable_and_ok_)) {
5969 TypeCheckAlwaysSucceeds(obj, target_type.
heap_type()))) {
5974 branch_depth.
depth,
false);
5980 SetSucceedingCodeDynamicallyUnreachable();
5982 c->br_merge()->reached =
true;
5985 if (opcode == kExprBrOnCastDesc) {
5995 c->br_merge()->reached =
true;
5999 Drop(*value_on_branch);
6006 bool fallthrough_nullable = flags.src_is_null && !flags.res_is_null;
6007 stack_value(1)->type = ValueType::RefMaybeNull(
6014 DCHECK(opcode == kExprBrOnCastFail || opcode == kExprBrOnCastDescFail);
6018 Push(flags.res_is_null ? src_type.
AsNonNull() : src_type);
6022 (TypeCheckBranch<PushBranchValues::kYes, RewriteStackTypes::kYes>(
6027 Value result_on_fallthrough = CreateValue(target_type);
6028 if (
V8_LIKELY(current_code_reachable_and_ok_)) {
6039 SetSucceedingCodeDynamicallyUnreachable();
6040 c->br_merge()->reached =
true;
6042 TypeCheckAlwaysSucceeds(obj, target_type.
heap_type()))) {
6046 &result_on_fallthrough);
6047 c->br_merge()->reached =
true;
6051 result_on_fallthrough = obj;
6054 if (opcode == kExprBrOnCastDescFail) {
6056 &result_on_fallthrough, branch_depth.
depth,
6060 &result_on_fallthrough, branch_depth.
depth,
6064 &result_on_fallthrough, branch_depth.
depth,
6067 c->br_merge()->reached =
true;
6072 Push(result_on_fallthrough);
6078 uint32_t opcode_length) {
6080 bool null_on_invalid = variant == unibrow::Utf8Variant::kUtf8NoTrap;
6082 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6089 return opcode_length + imm.
length;
6093 uint32_t opcode_length) {
6098 return opcode_length;
6102 uint32_t opcode_length) {
6105 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6106 ValueType addr_type = MemoryAddressType(imm.memory);
6111 return opcode_length + imm.length;
6115 uint32_t opcode_length) {
6118 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6119 ValueType addr_type = MemoryAddressType(imm.memory);
6120 auto [view, addr,
pos, bytes] =
6125 addr,
pos, bytes, next_pos, bytes_out);
6126 return opcode_length + imm.length;
6130 uint32_t opcode_length) {
6134 Value array = PopPackedArray(0,
kWasmI8, WasmArrayAccess::kRead);
6135 bool null_on_invalid = variant == unibrow::Utf8Variant::kUtf8NoTrap;
6140 return opcode_length;
6144 uint32_t opcode_length) {
6147 Value array = PopPackedArray(1,
kWasmI8, WasmArrayAccess::kWrite);
6152 return opcode_length;
6158 if (!
VALIDATE((opcode >> 8) == kGCPrefix)) {
6159 this->
DecodeError(
"invalid stringref opcode: %x", opcode);
6164 case kExprStringNewUtf8:
6165 return DecodeStringNewWtf8(unibrow::Utf8Variant::kUtf8, opcode_length);
6166 case kExprStringNewUtf8Try:
6167 return DecodeStringNewWtf8(unibrow::Utf8Variant::kUtf8NoTrap,
6169 case kExprStringNewLossyUtf8:
6172 case kExprStringNewWtf8:
6173 return DecodeStringNewWtf8(unibrow::Utf8Variant::kWtf8, opcode_length);
6174 case kExprStringNewWtf16: {
6177 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6178 ValueType addr_type = MemoryAddressType(imm.memory);
6183 return opcode_length + imm.length;
6185 case kExprStringConst: {
6187 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6190 return opcode_length + imm.
length;
6192 case kExprStringMeasureUtf8:
6193 return DecodeStringMeasureWtf8(unibrow::Utf8Variant::kUtf8,
6195 case kExprStringMeasureWtf8:
6196 return DecodeStringMeasureWtf8(unibrow::Utf8Variant::kWtf8,
6198 case kExprStringMeasureWtf16: {
6203 return opcode_length;
6205 case kExprStringEncodeUtf8:
6206 return DecodeStringEncodeWtf8(unibrow::Utf8Variant::kUtf8,
6208 case kExprStringEncodeLossyUtf8:
6211 case kExprStringEncodeWtf8:
6212 return DecodeStringEncodeWtf8(unibrow::Utf8Variant::kWtf8,
6214 case kExprStringEncodeWtf16: {
6217 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6218 ValueType addr_type = MemoryAddressType(imm.memory);
6223 return opcode_length + imm.length;
6225 case kExprStringConcat: {
6230 return opcode_length;
6232 case kExprStringEq: {
6237 return opcode_length;
6239 case kExprStringIsUSVSequence: {
6244 return opcode_length;
6246 case kExprStringAsWtf8: {
6251 return opcode_length;
6253 case kExprStringViewWtf8Advance: {
6259 return opcode_length;
6261 case kExprStringViewWtf8EncodeUtf8:
6262 return DecodeStringViewWtf8Encode(unibrow::Utf8Variant::kUtf8,
6264 case kExprStringViewWtf8EncodeLossyUtf8:
6267 case kExprStringViewWtf8EncodeWtf8:
6268 return DecodeStringViewWtf8Encode(unibrow::Utf8Variant::kWtf8,
6270 case kExprStringViewWtf8Slice: {
6276 return opcode_length;
6278 case kExprStringAsWtf16: {
6283 return opcode_length;
6285 case kExprStringViewWtf16Length: {
6290 return opcode_length;
6292 case kExprStringViewWtf16GetCodeunit: {
6298 return opcode_length;
6300 case kExprStringViewWtf16Encode: {
6303 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6304 ValueType addr_type = MemoryAddressType(imm.memory);
6305 auto [view, addr,
pos, codeunits] =
6310 return opcode_length + imm.length;
6312 case kExprStringViewWtf16Slice: {
6318 return opcode_length;
6320 case kExprStringAsIter: {
6325 return opcode_length;
6327 case kExprStringViewIterNext: {
6332 return opcode_length;
6334 case kExprStringViewIterAdvance: {
6340 return opcode_length;
6342 case kExprStringViewIterRewind: {
6348 return opcode_length;
6350 case kExprStringViewIterSlice: {
6356 return opcode_length;
6358 case kExprStringNewUtf8Array:
6359 return DecodeStringNewWtf8Array(unibrow::Utf8Variant::kUtf8,
6361 case kExprStringNewUtf8ArrayTry:
6362 return DecodeStringNewWtf8Array(unibrow::Utf8Variant::kUtf8NoTrap,
6364 case kExprStringNewLossyUtf8Array:
6367 case kExprStringNewWtf8Array:
6368 return DecodeStringNewWtf8Array(unibrow::Utf8Variant::kWtf8,
6370 case kExprStringNewWtf16Array: {
6374 Value array = PopPackedArray(0,
kWasmI16, WasmArrayAccess::kRead);
6378 return opcode_length;
6380 case kExprStringEncodeUtf8Array:
6381 return DecodeStringEncodeWtf8Array(unibrow::Utf8Variant::kUtf8,
6383 case kExprStringEncodeLossyUtf8Array:
6386 case kExprStringEncodeWtf8Array:
6387 return DecodeStringEncodeWtf8Array(unibrow::Utf8Variant::kWtf8,
6389 case kExprStringEncodeWtf16Array: {
6392 Value array = PopPackedArray(1,
kWasmI16, WasmArrayAccess::kWrite);
6397 return opcode_length;
6399 case kExprStringCompare: {
6404 return opcode_length;
6406 case kExprStringFromCodePoint: {
6412 return opcode_length;
6414 case kExprStringHash: {
6419 return opcode_length;
6422 this->
DecodeError(
"invalid stringref opcode: %x", opcode);
6426#undef NON_CONST_ONLY
6430 if (!
VALIDATE((opcode >> 8) == kAtomicPrefix)) {
6431 this->
DecodeError(
"invalid atomic opcode: 0x%x", opcode);
6437#define CASE_ATOMIC_STORE_OP(Name, Type) \
6438 case kExpr##Name: { \
6439 memtype = MachineType::Type(); \
6443#undef CASE_ATOMIC_STORE_OP
6444#define CASE_ATOMIC_OP(Name, Type) \
6445 case kExpr##Name: { \
6446 memtype = MachineType::Type(); \
6450#undef CASE_ATOMIC_OP
6451 case kExprAtomicFence: {
6452 uint8_t zero = this->
template read_u8<ValidationTag>(
6453 this->
pc_ + opcode_length,
"zero");
6456 "invalid atomic operand");
6460 return 1 + opcode_length;
6465 this->
DecodeError(
"invalid atomic opcode: 0x%x", opcode);
6469 const uint32_t element_size_log2 =
6472 MakeMemoryAccessImmediate(opcode_length, element_size_log2);
6473 if (!this->Validate(this->
pc_ + opcode_length, imm))
return false;
6476 "invalid alignment for atomic operation; expected "
6477 "alignment is %u, actual alignment is %u",
6482 WasmOpcodes::SignatureForAtomicOp(opcode, imm.
memory->is_memory64());
6492 return opcode_length + imm.
length;
6499 if (!
VALIDATE((opcode >> 8) == kNumericPrefix)) {
6500 this->
DecodeError(
"invalid numeric opcode: 0x%x", opcode);
6506 case kExprI32SConvertSatF32:
6507 case kExprI32UConvertSatF32:
6508 case kExprI32SConvertSatF64:
6509 case kExprI32UConvertSatF64:
6510 case kExprI64SConvertSatF32:
6511 case kExprI64UConvertSatF32:
6512 case kExprI64SConvertSatF64:
6513 case kExprI64UConvertSatF64: {
6514 BuildSimpleOperator(opcode,
sig);
6515 return opcode_length;
6517 case kExprMemoryInit: {
6519 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6523 return opcode_length + imm.
length;
6525 case kExprDataDrop: {
6527 "data segment index", validate);
6528 if (!this->ValidateDataSegment(this->
pc_ + opcode_length, imm)) {
6532 return opcode_length + imm.
length;
6534 case kExprMemoryCopy: {
6536 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6542 auto [dst, src,
size] = Pop(dst_type, src_type, size_type);
6544 return opcode_length + imm.
length;
6546 case kExprMemoryFill: {
6548 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6552 return opcode_length + imm.
length;
6554 case kExprTableInit: {
6556 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6560 return opcode_length + imm.
length;
6562 case kExprElemDrop: {
6564 "element segment index", validate);
6565 if (!this->ValidateElementSegment(this->
pc_ + opcode_length, imm)) {
6569 return opcode_length + imm.
length;
6571 case kExprTableCopy: {
6573 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6579 auto [dst, src,
size] = Pop(dst_type, src_type, size_type);
6581 return opcode_length + imm.
length;
6583 case kExprTableGrow: {
6585 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6587 auto [
value, delta] = Pop(imm.
table->type, table_address_type);
6591 return opcode_length + imm.
length;
6593 case kExprTableSize: {
6595 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6598 return opcode_length + imm.
length;
6600 case kExprTableFill: {
6602 if (!this->Validate(this->
pc_ + opcode_length, imm))
return 0;
6605 Pop(table_address_type, imm.
table->type, table_address_type);
6607 return opcode_length + imm.
length;
6609 case kExprF32LoadMemF16: {
6610 if (!
v8_flags.experimental_wasm_fp16) {
6612 "invalid numeric opcode: 0x%x, "
6613 "enable with --experimental-wasm-fp16",
6617 return DecodeLoadMem(LoadType::kF32LoadF16, 2);
6619 case kExprF32StoreMemF16: {
6620 if (!
v8_flags.experimental_wasm_fp16) {
6622 "invalid numeric opcode: 0x%x, "
6623 "enable with --experimental-wasm-fp16",
6627 return DecodeStoreMem(StoreType::kF32StoreF16, 2);
6630 this->
DecodeError(
"invalid numeric opcode: 0x%x", opcode);
6636 if ((opcode >> 8) != kAsmJsPrefix) {
6637 this->
DecodeError(
"Invalid opcode: 0x%x", opcode);
6642#define ASMJS_CASE(Op, ...) case kExpr##Op:
6649 const FunctionSig* asmJsSig = WasmOpcodes::AsmjsSignature(opcode);
6651 BuildSimpleOperator(opcode, asmJsSig);
6652 return opcode_length;
6657 this->
DecodeError(
"Invalid opcode: 0x%x", opcode);
6666 this->
DecodeError(value.pc(),
"%s does not have a shared type",
6667 SafeOpcodeNameAt(value.pc()));
6674 return &stack_.
back();
6682 DCHECK(merge == &c->start_merge || merge == &c->end_merge);
6684 if (merge->
arity == 1) {
6690 for (uint32_t
i = 0;
i < merge->
arity;
i++) {
6699 for (
Value& value : values) Push(value);
6703 size_t return_count =
sig->return_count();
6705 for (
size_t i = 0;
i < return_count; ++
i) {
6706 Push(
sig->GetReturn(
i));
6708 return stack_.
end() - return_count;
6715 const char* expected) {
6716 this->
DecodeError(val.pc(),
"%s[%d] expected %s, found %s of type %s",
6717 SafeOpcodeNameAt(this->
pc_), index, expected,
6718 SafeOpcodeNameAt(val.pc()), val.type.name().c_str());
6722 std::string expected) {
6723 PopTypeError(index, val, expected.c_str());
6728 PopTypeError(index, val, (
"type " + expected.
name()).c_str());
6737 "not enough arguments on the stack for %s (need %d, got %d)",
6738 SafeOpcodeNameAt(this->
pc_), needed, actual);
6742 Value value = Pop();
6743 ValidateStackValue(index, value, expected);
6751 PopTypeError(index, value, expected);
6757 uint32_t limit =
control_.back().stack_depth;
6761 NotEnoughArgumentsError(1, 0);
6763 return UnreachableValue(this->
pc_);
6767 return top_of_stack;
6771 Value value = Peek(depth);
6772 ValidateStackValue(index, value, expected);
6778 uint32_t limit =
control_.back().stack_depth;
6783 NotEnoughArgumentsError(depth + 1, stack_.
size() - limit);
6785 return UnreachableValue(this->
pc_);
6788 return *(stack_.
end() - depth - 1);
6798 requires((std::is_same_v<ValueType, ValueTypes> ||
6799 std::is_base_of_v<IndependentValueType, ValueTypes>) &&
6804 constexpr int kCount =
sizeof...(ValueTypes);
6805 EnsureStackArguments(kCount);
6811 auto ValidateAndGetNextArg = [
this,
i = 0](
ValueType type)
mutable {
6812 ValidateStackValue(
i, stack_.
end()[
i], type);
6813 return stack_.
end()[
i++];
6815 return {ValidateAndGetNextArg(expected_types)...};
6820 Value array = Pop();
6821 if (array.type.is_bottom()) {
6823 DCHECK(!current_code_reachable_and_ok_);
6830 if (array.type.is_reference_to(HeapType::kNone))
return array;
6831 if (
VALIDATE(array.type.is_object_reference() && array.type.has_index())) {
6836 (access == WasmArrayAccess::kRead ||
6842 PopTypeError(operand_index, array,
6843 (std::string(
"array of ") +
6844 (access == WasmArrayAccess::kWrite ?
"mutable " :
"") +
6845 expected_element_type.
name())
6854 uint32_t limit =
control_.back().stack_depth;
6857 count = std::min(
count,
static_cast<int>(stack_.
size() - limit));
6866 kNonStrictCounting =
false,
6867 kStrictCounting =
true
6898 template <StackElementsCountMode strict_count,
6899 PushBranchValues push_branch_values, MergeType merge_type,
6900 RewriteStackTypes rewrite_types>
6902 uint32_t arity = merge->
arity;
6903 uint32_t actual = stack_.
size() -
control_.back().stack_depth;
6905 if (arity == 0 && (!strict_count || actual == 0))
return true;
6908 if (arity == 1 && (strict_count ? actual == arity : actual >= arity)) {
6909 if (stack_.
back().type == merge->
vals.
first.type)
return true;
6911 return TypeCheckStackAgainstMerge_Slow<strict_count, push_branch_values,
6912 merge_type, rewrite_types>(merge);
6916 template <StackElementsCountMode strict_count,
6917 PushBranchValues push_branch_values, MergeType merge_type,
6918 RewriteStackTypes rewrite_types>
6921 constexpr const char* merge_description =
6922 merge_type == kBranchMerge ?
"branch"
6923 : merge_type == kReturnMerge ?
"return"
6924 : merge_type == kInitExprMerge ?
"constant expression"
6926 uint32_t arity = merge->
arity;
6927 uint32_t actual = stack_.
size() -
control_.back().stack_depth;
6932 if (
V8_UNLIKELY(strict_count ? actual != arity : actual < arity)) {
6933 this->
DecodeError(
"expected %u elements on the stack for %s, found %u",
6934 arity, merge_description, actual);
6938 Value* stack_values = stack_.
end() - arity;
6939 for (uint32_t
i = 0;
i < arity; ++
i) {
6940 Value& val = stack_values[
i];
6941 Value& old = (*merge)[
i];
6942 if (!
IsSubtypeOf(val.type, old.type, this->module_)) {
6943 this->
DecodeError(
"type error in %s[%u] (expected %s, got %s)",
6944 merge_description,
i, old.
type.name().c_str(),
6945 val.type.name().c_str());
6948 if constexpr (
static_cast<bool>(rewrite_types)) {
6950 val.type = old.type;
6956 if (
V8_UNLIKELY(strict_count && actual > arity)) {
6957 this->
DecodeError(
"expected %u elements on the stack for %s, found %u",
6958 arity, merge_description, actual);
6962 for (
int i = arity - 1, depth = 0;
i >= 0; --
i, ++depth) {
6963 Peek(depth,
i, (*merge)[
i].type);
6965 if constexpr (
static_cast<bool>(push_branch_values)) {
6966 uint32_t inserted_value_count =
6967 static_cast<uint32_t
>(EnsureStackArguments(arity));
6968 if (inserted_value_count > 0) {
6973 Value* stack_base = stack_value(arity);
6974 for (uint32_t
i = 0;
i < std::min(arity, inserted_value_count);
i++) {
6976 stack_base[
i].type = (*merge)[
i].type;
6984 template <StackElementsCountMode strict_count, MergeType merge_type>
6987 (TypeCheckStackAgainstMerge<strict_count, PushBranchValues::kNo,
6988 merge_type, RewriteStackTypes::kNo>(
6993 stack_.
size() >= this->sig_->return_count());
7000 return static_cast<int>(ptr - this->
start_);
7006 if (!
VALIDATE(TypeCheckFallThru()))
return;
7008 if (c->reachable()) c->end_merge.reached =
true;
7012 DCHECK(c->is_onearmed_if());
7013 if (c->end_merge.arity != c->start_merge.arity) {
7015 "start-arity and end-arity of one-armed if must match");
7018 for (uint32_t
i = 0;
i < c->start_merge.arity; ++
i) {
7022 this->
DecodeError(
"type error in merge[%u] (expected %s, got %s)",
i,
7031 return TypeCheckStackAgainstMerge<kStrictCounting, PushBranchValues::kYes,
7033 RewriteStackTypes::kNo>(
7044 template <PushBranchValues push_branch_values,
7045 RewriteStackTypes rewrite_types>
7047 return TypeCheckStackAgainstMerge<kNonStrictCounting, push_branch_values,
7048 kBranchMerge, rewrite_types>(
7053 this->end_ = this->
pc_;
7054 this->current_code_reachable_and_ok_ =
false;
7057 interface().OnFirstError(
this);
7063 return BuildSimpleOperator(opcode,
sig);
7068 if (
sig->parameter_count() == 1) {
7071 return BuildSimpleOperator(opcode,
sig->GetReturn(0),
sig->GetParam(0));
7075 return BuildSimpleOperator(opcode, ret,
sig->GetParam(0),
7083 Value val = Pop(arg_type);
7084 Value* ret = Push(return_type);
7091 auto [lval, rval] = Pop(lhs_type, rhs_type);
7097#define DEFINE_SIMPLE_SIG_OPERATOR(sig, ...) \
7098 int BuildSimpleOperator_##sig(WasmOpcode opcode) { \
7099 return BuildSimpleOperator(opcode, __VA_ARGS__); \
7102#undef DEFINE_SIMPLE_SIG_OPERATOR
7104 static constexpr ValidationTag validate = {};
7116#define DEFINE_EMPTY_CALLBACK(name, ...) \
7117 void name(FullDecoder* decoder, ##__VA_ARGS__) {}
7119#undef DEFINE_EMPTY_CALLBACK
7122#undef CALL_INTERFACE_IF_OK_AND_REACHABLE
7123#undef CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE
7125#undef TRACE_INST_FORMAT
7127#undef CHECK_PROTOTYPE_OPCODE
constexpr MachineRepresentation representation() const
constexpr uint8_t MemSize() const
size_t return_count() const
T GetParam(size_t index) const
T GetReturn(size_t index=0) const
base::Vector< const T > returns() const
size_t parameter_count() const
base::Vector< const T > all() const
void DeleteArray(T *pointer, size_t length)
ValueType element_type() const
BranchTableIterator(Decoder *decoder, const BranchTableImmediate &imm)
const uint32_t table_count_
const uint8_t *const start_
uint32_t cur_index() const
const uint8_t * pc() const
uint64_t read_u64(const uint8_t *pc, Name< ValidationTag > msg="expected 8 bytes")
const uint8_t * start() const
std::pair< int64_t, uint32_t > read_i64v(const uint8_t *pc, Name< ValidationTag > name="signed LEB64")
uint32_t read_u32(const uint8_t *pc, Name< ValidationTag > msg="expected 4 bytes")
std::pair< int64_t, uint32_t > read_i33v(const uint8_t *pc, Name< ValidationTag > name="signed LEB33")
std::pair< uint64_t, uint32_t > read_u64v(const uint8_t *pc, Name< ValidationTag > name="LEB64")
void V8_NOINLINE V8_PRESERVE_MOST errorf(const char *format, Args... args)
const uint8_t * pc() const
uint8_t read_u8(const uint8_t *pc, Name< ValidationTag > msg="expected 1 byte")
std::pair< uint32_t, uint32_t > read_u32v(const uint8_t *pc, Name< ValidationTag > name="LEB32")
std::pair< int32_t, uint32_t > read_i32v(const uint8_t *pc, Name< ValidationTag > name="signed LEB32")
const uint8_t * end() const
std::pair< WasmOpcode, uint32_t > read_prefixed_opcode(const uint8_t *pc, Name< ValidationTag > name="prefixed opcode")
void V8_NOINLINE V8_PRESERVE_MOST error(const char *msg)
uint32_t buffer_offset() const
const uint32_t table_count_
uint32_t cur_index() const
EffectHandlerTableIterator(Decoder *decoder, const EffectHandlerTableImmediate &imm)
const uint8_t *const start_
const uint8_t * pc() const
void shrink_to(uint32_t new_size)
V8_NOINLINE V8_PRESERVE_MOST void Grow(int slots_needed, Zone *zone)
V8_INLINE void EnsureMoreCapacity(int slots_needed, Zone *zone)
void emplace_back(Args &&... args)
T & operator[](uint32_t index)
FastZoneVector(int initial_size, Zone *zone)
static constexpr HeapType from_code(uint8_t code, bool is_shared)
static constexpr HeapType Index(ModuleTypeIndex index, bool shared, RefTypeKind kind, Exactness exact=Exactness::kAnySubtype)
constexpr Representation representation() const
constexpr bool is_index() const
constexpr ModuleTypeIndex ref_index() const
NoVector(Ts &&...) V8_NOEXCEPT
constexpr std::nullptr_t data() const
bool mutability(uint32_t index) const
ValueType field(uint32_t index) const
uint32_t cur_index() const
const uint8_t * pc() const
const uint8_t *const start_
TryTableIterator(Decoder *decoder, const TryTableImmediate &imm)
const uint32_t table_count_
void Populate(bool shared, RefTypeKind kind)
constexpr bool is_bottom() const
constexpr bool is_packed() const
constexpr bool is_reference() const
constexpr bool is_shared() const
constexpr bool is_string_view() const
constexpr bool has_index() const
constexpr Exactness exactness() const
constexpr bool is_numeric() const
constexpr bool is_defaultable() const
V8_EXPORT_PRIVATE std::string name() const
constexpr RefTypeKind ref_type_kind() const
constexpr ValueType AsExact(Exactness exact=Exactness::kExact) const
constexpr HeapType heap_type() const
static constexpr ValueType RefNull(ModuleTypeIndex index, bool shared, RefTypeKind kind)
ValueType AsExactIfProposalEnabled(Exactness exact=Exactness::kExact) const
constexpr ValueType Unpacked() const
static constexpr ValueType Ref(ModuleTypeIndex index, bool shared, RefTypeKind kind)
constexpr ModuleTypeIndex ref_index() const
static constexpr ValueType RefMaybeNull(ModuleTypeIndex index, Nullability nullable, bool shared, RefTypeKind kind)
constexpr ValueType AsNonNull() const
bool Validate(const uint8_t *pc, BranchDepthImmediate &imm, size_t control_depth)
bool Validate(const uint8_t *pc, BlockTypeImmediate &imm)
bool Validate(const uint8_t *pc, StringConstImmediate &imm)
bool Validate(const uint8_t *pc, MemoryInitImmediate &imm)
bool Validate(const uint8_t *pc, BranchTableImmediate &imm)
bool Validate(const uint8_t *pc, GlobalIndexImmediate &imm)
bool Validate(const uint8_t *pc, StructIndexImmediate &imm)
static uint32_t OpcodeLength(WasmDecoder *decoder, const uint8_t *pc, ImmediateObservers &... ios)
bool Validate(const uint8_t *pc, HeapTypeImmediate &imm)
bool Validate(const uint8_t *pc, MemoryCopyImmediate &imm)
bool Validate(const uint8_t *pc, ArrayIndexImmediate &imm)
bool Validate(const uint8_t *pc, CallIndirectImmediate &imm)
WasmDetectedFeatures * detected_
bool ValidateLocal(const uint8_t *pc, IndexImmediate &imm)
const WasmModule * module_
bool Validate(const uint8_t *pc, MemoryAccessImmediate &imm)
bool ValidateValueType(const uint8_t *pc, ValueType type)
WasmDecoder(Zone *zone, const WasmModule *module, WasmEnabledFeatures enabled, WasmDetectedFeatures *detected, const FunctionSig *sig, bool is_shared, const uint8_t *start, const uint8_t *end, uint32_t buffer_offset=0)
base::Vector< ValueType > local_types() const
bool ValidateElementSegment(const uint8_t *pc, IndexImmediate &imm)
bool Validate(const uint8_t *pc, SigIndexImmediate &imm)
const WasmEnabledFeatures enabled_
const std::pair< uint32_t, uint32_t > * current_inst_trace_
bool Validate(const uint8_t *pc, Simd128Immediate &imm)
bool Validate(const uint8_t *pc, WasmOpcode opcode, SimdLaneImmediate &imm)
bool ValidateFunction(const uint8_t *pc, IndexImmediate &imm)
bool ValidateDataSegment(const uint8_t *pc, IndexImmediate &imm)
bool Validate(const uint8_t *pc, CallFunctionImmediate &imm)
uint32_t num_locals() const
uint32_t DecodeLocals(const uint8_t *pc)
bool Validate(const uint8_t *pc, SelectTypeImmediate &imm)
bool Validate(const uint8_t *pc, MemoryIndexImmediate &imm)
bool ValidateCont(const uint8_t *pc, ContIndexImmediate &imm)
bool Validate(const uint8_t *pc, TagIndexImmediate &imm)
static BitVector * AnalyzeLoopAssignment(WasmDecoder *decoder, const uint8_t *pc, uint32_t locals_count, Zone *zone, bool *loop_is_innermost=nullptr)
bool Validate(const uint8_t *pc, FieldImmediate &imm)
bool Validate(const uint8_t *pc, TableCopyImmediate &imm)
bool CanReturnCall(const FunctionSig *target_sig)
bool Validate(const uint8_t *pc, TableInitImmediate &imm)
bool Validate(const uint8_t *pc, TableIndexImmediate &imm)
ValueType local_type(uint32_t index) const
bool ValidateHeapType(const uint8_t *pc, HeapType type)
V8_INLINE void DecodeError(Args... args)
static constexpr WasmEnabledFeatures All()
TraceLine(WasmFullDecoder *)
void AppendOpcode(WasmOpcode)
void RollbackLocalsInitialization(Control *c)
uint32_t DecodeAtomicOpcode(WasmOpcode opcode, uint32_t opcode_length)
V8_INLINE Value Peek(int depth=0)
static int UnknownOpcodeError(WasmFullDecoder *decoder, WasmOpcode opcode)
bool CheckStaticallyOutOfBounds(const WasmMemory *memory, uint64_t size, uint64_t offset)
typename Interface::Control Control
WasmCodePosition position() const
V8_INLINE Value Pop(int index, ValueType expected)
V8_INLINE void ValidateParameters(const FunctionSig *sig)
bool HasCatchAll(Control *block) const
int32_t current_catch() const
Value PopPackedArray(uint32_t operand_index, ValueType expected_element_type, WasmArrayAccess access)
bool TypeCheckOneArmedIf(Control *c)
V8_NOINLINE V8_PRESERVE_MOST void PopTypeError(int index, Value val, std::string expected)
V8_INLINE bool TypeCheckStackAgainstMerge(Merge< Value > *merge)
bool TypeCheckAlwaysFails(Value obj, HeapType expected_type, bool null_succeeds)
void SetSucceedingCodeDynamicallyUnreachable()
void DecodeFunctionBody()
int DecodeLoadLane(WasmOpcode opcode, LoadType type, uint32_t opcode_length)
int DecodeGCOpcode(WasmOpcode opcode, uint32_t opcode_length)
static Value UnreachableValue(const uint8_t *pc)
unsigned DecodeNumericOpcode(WasmOpcode opcode, uint32_t opcode_length)
Control * control_at(uint32_t depth)
int DecodeStringEncodeWtf8Array(unibrow::Utf8Variant variant, uint32_t opcode_length)
static constexpr OpcodeHandler GetOpcodeHandlerTableEntry(size_t idx)
void set_local_initialized(uint32_t local_index)
bool TypeCheckBranch(Control *c)
unsigned DecodeAsmJsOpcode(WasmOpcode opcode, uint32_t opcode_length)
V8_INLINE void DropArgs(const StructType *type)
Control * PushControl(ControlKind kind, const BlockTypeImmediate &imm)
V8_INLINE void ValidateStackValue(int index, Value value, ValueType expected)
Value * PushReturns(const FunctionSig *sig)
V8_PRESERVE_MOST V8_NOINLINE bool TypeCheckStackAgainstMerge_Slow(Merge< Value > *merge)
V8_INLINE void Drop(int count=1)
bool * initialized_locals_
ASSERT_TRIVIALLY_COPYABLE(Value)
int startrel(const uint8_t *ptr)
int DecodeStringMeasureWtf8(unibrow::Utf8Variant variant, uint32_t opcode_length)
int BuildSimplePrototypeOperator(WasmOpcode opcode)
std::conditional_t< Interface::kUsesPoppedArgs, base::SmallVector< Value, 8 >, NoVector > PoppedArgVector
V8_NOINLINE V8_PRESERVE_MOST void PopTypeError(int index, Value val, const char *expected)
int DecodeStoreLane(WasmOpcode opcode, StoreType type, uint32_t opcode_length)
V8_INLINE Value Peek(ValueType expected)
V8_INLINE MemoryAccessImmediate MakeMemoryAccessImmediate(uint32_t pc_offset, uint32_t max_alignment)
V8_INLINE ValueType TableAddressType(const WasmTable *table)
Value PopDescriptor(ModuleTypeIndex described_index)
V8_INLINE Value * Push(ValueType type)
int DecodeStringNewWtf8(unibrow::Utf8Variant variant, uint32_t opcode_length)
V8_INLINE PoppedArgVector PopArgs(const FunctionSig *sig)
V8_INLINE Value Peek(int depth, int index, ValueType expected)
V8_INLINE void Drop(const Value &)
void InitializeInitializedLocalsTracking(int non_defaultable_locals)
V8_INLINE ValueType MemoryAddressType(const WasmMemory *memory)
V8_INLINE PoppedArgVector PopArgs(const StructType *type)
int DecodeStoreMem(StoreType store, int prefix_len=1)
V8_INLINE Value CreateValue(ValueType type)
int DecodeLoadMem(LoadType type, int prefix_len=1)
int BuildSimpleOperator(WasmOpcode opcode, ValueType return_type, ValueType lhs_type, ValueType rhs_type)
uint32_t control_depth_of_current_catch() const
V8_INLINE int EnsureStackArguments(int count)
V8_NOINLINE V8_PRESERVE_MOST void NotEnoughArgumentsError(int needed, int actual)
uint32_t SimdExtractLane(WasmOpcode opcode, ValueType type, uint32_t opcode_length)
OpcodeHandler GetOpcodeHandler(uint8_t opcode)
int BuildSimpleOperator(WasmOpcode opcode, const FunctionSig *sig)
V8_INLINE void InitMerge(Merge< Value > *merge, uint32_t arity, func get_val)
WasmFullDecoder(Zone *zone, const WasmModule *module, WasmEnabledFeatures enabled, WasmDetectedFeatures *detected, const FunctionBody &body, InterfaceArgs &&... interface_args)
uint32_t pc_relative_offset() const
FastZoneVector< uint32_t > locals_initializers_stack_
void PushMergeValues(Control *c, Merge< Value > *merge)
uint32_t DecodeSimdOpcode(WasmOpcode opcode, uint32_t opcode_length)
static int NonConstError(WasmFullDecoder *decoder, WasmOpcode opcode)
V8_NOINLINE V8_PRESERVE_MOST int EnsureStackArguments_Slow(int count)
bool TypeCheckAlwaysSucceeds(Value obj, HeapType type)
const char * SafeOpcodeNameAt(const uint8_t *pc)
int DecodeLoadTransformMem(LoadType type, LoadTransformationKind transform, uint32_t opcode_length)
Value * stack_value(uint32_t depth) const
int ParseBrOnCast(WasmOpcode opcode, uint32_t pc_offset)
int BuildSimpleOperator(WasmOpcode opcode, ValueType return_type, ValueType arg_type)
int DecodeStringRefOpcode(WasmOpcode opcode, uint32_t opcode_length)
int DecodeStringNewWtf8Array(unibrow::Utf8Variant variant, uint32_t opcode_length)
FastZoneVector< Value > stack_
int DecodeStringEncodeWtf8(unibrow::Utf8Variant variant, uint32_t opcode_length)
V8_INLINE void DropArgs(const FunctionSig *sig)
uint32_t stack_size() const
uint32_t Simd8x16ShuffleOp(uint32_t opcode_length)
FastZoneVector< Control > control_
uint32_t control_depth() const
typename Interface::Value Value
V8_INLINE Value * Push(Value value)
uint32_t locals_initialization_stack_depth() const
void onFirstError() override
V8_INLINE void PushReturns(ReturnVector values)
int(*)(WasmFullDecoder *, WasmOpcode) OpcodeHandler
uint32_t SimdReplaceLane(WasmOpcode opcode, ValueType type, uint32_t opcode_length)
V8_NOINLINE V8_PRESERVE_MOST void PopTypeError(int index, Value val, ValueType expected)
V8_INLINE DECODE(LocalGet)
bool is_local_initialized(uint32_t local_index)
uint32_t SimdConstOp(uint32_t opcode_length)
DECODE(NopForTestingUnsupportedInLiftoff)
int DecodeStringViewWtf8Encode(unibrow::Utf8Variant variant, uint32_t opcode_length)
DECODE(ReturnCallIndirect)
base::OwnedVector< uint8_t > buffer_
const v8::base::TimeTicks end_
base::Vector< const DirectHandle< Object > > args
refactor address components for immediate indexing make OptimizeMaglevOnNextCall optimize to turbofan instead of maglev filter for tracing turbofan compilation nullptr
#define CALL_INTERFACE(name,...)
#define CASE_ATOMIC_STORE_OP(Name, Type)
#define CALL_INTERFACE_IF_OK_AND_REACHABLE(name,...)
#define DEFINE_EMPTY_CALLBACK(name,...)
#define CASE_ATOMIC_OP(Name, Type)
#define VALIDATE(condition)
#define ATOMIC_STORE_OP_LIST(V)
#define DECODE_IMPL(opcode)
#define ATOMIC_OP_LIST(V)
#define DECODE_IMPL_CONST2(opcode, name)
#define DECLARE_OPCODE_CASE(name,...)
#define CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(name,...)
#define INTERFACE_FUNCTIONS(F)
#define BUILD_SIMPLE_OPCODE(op, _, sig,...)
#define CHECK_PROTOTYPE_OPCODE(feat)
#define ASMJS_CASE(Op,...)
#define DECODE_IMPL_CONST(opcode)
#define DECODE_STORE_MEM(op,...)
#define DEFINE_SIMPLE_SIG_OPERATOR(sig,...)
#define SIMPLE_PROTOTYPE_CASE(name,...)
#define BUILD_SIMPLE_EXTENDED_CONST_OPCODE(op,...)
#define TRACE_INST_FORMAT
#define DECODE_LOAD_MEM(op,...)
#define DECODE_IMPL2(opcode, name)
std::optional< TNode< JSArray > > a
ZoneVector< RpoNumber > & result
static constexpr bool kUsesPoppedArgs
ZoneVector< Entry > entries
constexpr size_t RoundUpToPowerOfTwo(size_t value)
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)
bool CheckHardwareSupportsSimd()
const std::pair< uint32_t, uint32_t > invalid_instruction_trace
constexpr uint8_t kSharedFlagCode
constexpr IndependentHeapType kWasmStringRef
constexpr size_t kV8MaxWasmFunctionLocals
bool IsSameTypeHierarchy(HeapType type1, HeapType type2, const WasmModule *module)
constexpr IndependentValueType kWasmI8
constexpr IndependentValueType kWasmF32
static constexpr LoadType GetLoadType(WasmOpcode opcode)
constexpr IndependentHeapType kWasmAnyRef
constexpr IndependentHeapType kWasmStringViewWtf8
V8_INLINE void DecodeError(Decoder *decoder, const uint8_t *pc, const char *str, Args &&... args)
bool is_asmjs_module(const WasmModule *module)
constexpr IndependentHeapType kWasmEqRef
constexpr IndependentHeapType kWasmExternRef
constexpr IndependentValueType kWasmI32
constexpr IndependentHeapType kWasmStringViewIter
constexpr IndependentHeapType kWasmContRef
constexpr size_t kV8MaxWasmArrayNewFixedLength
constexpr IndependentHeapType kWasmI31Ref
constexpr size_t kV8MaxWasmTypes
constexpr IndependentHeapType kWasmExnRef
constexpr size_t kV8MaxWasmFunctionBrTableSize
constexpr IndependentHeapType kWasmStringViewWtf16
constexpr IndependentHeapType kWasmVoid
constexpr IndependentHeapType kWasmNullContRef
V8_INLINE bool IsSubtypeOf(ValueType subtype, ValueType supertype, const WasmModule *sub_module, const WasmModule *super_module)
constexpr IndependentHeapType kWasmBottom
constexpr IndependentValueType kWasmS128
static constexpr StoreType GetStoreType(WasmOpcode opcode)
unsigned OpcodeLength(const uint8_t *pc, const uint8_t *end)
Signature< ValueType > FunctionSig
constexpr IndependentValueType kWasmF64
constexpr bool is_reference(ValueKind kind)
constexpr IndependentValueType kWasmI64
constexpr IndependentValueType kWasmI16
constexpr IndependentHeapType kWasmRefString
constexpr IndependentHeapType kWasmArrayRef
constexpr IndependentHeapType kWasmNullExnRef
constexpr int kSimd128Size
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
bool IsShared(Tagged< Object > obj)
V8_EXPORT_PRIVATE FlagValues v8_flags
V8_EXPORT_PRIVATE constexpr int ElementSizeLog2Of(MachineRepresentation)
JSArrayBuffer::IsDetachableBit is_shared
constexpr uint32_t kMaxUInt32
#define PRINTF_FORMAT(format_param, dots_param)
#define DCHECK_LE(v1, v2)
#define CHECK_GE(lhs, rhs)
#define DCHECK_WITH_MSG(condition, msg)
#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)
BrOnCastFlags(uint8_t value)
union v8::internal::wasm::CatchCase::MaybeTagIndex maybe_tag
BranchDepthImmediate br_imm
base::Vector< CatchCase > catch_cases
Reachability innerReachability() const
Merge< Value > start_merge
bool is_try_catch() const
bool is_onearmed_if() const
bool is_try_catchall() const
Reachability reachability
bool is_incomplete_try() const
Merge< Value > * br_merge()
ControlBase(Zone *zone, ControlKind kind, uint32_t stack_depth, uint32_t init_stack_depth, const uint8_t *pc, Reachability reachability)
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(ControlBase)
uint32_t init_stack_depth
union v8::internal::wasm::HandlerCase::MaybeHandlerDepth maybe_depth
Merge(bool reached=false)
Value & operator[](uint32_t i)
union v8::internal::wasm::Merge::@174 vals
static constexpr ModuleTypeIndex Invalid()
PcForErrors(const uint8_t *pc)
const uint8_t * pc() const
PcForErrors(const uint8_t *)
const uint8_t * pc() const
ModuleTypeIndex descriptor
constexpr bool valid() const
ValueBase(const uint8_t *pc, ValueType type)
std::vector< TypeDefinition > types
HeapType heap_type(ModuleTypeIndex index) const
bool has_type(ModuleTypeIndex index) const
TagIndexImmediate tag_imm
#define V8_LIKELY(condition)
#define V8_UNLIKELY(condition)
std::unique_ptr< ValueMirror > value
std::unique_ptr< ValueMirror > key
const wasm::WasmModule * module_
#define FOREACH_SIMD_0_OPERAND_OPCODE(V)
#define FOREACH_ATOMIC_OPCODE(V)
#define FOREACH_GC_OPCODE(V)
#define FOREACH_SIMD_MEM_OPCODE(V)
#define FOREACH_SIMPLE_NON_CONST_OPCODE(V)
#define FOREACH_LOAD_MEM_OPCODE(V)
#define FOREACH_SIMD_MEM_1_OPERAND_OPCODE(V)
#define FOREACH_SIMPLE_PROTOTYPE_OPCODE(V)
#define FOREACH_NUMERIC_OPCODE(V)
#define FOREACH_ASMJS_COMPAT_OPCODE(V)
#define FOREACH_SIMD_OPCODE(V)
#define FOREACH_SIMD_1_OPERAND_OPCODE(V)
#define FOREACH_STORE_MEM_OPCODE(V)
#define FOREACH_ATOMIC_0_OPERAND_OPCODE(V)
#define FOREACH_SIMPLE_EXTENDED_CONST_OPCODE(V)
#define FOREACH_SIGNATURE(V)
#define FOREACH_SIMPLE_OPCODE(V)