summaryrefslogtreecommitdiff
path: root/chromium/v8/src/wasm/function-body-decoder-impl.h
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/v8/src/wasm/function-body-decoder-impl.h')
-rw-r--r--chromium/v8/src/wasm/function-body-decoder-impl.h263
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