diff options
Diffstat (limited to 'chromium/v8/src/wasm/function-body-decoder-impl.h')
-rw-r--r-- | chromium/v8/src/wasm/function-body-decoder-impl.h | 263 |
1 files changed, 151 insertions, 112 deletions
diff --git a/chromium/v8/src/wasm/function-body-decoder-impl.h b/chromium/v8/src/wasm/function-body-decoder-impl.h index ffbf85cde8e..04d918b0a4f 100644 --- a/chromium/v8/src/wasm/function-body-decoder-impl.h +++ b/chromium/v8/src/wasm/function-body-decoder-impl.h @@ -22,14 +22,12 @@ namespace wasm { struct WasmGlobal; struct WasmException; -#if DEBUG #define TRACE(...) \ do { \ if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ } while (false) -#else -#define TRACE(...) -#endif + +#define TRACE_INST_FORMAT " @%-8d #%-20s|" // Return the evaluation of `condition` if validate==true, DCHECK that it's // true and always return true otherwise. @@ -250,10 +248,11 @@ struct CallIndirectOperand { uint32_t table_index; uint32_t index; FunctionSig* sig = nullptr; - unsigned length; + unsigned length = 0; inline CallIndirectOperand(Decoder* decoder, const byte* pc) { unsigned len = 0; index = decoder->read_u32v<validate>(pc + 1, &len, "signature index"); + if (!VALIDATE(decoder->ok())) return; table_index = decoder->read_u8<validate>(pc + 1 + len, "table index"); if (!VALIDATE(table_index == 0)) { decoder->errorf(pc + 1 + len, "expected table index 0, found %u", @@ -342,7 +341,7 @@ template <Decoder::ValidateFlag validate> struct MemoryAccessOperand { uint32_t alignment; uint32_t offset; - unsigned length; + unsigned length = 0; inline MemoryAccessOperand(Decoder* decoder, const byte* pc, uint32_t max_alignment) { unsigned alignment_length; @@ -354,6 +353,7 @@ struct MemoryAccessOperand { "actual alignment is %u", max_alignment, alignment); } + if (!VALIDATE(decoder->ok())) return; unsigned offset_length; offset = decoder->read_u32v<validate>(pc + 1 + alignment_length, &offset_length, "offset"); @@ -386,11 +386,12 @@ struct SimdShiftOperand { // Operand for SIMD S8x16 shuffle operations. template <Decoder::ValidateFlag validate> struct Simd8x16ShuffleOperand { - uint8_t shuffle[kSimd128Size]; + uint8_t shuffle[kSimd128Size] = {0}; inline Simd8x16ShuffleOperand(Decoder* decoder, const byte* pc) { for (uint32_t i = 0; i < kSimd128Size; ++i) { shuffle[i] = decoder->read_u8<validate>(pc + 2 + i, "shuffle"); + if (!VALIDATE(decoder->ok())) return; } } }; @@ -550,6 +551,7 @@ struct ControlWithNamedConstructors : public ControlBase<Value> { F(StartFunctionBody, Control* block) \ F(FinishFunction) \ F(OnFirstError) \ + F(NextInstruction, WasmOpcode) \ /* Control: */ \ F(Block, Control* block) \ F(Loop, Control* block) \ @@ -582,12 +584,10 @@ struct ControlWithNamedConstructors : public ControlBase<Value> { F(BrIf, const Value& cond, Control* target) \ F(BrTable, const BranchTableOperand<validate>& operand, const Value& key) \ F(Else, Control* if_block) \ - F(LoadMem, ValueType type, MachineType mem_type, \ - const MemoryAccessOperand<validate>& operand, const Value& index, \ - Value* result) \ - F(StoreMem, ValueType type, MachineType mem_type, \ - const MemoryAccessOperand<validate>& operand, const Value& index, \ - const Value& value) \ + F(LoadMem, LoadType type, const MemoryAccessOperand<validate>& operand, \ + const Value& index, Value* result) \ + F(StoreMem, StoreType type, const MemoryAccessOperand<validate>& operand, \ + const Value& index, const Value& value) \ F(CurrentMemoryPages, Value* result) \ F(GrowMemory, const Value& value, Value* result) \ F(CallDirect, const CallFunctionOperand<validate>& operand, \ @@ -974,6 +974,8 @@ class WasmDecoder : public Decoder { return 5; case kExprF64Const: return 9; + case kNumericPrefix: + return 2; case kSimdPrefix: { byte simd_index = decoder->read_u8<validate>(pc + 1, "simd_index"); WasmOpcode opcode = @@ -1026,9 +1028,6 @@ class WasmDecoder : public Decoder { std::pair<uint32_t, uint32_t> StackEffect(const byte* pc) { WasmOpcode opcode = static_cast<WasmOpcode>(*pc); - if (WasmOpcodes::IsPrefixOpcode(opcode)) { - opcode = static_cast<WasmOpcode>(opcode << 8 | *(pc + 1)); - } // Handle "simple" opcodes with a fixed signature first. FunctionSig* sig = WasmOpcodes::Signature(opcode); if (!sig) sig = WasmOpcodes::AsmjsSignature(opcode); @@ -1039,10 +1038,8 @@ class WasmDecoder : public Decoder { switch (opcode) { case kExprSelect: return {3, 1}; - case kExprS128StoreMem: FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) return {2, 0}; - case kExprS128LoadMem: FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) case kExprTeeLocal: case kExprGrowMemory: @@ -1083,6 +1080,24 @@ class WasmDecoder : public Decoder { case kExprReturn: case kExprUnreachable: return {0, 0}; + case kNumericPrefix: + case kAtomicPrefix: + case kSimdPrefix: { + opcode = static_cast<WasmOpcode>(opcode << 8 | *(pc + 1)); + switch (opcode) { + case kExprI32AtomicStore: + case kExprI32AtomicStore8U: + case kExprI32AtomicStore16U: + case kExprS128StoreMem: + return {2, 0}; + default: { + sig = WasmOpcodes::Signature(opcode); + if (sig) { + return {sig->parameter_count(), sig->return_count()}; + } + } + } + } default: V8_Fatal(__FILE__, __LINE__, "unimplemented opcode: %x (%s)", opcode, WasmOpcodes::OpcodeName(opcode)); @@ -1142,9 +1157,6 @@ class WasmFullDecoder : public WasmDecoder<validate> { DCHECK(stack_.empty()); DCHECK(control_.empty()); - if (FLAG_wasm_code_fuzzer_gen_test) { - PrintRawWasmCode(this->start_, this->end_); - } base::ElapsedTimer decode_timer; if (FLAG_trace_wasm_decode_time) { decode_timer.Start(); @@ -1273,6 +1285,32 @@ class WasmFullDecoder : public WasmDecoder<validate> { return true; } + class TraceLine { + public: + static constexpr int kMaxLen = 512; + ~TraceLine() { + if (!FLAG_trace_wasm_decoder) return; + PrintF("%.*s\n", len_, buffer_); + } + + // Appends a formatted string. + PRINTF_FORMAT(2, 3) + void Append(const char* format, ...) { + if (!FLAG_trace_wasm_decoder) return; + va_list va_args; + va_start(va_args, format); + size_t remaining_len = kMaxLen - len_; + Vector<char> remaining_msg_space(buffer_ + len_, remaining_len); + int len = VSNPrintF(remaining_msg_space, format, va_args); + va_end(va_args); + len_ += len < 0 ? remaining_len : len; + } + + private: + char buffer_[kMaxLen]; + int len_ = 0; + }; + // Decodes the body of a function. void DecodeFunctionBody() { TRACE("wasm-decode %p...%p (module+%u, %d bytes)\n", @@ -1294,11 +1332,18 @@ class WasmFullDecoder : public WasmDecoder<validate> { while (this->pc_ < this->end_) { // decoding loop. unsigned len = 1; WasmOpcode opcode = static_cast<WasmOpcode>(*this->pc_); + + CALL_INTERFACE_IF_REACHABLE(NextInstruction, opcode); + #if DEBUG - if (FLAG_trace_wasm_decoder && !WasmOpcodes::IsPrefixOpcode(opcode)) { - TRACE(" @%-8d #%-20s|", startrel(this->pc_), - WasmOpcodes::OpcodeName(opcode)); + TraceLine trace_msg; +#define TRACE_PART(...) trace_msg.Append(__VA_ARGS__) + if (!WasmOpcodes::IsPrefixOpcode(opcode)) { + TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_), + WasmOpcodes::OpcodeName(opcode)); } +#else +#define TRACE_PART(...) #endif FunctionSig* sig = WasmOpcodes::Signature(opcode); @@ -1430,8 +1475,8 @@ class WasmFullDecoder : public WasmDecoder<validate> { this->error(this->pc_, "else already present for if"); break; } - c->kind = kControlIfElse; FallThruTo(c); + c->kind = kControlIfElse; CALL_INTERFACE_IF_PARENT_REACHABLE(Else, c); PushMergeValues(c, &c->start_merge); c->reachability = control_at(1)->innerReachability(); @@ -1450,6 +1495,7 @@ class WasmFullDecoder : public WasmDecoder<validate> { if (c->is_onearmed_if()) { // Emulate empty else arm. FallThruTo(c); + if (this->failed()) break; CALL_INTERFACE_IF_PARENT_REACHABLE(Else, c); PushMergeValues(c, &c->start_merge); c->reachability = control_at(1)->innerReachability(); @@ -1467,10 +1513,9 @@ class WasmFullDecoder : public WasmDecoder<validate> { } last_end_found_ = true; // The result of the block is the return value. - TRACE(" @%-8d #xx:%-20s|", startrel(this->pc_), - "(implicit) return"); + TRACE_PART("\n" TRACE_INST_FORMAT, startrel(this->pc_), + "(implicit) return"); DoReturn(c, true); - TRACE("\n"); } PopControl(c); @@ -1630,73 +1675,73 @@ class WasmFullDecoder : public WasmDecoder<validate> { break; } case kExprI32LoadMem8S: - len = DecodeLoadMem(kWasmI32, MachineType::Int8()); + len = 1 + DecodeLoadMem(LoadType::kI32Load8S); break; case kExprI32LoadMem8U: - len = DecodeLoadMem(kWasmI32, MachineType::Uint8()); + len = 1 + DecodeLoadMem(LoadType::kI32Load8U); break; case kExprI32LoadMem16S: - len = DecodeLoadMem(kWasmI32, MachineType::Int16()); + len = 1 + DecodeLoadMem(LoadType::kI32Load16S); break; case kExprI32LoadMem16U: - len = DecodeLoadMem(kWasmI32, MachineType::Uint16()); + len = 1 + DecodeLoadMem(LoadType::kI32Load16U); break; case kExprI32LoadMem: - len = DecodeLoadMem(kWasmI32, MachineType::Int32()); + len = 1 + DecodeLoadMem(LoadType::kI32Load); break; case kExprI64LoadMem8S: - len = DecodeLoadMem(kWasmI64, MachineType::Int8()); + len = 1 + DecodeLoadMem(LoadType::kI64Load8S); break; case kExprI64LoadMem8U: - len = DecodeLoadMem(kWasmI64, MachineType::Uint8()); + len = 1 + DecodeLoadMem(LoadType::kI64Load8U); break; case kExprI64LoadMem16S: - len = DecodeLoadMem(kWasmI64, MachineType::Int16()); + len = 1 + DecodeLoadMem(LoadType::kI64Load16S); break; case kExprI64LoadMem16U: - len = DecodeLoadMem(kWasmI64, MachineType::Uint16()); + len = 1 + DecodeLoadMem(LoadType::kI64Load16U); break; case kExprI64LoadMem32S: - len = DecodeLoadMem(kWasmI64, MachineType::Int32()); + len = 1 + DecodeLoadMem(LoadType::kI64Load32S); break; case kExprI64LoadMem32U: - len = DecodeLoadMem(kWasmI64, MachineType::Uint32()); + len = 1 + DecodeLoadMem(LoadType::kI64Load32U); break; case kExprI64LoadMem: - len = DecodeLoadMem(kWasmI64, MachineType::Int64()); + len = 1 + DecodeLoadMem(LoadType::kI64Load); break; case kExprF32LoadMem: - len = DecodeLoadMem(kWasmF32, MachineType::Float32()); + len = 1 + DecodeLoadMem(LoadType::kF32Load); break; case kExprF64LoadMem: - len = DecodeLoadMem(kWasmF64, MachineType::Float64()); + len = 1 + DecodeLoadMem(LoadType::kF64Load); break; case kExprI32StoreMem8: - len = DecodeStoreMem(kWasmI32, MachineType::Int8()); + len = 1 + DecodeStoreMem(StoreType::kI32Store8); break; case kExprI32StoreMem16: - len = DecodeStoreMem(kWasmI32, MachineType::Int16()); + len = 1 + DecodeStoreMem(StoreType::kI32Store16); break; case kExprI32StoreMem: - len = DecodeStoreMem(kWasmI32, MachineType::Int32()); + len = 1 + DecodeStoreMem(StoreType::kI32Store); break; case kExprI64StoreMem8: - len = DecodeStoreMem(kWasmI64, MachineType::Int8()); + len = 1 + DecodeStoreMem(StoreType::kI64Store8); break; case kExprI64StoreMem16: - len = DecodeStoreMem(kWasmI64, MachineType::Int16()); + len = 1 + DecodeStoreMem(StoreType::kI64Store16); break; case kExprI64StoreMem32: - len = DecodeStoreMem(kWasmI64, MachineType::Int32()); + len = 1 + DecodeStoreMem(StoreType::kI64Store32); break; case kExprI64StoreMem: - len = DecodeStoreMem(kWasmI64, MachineType::Int64()); + len = 1 + DecodeStoreMem(StoreType::kI64Store); break; case kExprF32StoreMem: - len = DecodeStoreMem(kWasmF32, MachineType::Float32()); + len = 1 + DecodeStoreMem(StoreType::kF32Store); break; case kExprF64StoreMem: - len = DecodeStoreMem(kWasmF64, MachineType::Float64()); + len = 1 + DecodeStoreMem(StoreType::kF64Store); break; case kExprGrowMemory: { if (!CheckHasMemory()) break; @@ -1742,14 +1787,31 @@ class WasmFullDecoder : public WasmDecoder<validate> { args_.data(), returns); break; } + case kNumericPrefix: { + CHECK_PROTOTYPE_OPCODE(sat_f2i_conversions); + ++len; + byte numeric_index = this->template read_u8<validate>( + this->pc_ + 1, "numeric index"); + opcode = static_cast<WasmOpcode>(opcode << 8 | numeric_index); + TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_), + WasmOpcodes::OpcodeName(opcode)); + sig = WasmOpcodes::Signature(opcode); + if (sig == nullptr) { + this->errorf(this->pc_, "Unrecognized numeric opcode: %x\n", + opcode); + return; + } + BuildSimpleOperator(opcode, sig); + break; + } case kSimdPrefix: { CHECK_PROTOTYPE_OPCODE(simd); len++; byte simd_index = this->template read_u8<validate>(this->pc_ + 1, "simd index"); opcode = static_cast<WasmOpcode>(opcode << 8 | simd_index); - TRACE(" @%-4d #%-20s|", startrel(this->pc_), - WasmOpcodes::OpcodeName(opcode)); + TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_), + WasmOpcodes::OpcodeName(opcode)); len += DecodeSimdOpcode(opcode); break; } @@ -1760,8 +1822,8 @@ class WasmFullDecoder : public WasmDecoder<validate> { byte atomic_index = this->template read_u8<validate>(this->pc_ + 1, "atomic index"); opcode = static_cast<WasmOpcode>(opcode << 8 | atomic_index); - TRACE(" @%-4d #%-20s|", startrel(this->pc_), - WasmOpcodes::OpcodeName(opcode)); + TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_), + WasmOpcodes::OpcodeName(opcode)); len += DecodeAtomicOpcode(opcode); break; } @@ -1782,62 +1844,64 @@ class WasmFullDecoder : public WasmDecoder<validate> { #if DEBUG if (FLAG_trace_wasm_decoder) { - PrintF(" "); + TRACE_PART(" "); for (Control& c : control_) { switch (c.kind) { case kControlIf: - PrintF("I"); + TRACE_PART("I"); break; case kControlBlock: - PrintF("B"); + TRACE_PART("B"); break; case kControlLoop: - PrintF("L"); + TRACE_PART("L"); break; case kControlTry: - PrintF("T"); + TRACE_PART("T"); break; default: break; } - if (c.start_merge.arity) PrintF("%u-", c.start_merge.arity); - PrintF("%u", c.end_merge.arity); - if (!c.reachable()) PrintF("%c", c.unreachable() ? '*' : '#'); + if (c.start_merge.arity) TRACE_PART("%u-", c.start_merge.arity); + TRACE_PART("%u", c.end_merge.arity); + if (!c.reachable()) TRACE_PART("%c", c.unreachable() ? '*' : '#'); } - PrintF(" | "); + TRACE_PART(" | "); for (size_t i = 0; i < stack_.size(); ++i) { auto& val = stack_[i]; WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc); if (WasmOpcodes::IsPrefixOpcode(opcode)) { opcode = static_cast<WasmOpcode>(opcode << 8 | *(val.pc + 1)); } - PrintF(" %c@%d:%s", WasmOpcodes::ShortNameOf(val.type), - static_cast<int>(val.pc - this->start_), - WasmOpcodes::OpcodeName(opcode)); + TRACE_PART(" %c@%d:%s", WasmOpcodes::ShortNameOf(val.type), + static_cast<int>(val.pc - this->start_), + WasmOpcodes::OpcodeName(opcode)); + // If the decoder failed, don't try to decode the operands, as this + // can trigger a DCHECK failure. + if (this->failed()) continue; switch (opcode) { case kExprI32Const: { - ImmI32Operand<validate> operand(this, val.pc); - PrintF("[%d]", operand.value); + ImmI32Operand<Decoder::kNoValidate> operand(this, val.pc); + TRACE_PART("[%d]", operand.value); break; } case kExprGetLocal: case kExprSetLocal: case kExprTeeLocal: { - LocalIndexOperand<Decoder::kValidate> operand(this, val.pc); - PrintF("[%u]", operand.index); + LocalIndexOperand<Decoder::kNoValidate> operand(this, val.pc); + TRACE_PART("[%u]", operand.index); break; } case kExprGetGlobal: case kExprSetGlobal: { - GlobalIndexOperand<validate> operand(this, val.pc); - PrintF("[%u]", operand.index); + GlobalIndexOperand<Decoder::kNoValidate> operand(this, val.pc); + TRACE_PART("[%u]", operand.index); break; } default: break; } } - PrintF("\n"); } #endif this->pc_ += len; @@ -1941,49 +2005,23 @@ class WasmFullDecoder : public WasmDecoder<validate> { } } - int DecodeLoadMem(ValueType type, MachineType mem_type) { + int DecodeLoadMem(LoadType type, int prefix_len = 0) { if (!CheckHasMemory()) return 0; - MemoryAccessOperand<validate> operand( - this, this->pc_, ElementSizeLog2Of(mem_type.representation())); - - auto index = Pop(0, kWasmI32); - auto* result = Push(type); - CALL_INTERFACE_IF_REACHABLE(LoadMem, type, mem_type, operand, index, - result); - return 1 + operand.length; - } - - int DecodeStoreMem(ValueType type, MachineType mem_type) { - if (!CheckHasMemory()) return 0; - MemoryAccessOperand<validate> operand( - this, this->pc_, ElementSizeLog2Of(mem_type.representation())); - auto value = Pop(1, type); - auto index = Pop(0, kWasmI32); - CALL_INTERFACE_IF_REACHABLE(StoreMem, type, mem_type, operand, index, - value); - return 1 + operand.length; - } - - int DecodePrefixedLoadMem(ValueType type, MachineType mem_type) { - if (!CheckHasMemory()) return 0; - MemoryAccessOperand<validate> operand( - this, this->pc_ + 1, ElementSizeLog2Of(mem_type.representation())); - + MemoryAccessOperand<validate> operand(this, this->pc_ + prefix_len, + type.size_log_2()); auto index = Pop(0, kWasmI32); - auto* result = Push(type); - CALL_INTERFACE_IF_REACHABLE(LoadMem, type, mem_type, operand, index, - result); + auto* result = Push(type.value_type()); + CALL_INTERFACE_IF_REACHABLE(LoadMem, type, operand, index, result); return operand.length; } - int DecodePrefixedStoreMem(ValueType type, MachineType mem_type) { + int DecodeStoreMem(StoreType store, int prefix_len = 0) { if (!CheckHasMemory()) return 0; - MemoryAccessOperand<validate> operand( - this, this->pc_ + 1, ElementSizeLog2Of(mem_type.representation())); - auto value = Pop(1, type); + MemoryAccessOperand<validate> operand(this, this->pc_ + prefix_len, + store.size_log_2()); + auto value = Pop(1, store.value_type()); auto index = Pop(0, kWasmI32); - CALL_INTERFACE_IF_REACHABLE(StoreMem, type, mem_type, operand, index, - value); + CALL_INTERFACE_IF_REACHABLE(StoreMem, store, operand, index, value); return operand.length; } @@ -2073,10 +2111,10 @@ class WasmFullDecoder : public WasmDecoder<validate> { break; } case kExprS128LoadMem: - len = DecodePrefixedLoadMem(kWasmS128, MachineType::Simd128()); + len = DecodeLoadMem(LoadType::kS128Load, 1); break; case kExprS128StoreMem: - len = DecodePrefixedStoreMem(kWasmS128, MachineType::Simd128()); + len = DecodeStoreMem(StoreType::kS128Store, 1); break; default: { FunctionSig* sig = WasmOpcodes::Signature(opcode); @@ -2347,6 +2385,7 @@ class EmptyInterface { }; #undef TRACE +#undef TRACE_INST_FORMAT #undef VALIDATE #undef CHECK_PROTOTYPE_OPCODE #undef OPCODE_ERROR |