[wasm][refactor] Rework immediate-argument abstractions
Motivation: The immediate-argument classes defined in function-body-decoder.h were often adding an offset to the provided pc. This was inconsistent, bug-prone, and counterintuitive. This CL imposes that all immediates are passed as pc the start of the immediate argument they are parsing. Some other smaller inconsistencies are fixed as well. Changes: src/wasm/: - Enforce that all Immediates are passed the pc at the start of the argument they are parsing. Adapt all call sites. - Remove unneeded offset arguments from two SIMD related immediates. - Add a pc argument to all Validate functions for immediates instead of using the Decoder's current pc. - Remove the (unused) pc argument from all Complete functions for immediates. - Introduce Validate() for BranchOnExceptionImmediate. - In WasmDecoder::Decode(), make sure len is updated before breaking out of the loop in case of a Validate() failure. - Change the default prefix_len of DecodeLoadMem/DecodeStoreMem to 1. wasm-interpreter.cc: - Change the default prefix_len of ExecuteLoad/Store to 1. - Adapt offsets in calls to Immediates. - Remove redundant opcode_length argument from ExecuteSimdOp, use len in its place. function-body-decoder-unittest.cc - Adapt offsets in calls to Immediates. - Introduce and use EXPECT_OK, as is done in other tests. Change-Id: I534606c0e238af309804d4a7c8cec75b1e49c6ad Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2267381 Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#68559}
This commit is contained in:
parent
1f80b36c4b
commit
55ddbaa054
File diff suppressed because it is too large
Load Diff
@ -244,7 +244,7 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
|
||||
case kExprBlock:
|
||||
case kExprTry: {
|
||||
BlockTypeImmediate<Decoder::kNoValidate> imm(WasmFeatures::All(), &i,
|
||||
i.pc());
|
||||
i.pc() + 1);
|
||||
os << " @" << i.pc_offset();
|
||||
if (decoder.Complete(imm)) {
|
||||
for (uint32_t i = 0; i < imm.out_arity(); i++) {
|
||||
@ -259,33 +259,33 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
|
||||
control_depth--;
|
||||
break;
|
||||
case kExprBr: {
|
||||
BranchDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc());
|
||||
BranchDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc() + 1);
|
||||
os << " depth=" << imm.depth;
|
||||
break;
|
||||
}
|
||||
case kExprBrIf: {
|
||||
BranchDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc());
|
||||
BranchDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc() + 1);
|
||||
os << " depth=" << imm.depth;
|
||||
break;
|
||||
}
|
||||
case kExprBrTable: {
|
||||
BranchTableImmediate<Decoder::kNoValidate> imm(&i, i.pc());
|
||||
BranchTableImmediate<Decoder::kNoValidate> imm(&i, i.pc() + 1);
|
||||
os << " entries=" << imm.table_count;
|
||||
break;
|
||||
}
|
||||
case kExprCallIndirect: {
|
||||
CallIndirectImmediate<Decoder::kNoValidate> imm(WasmFeatures::All(), &i,
|
||||
i.pc());
|
||||
i.pc() + 1);
|
||||
os << " sig #" << imm.sig_index;
|
||||
if (decoder.Complete(i.pc(), imm)) {
|
||||
if (decoder.Complete(imm)) {
|
||||
os << ": " << *imm.sig;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kExprCallFunction: {
|
||||
CallFunctionImmediate<Decoder::kNoValidate> imm(&i, i.pc());
|
||||
CallFunctionImmediate<Decoder::kNoValidate> imm(&i, i.pc() + 1);
|
||||
os << " function #" << imm.index;
|
||||
if (decoder.Complete(i.pc(), imm)) {
|
||||
if (decoder.Complete(imm)) {
|
||||
os << ": " << *imm.sig;
|
||||
}
|
||||
break;
|
||||
|
@ -1610,7 +1610,7 @@ class ModuleDecoderImpl : public Decoder {
|
||||
uint32_t len = 0;
|
||||
switch (opcode) {
|
||||
case kExprGlobalGet: {
|
||||
GlobalIndexImmediate<Decoder::kValidate> imm(this, pc() - 1);
|
||||
GlobalIndexImmediate<Decoder::kValidate> imm(this, pc());
|
||||
if (module->globals.size() <= imm.index) {
|
||||
error("global index is out of bounds");
|
||||
expr.kind = WasmInitExpr::kNone;
|
||||
@ -1632,28 +1632,28 @@ class ModuleDecoderImpl : public Decoder {
|
||||
break;
|
||||
}
|
||||
case kExprI32Const: {
|
||||
ImmI32Immediate<Decoder::kValidate> imm(this, pc() - 1);
|
||||
ImmI32Immediate<Decoder::kValidate> imm(this, pc());
|
||||
expr.kind = WasmInitExpr::kI32Const;
|
||||
expr.val.i32_const = imm.value;
|
||||
len = imm.length;
|
||||
break;
|
||||
}
|
||||
case kExprF32Const: {
|
||||
ImmF32Immediate<Decoder::kValidate> imm(this, pc() - 1);
|
||||
ImmF32Immediate<Decoder::kValidate> imm(this, pc());
|
||||
expr.kind = WasmInitExpr::kF32Const;
|
||||
expr.val.f32_const = imm.value;
|
||||
len = imm.length;
|
||||
break;
|
||||
}
|
||||
case kExprI64Const: {
|
||||
ImmI64Immediate<Decoder::kValidate> imm(this, pc() - 1);
|
||||
ImmI64Immediate<Decoder::kValidate> imm(this, pc());
|
||||
expr.kind = WasmInitExpr::kI64Const;
|
||||
expr.val.i64_const = imm.value;
|
||||
len = imm.length;
|
||||
break;
|
||||
}
|
||||
case kExprF64Const: {
|
||||
ImmF64Immediate<Decoder::kValidate> imm(this, pc() - 1);
|
||||
ImmF64Immediate<Decoder::kValidate> imm(this, pc());
|
||||
expr.kind = WasmInitExpr::kF64Const;
|
||||
expr.val.f64_const = imm.value;
|
||||
len = imm.length;
|
||||
@ -1662,7 +1662,7 @@ class ModuleDecoderImpl : public Decoder {
|
||||
case kExprRefNull: {
|
||||
if (enabled_features_.has_reftypes() || enabled_features_.has_eh()) {
|
||||
HeapTypeImmediate<Decoder::kValidate> imm(WasmFeatures::All(), this,
|
||||
pc() - 1);
|
||||
pc());
|
||||
expr.kind = WasmInitExpr::kRefNullConst;
|
||||
len = imm.length;
|
||||
ValueType type = ValueType::Ref(imm.type, kNullable);
|
||||
@ -1677,7 +1677,7 @@ class ModuleDecoderImpl : public Decoder {
|
||||
}
|
||||
case kExprRefFunc: {
|
||||
if (enabled_features_.has_reftypes()) {
|
||||
FunctionIndexImmediate<Decoder::kValidate> imm(this, pc() - 1);
|
||||
FunctionIndexImmediate<Decoder::kValidate> imm(this, pc());
|
||||
if (module->functions.size() <= imm.index) {
|
||||
errorf(pc() - 1, "invalid function index: %u", imm.index);
|
||||
break;
|
||||
@ -2023,8 +2023,7 @@ class ModuleDecoderImpl : public Decoder {
|
||||
if (failed()) return index;
|
||||
switch (opcode) {
|
||||
case kExprRefNull: {
|
||||
HeapTypeImmediate<kValidate> imm(WasmFeatures::All(), this,
|
||||
this->pc() - 1);
|
||||
HeapTypeImmediate<kValidate> imm(WasmFeatures::All(), this, this->pc());
|
||||
consume_bytes(imm.length, "ref.null immediate");
|
||||
index = WasmElemSegment::kNullIndex;
|
||||
break;
|
||||
|
@ -797,7 +797,7 @@ class SideTable : public ZoneObject {
|
||||
case kExprLoop: {
|
||||
bool is_loop = opcode == kExprLoop;
|
||||
BlockTypeImmediate<Decoder::kNoValidate> imm(WasmFeatures::All(), &i,
|
||||
i.pc());
|
||||
i.pc() + 1);
|
||||
if (imm.type == kWasmBottom) {
|
||||
imm.sig = module->signature(imm.sig_index);
|
||||
}
|
||||
@ -819,7 +819,7 @@ class SideTable : public ZoneObject {
|
||||
}
|
||||
case kExprIf: {
|
||||
BlockTypeImmediate<Decoder::kNoValidate> imm(WasmFeatures::All(), &i,
|
||||
i.pc());
|
||||
i.pc() + 1);
|
||||
if (imm.type == kWasmBottom) {
|
||||
imm.sig = module->signature(imm.sig_index);
|
||||
}
|
||||
@ -859,7 +859,7 @@ class SideTable : public ZoneObject {
|
||||
}
|
||||
case kExprTry: {
|
||||
BlockTypeImmediate<Decoder::kNoValidate> imm(WasmFeatures::All(), &i,
|
||||
i.pc());
|
||||
i.pc() + 1);
|
||||
if (imm.type == kWasmBottom) {
|
||||
imm.sig = module->signature(imm.sig_index);
|
||||
}
|
||||
@ -894,7 +894,7 @@ class SideTable : public ZoneObject {
|
||||
break;
|
||||
}
|
||||
case kExprBrOnExn: {
|
||||
BranchOnExceptionImmediate<Decoder::kNoValidate> imm(&i, i.pc());
|
||||
BranchOnExceptionImmediate<Decoder::kNoValidate> imm(&i, i.pc() + 1);
|
||||
uint32_t depth = imm.depth.depth; // Extracted for convenience.
|
||||
imm.index.exception = &module->exceptions[imm.index.index];
|
||||
DCHECK_EQ(0, imm.index.exception->sig->return_count());
|
||||
@ -923,21 +923,21 @@ class SideTable : public ZoneObject {
|
||||
break;
|
||||
}
|
||||
case kExprBr: {
|
||||
BranchDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc());
|
||||
BranchDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc() + 1);
|
||||
TRACE("control @%u: Br[depth=%u]\n", i.pc_offset(), imm.depth);
|
||||
Control* c = &control_stack[control_stack.size() - imm.depth - 1];
|
||||
if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
|
||||
break;
|
||||
}
|
||||
case kExprBrIf: {
|
||||
BranchDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc());
|
||||
BranchDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc() + 1);
|
||||
TRACE("control @%u: BrIf[depth=%u]\n", i.pc_offset(), imm.depth);
|
||||
Control* c = &control_stack[control_stack.size() - imm.depth - 1];
|
||||
if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
|
||||
break;
|
||||
}
|
||||
case kExprBrTable: {
|
||||
BranchTableImmediate<Decoder::kNoValidate> imm(&i, i.pc());
|
||||
BranchTableImmediate<Decoder::kNoValidate> imm(&i, i.pc() + 1);
|
||||
BranchTableIterator<Decoder::kNoValidate> iterator(&i, imm);
|
||||
TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(),
|
||||
imm.table_count);
|
||||
@ -1379,12 +1379,13 @@ class WasmInterpreterInternals {
|
||||
pc_t ReturnPc(Decoder* decoder, InterpreterCode* code, pc_t pc) {
|
||||
switch (code->start[pc]) {
|
||||
case kExprCallFunction: {
|
||||
CallFunctionImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc));
|
||||
CallFunctionImmediate<Decoder::kNoValidate> imm(decoder,
|
||||
code->at(pc + 1));
|
||||
return pc + 1 + imm.length;
|
||||
}
|
||||
case kExprCallIndirect: {
|
||||
CallIndirectImmediate<Decoder::kNoValidate> imm(WasmFeatures::All(),
|
||||
decoder, code->at(pc));
|
||||
CallIndirectImmediate<Decoder::kNoValidate> imm(
|
||||
WasmFeatures::All(), decoder, code->at(pc + 1));
|
||||
return pc + 1 + imm.length;
|
||||
}
|
||||
default:
|
||||
@ -1521,12 +1522,11 @@ class WasmInterpreterInternals {
|
||||
template <typename ctype, typename mtype>
|
||||
bool ExecuteLoad(Decoder* decoder, InterpreterCode* code, pc_t pc,
|
||||
int* const len, MachineRepresentation rep,
|
||||
int prefix_len = 0) {
|
||||
// Some opcodes have a prefix byte, and MemoryAccessImmediate assumes that
|
||||
// the memarg is 1 byte from pc. We don't increment pc at the caller,
|
||||
// because we want to keep pc to the start of the operation to keep trap
|
||||
// reporting and tracing accurate, otherwise those will report at the middle
|
||||
// of an opcode.
|
||||
uint32_t prefix_len = 1) {
|
||||
// prefix_len is the length of the opcode, before the immediate. We don't
|
||||
// increment pc at the caller, because we want to keep pc to the start of
|
||||
// the operation to keep trap reporting and tracing accurate, otherwise
|
||||
// those will report at the middle of an opcode.
|
||||
MemoryAccessImmediate<Decoder::kNoValidate> imm(
|
||||
decoder, code->at(pc + prefix_len), sizeof(ctype));
|
||||
uint32_t index = Pop().to<uint32_t>();
|
||||
@ -1554,12 +1554,11 @@ class WasmInterpreterInternals {
|
||||
template <typename ctype, typename mtype>
|
||||
bool ExecuteStore(Decoder* decoder, InterpreterCode* code, pc_t pc,
|
||||
int* const len, MachineRepresentation rep,
|
||||
int prefix_len = 0) {
|
||||
// Some opcodes have a prefix byte, and MemoryAccessImmediate assumes that
|
||||
// the memarg is 1 byte from pc. We don't increment pc at the caller,
|
||||
// because we want to keep pc to the start of the operation to keep trap
|
||||
// reporting and tracing accurate, otherwise those will report at the middle
|
||||
// of an opcode.
|
||||
uint32_t prefix_len = 1) {
|
||||
// prefix_len is the length of the opcode, before the immediate. We don't
|
||||
// increment pc at the caller, because we want to keep pc to the start of
|
||||
// the operation to keep trap reporting and tracing accurate, otherwise
|
||||
// those will report at the middle of an opcode.
|
||||
MemoryAccessImmediate<Decoder::kNoValidate> imm(
|
||||
decoder, code->at(pc + prefix_len), sizeof(ctype));
|
||||
ctype val = Pop().to<ctype>();
|
||||
@ -1587,7 +1586,7 @@ class WasmInterpreterInternals {
|
||||
bool ExtractAtomicOpParams(Decoder* decoder, InterpreterCode* code,
|
||||
Address* address, pc_t pc, int* const len,
|
||||
type* val = nullptr, type* val2 = nullptr) {
|
||||
MemoryAccessImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc + 1),
|
||||
MemoryAccessImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc + 2),
|
||||
sizeof(type));
|
||||
if (val2) *val2 = static_cast<type>(Pop().to<op_type>());
|
||||
if (val) *val = static_cast<type>(Pop().to<op_type>());
|
||||
@ -1610,7 +1609,8 @@ class WasmInterpreterInternals {
|
||||
pc_t pc, int* const len,
|
||||
uint32_t* buffer_offset, type* val,
|
||||
int64_t* timeout = nullptr) {
|
||||
MemoryAccessImmediate<Decoder::kValidate> imm(decoder, code->at(pc + 1),
|
||||
// TODO(manoskouk): Introduce test which exposes wrong pc offset below.
|
||||
MemoryAccessImmediate<Decoder::kValidate> imm(decoder, code->at(pc + *len),
|
||||
sizeof(type));
|
||||
if (timeout) {
|
||||
*timeout = Pop().to<int64_t>();
|
||||
@ -1662,7 +1662,8 @@ class WasmInterpreterInternals {
|
||||
Push(WasmValue(ExecuteI64UConvertSatF64(Pop().to<double>())));
|
||||
return true;
|
||||
case kExprMemoryInit: {
|
||||
MemoryInitImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc));
|
||||
MemoryInitImmediate<Decoder::kNoValidate> imm(decoder,
|
||||
code->at(pc + 2));
|
||||
// The data segment index must be in bounds since it is required by
|
||||
// validation.
|
||||
DCHECK_LT(imm.data_segment_index, module()->num_declared_data_segments);
|
||||
@ -1686,7 +1687,7 @@ class WasmInterpreterInternals {
|
||||
return true;
|
||||
}
|
||||
case kExprDataDrop: {
|
||||
DataDropImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc));
|
||||
DataDropImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc + 2));
|
||||
// The data segment index must be in bounds since it is required by
|
||||
// validation.
|
||||
DCHECK_LT(imm.index, module()->num_declared_data_segments);
|
||||
@ -1695,7 +1696,8 @@ class WasmInterpreterInternals {
|
||||
return true;
|
||||
}
|
||||
case kExprMemoryCopy: {
|
||||
MemoryCopyImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc));
|
||||
MemoryCopyImmediate<Decoder::kNoValidate> imm(decoder,
|
||||
code->at(pc + 2));
|
||||
*len += imm.length;
|
||||
auto size = Pop().to<uint32_t>();
|
||||
auto src = Pop().to<uint32_t>();
|
||||
@ -1714,7 +1716,7 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
case kExprMemoryFill: {
|
||||
MemoryIndexImmediate<Decoder::kNoValidate> imm(decoder,
|
||||
code->at(pc + 1));
|
||||
code->at(pc + 2));
|
||||
*len += imm.length;
|
||||
auto size = Pop().to<uint32_t>();
|
||||
auto value = Pop().to<uint32_t>();
|
||||
@ -1729,7 +1731,7 @@ class WasmInterpreterInternals {
|
||||
return true;
|
||||
}
|
||||
case kExprTableInit: {
|
||||
TableInitImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc));
|
||||
TableInitImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc + 2));
|
||||
*len += imm.length;
|
||||
auto size = Pop().to<uint32_t>();
|
||||
auto src = Pop().to<uint32_t>();
|
||||
@ -1742,13 +1744,13 @@ class WasmInterpreterInternals {
|
||||
return ok;
|
||||
}
|
||||
case kExprElemDrop: {
|
||||
ElemDropImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc));
|
||||
ElemDropImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc + 2));
|
||||
*len += imm.length;
|
||||
instance_object_->dropped_elem_segments()[imm.index] = 1;
|
||||
return true;
|
||||
}
|
||||
case kExprTableCopy: {
|
||||
TableCopyImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc));
|
||||
TableCopyImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc + 2));
|
||||
auto size = Pop().to<uint32_t>();
|
||||
auto src = Pop().to<uint32_t>();
|
||||
auto dst = Pop().to<uint32_t>();
|
||||
@ -1762,7 +1764,7 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
case kExprTableGrow: {
|
||||
TableIndexImmediate<Decoder::kNoValidate> imm(decoder,
|
||||
code->at(pc + 1));
|
||||
code->at(pc + 2));
|
||||
HandleScope handle_scope(isolate_);
|
||||
auto table = handle(
|
||||
WasmTableObject::cast(instance_object_->tables().get(imm.index)),
|
||||
@ -1776,7 +1778,7 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
case kExprTableSize: {
|
||||
TableIndexImmediate<Decoder::kNoValidate> imm(decoder,
|
||||
code->at(pc + 1));
|
||||
code->at(pc + 2));
|
||||
HandleScope handle_scope(isolate_);
|
||||
auto table = handle(
|
||||
WasmTableObject::cast(instance_object_->tables().get(imm.index)),
|
||||
@ -1788,7 +1790,7 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
case kExprTableFill: {
|
||||
TableIndexImmediate<Decoder::kNoValidate> imm(decoder,
|
||||
code->at(pc + 1));
|
||||
code->at(pc + 2));
|
||||
HandleScope handle_scope(isolate_);
|
||||
auto count = Pop().to<uint32_t>();
|
||||
auto value = Pop().to_externref();
|
||||
@ -2077,7 +2079,7 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
|
||||
bool ExecuteSimdOp(WasmOpcode opcode, Decoder* decoder, InterpreterCode* code,
|
||||
pc_t pc, int* const len, uint32_t opcode_length) {
|
||||
pc_t pc, int* const len) {
|
||||
switch (opcode) {
|
||||
#define SPLAT_CASE(format, sType, valType, num) \
|
||||
case kExpr##format##Splat: { \
|
||||
@ -2095,16 +2097,15 @@ class WasmInterpreterInternals {
|
||||
SPLAT_CASE(I16x8, int8, int32_t, 8)
|
||||
SPLAT_CASE(I8x16, int16, int32_t, 16)
|
||||
#undef SPLAT_CASE
|
||||
#define EXTRACT_LANE_CASE(format, name) \
|
||||
case kExpr##format##ExtractLane: { \
|
||||
SimdLaneImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc), \
|
||||
opcode_length); \
|
||||
*len += 1; \
|
||||
WasmValue val = Pop(); \
|
||||
Simd128 s = val.to_s128(); \
|
||||
auto ss = s.to_##name(); \
|
||||
Push(WasmValue(ss.val[LANE(imm.lane, ss)])); \
|
||||
return true; \
|
||||
#define EXTRACT_LANE_CASE(format, name) \
|
||||
case kExpr##format##ExtractLane: { \
|
||||
SimdLaneImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc + *len)); \
|
||||
*len += 1; \
|
||||
WasmValue val = Pop(); \
|
||||
Simd128 s = val.to_s128(); \
|
||||
auto ss = s.to_##name(); \
|
||||
Push(WasmValue(ss.val[LANE(imm.lane, ss)])); \
|
||||
return true; \
|
||||
}
|
||||
EXTRACT_LANE_CASE(F64x2, f64x2)
|
||||
EXTRACT_LANE_CASE(F32x4, f32x4)
|
||||
@ -2118,24 +2119,23 @@ class WasmInterpreterInternals {
|
||||
// unsigned extracts, we will cast it int8_t -> uint8_t -> uint32_t. We
|
||||
// add the DCHECK to ensure that if the array type changes, we know to
|
||||
// change this function.
|
||||
#define EXTRACT_LANE_EXTEND_CASE(format, name, sign, extended_type) \
|
||||
case kExpr##format##ExtractLane##sign: { \
|
||||
SimdLaneImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc), \
|
||||
opcode_length); \
|
||||
*len += 1; \
|
||||
WasmValue val = Pop(); \
|
||||
Simd128 s = val.to_s128(); \
|
||||
auto ss = s.to_##name(); \
|
||||
auto res = ss.val[LANE(imm.lane, ss)]; \
|
||||
DCHECK(std::is_signed<decltype(res)>::value); \
|
||||
if (std::is_unsigned<extended_type>::value) { \
|
||||
using unsigned_type = std::make_unsigned<decltype(res)>::type; \
|
||||
Push(WasmValue( \
|
||||
static_cast<extended_type>(static_cast<unsigned_type>(res)))); \
|
||||
} else { \
|
||||
Push(WasmValue(static_cast<extended_type>(res))); \
|
||||
} \
|
||||
return true; \
|
||||
#define EXTRACT_LANE_EXTEND_CASE(format, name, sign, extended_type) \
|
||||
case kExpr##format##ExtractLane##sign: { \
|
||||
SimdLaneImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc + *len)); \
|
||||
*len += 1; \
|
||||
WasmValue val = Pop(); \
|
||||
Simd128 s = val.to_s128(); \
|
||||
auto ss = s.to_##name(); \
|
||||
auto res = ss.val[LANE(imm.lane, ss)]; \
|
||||
DCHECK(std::is_signed<decltype(res)>::value); \
|
||||
if (std::is_unsigned<extended_type>::value) { \
|
||||
using unsigned_type = std::make_unsigned<decltype(res)>::type; \
|
||||
Push(WasmValue( \
|
||||
static_cast<extended_type>(static_cast<unsigned_type>(res)))); \
|
||||
} else { \
|
||||
Push(WasmValue(static_cast<extended_type>(res))); \
|
||||
} \
|
||||
return true; \
|
||||
}
|
||||
EXTRACT_LANE_EXTEND_CASE(I16x8, i16x8, S, int32_t)
|
||||
EXTRACT_LANE_EXTEND_CASE(I16x8, i16x8, U, uint32_t)
|
||||
@ -2376,17 +2376,16 @@ class WasmInterpreterInternals {
|
||||
CMPOP_CASE(I8x16LeU, i8x16, int16, int16, 16,
|
||||
static_cast<uint8_t>(a) <= static_cast<uint8_t>(b))
|
||||
#undef CMPOP_CASE
|
||||
#define REPLACE_LANE_CASE(format, name, stype, ctype) \
|
||||
case kExpr##format##ReplaceLane: { \
|
||||
SimdLaneImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc), \
|
||||
opcode_length); \
|
||||
*len += 1; \
|
||||
WasmValue new_val = Pop(); \
|
||||
WasmValue simd_val = Pop(); \
|
||||
stype s = simd_val.to_s128().to_##name(); \
|
||||
s.val[LANE(imm.lane, s)] = new_val.to<ctype>(); \
|
||||
Push(WasmValue(Simd128(s))); \
|
||||
return true; \
|
||||
#define REPLACE_LANE_CASE(format, name, stype, ctype) \
|
||||
case kExpr##format##ReplaceLane: { \
|
||||
SimdLaneImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc + *len)); \
|
||||
*len += 1; \
|
||||
WasmValue new_val = Pop(); \
|
||||
WasmValue simd_val = Pop(); \
|
||||
stype s = simd_val.to_s128().to_##name(); \
|
||||
s.val[LANE(imm.lane, s)] = new_val.to<ctype>(); \
|
||||
Push(WasmValue(Simd128(s))); \
|
||||
return true; \
|
||||
}
|
||||
REPLACE_LANE_CASE(F64x2, f64x2, float2, double)
|
||||
REPLACE_LANE_CASE(F32x4, f32x4, float4, float)
|
||||
@ -2398,11 +2397,11 @@ class WasmInterpreterInternals {
|
||||
case kExprS128LoadMem:
|
||||
return ExecuteLoad<Simd128, Simd128>(decoder, code, pc, len,
|
||||
MachineRepresentation::kSimd128,
|
||||
/*prefix_len=*/opcode_length);
|
||||
/*prefix_len=*/*len);
|
||||
case kExprS128StoreMem:
|
||||
return ExecuteStore<Simd128, Simd128>(decoder, code, pc, len,
|
||||
MachineRepresentation::kSimd128,
|
||||
/*prefix_len=*/opcode_length);
|
||||
/*prefix_len=*/*len);
|
||||
#define SHIFT_CASE(op, name, stype, count, expr) \
|
||||
case kExpr##op: { \
|
||||
uint32_t shift = Pop().to<uint32_t>(); \
|
||||
@ -2563,8 +2562,8 @@ class WasmInterpreterInternals {
|
||||
return true;
|
||||
}
|
||||
case kExprS8x16Shuffle: {
|
||||
Simd8x16ShuffleImmediate<Decoder::kNoValidate> imm(
|
||||
decoder, code->at(pc), opcode_length);
|
||||
Simd8x16ShuffleImmediate<Decoder::kNoValidate> imm(decoder,
|
||||
code->at(pc + *len));
|
||||
*len += 16;
|
||||
int16 v2 = Pop().to_s128().to_i8x16();
|
||||
int16 v1 = Pop().to_s128().to_i8x16();
|
||||
@ -2671,7 +2670,7 @@ class WasmInterpreterInternals {
|
||||
// the prefix_len for ExecuteLoad is len, minus the prefix byte itself.
|
||||
// Think of prefix_len as: number of extra bytes that make up this op.
|
||||
if (!ExecuteLoad<result_type, load_type>(decoder, code, pc, len, rep,
|
||||
/*prefix_len=*/*len - 1)) {
|
||||
/*prefix_len=*/*len)) {
|
||||
return false;
|
||||
}
|
||||
result_type v = Pop().to<result_type>();
|
||||
@ -2687,7 +2686,7 @@ class WasmInterpreterInternals {
|
||||
static_assert(sizeof(wide_type) == sizeof(narrow_type) * 2,
|
||||
"size mismatch for wide and narrow types");
|
||||
if (!ExecuteLoad<uint64_t, uint64_t>(decoder, code, pc, len, rep,
|
||||
/*prefix_len=*/*len - 1)) {
|
||||
/*prefix_len=*/*len)) {
|
||||
return false;
|
||||
}
|
||||
constexpr int lanes = kSimd128Size / sizeof(wide_type);
|
||||
@ -2960,15 +2959,16 @@ class WasmInterpreterInternals {
|
||||
DCHECK_NOT_NULL(code->start);
|
||||
|
||||
int len = 1;
|
||||
// We need to store this, because SIMD opcodes are LEB encoded, and later
|
||||
// on when executing, we need to know where to read immediates from.
|
||||
uint32_t simd_opcode_length = 0;
|
||||
byte orig = code->start[pc];
|
||||
WasmOpcode opcode = static_cast<WasmOpcode>(orig);
|
||||
|
||||
// If the opcode is a prefix, read the suffix and add the extra length to
|
||||
// 'len'.
|
||||
if (WasmOpcodes::IsPrefixOpcode(opcode)) {
|
||||
uint32_t prefixed_opcode_length = 0;
|
||||
opcode = decoder.read_prefixed_opcode<Decoder::kNoValidate>(
|
||||
&code->start[pc], &simd_opcode_length);
|
||||
len += simd_opcode_length;
|
||||
code->at(pc), &prefixed_opcode_length);
|
||||
len += prefixed_opcode_length;
|
||||
}
|
||||
|
||||
// If max is 0, break. If max is positive (a limit is set), decrement it.
|
||||
@ -2997,14 +2997,14 @@ class WasmInterpreterInternals {
|
||||
case kExprBlock:
|
||||
case kExprLoop:
|
||||
case kExprTry: {
|
||||
BlockTypeImmediate<Decoder::kNoValidate> imm(WasmFeatures::All(),
|
||||
&decoder, code->at(pc));
|
||||
BlockTypeImmediate<Decoder::kNoValidate> imm(
|
||||
WasmFeatures::All(), &decoder, code->at(pc + 1));
|
||||
len = 1 + imm.length;
|
||||
break;
|
||||
}
|
||||
case kExprIf: {
|
||||
BlockTypeImmediate<Decoder::kNoValidate> imm(WasmFeatures::All(),
|
||||
&decoder, code->at(pc));
|
||||
BlockTypeImmediate<Decoder::kNoValidate> imm(
|
||||
WasmFeatures::All(), &decoder, code->at(pc + 1));
|
||||
WasmValue cond = Pop();
|
||||
bool is_true = cond.to<uint32_t>() != 0;
|
||||
if (is_true) {
|
||||
@ -3025,7 +3025,7 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
case kExprThrow: {
|
||||
ExceptionIndexImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc));
|
||||
code->at(pc + 1));
|
||||
CommitPc(pc); // Needed for local unwinding.
|
||||
const WasmException* exception = &module()->exceptions[imm.index];
|
||||
if (!DoThrowException(exception, imm.index)) return;
|
||||
@ -3044,8 +3044,8 @@ class WasmInterpreterInternals {
|
||||
continue; // Do not bump pc.
|
||||
}
|
||||
case kExprBrOnExn: {
|
||||
BranchOnExceptionImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc));
|
||||
BranchOnExceptionImmediate<Decoder::kNoValidate> imm(
|
||||
&decoder, code->at(pc + 1));
|
||||
HandleScope handle_scope(isolate_); // Avoid leaking handles.
|
||||
WasmValue ex = Pop();
|
||||
Handle<Object> exception = ex.to_externref();
|
||||
@ -3063,8 +3063,8 @@ class WasmInterpreterInternals {
|
||||
break;
|
||||
}
|
||||
case kExprSelectWithType: {
|
||||
SelectTypeImmediate<Decoder::kNoValidate> imm(WasmFeatures::All(),
|
||||
&decoder, code->at(pc));
|
||||
SelectTypeImmediate<Decoder::kNoValidate> imm(
|
||||
WasmFeatures::All(), &decoder, code->at(pc + 1));
|
||||
len = 1 + imm.length;
|
||||
V8_FALLTHROUGH;
|
||||
}
|
||||
@ -3078,14 +3078,14 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
case kExprBr: {
|
||||
BranchDepthImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc));
|
||||
code->at(pc + 1));
|
||||
len = DoBreak(code, pc, imm.depth);
|
||||
TRACE(" br => @%zu\n", pc + len);
|
||||
break;
|
||||
}
|
||||
case kExprBrIf: {
|
||||
BranchDepthImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc));
|
||||
code->at(pc + 1));
|
||||
WasmValue cond = Pop();
|
||||
bool is_true = cond.to<uint32_t>() != 0;
|
||||
if (is_true) {
|
||||
@ -3099,7 +3099,7 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
case kExprBrTable: {
|
||||
BranchTableImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc));
|
||||
code->at(pc + 1));
|
||||
BranchTableIterator<Decoder::kNoValidate> iterator(&decoder, imm);
|
||||
uint32_t key = Pop().to<uint32_t>();
|
||||
uint32_t depth = 0;
|
||||
@ -3124,39 +3124,39 @@ class WasmInterpreterInternals {
|
||||
break;
|
||||
}
|
||||
case kExprI32Const: {
|
||||
ImmI32Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
|
||||
ImmI32Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc + 1));
|
||||
Push(WasmValue(imm.value));
|
||||
len = 1 + imm.length;
|
||||
break;
|
||||
}
|
||||
case kExprI64Const: {
|
||||
ImmI64Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
|
||||
ImmI64Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc + 1));
|
||||
Push(WasmValue(imm.value));
|
||||
len = 1 + imm.length;
|
||||
break;
|
||||
}
|
||||
case kExprF32Const: {
|
||||
ImmF32Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
|
||||
ImmF32Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc + 1));
|
||||
Push(WasmValue(imm.value));
|
||||
len = 1 + imm.length;
|
||||
break;
|
||||
}
|
||||
case kExprF64Const: {
|
||||
ImmF64Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
|
||||
ImmF64Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc + 1));
|
||||
Push(WasmValue(imm.value));
|
||||
len = 1 + imm.length;
|
||||
break;
|
||||
}
|
||||
case kExprRefNull: {
|
||||
HeapTypeImmediate<Decoder::kNoValidate> imm(WasmFeatures::All(),
|
||||
&decoder, code->at(pc));
|
||||
HeapTypeImmediate<Decoder::kNoValidate> imm(
|
||||
WasmFeatures::All(), &decoder, code->at(pc + 1));
|
||||
len = 1 + imm.length;
|
||||
Push(WasmValue(isolate_->factory()->null_value()));
|
||||
break;
|
||||
}
|
||||
case kExprRefFunc: {
|
||||
FunctionIndexImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc));
|
||||
code->at(pc + 1));
|
||||
HandleScope handle_scope(isolate_); // Avoid leaking handles.
|
||||
|
||||
Handle<WasmExternalFunction> function =
|
||||
@ -3167,14 +3167,16 @@ class WasmInterpreterInternals {
|
||||
break;
|
||||
}
|
||||
case kExprLocalGet: {
|
||||
LocalIndexImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
|
||||
LocalIndexImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc + 1));
|
||||
HandleScope handle_scope(isolate_); // Avoid leaking handles.
|
||||
Push(GetStackValue(frames_.back().sp + imm.index));
|
||||
len = 1 + imm.length;
|
||||
break;
|
||||
}
|
||||
case kExprLocalSet: {
|
||||
LocalIndexImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
|
||||
LocalIndexImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc + 1));
|
||||
HandleScope handle_scope(isolate_); // Avoid leaking handles.
|
||||
WasmValue val = Pop();
|
||||
SetStackValue(frames_.back().sp + imm.index, val);
|
||||
@ -3182,7 +3184,8 @@ class WasmInterpreterInternals {
|
||||
break;
|
||||
}
|
||||
case kExprLocalTee: {
|
||||
LocalIndexImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
|
||||
LocalIndexImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc + 1));
|
||||
HandleScope handle_scope(isolate_); // Avoid leaking handles.
|
||||
WasmValue val = Pop();
|
||||
SetStackValue(frames_.back().sp + imm.index, val);
|
||||
@ -3196,7 +3199,7 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
case kExprCallFunction: {
|
||||
CallFunctionImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc));
|
||||
code->at(pc + 1));
|
||||
InterpreterCode* target = codemap_.GetCode(imm.index);
|
||||
CHECK(!target->function->imported);
|
||||
// Execute an internal call.
|
||||
@ -3207,7 +3210,7 @@ class WasmInterpreterInternals {
|
||||
|
||||
case kExprCallIndirect: {
|
||||
CallIndirectImmediate<Decoder::kNoValidate> imm(
|
||||
WasmFeatures::All(), &decoder, code->at(pc));
|
||||
WasmFeatures::All(), &decoder, code->at(pc + 1));
|
||||
uint32_t entry_index = Pop().to<uint32_t>();
|
||||
CommitPc(pc); // TODO(wasm): Be more disciplined about committing PC.
|
||||
CallResult result =
|
||||
@ -3228,7 +3231,7 @@ class WasmInterpreterInternals {
|
||||
|
||||
case kExprReturnCall: {
|
||||
CallFunctionImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc));
|
||||
code->at(pc + 1));
|
||||
InterpreterCode* target = codemap_.GetCode(imm.index);
|
||||
|
||||
CHECK(!target->function->imported);
|
||||
@ -3240,7 +3243,7 @@ class WasmInterpreterInternals {
|
||||
|
||||
case kExprReturnCallIndirect: {
|
||||
CallIndirectImmediate<Decoder::kNoValidate> imm(
|
||||
WasmFeatures::All(), &decoder, code->at(pc));
|
||||
WasmFeatures::All(), &decoder, code->at(pc + 1));
|
||||
uint32_t entry_index = Pop().to<uint32_t>();
|
||||
CommitPc(pc); // TODO(wasm): Be more disciplined about committing PC.
|
||||
|
||||
@ -3268,7 +3271,7 @@ class WasmInterpreterInternals {
|
||||
|
||||
case kExprGlobalGet: {
|
||||
GlobalIndexImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc));
|
||||
code->at(pc + 1));
|
||||
HandleScope handle_scope(isolate_);
|
||||
Push(WasmInstanceObject::GetGlobalValue(
|
||||
instance_object_, module()->globals[imm.index]));
|
||||
@ -3277,7 +3280,7 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
case kExprGlobalSet: {
|
||||
GlobalIndexImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc));
|
||||
code->at(pc + 1));
|
||||
auto& global = module()->globals[imm.index];
|
||||
switch (global.type.kind()) {
|
||||
#define CASE_TYPE(valuetype, ctype) \
|
||||
@ -3314,7 +3317,8 @@ class WasmInterpreterInternals {
|
||||
break;
|
||||
}
|
||||
case kExprTableGet: {
|
||||
TableIndexImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
|
||||
TableIndexImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc + 1));
|
||||
HandleScope handle_scope(isolate_);
|
||||
auto table = handle(
|
||||
WasmTableObject::cast(instance_object_->tables().get(imm.index)),
|
||||
@ -3331,7 +3335,8 @@ class WasmInterpreterInternals {
|
||||
break;
|
||||
}
|
||||
case kExprTableSet: {
|
||||
TableIndexImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
|
||||
TableIndexImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc + 1));
|
||||
HandleScope handle_scope(isolate_);
|
||||
auto table = handle(
|
||||
WasmTableObject::cast(instance_object_->tables().get(imm.index)),
|
||||
@ -3434,7 +3439,7 @@ class WasmInterpreterInternals {
|
||||
#undef ASMJS_STORE_CASE
|
||||
case kExprMemoryGrow: {
|
||||
MemoryIndexImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc));
|
||||
code->at(pc + 1));
|
||||
uint32_t delta_pages = Pop().to<uint32_t>();
|
||||
HandleScope handle_scope(isolate_); // Avoid leaking handles.
|
||||
Handle<WasmMemoryObject> memory(instance_object_->memory_object(),
|
||||
@ -3450,7 +3455,7 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
case kExprMemorySize: {
|
||||
MemoryIndexImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||
code->at(pc));
|
||||
code->at(pc + 1));
|
||||
Push(WasmValue(static_cast<uint32_t>(instance_object_->memory_size() /
|
||||
kWasmPageSize)));
|
||||
len = 1 + imm.length;
|
||||
@ -3497,9 +3502,7 @@ class WasmInterpreterInternals {
|
||||
break;
|
||||
}
|
||||
case kSimdPrefix: {
|
||||
if (!ExecuteSimdOp(opcode, &decoder, code, pc, &len,
|
||||
simd_opcode_length))
|
||||
return;
|
||||
if (!ExecuteSimdOp(opcode, &decoder, code, pc, &len)) return;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,14 @@ namespace function_body_decoder_unittest {
|
||||
#define WASM_IF_OP kExprIf, kLocalVoid
|
||||
#define WASM_LOOP_OP kExprLoop, kLocalVoid
|
||||
|
||||
#define EXPECT_OK(result) \
|
||||
do { \
|
||||
if (!result.ok()) { \
|
||||
GTEST_NONFATAL_FAILURE_(result.error().message().c_str()); \
|
||||
return; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
static const byte kCodeGetLocal0[] = {kExprLocalGet, 0};
|
||||
static const byte kCodeGetLocal1[] = {kExprLocalGet, 1};
|
||||
static const byte kCodeSetLocal0[] = {WASM_SET_LOCAL(0, WASM_ZERO)};
|
||||
@ -3398,14 +3406,14 @@ class BranchTableIteratorTest : public TestWithZone {
|
||||
BranchTableIteratorTest() : TestWithZone() {}
|
||||
void CheckBrTableSize(const byte* start, const byte* end) {
|
||||
Decoder decoder(start, end);
|
||||
BranchTableImmediate<Decoder::kValidate> operand(&decoder, start);
|
||||
BranchTableImmediate<Decoder::kValidate> operand(&decoder, start + 1);
|
||||
BranchTableIterator<Decoder::kValidate> iterator(&decoder, operand);
|
||||
EXPECT_EQ(end - start - 1u, iterator.length());
|
||||
EXPECT_TRUE(decoder.ok());
|
||||
EXPECT_OK(decoder);
|
||||
}
|
||||
void CheckBrTableError(const byte* start, const byte* end) {
|
||||
Decoder decoder(start, end);
|
||||
BranchTableImmediate<Decoder::kValidate> operand(&decoder, start);
|
||||
BranchTableImmediate<Decoder::kValidate> operand(&decoder, start + 1);
|
||||
BranchTableIterator<Decoder::kValidate> iterator(&decoder, operand);
|
||||
iterator.length();
|
||||
EXPECT_FALSE(decoder.ok());
|
||||
@ -3872,6 +3880,7 @@ TEST_F(BytecodeIteratorTest, WithLocalDecls) {
|
||||
#undef WASM_IF_OP
|
||||
#undef WASM_LOOP_OP
|
||||
#undef WASM_BRV_IF_ZERO
|
||||
#undef EXPECT_OK
|
||||
|
||||
} // namespace function_body_decoder_unittest
|
||||
} // namespace wasm
|
||||
|
Loading…
Reference in New Issue
Block a user