5 #ifndef V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_ 6 #define V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_ 11 #include "src/base/platform/elapsed-timer.h" 12 #include "src/bit-vector.h" 13 #include "src/wasm/decoder.h" 14 #include "src/wasm/function-body-decoder.h" 15 #include "src/wasm/wasm-features.h" 16 #include "src/wasm/wasm-limits.h" 17 #include "src/wasm/wasm-module.h" 18 #include "src/wasm/wasm-opcodes.h" 29 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ 32 #define TRACE_INST_FORMAT " @%-8d #%-20s|" 36 #define VALIDATE(condition) \ 37 (validate ? (condition) : [&] { \ 42 #define RET_ON_PROTOTYPE_OPCODE(feat) \ 43 DCHECK(!this->module_ || this->module_->origin == kWasmOrigin); \ 44 if (!this->enabled_.feat) { \ 45 this->error("Invalid opcode (enable with --experimental-wasm-" #feat ")"); \ 47 this->detected_->feat = true; \ 50 #define CHECK_PROTOTYPE_OPCODE(feat) \ 51 DCHECK(!this->module_ || this->module_->origin == kWasmOrigin); \ 52 if (!this->enabled_.feat) { \ 53 this->error("Invalid opcode (enable with --experimental-wasm-" #feat ")"); \ 56 this->detected_->feat = true; \ 59 #define OPCODE_ERROR(opcode, message) \ 60 (this->errorf(this->pc_, "%s: %s", WasmOpcodes::OpcodeName(opcode), \ 63 #define ATOMIC_OP_LIST(V) \ 64 V(AtomicWake, Uint32) \ 65 V(I32AtomicWait, Uint32) \ 66 V(I32AtomicLoad, Uint32) \ 67 V(I64AtomicLoad, Uint64) \ 68 V(I32AtomicLoad8U, Uint8) \ 69 V(I32AtomicLoad16U, Uint16) \ 70 V(I64AtomicLoad8U, Uint8) \ 71 V(I64AtomicLoad16U, Uint16) \ 72 V(I64AtomicLoad32U, Uint32) \ 73 V(I32AtomicAdd, Uint32) \ 74 V(I32AtomicAdd8U, Uint8) \ 75 V(I32AtomicAdd16U, Uint16) \ 76 V(I64AtomicAdd, Uint64) \ 77 V(I64AtomicAdd8U, Uint8) \ 78 V(I64AtomicAdd16U, Uint16) \ 79 V(I64AtomicAdd32U, Uint32) \ 80 V(I32AtomicSub, Uint32) \ 81 V(I64AtomicSub, Uint64) \ 82 V(I32AtomicSub8U, Uint8) \ 83 V(I32AtomicSub16U, Uint16) \ 84 V(I64AtomicSub8U, Uint8) \ 85 V(I64AtomicSub16U, Uint16) \ 86 V(I64AtomicSub32U, Uint32) \ 87 V(I32AtomicAnd, Uint32) \ 88 V(I64AtomicAnd, Uint64) \ 89 V(I32AtomicAnd8U, Uint8) \ 90 V(I32AtomicAnd16U, Uint16) \ 91 V(I64AtomicAnd8U, Uint8) \ 92 V(I64AtomicAnd16U, Uint16) \ 93 V(I64AtomicAnd32U, Uint32) \ 94 V(I32AtomicOr, Uint32) \ 95 V(I64AtomicOr, Uint64) \ 96 V(I32AtomicOr8U, Uint8) \ 97 V(I32AtomicOr16U, Uint16) \ 98 V(I64AtomicOr8U, Uint8) \ 99 V(I64AtomicOr16U, Uint16) \ 100 V(I64AtomicOr32U, Uint32) \ 101 V(I32AtomicXor, Uint32) \ 102 V(I64AtomicXor, Uint64) \ 103 V(I32AtomicXor8U, Uint8) \ 104 V(I32AtomicXor16U, Uint16) \ 105 V(I64AtomicXor8U, Uint8) \ 106 V(I64AtomicXor16U, Uint16) \ 107 V(I64AtomicXor32U, Uint32) \ 108 V(I32AtomicExchange, Uint32) \ 109 V(I64AtomicExchange, Uint64) \ 110 V(I32AtomicExchange8U, Uint8) \ 111 V(I32AtomicExchange16U, Uint16) \ 112 V(I64AtomicExchange8U, Uint8) \ 113 V(I64AtomicExchange16U, Uint16) \ 114 V(I64AtomicExchange32U, Uint32) \ 115 V(I32AtomicCompareExchange, Uint32) \ 116 V(I64AtomicCompareExchange, Uint64) \ 117 V(I32AtomicCompareExchange8U, Uint8) \ 118 V(I32AtomicCompareExchange16U, Uint16) \ 119 V(I64AtomicCompareExchange8U, Uint8) \ 120 V(I64AtomicCompareExchange16U, Uint16) \ 121 V(I64AtomicCompareExchange32U, Uint32) 123 #define ATOMIC_STORE_OP_LIST(V) \ 124 V(I32AtomicStore, Uint32) \ 125 V(I64AtomicStore, Uint64) \ 126 V(I32AtomicStore8U, Uint8) \ 127 V(I32AtomicStore16U, Uint16) \ 128 V(I64AtomicStore8U, Uint8) \ 129 V(I64AtomicStore16U, Uint16) \ 130 V(I64AtomicStore32U, Uint32) 133 template <Decoder::Val
idateFlag val
idate>
136 ValueType
type = kWasmStmt;
140 index = decoder->read_u32v<validate>(pc + 1, &length,
"local index");
144 template <Decoder::Val
idateFlag val
idate>
151 index = decoder->read_u32v<validate>(pc + 1, &length,
"exception index");
155 template <Decoder::Val
idateFlag val
idate>
160 value = decoder->read_i32v<validate>(pc + 1, &length,
"immi32");
164 template <Decoder::Val
idateFlag val
idate>
169 value = decoder->read_i64v<validate>(pc + 1, &length,
"immi64");
173 template <Decoder::Val
idateFlag val
idate>
179 uint32_t tmp = decoder->read_u32<validate>(pc + 1,
"immf32");
180 memcpy(&value, &tmp,
sizeof(value));
184 template <Decoder::Val
idateFlag val
idate>
190 uint64_t tmp = decoder->read_u64<validate>(pc + 1,
"immf64");
191 memcpy(&value, &tmp,
sizeof(value));
195 template <Decoder::Val
idateFlag val
idate>
198 ValueType
type = kWasmStmt;
203 index = decoder->read_u32v<validate>(pc + 1, &length,
"global index");
207 template <Decoder::Val
idateFlag val
idate>
210 ValueType
type = kWasmStmt;
216 uint8_t val = decoder->read_u8<validate>(pc + 1,
"block type");
217 if (!decode_local_type(val, &
type)) {
219 if (!VALIDATE(enabled.mv)) {
220 decoder->error(pc + 1,
"invalid block type");
223 if (!VALIDATE(decoder->ok()))
return;
225 decoder->read_i32v<validate>(pc + 1, &length,
"block arity");
226 if (!VALIDATE(length > 0 && index >= 0)) {
227 decoder->error(pc + 1,
"invalid block type index");
230 sig_index =
static_cast<uint32_t>(index);
236 inline bool decode_local_type(uint8_t val, ValueType* result) {
237 switch (static_cast<ValueTypeCode>(val)) {
257 *result = kWasmAnyFunc;
260 *result = kWasmAnyRef;
269 if (
type != kWasmVar)
return 0;
270 return static_cast<uint32_t>(sig->parameter_count());
273 if (
type == kWasmStmt)
return 0;
274 if (
type != kWasmVar)
return 1;
275 return static_cast<uint32_t>(sig->return_count());
278 DCHECK_EQ(kWasmVar,
type);
279 return sig->GetParam(index);
281 ValueType out_type(
uint32_t index) {
282 if (
type == kWasmVar)
return sig->GetReturn(index);
283 DCHECK_NE(kWasmStmt,
type);
289 template <Decoder::Val
idateFlag val
idate>
294 depth = decoder->read_u32v<validate>(pc + 1, &length,
"break depth");
298 template <Decoder::Val
idateFlag val
idate>
306 sig_index = decoder->read_u32v<validate>(pc + 1, &len,
"signature index");
307 if (!VALIDATE(decoder->ok()))
return;
308 table_index = decoder->read_u8<validate>(pc + 1 + len,
"table index");
309 if (!VALIDATE(table_index == 0)) {
310 decoder->errorf(pc + 1 + len,
"expected table index 0, found %u",
317 template <Decoder::Val
idateFlag val
idate>
323 index = decoder->read_u32v<validate>(pc + 1, &length,
"function index");
327 template <Decoder::Val
idateFlag val
idate>
332 index = decoder->read_u8<validate>(pc + 1,
"memory index");
333 if (!VALIDATE(index == 0)) {
334 decoder->errorf(pc + 1,
"expected memory index 0, found %u", index);
339 template <Decoder::Val
idateFlag val
idate>
344 index = decoder->read_u8<validate>(pc + 1,
"table index");
345 if (!VALIDATE(index == 0)) {
346 decoder->errorf(pc + 1,
"expected table index 0, found %u", index);
351 template <Decoder::Val
idateFlag val
idate>
357 DCHECK_EQ(kExprBrTable, decoder->read_u8<validate>(pc,
"opcode"));
360 table_count = decoder->read_u32v<validate>(pc + 1, &len,
"table count");
361 table = pc + 1 + len;
366 template <Decoder::Val
idateFlag val
idate>
369 uint32_t cur_index() {
return index_; }
370 bool has_next() {
return VALIDATE(decoder_->ok()) && index_ <= table_count_; }
376 decoder_->read_u32v<validate>(pc_, &length,
"branch table entry");
383 while (has_next()) next();
384 return static_cast<uint32_t>(pc_ - start_);
386 const byte* pc() {
return pc_; }
393 table_count_(imm.table_count) {}
403 template <Decoder::Val
idateFlag val
idate>
412 decoder->read_u32v<validate>(pc + 1, &alignment_length,
"alignment");
413 if (!VALIDATE(alignment <= max_alignment)) {
414 decoder->errorf(pc + 1,
415 "invalid alignment; expected maximum alignment is %u, " 416 "actual alignment is %u",
417 max_alignment, alignment);
419 if (!VALIDATE(decoder->ok()))
return;
421 offset = decoder->read_u32v<validate>(pc + 1 + alignment_length,
422 &offset_length,
"offset");
423 length = alignment_length + offset_length;
428 template <Decoder::Val
idateFlag val
idate>
434 lane = decoder->read_u8<validate>(pc + 2,
"lane");
439 template <Decoder::Val
idateFlag val
idate>
445 shift = decoder->read_u8<validate>(pc + 2,
"shift");
450 template <Decoder::Val
idateFlag val
idate>
452 uint8_t shuffle[kSimd128Size] = {0};
456 shuffle[
i] = decoder->read_u8<validate>(pc + 2 +
i,
"shuffle");
457 if (!VALIDATE(decoder->ok()))
return;
462 template <Decoder::Val
idateFlag val
idate>
469 : memory(decoder, pc + 1) {
470 if (!VALIDATE(decoder->ok()))
return;
472 data_segment_index = decoder->read_i32v<validate>(
473 pc + 2 + memory.length, &len,
"data segment index");
474 length = memory.length + len;
478 template <Decoder::Val
idateFlag val
idate>
484 index = decoder->read_i32v<validate>(pc + 2, &length,
"data segment index");
488 template <Decoder::Val
idateFlag val
idate>
495 : table(decoder, pc + 1) {
496 if (!VALIDATE(decoder->ok()))
return;
498 elem_segment_index = decoder->read_i32v<validate>(
499 pc + 2 + table.length, &len,
"elem segment index");
500 length = table.length + len;
504 template <Decoder::Val
idateFlag val
idate>
510 index = decoder->read_i32v<validate>(pc + 2, &length,
"elem segment index");
520 static ValueBase Unreachable(
const byte* pc) {
return {pc, kWasmVar}; }
525 template <
typename Value>
537 Merge(
bool reached =
false) : reached(reached) {}
541 return arity == 1 ? vals.first : vals.array[
i];
545 enum ControlKind : uint8_t {
555 enum Reachability : uint8_t {
565 template <
typename Value>
570 Reachability reachability = kReachable;
578 : kind(kind), stack_depth(stack_depth), pc(pc) {}
581 bool reachable()
const {
return reachability == kReachable; }
587 bool unreachable()
const {
return reachability == kUnreachable; }
590 Reachability innerReachability()
const {
591 return reachability == kReachable ? kReachable : kSpecOnlyReachable;
594 bool is_if()
const {
return is_onearmed_if() || is_if_else(); }
595 bool is_onearmed_if()
const {
return kind == kControlIf; }
596 bool is_if_else()
const {
return kind == kControlIfElse; }
597 bool is_block()
const {
return kind == kControlBlock; }
598 bool is_loop()
const {
return kind == kControlLoop; }
599 bool is_incomplete_try()
const {
return kind == kControlTry; }
600 bool is_try_catch()
const {
return kind == kControlTryCatch; }
601 bool is_try_catchall()
const {
return kind == kControlTryCatchAll; }
602 bool is_try()
const {
603 return is_incomplete_try() || is_try_catch() || is_try_catchall();
607 return is_loop() ? &this->start_merge : &this->end_merge;
612 return {kControlBlock, stack_depth, pc};
616 return {kControlIf, stack_depth, pc};
620 return {kControlLoop, stack_depth, pc};
624 return {kControlTry, stack_depth, pc};
628 #define CONCRETE_NAMED_CONSTRUCTOR(concrete_type, abstract_type, name) \ 629 template <typename... Args> \ 630 static concrete_type name(Args&&... args) { \ 632 static_cast<abstract_type&>(val) = \ 633 abstract_type::name(std::forward<Args>(args)...); \ 641 template <
typename ConcreteType>
644 CONCRETE_NAMED_CONSTRUCTOR(ConcreteType,
ValueBase, Unreachable)
645 CONCRETE_NAMED_CONSTRUCTOR(ConcreteType,
ValueBase, New)
655 template <
typename ConcreteType,
typename Value>
667 #define INTERFACE_FUNCTIONS(F) \ 670 F(StartFunctionBody, Control* block) \ 673 F(NextInstruction, WasmOpcode) \ 675 F(Block, Control* block) \ 676 F(Loop, Control* block) \ 677 F(Try, Control* block) \ 678 F(If, const Value& cond, Control* if_block) \ 679 F(FallThruTo, Control* c) \ 680 F(PopControl, Control* block) \ 681 F(EndControl, Control* block) \ 683 F(UnOp, WasmOpcode opcode, FunctionSig*, const Value& value, Value* result) \ 684 F(BinOp, WasmOpcode opcode, FunctionSig*, const Value& lhs, \ 685 const Value& rhs, Value* result) \ 686 F(I32Const, Value* result, int32_t value) \ 687 F(I64Const, Value* result, int64_t value) \ 688 F(F32Const, Value* result, float value) \ 689 F(F64Const, Value* result, double value) \ 690 F(RefNull, Value* result) \ 691 F(Drop, const Value& value) \ 692 F(DoReturn, Vector<Value> values, bool implicit) \ 693 F(GetLocal, Value* result, const LocalIndexImmediate<validate>& imm) \ 694 F(SetLocal, const Value& value, const LocalIndexImmediate<validate>& imm) \ 695 F(TeeLocal, const Value& value, Value* result, \ 696 const LocalIndexImmediate<validate>& imm) \ 697 F(GetGlobal, Value* result, const GlobalIndexImmediate<validate>& imm) \ 698 F(SetGlobal, const Value& value, const GlobalIndexImmediate<validate>& imm) \ 700 F(Select, const Value& cond, const Value& fval, const Value& tval, \ 702 F(Br, Control* target) \ 703 F(BrIf, const Value& cond, Control* target) \ 704 F(BrTable, const BranchTableImmediate<validate>& imm, const Value& key) \ 705 F(Else, Control* if_block) \ 706 F(LoadMem, LoadType type, const MemoryAccessImmediate<validate>& imm, \ 707 const Value& index, Value* result) \ 708 F(StoreMem, StoreType type, const MemoryAccessImmediate<validate>& imm, \ 709 const Value& index, const Value& value) \ 710 F(CurrentMemoryPages, Value* result) \ 711 F(MemoryGrow, const Value& value, Value* result) \ 712 F(CallDirect, const CallFunctionImmediate<validate>& imm, \ 713 const Value args[], Value returns[]) \ 714 F(CallIndirect, const Value& index, \ 715 const CallIndirectImmediate<validate>& imm, const Value args[], \ 717 F(SimdOp, WasmOpcode opcode, Vector<Value> args, Value* result) \ 718 F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate<validate>& imm, \ 719 const Vector<Value> inputs, Value* result) \ 720 F(SimdShiftOp, WasmOpcode opcode, const SimdShiftImmediate<validate>& imm, \ 721 const Value& input, Value* result) \ 722 F(Simd8x16ShuffleOp, const Simd8x16ShuffleImmediate<validate>& imm, \ 723 const Value& input0, const Value& input1, Value* result) \ 724 F(Throw, const ExceptionIndexImmediate<validate>& imm, \ 725 const Vector<Value>& args) \ 726 F(Rethrow, Control* block) \ 727 F(CatchException, const ExceptionIndexImmediate<validate>& imm, \ 728 Control* block, Vector<Value> caught_values) \ 729 F(CatchAll, Control* block) \ 730 F(AtomicOp, WasmOpcode opcode, Vector<Value> args, \ 731 const MemoryAccessImmediate<validate>& imm, Value* result) \ 732 F(MemoryInit, const MemoryInitImmediate<validate>& imm, Vector<Value> args) \ 733 F(MemoryDrop, const MemoryDropImmediate<validate>& imm) \ 734 F(MemoryCopy, const MemoryIndexImmediate<validate>& imm, Vector<Value> args) \ 735 F(MemoryFill, const MemoryIndexImmediate<validate>& imm, Vector<Value> args) \ 736 F(TableInit, const TableInitImmediate<validate>& imm, Vector<Value> args) \ 737 F(TableDrop, const TableDropImmediate<validate>& imm) \ 738 F(TableCopy, const TableIndexImmediate<validate>& imm, Vector<Value> args) 742 template <Decoder::Val
idateFlag val
idate>
747 const byte* end,
uint32_t buffer_offset = 0)
748 :
Decoder(start, end, buffer_offset),
753 local_types_(
nullptr) {}
762 return local_types_ ==
nullptr 764 :
static_cast<uint32_t>(local_types_->size());
770 DCHECK_NOT_NULL(type_list);
771 DCHECK_EQ(0, type_list->size());
773 if (sig !=
nullptr) {
774 type_list->assign(sig->parameters().begin(), sig->parameters().end());
777 uint32_t entries = decoder->consume_u32v(
"local decls count");
778 if (decoder->failed())
return false;
780 TRACE(
"local decls count: %u\n", entries);
781 while (entries-- > 0 && VALIDATE(decoder->ok()) && decoder->more()) {
782 uint32_t count = decoder->consume_u32v(
"local count");
783 if (decoder->failed())
return false;
785 DCHECK_LE(type_list->size(), kV8MaxWasmFunctionLocals);
786 if (count > kV8MaxWasmFunctionLocals - type_list->size()) {
787 decoder->error(decoder->pc() - 1,
"local count too large");
790 byte code = decoder->consume_u8(
"local type");
791 if (decoder->failed())
return false;
808 if (enabled.anyref) {
812 decoder->error(decoder->pc() - 1,
"invalid local type");
814 case kLocalExceptRef:
816 type = kWasmExceptRef;
819 decoder->error(decoder->pc() - 1,
"invalid local type");
828 decoder->error(decoder->pc() - 1,
"invalid local type");
831 type_list->insert(type_list->end(), count,
type);
833 DCHECK(decoder->ok());
839 if (pc >= decoder->end())
return nullptr;
840 if (*pc != kExprLoop)
return nullptr;
847 while (pc < decoder->end() && VALIDATE(decoder->ok())) {
848 WasmOpcode opcode =
static_cast<WasmOpcode
>(*pc);
855 length = OpcodeLength(decoder, pc);
859 case kExprTeeLocal: {
861 if (assigned->length() > 0 &&
862 imm.index <
static_cast<uint32_t>(assigned->length())) {
864 assigned->Add(imm.index);
866 length = 1 + imm.length;
869 case kExprMemoryGrow:
870 case kExprCallFunction:
871 case kExprCallIndirect:
874 assigned->Add(locals_count - 1);
875 length = OpcodeLength(decoder, pc);
881 length = OpcodeLength(decoder, pc);
884 if (depth <= 0)
break;
887 return VALIDATE(decoder->ok()) ? assigned :
nullptr;
891 if (!VALIDATE(imm.index < total_locals())) {
892 errorf(pc + 1,
"invalid local index: %u", imm.index);
895 imm.type = local_types_ ? local_types_->at(imm.index) : kWasmStmt;
900 if (!VALIDATE(module_ !=
nullptr &&
901 imm.index < module_->exceptions.size())) {
902 errorf(pc + 1,
"Invalid exception index: %u", imm.index);
905 imm.exception = &module_->exceptions[imm.index];
910 if (!VALIDATE(module_ !=
nullptr && imm.index < module_->globals.size())) {
911 errorf(pc + 1,
"invalid global index: %u", imm.index);
914 imm.global = &module_->globals[imm.index];
915 imm.type = imm.global->type;
920 if (!VALIDATE(module_ !=
nullptr &&
921 imm.index < module_->functions.size())) {
924 imm.sig = module_->functions[imm.index].sig;
929 if (Complete(pc, imm)) {
932 errorf(pc + 1,
"invalid function index: %u", imm.index);
937 if (!VALIDATE(module_ !=
nullptr &&
938 imm.sig_index < module_->signatures.size())) {
941 imm.sig = module_->signatures[imm.sig_index];
946 if (!VALIDATE(module_ !=
nullptr && !module_->tables.empty())) {
947 error(
"function table has to exist to execute call_indirect");
950 if (!Complete(pc, imm)) {
951 errorf(pc + 1,
"invalid signature index: #%u", imm.sig_index);
958 size_t control_depth) {
959 if (!VALIDATE(imm.depth < control_depth)) {
960 errorf(pc + 1,
"invalid break depth: %u", imm.depth);
967 size_t block_depth) {
968 if (!VALIDATE(imm.table_count < kV8MaxWasmFunctionSize)) {
969 errorf(pc + 1,
"invalid table count (> max function size): %u",
973 return checkAvailable(imm.table_count);
976 inline bool Validate(
const byte* pc, WasmOpcode opcode,
978 uint8_t num_lanes = 0;
980 case kExprF32x4ExtractLane:
981 case kExprF32x4ReplaceLane:
982 case kExprI32x4ExtractLane:
983 case kExprI32x4ReplaceLane:
986 case kExprI16x8ExtractLane:
987 case kExprI16x8ReplaceLane:
990 case kExprI8x16ExtractLane:
991 case kExprI8x16ReplaceLane:
998 if (!VALIDATE(imm.lane >= 0 && imm.lane < num_lanes)) {
999 error(pc_ + 2,
"invalid lane index");
1006 inline bool Validate(
const byte* pc, WasmOpcode opcode,
1008 uint8_t max_shift = 0;
1011 case kExprI32x4ShrS:
1012 case kExprI32x4ShrU:
1016 case kExprI16x8ShrS:
1017 case kExprI16x8ShrU:
1021 case kExprI8x16ShrS:
1022 case kExprI8x16ShrU:
1029 if (!VALIDATE(imm.shift >= 0 && imm.shift < max_shift)) {
1030 error(pc_ + 2,
"invalid shift amount");
1037 inline bool Validate(
const byte* pc,
1039 uint8_t max_lane = 0;
1041 max_lane = std::max(max_lane, imm.shuffle[
i]);
1044 if (!VALIDATE(max_lane <= 2 * kSimd128Size)) {
1045 error(pc_ + 2,
"invalid shuffle mask");
1052 if (imm.type != kWasmVar)
return true;
1053 if (!VALIDATE((module_ && imm.sig_index < module_->signatures.size()))) {
1056 imm.sig = module_->signatures[imm.sig_index];
1061 if (!Complete(imm)) {
1062 errorf(pc_,
"block type index %u out of bounds (%zu signatures)",
1063 imm.sig_index, module_ ? module_->signatures.size() : 0);
1070 if (!VALIDATE(module_ !=
nullptr && module_->has_memory)) {
1071 errorf(pc_ + 1,
"memory instruction with no memory");
1078 if (!Validate(imm.memory))
return false;
1089 if (!VALIDATE(module_ !=
nullptr && imm.index < module_->tables.size())) {
1090 errorf(pc_ + 1,
"invalid table index: %u", imm.index);
1097 if (!Validate(pc_ + 1, imm.table))
return false;
1098 if (!VALIDATE(module_ !=
nullptr &&
1099 imm.elem_segment_index < module_->table_inits.size())) {
1100 errorf(pc_ + 2,
"invalid element segment index: %u",
1101 imm.elem_segment_index);
1108 if (!VALIDATE(module_ !=
nullptr &&
1109 imm.index < module_->table_inits.size())) {
1110 errorf(pc_ + 2,
"invalid element segment index: %u", imm.index);
1117 WasmOpcode opcode =
static_cast<WasmOpcode
>(*pc);
1119 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: 1120 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
1121 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
1122 #undef DECLARE_OPCODE_CASE 1125 return 1 + imm.length;
1131 return 1 + imm.length;
1133 case kExprSetGlobal:
1134 case kExprGetGlobal: {
1136 return 1 + imm.length;
1139 case kExprCallFunction: {
1141 return 1 + imm.length;
1143 case kExprCallIndirect: {
1145 return 1 + imm.length;
1153 return 1 + imm.length;
1159 return 1 + imm.length;
1164 case kExprGetLocal: {
1166 return 1 + imm.length;
1168 case kExprBrTable: {
1171 return 1 + iterator.length();
1173 case kExprI32Const: {
1175 return 1 + imm.length;
1177 case kExprI64Const: {
1179 return 1 + imm.length;
1181 case kExprRefNull: {
1184 case kExprMemoryGrow:
1185 case kExprMemorySize: {
1187 return 1 + imm.length;
1193 case kNumericPrefix: {
1194 byte numeric_index =
1195 decoder->read_u8<validate>(pc + 1,
"numeric_index");
1197 static_cast<WasmOpcode
>(kNumericPrefix << 8 | numeric_index);
1199 case kExprI32SConvertSatF32:
1200 case kExprI32UConvertSatF32:
1201 case kExprI32SConvertSatF64:
1202 case kExprI32UConvertSatF64:
1203 case kExprI64SConvertSatF32:
1204 case kExprI64UConvertSatF32:
1205 case kExprI64SConvertSatF64:
1206 case kExprI64UConvertSatF64:
1208 case kExprMemoryInit: {
1210 return 2 + imm.length;
1212 case kExprMemoryDrop: {
1214 return 2 + imm.length;
1216 case kExprMemoryCopy:
1217 case kExprMemoryFill: {
1219 return 2 + imm.length;
1221 case kExprTableInit: {
1223 return 2 + imm.length;
1225 case kExprTableDrop: {
1227 return 2 + imm.length;
1229 case kExprTableCopy: {
1231 return 2 + imm.length;
1234 decoder->error(pc,
"invalid numeric opcode");
1239 byte simd_index = decoder->read_u8<validate>(pc + 1,
"simd_index");
1241 static_cast<WasmOpcode
>(kSimdPrefix << 8 | simd_index);
1243 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: 1244 FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
1245 #undef DECLARE_OPCODE_CASE 1247 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: 1248 FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
1249 #undef DECLARE_OPCODE_CASE 1251 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: 1252 FOREACH_SIMD_MEM_OPCODE(DECLARE_OPCODE_CASE)
1253 #undef DECLARE_OPCODE_CASE 1256 return 2 + imm.length;
1259 case kExprS8x16Shuffle:
1260 return 2 + kSimd128Size;
1262 decoder->error(pc,
"invalid SIMD opcode");
1266 case kAtomicPrefix: {
1267 byte atomic_index = decoder->read_u8<validate>(pc + 1,
"atomic_index");
1269 static_cast<WasmOpcode
>(kAtomicPrefix << 8 | atomic_index);
1271 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: 1272 FOREACH_ATOMIC_OPCODE(DECLARE_OPCODE_CASE)
1273 #undef DECLARE_OPCODE_CASE 1276 return 2 + imm.length;
1279 decoder->error(pc,
"invalid Atomics opcode");
1288 std::pair<uint32_t, uint32_t> StackEffect(
const byte* pc) {
1289 WasmOpcode opcode =
static_cast<WasmOpcode
>(*pc);
1291 FunctionSig* sig = WasmOpcodes::Signature(opcode);
1292 if (!sig) sig = WasmOpcodes::AsmjsSignature(opcode);
1293 if (sig)
return {sig->parameter_count(), sig->return_count()};
1295 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: 1300 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
1302 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
1304 case kExprMemoryGrow:
1307 case kExprSetGlobal:
1314 case kExprGetGlobal:
1320 case kExprMemorySize:
1322 case kExprCallFunction: {
1324 CHECK(Complete(pc, imm));
1325 return {imm.sig->parameter_count(), imm.sig->return_count()};
1327 case kExprCallIndirect: {
1329 CHECK(Complete(pc, imm));
1331 return {imm.sig->parameter_count() + 1,
1332 imm.sig->return_count()};
1341 case kExprUnreachable:
1343 case kNumericPrefix:
1346 opcode =
static_cast<WasmOpcode
>(opcode << 8 | *(pc + 1));
1348 FOREACH_SIMD_1_OPERAND_1_PARAM_OPCODE(DECLARE_OPCODE_CASE)
1350 FOREACH_SIMD_1_OPERAND_2_PARAM_OPCODE(DECLARE_OPCODE_CASE)
1351 FOREACH_SIMD_MASK_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
1354 sig = WasmOpcodes::Signature(opcode);
1356 return {sig->parameter_count(), sig->return_count()};
1363 V8_Fatal(__FILE__, __LINE__,
"unimplemented opcode: %x (%s)", opcode,
1364 WasmOpcodes::OpcodeName(opcode));
1367 #undef DECLARE_OPCODE_CASE 1372 #define CALL_INTERFACE(name, ...) interface_.name(this, ##__VA_ARGS__) 1373 #define CALL_INTERFACE_IF_REACHABLE(name, ...) \ 1375 DCHECK(!control_.empty()); \ 1376 if (VALIDATE(this->ok()) && control_.back().reachable()) { \ 1377 interface_.name(this, ##__VA_ARGS__); \ 1380 #define CALL_INTERFACE_IF_PARENT_REACHABLE(name, ...) \ 1382 DCHECK(!control_.empty()); \ 1383 if (VALIDATE(this->ok()) && \ 1384 (control_.size() == 1 || control_at(1)->reachable())) { \ 1385 interface_.name(this, ##__VA_ARGS__); \ 1389 template <Decoder::Val
idateFlag val
idate,
typename Interface>
1391 using Value =
typename Interface::Value;
1392 using Control =
typename Interface::Control;
1397 ASSERT_TRIVIALLY_COPYABLE(Value);
1400 template <
typename... InterfaceArgs>
1403 const FunctionBody& body, InterfaceArgs&&... interface_args)
1405 body.end, body.offset),
1407 interface_(std::forward<InterfaceArgs>(interface_args)...),
1408 local_type_vec_(zone),
1412 last_end_found_(
false) {
1413 this->local_types_ = &local_type_vec_;
1416 Interface& interface() {
return interface_; }
1419 DCHECK(stack_.empty());
1420 DCHECK(control_.empty());
1423 if (FLAG_trace_wasm_decode_time) {
1424 decode_timer.Start();
1427 if (this->end_ < this->pc_) {
1428 this->error(
"function body end < start");
1432 DCHECK_EQ(0, this->local_types_->size());
1434 this->local_types_);
1435 CALL_INTERFACE(StartFunction);
1436 DecodeFunctionBody();
1437 if (!this->failed()) CALL_INTERFACE(FinishFunction);
1439 if (this->failed())
return this->TraceFailed();
1441 if (!control_.empty()) {
1444 if (control_.size() > 1) {
1445 this->error(control_.back().pc,
"unterminated control structure");
1447 this->error(
"function body must end with \"end\" opcode");
1449 return TraceFailed();
1452 if (!last_end_found_) {
1453 this->error(
"function body must end with \"end\" opcode");
1457 if (FLAG_trace_wasm_decode_time) {
1458 double ms = decode_timer.Elapsed().InMillisecondsF();
1459 PrintF(
"wasm-decode %s (%0.3f ms)\n\n",
1460 VALIDATE(this->ok()) ?
"ok" :
"failed", ms);
1462 TRACE(
"wasm-decode %s\n\n", VALIDATE(this->ok()) ?
"ok" :
"failed");
1468 bool TraceFailed() {
1469 TRACE(
"wasm-error module+%-6d func+%d: %s\n\n", this->error_offset_,
1470 this->GetBufferRelativeOffset(this->error_offset_),
1471 this->error_msg_.c_str());
1475 const char* SafeOpcodeNameAt(
const byte* pc) {
1476 if (pc >= this->end_)
return "<end>";
1477 return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(*pc));
1480 inline Zone* zone()
const {
return zone_; }
1483 return static_cast<uint32_t>(local_type_vec_.size());
1486 inline ValueType GetLocalType(
uint32_t index) {
1487 return local_type_vec_[index];
1491 int offset =
static_cast<int>(this->pc_ - this->start_);
1492 DCHECK_EQ(this->pc_ - this->start_, offset);
1496 inline uint32_t control_depth()
const {
1497 return static_cast<uint32_t>(control_.size());
1500 inline Control* control_at(
uint32_t depth) {
1501 DCHECK_GT(control_.size(), depth);
1502 return &control_.back() - depth;
1505 inline uint32_t stack_size()
const {
1506 DCHECK_GE(kMaxUInt32, stack_.size());
1507 return static_cast<uint32_t>(stack_.size());
1510 inline Value* stack_value(
uint32_t depth) {
1511 DCHECK_GT(stack_.size(), depth);
1512 return &stack_[stack_.size() - depth - 1];
1515 inline Value& GetMergeValueFromStack(
1517 DCHECK(merge == &c->start_merge || merge == &c->end_merge);
1518 DCHECK_GT(merge->arity,
i);
1519 DCHECK_GE(stack_.size(), c->stack_depth + merge->arity);
1520 return stack_[stack_.size() - merge->arity +
i];
1524 static constexpr
size_t kErrorMsgSize = 128;
1528 Interface interface_;
1534 bool last_end_found_;
1536 bool CheckHasMemory() {
1537 if (!VALIDATE(this->module_->has_memory)) {
1538 this->error(this->pc_ - 1,
"memory instruction with no memory");
1544 bool CheckHasSharedMemory() {
1545 if (!VALIDATE(this->module_->has_shared_memory)) {
1546 this->error(this->pc_ - 1,
"Atomic opcodes used without shared memory");
1554 static constexpr
int kMaxLen = 512;
1556 if (!FLAG_trace_wasm_decoder)
return;
1557 PrintF(
"%.*s\n", len_, buffer_);
1562 void Append(
const char* format, ...) {
1563 if (!FLAG_trace_wasm_decoder)
return;
1565 va_start(va_args, format);
1566 size_t remaining_len = kMaxLen - len_;
1567 Vector<char> remaining_msg_space(buffer_ + len_, remaining_len);
1568 int len = VSNPrintF(remaining_msg_space, format, va_args);
1570 len_ += len < 0 ? remaining_len : len;
1574 char buffer_[kMaxLen];
1579 void DecodeFunctionBody() {
1580 TRACE(
"wasm-decode %p...%p (module+%u, %d bytes)\n",
1581 reinterpret_cast<const void*>(this->start()),
1582 reinterpret_cast<const void*>(this->end()), this->pc_offset(),
1583 static_cast<int>(this->end() - this->start()));
1587 auto* c = PushBlock();
1588 InitMerge(&c->start_merge, 0, [](
uint32_t) -> Value { UNREACHABLE(); });
1589 InitMerge(&c->end_merge,
1590 static_cast<uint32_t>(this->sig_->return_count()),
1592 return Value::New(this->pc_, this->sig_->GetReturn(
i)); });
1593 CALL_INTERFACE(StartFunctionBody, c);
1596 while (this->pc_ < this->end_) {
1598 WasmOpcode opcode =
static_cast<WasmOpcode
>(*this->pc_);
1600 CALL_INTERFACE_IF_REACHABLE(NextInstruction, opcode);
1603 TraceLine trace_msg;
1604 #define TRACE_PART(...) trace_msg.Append(__VA_ARGS__) 1605 if (!WasmOpcodes::IsPrefixOpcode(opcode)) {
1606 TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
1607 WasmOpcodes::OpcodeName(opcode));
1610 #define TRACE_PART(...) 1615 BuildSimpleOperator(opcode, sig);
1623 if (!this->Validate(imm))
break;
1625 auto* block = PushBlock();
1626 SetBlockType(block, imm);
1627 CALL_INTERFACE_IF_REACHABLE(
Block, block);
1628 PushMergeValues(block, &block->start_merge);
1629 len = 1 + imm.length;
1632 case kExprRethrow: {
1633 CHECK_PROTOTYPE_OPCODE(eh);
1635 if (!this->Validate(this->pc_, imm, control_.size()))
break;
1636 Control* c = control_at(imm.depth);
1637 if (!VALIDATE(c->is_try_catchall() || c->is_try_catch())) {
1638 this->error(
"rethrow not targeting catch or catch-all");
1641 CALL_INTERFACE_IF_REACHABLE(Rethrow, c);
1642 len = 1 + imm.length;
1647 CHECK_PROTOTYPE_OPCODE(eh);
1649 len = 1 + imm.length;
1650 if (!this->Validate(this->pc_, imm))
break;
1651 PopArgs(imm.exception->ToFunctionSig());
1652 CALL_INTERFACE_IF_REACHABLE(
Throw, imm, VectorOf(args_));
1657 CHECK_PROTOTYPE_OPCODE(eh);
1659 if (!this->Validate(imm))
break;
1661 auto* try_block = PushTry();
1662 SetBlockType(try_block, imm);
1663 len = 1 + imm.length;
1664 CALL_INTERFACE_IF_REACHABLE(Try, try_block);
1665 PushMergeValues(try_block, &try_block->start_merge);
1669 CHECK_PROTOTYPE_OPCODE(eh);
1671 if (!this->Validate(this->pc_, imm))
break;
1672 len = 1 + imm.length;
1673 if (!VALIDATE(!control_.empty())) {
1674 this->error(
"catch does not match any try");
1677 Control* c = &control_.back();
1678 if (!VALIDATE(c->is_try())) {
1679 this->error(
"catch does not match any try");
1682 if (!VALIDATE(!c->is_try_catchall())) {
1683 this->error(
"catch after catch-all for try");
1686 c->kind = kControlTryCatch;
1688 stack_.resize(c->stack_depth);
1690 for (
size_t i = 0, e = sig->parameter_count();
i < e; ++
i) {
1691 Push(sig->GetParam(
i));
1694 sig->parameter_count());
1695 c->reachability = control_at(1)->innerReachability();
1696 CALL_INTERFACE_IF_PARENT_REACHABLE(CatchException, imm, c, values);
1699 case kExprCatchAll: {
1700 CHECK_PROTOTYPE_OPCODE(eh);
1701 if (!VALIDATE(!control_.empty())) {
1702 this->error(
"catch-all does not match any try");
1705 Control* c = &control_.back();
1706 if (!VALIDATE(c->is_try())) {
1707 this->error(
"catch-all does not match any try");
1710 if (!VALIDATE(!c->is_try_catchall())) {
1711 this->error(
"catch-all already present for try");
1714 c->kind = kControlTryCatchAll;
1716 stack_.resize(c->stack_depth);
1717 c->reachability = control_at(1)->innerReachability();
1718 CALL_INTERFACE_IF_PARENT_REACHABLE(CatchAll, c);
1723 if (!this->Validate(imm))
break;
1725 auto* block = PushLoop();
1726 SetBlockType(&control_.back(), imm);
1727 len = 1 + imm.length;
1728 CALL_INTERFACE_IF_REACHABLE(Loop, block);
1729 PushMergeValues(block, &block->start_merge);
1734 if (!this->Validate(imm))
break;
1735 auto cond = Pop(0, kWasmI32);
1737 if (!VALIDATE(this->ok()))
break;
1738 auto* if_block = PushIf();
1739 SetBlockType(if_block, imm);
1740 CALL_INTERFACE_IF_REACHABLE(If, cond, if_block);
1741 len = 1 + imm.length;
1742 PushMergeValues(if_block, &if_block->start_merge);
1746 if (!VALIDATE(!control_.empty())) {
1747 this->error(
"else does not match any if");
1750 Control* c = &control_.back();
1751 if (!VALIDATE(c->is_if())) {
1752 this->error(this->pc_,
"else does not match an if");
1755 if (c->is_if_else()) {
1756 this->error(this->pc_,
"else already present for if");
1760 c->kind = kControlIfElse;
1761 CALL_INTERFACE_IF_PARENT_REACHABLE(Else, c);
1762 PushMergeValues(c, &c->start_merge);
1763 c->reachability = control_at(1)->innerReachability();
1767 if (!VALIDATE(!control_.empty())) {
1768 this->error(
"end does not match any if, try, or block");
1771 Control* c = &control_.back();
1772 if (!VALIDATE(!c->is_incomplete_try())) {
1773 this->error(this->pc_,
"missing catch or catch-all in try");
1776 if (c->is_onearmed_if()) {
1779 if (this->failed())
break;
1780 CALL_INTERFACE_IF_PARENT_REACHABLE(Else, c);
1781 PushMergeValues(c, &c->start_merge);
1782 c->reachability = control_at(1)->innerReachability();
1784 if (c->is_try_catch()) {
1787 c->reachability = control_at(1)->innerReachability();
1788 CALL_INTERFACE_IF_PARENT_REACHABLE(CatchAll, c);
1789 CALL_INTERFACE_IF_REACHABLE(Rethrow, c);
1795 if (!c->is_loop()) PushMergeValues(c, &c->end_merge);
1797 if (control_.size() == 1) {
1799 if (!VALIDATE(this->pc_ + 1 == this->end_)) {
1800 this->error(this->pc_ + 1,
"trailing code after function end");
1803 last_end_found_ =
true;
1805 TRACE_PART(
"\n" TRACE_INST_FORMAT, startrel(this->pc_),
1806 "(implicit) return");
1814 auto cond = Pop(2, kWasmI32);
1816 auto tval = Pop(0, fval.type);
1817 auto* result = Push(tval.type == kWasmVar ? fval.type : tval.type);
1818 CALL_INTERFACE_IF_REACHABLE(Select, cond, fval, tval, result);
1823 if (!this->Validate(this->pc_, imm, control_.size()))
break;
1824 Control* c = control_at(imm.depth);
1825 if (imm.depth == control_.size() - 1) {
1828 if (!TypeCheckBreak(c))
break;
1829 if (control_.back().reachable()) {
1830 CALL_INTERFACE(Br, c);
1831 c->br_merge()->reached =
true;
1834 len = 1 + imm.length;
1840 auto cond = Pop(0, kWasmI32);
1841 if (this->failed())
break;
1842 if (!this->Validate(this->pc_, imm, control_.size()))
break;
1843 Control* c = control_at(imm.depth);
1844 if (!TypeCheckBreak(c))
break;
1845 if (control_.back().reachable()) {
1846 CALL_INTERFACE(BrIf, cond, c);
1847 c->br_merge()->reached =
true;
1849 len = 1 + imm.length;
1852 case kExprBrTable: {
1855 auto key = Pop(0, kWasmI32);
1856 if (this->failed())
break;
1857 if (!this->Validate(this->pc_, imm, control_.size()))
break;
1859 std::vector<bool> br_targets(control_.size());
1860 while (iterator.has_next()) {
1861 const uint32_t i = iterator.cur_index();
1862 const byte* pos = iterator.pc();
1864 if (!VALIDATE(target < control_.size())) {
1866 "improper branch in br_table target %u (depth %u)",
1871 if (br_targets[target])
continue;
1872 br_targets[target] =
true;
1874 Control* c = control_at(target);
1875 uint32_t arity = c->br_merge()->arity;
1878 }
else if (!VALIDATE(br_arity == arity)) {
1880 "inconsistent arity in br_table target %u" 1881 " (previous was %u, this one %u)",
1882 i, br_arity, arity);
1884 if (!TypeCheckBreak(c))
break;
1886 if (this->failed())
break;
1888 if (control_.back().reachable()) {
1889 CALL_INTERFACE(BrTable, imm, key);
1891 for (
uint32_t depth = control_depth(); depth-- > 0;) {
1892 if (!br_targets[depth])
continue;
1893 control_at(depth)->br_merge()->reached =
true;
1897 len = 1 + iterator.length();
1902 DoReturn(&control_.back(),
false);
1905 case kExprUnreachable: {
1906 CALL_INTERFACE_IF_REACHABLE(Unreachable);
1910 case kExprI32Const: {
1912 auto* value = Push(kWasmI32);
1913 CALL_INTERFACE_IF_REACHABLE(I32Const, value, imm.value);
1914 len = 1 + imm.length;
1917 case kExprI64Const: {
1919 auto* value = Push(kWasmI64);
1920 CALL_INTERFACE_IF_REACHABLE(I64Const, value, imm.value);
1921 len = 1 + imm.length;
1924 case kExprF32Const: {
1926 auto* value = Push(kWasmF32);
1927 CALL_INTERFACE_IF_REACHABLE(F32Const, value, imm.value);
1928 len = 1 + imm.length;
1931 case kExprF64Const: {
1933 auto* value = Push(kWasmF64);
1934 CALL_INTERFACE_IF_REACHABLE(F64Const, value, imm.value);
1935 len = 1 + imm.length;
1938 case kExprRefNull: {
1939 CHECK_PROTOTYPE_OPCODE(anyref);
1940 auto* value = Push(kWasmAnyRef);
1941 CALL_INTERFACE_IF_REACHABLE(RefNull, value);
1945 case kExprGetLocal: {
1947 if (!this->Validate(this->pc_, imm))
break;
1948 auto* value = Push(imm.type);
1949 CALL_INTERFACE_IF_REACHABLE(GetLocal, value, imm);
1950 len = 1 + imm.length;
1953 case kExprSetLocal: {
1955 if (!this->Validate(this->pc_, imm))
break;
1956 auto value = Pop(0, local_type_vec_[imm.index]);
1957 CALL_INTERFACE_IF_REACHABLE(SetLocal, value, imm);
1958 len = 1 + imm.length;
1961 case kExprTeeLocal: {
1963 if (!this->Validate(this->pc_, imm))
break;
1964 auto value = Pop(0, local_type_vec_[imm.index]);
1965 auto* result = Push(value.type);
1966 CALL_INTERFACE_IF_REACHABLE(TeeLocal, value, result, imm);
1967 len = 1 + imm.length;
1972 CALL_INTERFACE_IF_REACHABLE(Drop, value);
1975 case kExprGetGlobal: {
1977 len = 1 + imm.length;
1978 if (!this->Validate(this->pc_, imm))
break;
1979 auto* result = Push(imm.type);
1980 CALL_INTERFACE_IF_REACHABLE(GetGlobal, result, imm);
1983 case kExprSetGlobal: {
1985 len = 1 + imm.length;
1986 if (!this->Validate(this->pc_, imm))
break;
1987 if (!VALIDATE(imm.global->mutability)) {
1988 this->errorf(this->pc_,
"immutable global #%u cannot be assigned",
1992 auto value = Pop(0, imm.type);
1993 CALL_INTERFACE_IF_REACHABLE(SetGlobal, value, imm);
1996 case kExprI32LoadMem8S:
1997 len = 1 + DecodeLoadMem(LoadType::kI32Load8S);
1999 case kExprI32LoadMem8U:
2000 len = 1 + DecodeLoadMem(LoadType::kI32Load8U);
2002 case kExprI32LoadMem16S:
2003 len = 1 + DecodeLoadMem(LoadType::kI32Load16S);
2005 case kExprI32LoadMem16U:
2006 len = 1 + DecodeLoadMem(LoadType::kI32Load16U);
2008 case kExprI32LoadMem:
2009 len = 1 + DecodeLoadMem(LoadType::kI32Load);
2011 case kExprI64LoadMem8S:
2012 len = 1 + DecodeLoadMem(LoadType::kI64Load8S);
2014 case kExprI64LoadMem8U:
2015 len = 1 + DecodeLoadMem(LoadType::kI64Load8U);
2017 case kExprI64LoadMem16S:
2018 len = 1 + DecodeLoadMem(LoadType::kI64Load16S);
2020 case kExprI64LoadMem16U:
2021 len = 1 + DecodeLoadMem(LoadType::kI64Load16U);
2023 case kExprI64LoadMem32S:
2024 len = 1 + DecodeLoadMem(LoadType::kI64Load32S);
2026 case kExprI64LoadMem32U:
2027 len = 1 + DecodeLoadMem(LoadType::kI64Load32U);
2029 case kExprI64LoadMem:
2030 len = 1 + DecodeLoadMem(LoadType::kI64Load);
2032 case kExprF32LoadMem:
2033 len = 1 + DecodeLoadMem(LoadType::kF32Load);
2035 case kExprF64LoadMem:
2036 len = 1 + DecodeLoadMem(LoadType::kF64Load);
2038 case kExprI32StoreMem8:
2039 len = 1 + DecodeStoreMem(StoreType::kI32Store8);
2041 case kExprI32StoreMem16:
2042 len = 1 + DecodeStoreMem(StoreType::kI32Store16);
2044 case kExprI32StoreMem:
2045 len = 1 + DecodeStoreMem(StoreType::kI32Store);
2047 case kExprI64StoreMem8:
2048 len = 1 + DecodeStoreMem(StoreType::kI64Store8);
2050 case kExprI64StoreMem16:
2051 len = 1 + DecodeStoreMem(StoreType::kI64Store16);
2053 case kExprI64StoreMem32:
2054 len = 1 + DecodeStoreMem(StoreType::kI64Store32);
2056 case kExprI64StoreMem:
2057 len = 1 + DecodeStoreMem(StoreType::kI64Store);
2059 case kExprF32StoreMem:
2060 len = 1 + DecodeStoreMem(StoreType::kF32Store);
2062 case kExprF64StoreMem:
2063 len = 1 + DecodeStoreMem(StoreType::kF64Store);
2065 case kExprMemoryGrow: {
2066 if (!CheckHasMemory())
break;
2068 len = 1 + imm.length;
2069 DCHECK_NOT_NULL(this->module_);
2070 if (!VALIDATE(this->module_->origin == kWasmOrigin)) {
2071 this->error(
"grow_memory is not supported for asmjs modules");
2074 auto value = Pop(0, kWasmI32);
2075 auto* result = Push(kWasmI32);
2076 CALL_INTERFACE_IF_REACHABLE(MemoryGrow, value, result);
2079 case kExprMemorySize: {
2080 if (!CheckHasMemory())
break;
2082 auto* result = Push(kWasmI32);
2083 len = 1 + imm.length;
2084 CALL_INTERFACE_IF_REACHABLE(CurrentMemoryPages, result);
2087 case kExprCallFunction: {
2089 len = 1 + imm.length;
2090 if (!this->Validate(this->pc_, imm))
break;
2093 auto* returns = PushReturns(imm.sig);
2094 CALL_INTERFACE_IF_REACHABLE(CallDirect, imm, args_.data(), returns);
2097 case kExprCallIndirect: {
2099 len = 1 + imm.length;
2100 if (!this->Validate(this->pc_, imm))
break;
2101 auto index = Pop(0, kWasmI32);
2103 auto* returns = PushReturns(imm.sig);
2104 CALL_INTERFACE_IF_REACHABLE(CallIndirect, index, imm, args_.data(),
2108 case kNumericPrefix: {
2110 byte numeric_index = this->
template read_u8<validate>(
2111 this->pc_ + 1,
"numeric index");
2112 opcode =
static_cast<WasmOpcode
>(opcode << 8 | numeric_index);
2113 if (opcode < kExprMemoryInit) {
2114 CHECK_PROTOTYPE_OPCODE(sat_f2i_conversions);
2116 CHECK_PROTOTYPE_OPCODE(bulk_memory);
2118 TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
2119 WasmOpcodes::OpcodeName(opcode));
2120 len += DecodeNumericOpcode(opcode);
2124 CHECK_PROTOTYPE_OPCODE(simd);
2127 this->
template read_u8<validate>(this->pc_ + 1,
"simd index");
2128 opcode =
static_cast<WasmOpcode
>(opcode << 8 | simd_index);
2129 TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
2130 WasmOpcodes::OpcodeName(opcode));
2131 len += DecodeSimdOpcode(opcode);
2134 case kAtomicPrefix: {
2135 CHECK_PROTOTYPE_OPCODE(threads);
2136 if (!CheckHasSharedMemory())
break;
2139 this->
template read_u8<validate>(this->pc_ + 1,
"atomic index");
2140 opcode =
static_cast<WasmOpcode
>(opcode << 8 | atomic_index);
2141 TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
2142 WasmOpcodes::OpcodeName(opcode));
2143 len += DecodeAtomicOpcode(opcode);
2148 #define SIMPLE_PROTOTYPE_CASE(name, opc, sig) \ 2150 FOREACH_SIMPLE_PROTOTYPE_OPCODE(SIMPLE_PROTOTYPE_CASE)
2151 #undef SIMPLE_PROTOTYPE_CASE 2152 BuildSimplePrototypeOperator(opcode);
2156 if (this->module_ !=
nullptr &&
2157 this->module_->origin == kAsmJsOrigin) {
2158 sig = WasmOpcodes::AsmjsSignature(opcode);
2160 BuildSimpleOperator(opcode, sig);
2163 this->error(
"Invalid opcode");
2171 if (FLAG_trace_wasm_decoder) {
2173 for (Control& c : control_) {
2190 if (c.start_merge.arity) TRACE_PART(
"%u-", c.start_merge.arity);
2191 TRACE_PART(
"%u", c.end_merge.arity);
2192 if (!c.reachable()) TRACE_PART(
"%c", c.unreachable() ?
'*' :
'#');
2195 for (
size_t i = 0;
i < stack_.size(); ++
i) {
2196 auto& val = stack_[
i];
2197 WasmOpcode opcode =
static_cast<WasmOpcode
>(*val.pc);
2198 if (WasmOpcodes::IsPrefixOpcode(opcode)) {
2199 opcode =
static_cast<WasmOpcode
>(opcode << 8 | *(val.pc + 1));
2201 TRACE_PART(
" %c@%d:%s", ValueTypes::ShortNameOf(val.type),
2202 static_cast<int>(val.pc - this->start_),
2203 WasmOpcodes::OpcodeName(opcode));
2206 if (this->failed())
continue;
2208 case kExprI32Const: {
2210 TRACE_PART(
"[%d]", imm.value);
2215 case kExprTeeLocal: {
2217 TRACE_PART(
"[%u]", imm.index);
2220 case kExprGetGlobal:
2221 case kExprSetGlobal: {
2223 TRACE_PART(
"[%u]", imm.index);
2234 if (!VALIDATE(this->pc_ == this->end_) && this->ok()) {
2235 this->error(
"Beyond end of code");
2240 DCHECK(!control_.empty());
2241 auto* current = &control_.back();
2242 stack_.resize(current->stack_depth);
2243 CALL_INTERFACE_IF_REACHABLE(EndControl, current);
2244 current->reachability = kUnreachable;
2247 template<
typename func>
2249 merge->arity = arity;
2251 merge->vals.first = get_val(0);
2252 }
else if (arity > 1) {
2253 merge->vals.array = zone_->NewArray<Value>(arity);
2255 merge->vals.array[
i] = get_val(
i);
2261 DCHECK_EQ(imm.in_arity(), this->args_.size());
2262 const byte* pc = this->pc_;
2263 Value* args = this->args_.data();
2264 InitMerge(&c->end_merge, imm.out_arity(), [pc, &imm](
uint32_t i) {
2265 return Value::New(pc, imm.out_type(
i));
2267 InitMerge(&c->start_merge, imm.in_arity(),
2273 int count = sig ?
static_cast<int>(sig->parameter_count()) : 0;
2274 args_.resize(count);
2275 for (
int i = count - 1;
i >= 0; --
i) {
2276 args_[
i] = Pop(
i, sig->GetParam(
i));
2281 DCHECK_GE(1, sig->return_count());
2282 return sig->return_count() == 0 ? kWasmStmt : sig->GetReturn();
2285 Control* PushControl(Control&& new_control) {
2286 Reachability reachability =
2287 control_.empty() ? kReachable : control_.back().innerReachability();
2288 control_.emplace_back(std::move(new_control));
2289 Control* c = &control_.back();
2290 c->reachability = reachability;
2291 c->start_merge.reached = c->reachable();
2295 Control* PushBlock() {
2296 return PushControl(Control::Block(this->pc_, stack_size()));
2298 Control* PushLoop() {
2299 return PushControl(Control::Loop(this->pc_, stack_size()));
2302 return PushControl(Control::If(this->pc_, stack_size()));
2304 Control* PushTry() {
2306 return PushControl(Control::Try(this->pc_, stack_size()));
2309 void PopControl(Control* c) {
2310 DCHECK_EQ(c, &control_.back());
2311 CALL_INTERFACE_IF_PARENT_REACHABLE(PopControl, c);
2312 bool reached = c->end_merge.reached;
2313 control_.pop_back();
2316 if (!control_.empty() && !reached && control_.back().reachable()) {
2317 control_.back().reachability = kSpecOnlyReachable;
2322 if (!CheckHasMemory())
return 0;
2325 auto index = Pop(0, kWasmI32);
2326 auto* result = Push(
type.value_type());
2327 CALL_INTERFACE_IF_REACHABLE(LoadMem,
type, imm, index, result);
2331 int DecodeStoreMem(
StoreType store,
int prefix_len = 0) {
2332 if (!CheckHasMemory())
return 0;
2334 store.size_log_2());
2335 auto value = Pop(1, store.value_type());
2336 auto index = Pop(0, kWasmI32);
2337 CALL_INTERFACE_IF_REACHABLE(StoreMem, store, imm, index, value);
2341 uint32_t SimdExtractLane(WasmOpcode opcode, ValueType
type) {
2343 if (this->Validate(this->pc_, opcode, imm)) {
2344 Value inputs[] = {Pop(0, kWasmS128)};
2345 auto* result = Push(
type);
2346 CALL_INTERFACE_IF_REACHABLE(SimdLaneOp, opcode, imm, ArrayVector(inputs),
2352 uint32_t SimdReplaceLane(WasmOpcode opcode, ValueType
type) {
2354 if (this->Validate(this->pc_, opcode, imm)) {
2356 inputs[1] = Pop(1,
type);
2357 inputs[0] = Pop(0, kWasmS128);
2358 auto* result = Push(kWasmS128);
2359 CALL_INTERFACE_IF_REACHABLE(SimdLaneOp, opcode, imm, ArrayVector(inputs),
2365 uint32_t SimdShiftOp(WasmOpcode opcode) {
2367 if (this->Validate(this->pc_, opcode, imm)) {
2368 auto input = Pop(0, kWasmS128);
2369 auto* result = Push(kWasmS128);
2370 CALL_INTERFACE_IF_REACHABLE(SimdShiftOp, opcode, imm, input, result);
2377 if (this->Validate(this->pc_, imm)) {
2378 auto input1 = Pop(1, kWasmS128);
2379 auto input0 = Pop(0, kWasmS128);
2380 auto* result = Push(kWasmS128);
2381 CALL_INTERFACE_IF_REACHABLE(Simd8x16ShuffleOp, imm, input0, input1,
2387 uint32_t DecodeSimdOpcode(WasmOpcode opcode) {
2390 case kExprF32x4ExtractLane: {
2391 len = SimdExtractLane(opcode, kWasmF32);
2394 case kExprI32x4ExtractLane:
2395 case kExprI16x8ExtractLane:
2396 case kExprI8x16ExtractLane: {
2397 len = SimdExtractLane(opcode, kWasmI32);
2400 case kExprF32x4ReplaceLane: {
2401 len = SimdReplaceLane(opcode, kWasmF32);
2404 case kExprI32x4ReplaceLane:
2405 case kExprI16x8ReplaceLane:
2406 case kExprI8x16ReplaceLane: {
2407 len = SimdReplaceLane(opcode, kWasmI32);
2411 case kExprI32x4ShrS:
2412 case kExprI32x4ShrU:
2414 case kExprI16x8ShrS:
2415 case kExprI16x8ShrU:
2417 case kExprI8x16ShrS:
2418 case kExprI8x16ShrU: {
2419 len = SimdShiftOp(opcode);
2422 case kExprS8x16Shuffle: {
2423 len = Simd8x16ShuffleOp();
2426 case kExprS128LoadMem:
2427 len = DecodeLoadMem(LoadType::kS128Load, 1);
2429 case kExprS128StoreMem:
2430 len = DecodeStoreMem(StoreType::kS128Store, 1);
2433 FunctionSig* sig = WasmOpcodes::Signature(opcode);
2434 if (!VALIDATE(sig !=
nullptr)) {
2435 this->error(
"invalid simd opcode");
2440 sig->return_count() == 0 ? nullptr : Push(GetReturnType(sig));
2441 CALL_INTERFACE_IF_REACHABLE(SimdOp, opcode, VectorOf(args_), results);
2447 uint32_t DecodeAtomicOpcode(WasmOpcode opcode) {
2450 FunctionSig* sig = WasmOpcodes::Signature(opcode);
2451 if (sig !=
nullptr) {
2454 #define CASE_ATOMIC_STORE_OP(Name, Type) \ 2455 case kExpr##Name: { \ 2456 memtype = MachineType::Type(); \ 2457 ret_type = kWasmStmt; \ 2460 ATOMIC_STORE_OP_LIST(CASE_ATOMIC_STORE_OP)
2461 #undef CASE_ATOMIC_OP 2462 #define CASE_ATOMIC_OP(Name, Type) \ 2463 case kExpr##Name: { \ 2464 memtype = MachineType::Type(); \ 2465 ret_type = GetReturnType(sig); \ 2468 ATOMIC_OP_LIST(CASE_ATOMIC_OP)
2469 #undef CASE_ATOMIC_OP 2471 this->error(
"invalid atomic opcode");
2475 this, this->pc_ + 1, ElementSizeLog2Of(memtype.representation()));
2478 auto result = ret_type == kWasmStmt ? nullptr : Push(GetReturnType(sig));
2479 CALL_INTERFACE_IF_REACHABLE(AtomicOp, opcode, VectorOf(args_), imm,
2482 this->error(
"invalid atomic opcode");
2487 unsigned DecodeNumericOpcode(WasmOpcode opcode) {
2489 FunctionSig* sig = WasmOpcodes::Signature(opcode);
2490 if (sig !=
nullptr) {
2492 case kExprI32SConvertSatF32:
2493 case kExprI32UConvertSatF32:
2494 case kExprI32SConvertSatF64:
2495 case kExprI32UConvertSatF64:
2496 case kExprI64SConvertSatF32:
2497 case kExprI64UConvertSatF32:
2498 case kExprI64SConvertSatF64:
2499 case kExprI64UConvertSatF64:
2500 BuildSimpleOperator(opcode, sig);
2502 case kExprMemoryInit: {
2504 if (!this->Validate(imm))
break;
2507 CALL_INTERFACE_IF_REACHABLE(MemoryInit, imm, VectorOf(args_));
2510 case kExprMemoryDrop: {
2512 if (!this->Validate(imm))
break;
2514 CALL_INTERFACE_IF_REACHABLE(MemoryDrop, imm);
2517 case kExprMemoryCopy: {
2519 if (!this->Validate(imm))
break;
2522 CALL_INTERFACE_IF_REACHABLE(MemoryCopy, imm, VectorOf(args_));
2525 case kExprMemoryFill: {
2527 if (!this->Validate(imm))
break;
2530 CALL_INTERFACE_IF_REACHABLE(MemoryFill, imm, VectorOf(args_));
2533 case kExprTableInit: {
2535 if (!this->Validate(imm))
break;
2538 CALL_INTERFACE_IF_REACHABLE(TableInit, imm, VectorOf(args_));
2541 case kExprTableDrop: {
2543 if (!this->Validate(imm))
break;
2545 CALL_INTERFACE_IF_REACHABLE(TableDrop, imm);
2548 case kExprTableCopy: {
2550 if (!this->Validate(this->pc_ + 1, imm))
break;
2553 CALL_INTERFACE_IF_REACHABLE(TableCopy, imm, VectorOf(args_));
2557 this->error(
"invalid numeric opcode");
2561 this->error(
"invalid numeric opcode");
2566 void DoReturn(Control* c,
bool implicit) {
2567 int return_count =
static_cast<int>(this->sig_->return_count());
2568 args_.resize(return_count);
2571 for (
int i = return_count - 1;
i >= 0; --
i) {
2572 args_[
i] = Pop(
i, this->sig_->GetReturn(
i));
2576 if (implicit && c->end_merge.reached) c->reachability = kReachable;
2577 CALL_INTERFACE_IF_REACHABLE(DoReturn, VectorOf(args_), implicit);
2582 inline Value* Push(ValueType
type) {
2583 DCHECK_NE(kWasmStmt,
type);
2584 stack_.push_back(Value::New(this->pc_,
type));
2585 return &stack_.back();
2588 void PushMergeValues(Control* c,
Merge<Value>* merge) {
2589 DCHECK_EQ(c, &control_.back());
2590 DCHECK(merge == &c->start_merge || merge == &c->end_merge);
2591 stack_.resize(c->stack_depth);
2592 if (merge->arity == 1) {
2593 stack_.push_back(merge->vals.first);
2596 stack_.push_back(merge->vals.array[
i]);
2599 DCHECK_EQ(c->stack_depth + merge->arity, stack_.size());
2603 size_t return_count = sig->return_count();
2604 if (return_count == 0)
return nullptr;
2605 size_t old_size = stack_.size();
2606 for (
size_t i = 0;
i < return_count; ++
i) {
2607 Push(sig->GetReturn(
i));
2609 return stack_.data() + old_size;
2612 Value Pop(
int index, ValueType expected) {
2614 if (!VALIDATE(val.type == expected || val.type == kWasmVar ||
2615 expected == kWasmVar)) {
2616 this->errorf(val.pc,
"%s[%d] expected type %s, found %s of type %s",
2617 SafeOpcodeNameAt(this->pc_), index,
2618 ValueTypes::TypeName(expected), SafeOpcodeNameAt(val.pc),
2619 ValueTypes::TypeName(val.type));
2625 DCHECK(!control_.empty());
2626 uint32_t limit = control_.back().stack_depth;
2627 if (stack_.size() <= limit) {
2629 if (!VALIDATE(control_.back().unreachable())) {
2630 this->errorf(this->pc_,
"%s found empty stack",
2631 SafeOpcodeNameAt(this->pc_));
2633 return Value::Unreachable(this->pc_);
2635 auto val = stack_.back();
2640 int startrel(
const byte* ptr) {
return static_cast<int>(ptr - this->start_); }
2642 void FallThruTo(Control* c) {
2643 DCHECK_EQ(c, &control_.back());
2644 if (!TypeCheckFallThru(c))
return;
2645 if (!c->reachable())
return;
2647 if (!c->is_loop()) CALL_INTERFACE(FallThruTo, c);
2648 c->end_merge.reached =
true;
2651 bool TypeCheckMergeValues(Control* c,
Merge<Value>* merge) {
2652 DCHECK(merge == &c->start_merge || merge == &c->end_merge);
2653 DCHECK_GE(stack_.size(), c->stack_depth + merge->arity);
2656 auto& val = GetMergeValueFromStack(c, merge,
i);
2657 auto& old = (*merge)[
i];
2658 if (val.type != old.type) {
2662 if (!VALIDATE(val.type == kWasmVar)) {
2664 this->pc_,
"type error in merge[%u] (expected %s, got %s)",
i,
2665 ValueTypes::TypeName(old.type), ValueTypes::TypeName(val.type));
2668 val.type = old.type;
2675 bool TypeCheckFallThru(Control* c) {
2676 DCHECK_EQ(c, &control_.back());
2677 if (!validate)
return true;
2678 uint32_t expected = c->end_merge.arity;
2679 DCHECK_GE(stack_.size(), c->stack_depth);
2682 if (!InsertUnreachablesIfNecessary(expected, actual) || actual > expected) {
2685 "expected %u elements on the stack for fallthru to @%d, found %u",
2686 expected, startrel(c->pc), actual);
2690 return TypeCheckMergeValues(c, &c->end_merge);
2693 bool TypeCheckBreak(Control* c) {
2695 uint32_t expected = c->br_merge()->arity;
2696 DCHECK_GE(stack_.size(), control_.back().stack_depth);
2698 static_cast<uint32_t>(stack_.size()) - control_.back().stack_depth;
2699 if (!InsertUnreachablesIfNecessary(expected, actual)) {
2700 this->errorf(this->pc_,
2701 "expected %u elements on the stack for br to @%d, found %u",
2702 expected, startrel(c->pc), actual);
2705 return TypeCheckMergeValues(c, c->br_merge());
2708 inline bool InsertUnreachablesIfNecessary(
uint32_t expected,
2710 if (V8_LIKELY(actual >= expected)) {
2713 if (!VALIDATE(control_.back().unreachable())) {
2721 auto pos = stack_.begin() + (stack_.size() - actual);
2722 stack_.insert(pos, (expected - actual), Value::Unreachable(this->pc_));
2726 void onFirstError()
override {
2727 this->end_ = this->pc_;
2728 TRACE(
" !%s\n", this->error_msg_.c_str());
2729 CALL_INTERFACE(OnFirstError);
2732 void BuildSimplePrototypeOperator(WasmOpcode opcode) {
2733 if (WasmOpcodes::IsSignExtensionOpcode(opcode)) {
2734 RET_ON_PROTOTYPE_OPCODE(se);
2736 if (WasmOpcodes::IsAnyRefOpcode(opcode)) {
2737 RET_ON_PROTOTYPE_OPCODE(anyref);
2739 FunctionSig* sig = WasmOpcodes::Signature(opcode);
2740 BuildSimpleOperator(opcode, sig);
2743 inline void BuildSimpleOperator(WasmOpcode opcode,
FunctionSig* sig) {
2744 switch (sig->parameter_count()) {
2746 auto val = Pop(0, sig->GetParam(0));
2748 sig->return_count() == 0 ? nullptr : Push(sig->GetReturn(0));
2749 CALL_INTERFACE_IF_REACHABLE(UnOp, opcode, sig, val, ret);
2753 auto rval = Pop(1, sig->GetParam(1));
2754 auto lval = Pop(0, sig->GetParam(0));
2756 sig->return_count() == 0 ? nullptr : Push(sig->GetReturn(0));
2757 CALL_INTERFACE_IF_REACHABLE(BinOp, opcode, sig, lval, rval, ret);
2766 #undef CALL_INTERFACE 2767 #undef CALL_INTERFACE_IF_REACHABLE 2768 #undef CALL_INTERFACE_IF_PARENT_REACHABLE 2772 static constexpr Decoder::ValidateFlag validate = Decoder::kValidate;
2777 #define DEFINE_EMPTY_CALLBACK(name, ...) \ 2778 void name(FullDecoder* decoder, ##__VA_ARGS__) {} 2779 INTERFACE_FUNCTIONS(DEFINE_EMPTY_CALLBACK)
2780 #undef DEFINE_EMPTY_CALLBACK 2784 #undef TRACE_INST_FORMAT 2786 #undef CHECK_PROTOTYPE_OPCODE 2793 #endif // V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_