Commit eeaceccb authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] [decoder] Templatize decode function for unchecked decoding

In the C++ wasm interpreter, we decode LEB encoded immediates each time
we execute the respective instruction. The whole instruction sequence
was validated before, thus we know that all integers are valid.
This CL refactors several Decoder methods to allow for either checked
or unchecked decoding. In the checked case, an error is set if a check
fails, in the unchecked case, a DCHECK will fail.

This improves performance of the interpreter by 20.5%.

R=ahaas@chromium.org
BUG=v8:5822

Change-Id: If69efd4f6fbe19d84bfc2f4aa000f429a8e22bf5
Reviewed-on: https://chromium-review.googlesource.com/468786
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44406}
parent 02b4d0e6
......@@ -52,120 +52,86 @@ class Decoder {
return true;
}
// Reads a single 8-bit byte, reporting an error if out of bounds.
inline uint8_t checked_read_u8(const byte* pc,
const char* msg = "expected 1 byte") {
return check(pc, 1, msg) ? *pc : 0;
// Reads an 8-bit unsigned integer.
template <bool checked>
inline uint8_t read_u8(const byte* pc, const char* msg = "expected 1 byte") {
return read_little_endian<uint8_t, checked>(pc, msg);
}
// Reads 16-bit word, reporting an error if out of bounds.
inline uint16_t checked_read_u16(const byte* pc,
// Reads a 16-bit unsigned integer (little endian).
template <bool checked>
inline uint16_t read_u16(const byte* pc,
const char* msg = "expected 2 bytes") {
return check(pc, 2, msg) ? read_u16(pc) : 0;
return read_little_endian<uint16_t, checked>(pc, msg);
}
// Reads 32-bit word, reporting an error if out of bounds.
inline uint32_t checked_read_u32(const byte* pc,
// Reads a 32-bit unsigned integer (little endian).
template <bool checked>
inline uint32_t read_u32(const byte* pc,
const char* msg = "expected 4 bytes") {
return check(pc, 4, msg) ? read_u32(pc) : 0;
return read_little_endian<uint32_t, checked>(pc, msg);
}
// Reads 64-bit word, reporting an error if out of bounds.
inline uint64_t checked_read_u64(const byte* pc,
// Reads a 64-bit unsigned integer (little endian).
template <bool checked>
inline uint64_t read_u64(const byte* pc,
const char* msg = "expected 8 bytes") {
return check(pc, 8, msg) ? read_u64(pc) : 0;
return read_little_endian<uint64_t, checked>(pc, msg);
}
// Reads a variable-length unsigned integer (little endian).
uint32_t checked_read_u32v(const byte* pc, unsigned* length,
template <bool checked>
uint32_t read_u32v(const byte* pc, unsigned* length,
const char* name = "LEB32") {
return checked_read_leb<uint32_t, false, false>(pc, length, name);
return read_leb<uint32_t, checked, false, false>(pc, length, name);
}
// Reads a variable-length signed integer (little endian).
int32_t checked_read_i32v(const byte* pc, unsigned* length,
template <bool checked>
int32_t read_i32v(const byte* pc, unsigned* length,
const char* name = "signed LEB32") {
return checked_read_leb<int32_t, false, false>(pc, length, name);
return read_leb<int32_t, checked, false, false>(pc, length, name);
}
// Reads a variable-length unsigned integer (little endian).
uint64_t checked_read_u64v(const byte* pc, unsigned* length,
template <bool checked>
uint64_t read_u64v(const byte* pc, unsigned* length,
const char* name = "LEB64") {
return checked_read_leb<uint64_t, false, false>(pc, length, name);
return read_leb<uint64_t, checked, false, false>(pc, length, name);
}
// Reads a variable-length signed integer (little endian).
int64_t checked_read_i64v(const byte* pc, unsigned* length,
template <bool checked>
int64_t read_i64v(const byte* pc, unsigned* length,
const char* name = "signed LEB64") {
return checked_read_leb<int64_t, false, false>(pc, length, name);
}
// Reads a single 16-bit unsigned integer (little endian).
inline uint16_t read_u16(const byte* ptr) {
DCHECK(ptr >= start_ && (ptr + 2) <= end_);
return ReadLittleEndianValue<uint16_t>(ptr);
}
// Reads a single 32-bit unsigned integer (little endian).
inline uint32_t read_u32(const byte* ptr) {
DCHECK(ptr >= start_ && (ptr + 4) <= end_);
return ReadLittleEndianValue<uint32_t>(ptr);
}
// Reads a single 64-bit unsigned integer (little endian).
inline uint64_t read_u64(const byte* ptr) {
DCHECK(ptr >= start_ && (ptr + 8) <= end_);
return ReadLittleEndianValue<uint64_t>(ptr);
return read_leb<int64_t, checked, false, false>(pc, length, name);
}
// Reads a 8-bit unsigned integer (byte) and advances {pc_}.
uint8_t consume_u8(const char* name = nullptr) {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
name ? name : "uint8_t");
if (checkAvailable(1)) {
byte val = *(pc_++);
TRACE("%02x = %d\n", val, val);
return val;
}
return traceOffEnd<uint8_t, true>();
uint8_t consume_u8(const char* name = "uint8_t") {
return consume_little_endian<uint8_t>(name);
}
// Reads a 16-bit unsigned integer (little endian) and advances {pc_}.
uint16_t consume_u16(const char* name = nullptr) {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
name ? name : "uint16_t");
if (checkAvailable(2)) {
uint16_t val = read_u16(pc_);
TRACE("%02x %02x = %d\n", pc_[0], pc_[1], val);
pc_ += 2;
return val;
}
return traceOffEnd<uint16_t, true>();
uint16_t consume_u16(const char* name = "uint16_t") {
return consume_little_endian<uint16_t>(name);
}
// Reads a single 32-bit unsigned integer (little endian) and advances {pc_}.
uint32_t consume_u32(const char* name = nullptr) {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
name ? name : "uint32_t");
if (checkAvailable(4)) {
uint32_t val = read_u32(pc_);
TRACE("%02x %02x %02x %02x = %u\n", pc_[0], pc_[1], pc_[2], pc_[3], val);
pc_ += 4;
return val;
}
return traceOffEnd<uint32_t, true>();
uint32_t consume_u32(const char* name = "uint32_t") {
return consume_little_endian<uint32_t>(name);
}
// Reads a LEB128 variable-length unsigned 32-bit integer and advances {pc_}.
uint32_t consume_u32v(const char* name = nullptr) {
unsigned length = 0;
return checked_read_leb<uint32_t, true, true>(pc_, &length, name);
return read_leb<uint32_t, true, true, true>(pc_, &length, name);
}
// Reads a LEB128 variable-length signed 32-bit integer and advances {pc_}.
int32_t consume_i32v(const char* name = nullptr) {
unsigned length = 0;
return checked_read_leb<int32_t, true, true>(pc_, &length, name);
return read_leb<int32_t, true, true, true>(pc_, &length, name);
}
// Consume {size} bytes and send them to the bit bucket, advancing {pc_}.
......@@ -221,15 +187,16 @@ class Decoder {
// Behavior triggered on first error, overridden in subclasses.
virtual void onFirstError() {}
// Debugging helper to print bytes up to the end.
template <typename T, bool update_pc>
T traceOffEnd() {
for (const byte* ptr = pc_; ptr < end_; ptr++) {
TRACE("%02x ", *ptr);
// Debugging helper to print a bytes range as hex bytes.
void traceByteRange(const byte* start, const byte* end) {
DCHECK_LE(start, end);
for (const byte* p = start; p < end; ++p) TRACE("%02x ", *p);
}
// Debugging helper to print bytes up to the end.
void traceOffEnd() {
traceByteRange(pc_, end_);
TRACE("<end>\n");
if (update_pc) pc_ = end_;
return T{0};
}
// Converts the given value to a {Result}, copying the error if necessary.
......@@ -276,8 +243,33 @@ class Decoder {
std::unique_ptr<char[]> error_msg_;
private:
template <typename IntType, bool advance_pc, bool trace>
inline IntType checked_read_leb(const byte* pc, unsigned* length,
template <typename IntType, bool checked>
inline IntType read_little_endian(const byte* pc, const char* msg) {
if (!checked) {
DCHECK(check(pc, sizeof(IntType), msg));
} else if (!check(pc, sizeof(IntType), msg)) {
return IntType{0};
}
return ReadLittleEndianValue<IntType>(pc);
}
template <typename IntType>
inline IntType consume_little_endian(const char* name) {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), name);
if (!checkAvailable(sizeof(IntType))) {
traceOffEnd();
pc_ = end_;
return IntType{0};
}
IntType val = read_little_endian<IntType, false>(pc_, name);
traceByteRange(pc_, pc_ + sizeof(IntType));
TRACE("= %d\n", val);
pc_ += sizeof(IntType);
return val;
}
template <typename IntType, bool checked, bool advance_pc, bool trace>
inline IntType read_leb(const byte* pc, unsigned* length,
const char* name = "varint") {
DCHECK_IMPLIES(advance_pc, pc == pc_);
constexpr bool is_signed = std::is_signed<IntType>::value;
......@@ -285,15 +277,19 @@ class Decoder {
constexpr int kMaxLength = (sizeof(IntType) * 8 + 6) / 7;
const byte* ptr = pc;
const byte* end = Min(end_, ptr + kMaxLength);
// The end variable is only used if checked == true. MSVC recognizes this.
USE(end);
int shift = 0;
byte b = 0;
IntType result = 0;
for (;;) {
if (V8_UNLIKELY(ptr >= end)) {
if (checked && V8_UNLIKELY(ptr >= end)) {
TRACE_IF(trace, "<end> ");
errorf(ptr, "expected %s", name);
result = 0;
break;
}
DCHECK_GT(end, ptr);
b = *ptr++;
TRACE_IF(trace, "%02x ", b);
result = result | ((static_cast<IntType>(b) & 0x7F) << shift);
......@@ -314,10 +310,14 @@ class Decoder {
constexpr int kSignExtBits = kExtraBits - (is_signed ? 1 : 0);
const byte checked_bits = b & (0xFF << kSignExtBits);
constexpr byte kSignExtendedExtraBits = 0x7f & (0xFF << kSignExtBits);
if (checked_bits != 0 &&
(!is_signed || checked_bits != kSignExtendedExtraBits)) {
bool valid_extra_bits =
checked_bits == 0 ||
(is_signed && checked_bits == kSignExtendedExtraBits);
if (!checked) {
DCHECK(valid_extra_bits);
} else if (!valid_extra_bits) {
error(ptr, "extra bits in varint");
return 0;
result = 0;
}
}
if (is_signed && *length < kMaxLength) {
......
This diff is collapsed.
This diff is collapsed.
......@@ -170,7 +170,7 @@ class V8_EXPORT_PRIVATE BytecodeIterator : public NON_EXPORTED_BASE(Decoder) {
}
WasmOpcode current() {
return static_cast<WasmOpcode>(checked_read_u8(pc_, "expected bytecode"));
return static_cast<WasmOpcode>(read_u8<false>(pc_, "expected bytecode"));
}
void next() {
......
......@@ -976,7 +976,7 @@ class ModuleDecoder : public Decoder {
unsigned len = 0;
switch (opcode) {
case kExprGetGlobal: {
GlobalIndexOperand operand(this, pc() - 1);
GlobalIndexOperand<true> operand(this, pc() - 1);
if (module->globals.size() <= operand.index) {
error("global index is out of bounds");
expr.kind = WasmInitExpr::kNone;
......@@ -998,28 +998,28 @@ class ModuleDecoder : public Decoder {
break;
}
case kExprI32Const: {
ImmI32Operand operand(this, pc() - 1);
ImmI32Operand<true> operand(this, pc() - 1);
expr.kind = WasmInitExpr::kI32Const;
expr.val.i32_const = operand.value;
len = operand.length;
break;
}
case kExprF32Const: {
ImmF32Operand operand(this, pc() - 1);
ImmF32Operand<true> operand(this, pc() - 1);
expr.kind = WasmInitExpr::kF32Const;
expr.val.f32_const = operand.value;
len = operand.length;
break;
}
case kExprI64Const: {
ImmI64Operand operand(this, pc() - 1);
ImmI64Operand<true> operand(this, pc() - 1);
expr.kind = WasmInitExpr::kI64Const;
expr.val.i64_const = operand.value;
len = operand.length;
break;
}
case kExprF64Const: {
ImmF64Operand operand(this, pc() - 1);
ImmF64Operand<true> operand(this, pc() - 1);
expr.kind = WasmInitExpr::kF64Const;
expr.val.f64_const = operand.value;
len = operand.length;
......
......@@ -808,22 +808,22 @@ class ControlTransfers : public ZoneObject {
break;
}
case kExprBr: {
BreakDepthOperand operand(&i, i.pc());
BreakDepthOperand<false> operand(&i, i.pc());
TRACE("control @%u: Br[depth=%u]\n", i.pc_offset(), operand.depth);
Control* c = &control_stack[control_stack.size() - operand.depth - 1];
c->Ref(&map_, start, i.pc());
break;
}
case kExprBrIf: {
BreakDepthOperand operand(&i, i.pc());
BreakDepthOperand<false> operand(&i, i.pc());
TRACE("control @%u: BrIf[depth=%u]\n", i.pc_offset(), operand.depth);
Control* c = &control_stack[control_stack.size() - operand.depth - 1];
c->Ref(&map_, start, i.pc());
break;
}
case kExprBrTable: {
BranchTableOperand operand(&i, i.pc());
BranchTableIterator iterator(&i, operand);
BranchTableOperand<false> operand(&i, i.pc());
BranchTableIterator<false> iterator(&i, operand);
TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(),
operand.table_count);
while (iterator.has_next()) {
......@@ -1385,11 +1385,11 @@ class ThreadImpl {
pc_t ReturnPc(Decoder* decoder, InterpreterCode* code, pc_t pc) {
switch (code->orig_start[pc]) {
case kExprCallFunction: {
CallFunctionOperand operand(decoder, code->at(pc));
CallFunctionOperand<false> operand(decoder, code->at(pc));
return pc + 1 + operand.length;
}
case kExprCallIndirect: {
CallIndirectOperand operand(decoder, code->at(pc));
CallIndirectOperand<false> operand(decoder, code->at(pc));
return pc + 1 + operand.length;
}
default:
......@@ -1466,7 +1466,7 @@ class ThreadImpl {
template <typename ctype, typename mtype>
bool ExecuteLoad(Decoder* decoder, InterpreterCode* code, pc_t pc, int& len) {
MemoryAccessOperand operand(decoder, code->at(pc), sizeof(ctype));
MemoryAccessOperand<false> operand(decoder, code->at(pc), sizeof(ctype));
uint32_t index = Pop().to<uint32_t>();
if (!BoundsCheck<mtype>(instance()->mem_size, operand.offset, index)) {
DoTrap(kTrapMemOutOfBounds, pc);
......@@ -1483,7 +1483,7 @@ class ThreadImpl {
template <typename ctype, typename mtype>
bool ExecuteStore(Decoder* decoder, InterpreterCode* code, pc_t pc,
int& len) {
MemoryAccessOperand operand(decoder, code->at(pc), sizeof(ctype));
MemoryAccessOperand<false> operand(decoder, code->at(pc), sizeof(ctype));
WasmVal val = Pop();
uint32_t index = Pop().to<uint32_t>();
......@@ -1574,19 +1574,19 @@ class ThreadImpl {
case kExprNop:
break;
case kExprBlock: {
BlockTypeOperand operand(&decoder, code->at(pc));
BlockTypeOperand<false> operand(&decoder, code->at(pc));
blocks_.push_back({pc, stack_.size(), frames_.size(), operand.arity});
len = 1 + operand.length;
break;
}
case kExprLoop: {
BlockTypeOperand operand(&decoder, code->at(pc));
BlockTypeOperand<false> operand(&decoder, code->at(pc));
blocks_.push_back({pc, stack_.size(), frames_.size(), 0});
len = 1 + operand.length;
break;
}
case kExprIf: {
BlockTypeOperand operand(&decoder, code->at(pc));
BlockTypeOperand<false> operand(&decoder, code->at(pc));
WasmVal cond = Pop();
bool is_true = cond.to<uint32_t>() != 0;
blocks_.push_back({pc, stack_.size(), frames_.size(), operand.arity});
......@@ -1614,13 +1614,13 @@ class ThreadImpl {
break;
}
case kExprBr: {
BreakDepthOperand operand(&decoder, code->at(pc));
BreakDepthOperand<false> operand(&decoder, code->at(pc));
len = DoBreak(code, pc, operand.depth);
TRACE(" br => @%zu\n", pc + len);
break;
}
case kExprBrIf: {
BreakDepthOperand operand(&decoder, code->at(pc));
BreakDepthOperand<false> operand(&decoder, code->at(pc));
WasmVal cond = Pop();
bool is_true = cond.to<uint32_t>() != 0;
if (is_true) {
......@@ -1633,8 +1633,8 @@ class ThreadImpl {
break;
}
case kExprBrTable: {
BranchTableOperand operand(&decoder, code->at(pc));
BranchTableIterator iterator(&decoder, operand);
BranchTableOperand<false> operand(&decoder, code->at(pc));
BranchTableIterator<false> iterator(&decoder, operand);
uint32_t key = Pop().to<uint32_t>();
uint32_t depth = 0;
if (key >= operand.table_count) key = operand.table_count;
......@@ -1660,44 +1660,44 @@ class ThreadImpl {
break;
}
case kExprI32Const: {
ImmI32Operand operand(&decoder, code->at(pc));
ImmI32Operand<false> operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value));
len = 1 + operand.length;
break;
}
case kExprI64Const: {
ImmI64Operand operand(&decoder, code->at(pc));
ImmI64Operand<false> operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value));
len = 1 + operand.length;
break;
}
case kExprF32Const: {
ImmF32Operand operand(&decoder, code->at(pc));
ImmF32Operand<false> operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value));
len = 1 + operand.length;
break;
}
case kExprF64Const: {
ImmF64Operand operand(&decoder, code->at(pc));
ImmF64Operand<false> operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value));
len = 1 + operand.length;
break;
}
case kExprGetLocal: {
LocalIndexOperand operand(&decoder, code->at(pc));
LocalIndexOperand<false> operand(&decoder, code->at(pc));
Push(pc, stack_[frames_.back().sp + operand.index]);
len = 1 + operand.length;
break;
}
case kExprSetLocal: {
LocalIndexOperand operand(&decoder, code->at(pc));
LocalIndexOperand<false> operand(&decoder, code->at(pc));
WasmVal val = Pop();
stack_[frames_.back().sp + operand.index] = val;
len = 1 + operand.length;
break;
}
case kExprTeeLocal: {
LocalIndexOperand operand(&decoder, code->at(pc));
LocalIndexOperand<false> operand(&decoder, code->at(pc));
WasmVal val = Pop();
stack_[frames_.back().sp + operand.index] = val;
Push(pc, val);
......@@ -1709,7 +1709,7 @@ class ThreadImpl {
break;
}
case kExprCallFunction: {
CallFunctionOperand operand(&decoder, code->at(pc));
CallFunctionOperand<false> operand(&decoder, code->at(pc));
InterpreterCode* target = codemap()->GetCode(operand.index);
if (target->function->imported) {
CommitPc(pc);
......@@ -1741,7 +1741,7 @@ class ThreadImpl {
continue; // don't bump pc
} break;
case kExprCallIndirect: {
CallIndirectOperand operand(&decoder, code->at(pc));
CallIndirectOperand<false> operand(&decoder, code->at(pc));
uint32_t entry_index = Pop().to<uint32_t>();
// Assume only one table for now.
DCHECK_LE(module()->function_tables.size(), 1u);
......@@ -1768,7 +1768,7 @@ class ThreadImpl {
}
} break;
case kExprGetGlobal: {
GlobalIndexOperand operand(&decoder, code->at(pc));
GlobalIndexOperand<false> operand(&decoder, code->at(pc));
const WasmGlobal* global = &module()->globals[operand.index];
byte* ptr = instance()->globals_start + global->offset;
WasmVal val;
......@@ -1787,7 +1787,7 @@ class ThreadImpl {
break;
}
case kExprSetGlobal: {
GlobalIndexOperand operand(&decoder, code->at(pc));
GlobalIndexOperand<false> operand(&decoder, code->at(pc));
const WasmGlobal* global = &module()->globals[operand.index];
byte* ptr = instance()->globals_start + global->offset;
WasmVal val = Pop();
......@@ -1889,7 +1889,7 @@ class ThreadImpl {
ASMJS_STORE_CASE(F64AsmjsStoreMem, double, double);
#undef ASMJS_STORE_CASE
case kExprGrowMemory: {
MemoryIndexOperand operand(&decoder, code->at(pc));
MemoryIndexOperand<false> operand(&decoder, code->at(pc));
uint32_t delta_pages = Pop().to<uint32_t>();
Push(pc, WasmVal(ExecuteGrowMemory(
delta_pages, codemap_->maybe_instance(), instance())));
......@@ -1897,7 +1897,7 @@ class ThreadImpl {
break;
}
case kExprMemorySize: {
MemoryIndexOperand operand(&decoder, code->at(pc));
MemoryIndexOperand<false> operand(&decoder, code->at(pc));
Push(pc, WasmVal(static_cast<uint32_t>(instance()->mem_size /
WasmModule::kPageSize)));
len = 1 + operand.length;
......
......@@ -102,7 +102,7 @@ void wasm::PrintWasmText(const WasmModule *module,
case kExprIf:
case kExprBlock:
case kExprTry: {
BlockTypeOperand operand(&i, i.pc());
BlockTypeOperand<false> operand(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode);
for (unsigned i = 0; i < operand.arity; i++) {
os << " " << WasmOpcodes::TypeName(operand.read_entry(i));
......@@ -112,7 +112,7 @@ void wasm::PrintWasmText(const WasmModule *module,
}
case kExprBr:
case kExprBrIf: {
BreakDepthOperand operand(&i, i.pc());
BreakDepthOperand<false> operand(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.depth;
break;
}
......@@ -124,20 +124,20 @@ void wasm::PrintWasmText(const WasmModule *module,
os << "end";
break;
case kExprBrTable: {
BranchTableOperand operand(&i, i.pc());
BranchTableIterator iterator(&i, operand);
BranchTableOperand<false> operand(&i, i.pc());
BranchTableIterator<false> iterator(&i, operand);
os << "br_table";
while (iterator.has_next()) os << ' ' << iterator.next();
break;
}
case kExprCallIndirect: {
CallIndirectOperand operand(&i, i.pc());
CallIndirectOperand<false> operand(&i, i.pc());
DCHECK_EQ(0, operand.table_index);
os << "call_indirect " << operand.index;
break;
}
case kExprCallFunction: {
CallFunctionOperand operand(&i, i.pc());
CallFunctionOperand<false> operand(&i, i.pc());
os << "call " << operand.index;
break;
}
......@@ -145,19 +145,19 @@ void wasm::PrintWasmText(const WasmModule *module,
case kExprSetLocal:
case kExprTeeLocal:
case kExprCatch: {
LocalIndexOperand operand(&i, i.pc());
LocalIndexOperand<false> operand(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.index;
break;
}
case kExprGetGlobal:
case kExprSetGlobal: {
GlobalIndexOperand operand(&i, i.pc());
GlobalIndexOperand<false> operand(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.index;
break;
}
#define CASE_CONST(type, str, cast_type) \
case kExpr##type##Const: { \
Imm##type##Operand operand(&i, i.pc()); \
Imm##type##Operand<false> operand(&i, i.pc()); \
os << #str ".const " << static_cast<cast_type>(operand.value); \
break; \
}
......@@ -169,7 +169,7 @@ void wasm::PrintWasmText(const WasmModule *module,
#define CASE_OPCODE(opcode, _, __) case kExpr##opcode:
FOREACH_LOAD_MEM_OPCODE(CASE_OPCODE)
FOREACH_STORE_MEM_OPCODE(CASE_OPCODE) {
MemoryAccessOperand operand(&i, i.pc(), kMaxUInt32);
MemoryAccessOperand<false> operand(&i, i.pc(), kMaxUInt32);
os << WasmOpcodes::OpcodeName(opcode) << " offset=" << operand.offset
<< " align=" << (1ULL << operand.alignment);
break;
......
......@@ -25,7 +25,7 @@ class DecoderTest : public TestWithZone {
decoder.Reset(data, data + sizeof(data)); \
unsigned length; \
EXPECT_EQ(static_cast<uint32_t>(expected), \
decoder.checked_read_u32v(decoder.start(), &length)); \
decoder.read_u32v<true>(decoder.start(), &length)); \
EXPECT_EQ(static_cast<unsigned>(expected_length), length); \
EXPECT_EQ(data, decoder.pc()); \
EXPECT_TRUE(decoder.ok()); \
......@@ -38,7 +38,7 @@ class DecoderTest : public TestWithZone {
const byte data[] = {__VA_ARGS__}; \
decoder.Reset(data, data + sizeof(data)); \
unsigned length; \
EXPECT_EQ(expected, decoder.checked_read_i32v(decoder.start(), &length)); \
EXPECT_EQ(expected, decoder.read_i32v<true>(decoder.start(), &length)); \
EXPECT_EQ(static_cast<unsigned>(expected_length), length); \
EXPECT_EQ(data, decoder.pc()); \
EXPECT_TRUE(decoder.ok()); \
......@@ -52,7 +52,7 @@ class DecoderTest : public TestWithZone {
decoder.Reset(data, data + sizeof(data)); \
unsigned length; \
EXPECT_EQ(static_cast<uint64_t>(expected), \
decoder.checked_read_u64v(decoder.start(), &length)); \
decoder.read_u64v<false>(decoder.start(), &length)); \
EXPECT_EQ(static_cast<unsigned>(expected_length), length); \
} while (false)
......@@ -61,7 +61,7 @@ class DecoderTest : public TestWithZone {
const byte data[] = {__VA_ARGS__}; \
decoder.Reset(data, data + sizeof(data)); \
unsigned length; \
EXPECT_EQ(expected, decoder.checked_read_i64v(decoder.start(), &length)); \
EXPECT_EQ(expected, decoder.read_i64v<false>(decoder.start(), &length)); \
EXPECT_EQ(static_cast<unsigned>(expected_length), length); \
} while (false)
......@@ -374,7 +374,7 @@ TEST_F(DecoderTest, ReadU32v_off_end1) {
static const byte data[] = {U32V_1(11)};
unsigned length = 0;
decoder.Reset(data, data);
decoder.checked_read_u32v(decoder.start(), &length);
decoder.read_u32v<true>(decoder.start(), &length);
EXPECT_EQ(0u, length);
EXPECT_FALSE(decoder.ok());
}
......@@ -384,7 +384,7 @@ TEST_F(DecoderTest, ReadU32v_off_end2) {
for (size_t i = 0; i < sizeof(data); i++) {
unsigned length = 0;
decoder.Reset(data, data + i);
decoder.checked_read_u32v(decoder.start(), &length);
decoder.read_u32v<true>(decoder.start(), &length);
EXPECT_EQ(i, length);
EXPECT_FALSE(decoder.ok());
}
......@@ -395,7 +395,7 @@ TEST_F(DecoderTest, ReadU32v_off_end3) {
for (size_t i = 0; i < sizeof(data); i++) {
unsigned length = 0;
decoder.Reset(data, data + i);
decoder.checked_read_u32v(decoder.start(), &length);
decoder.read_u32v<true>(decoder.start(), &length);
EXPECT_EQ(i, length);
EXPECT_FALSE(decoder.ok());
}
......@@ -406,7 +406,7 @@ TEST_F(DecoderTest, ReadU32v_off_end4) {
for (size_t i = 0; i < sizeof(data); i++) {
unsigned length = 0;
decoder.Reset(data, data + i);
decoder.checked_read_u32v(decoder.start(), &length);
decoder.read_u32v<true>(decoder.start(), &length);
EXPECT_EQ(i, length);
EXPECT_FALSE(decoder.ok());
}
......@@ -417,7 +417,7 @@ TEST_F(DecoderTest, ReadU32v_off_end5) {
for (size_t i = 0; i < sizeof(data); i++) {
unsigned length = 0;
decoder.Reset(data, data + i);
decoder.checked_read_u32v(decoder.start(), &length);
decoder.read_u32v<true>(decoder.start(), &length);
EXPECT_EQ(i, length);
EXPECT_FALSE(decoder.ok());
}
......@@ -429,7 +429,7 @@ TEST_F(DecoderTest, ReadU32v_extra_bits) {
data[4] = static_cast<byte>(i << 4);
unsigned length = 0;
decoder.Reset(data, data + sizeof(data));
decoder.checked_read_u32v(decoder.start(), &length);
decoder.read_u32v<true>(decoder.start(), &length);
EXPECT_EQ(5u, length);
EXPECT_FALSE(decoder.ok());
}
......@@ -440,7 +440,7 @@ TEST_F(DecoderTest, ReadI32v_extra_bits_negative) {
unsigned length = 0;
byte data[] = {0xff, 0xff, 0xff, 0xff, 0x7f};
decoder.Reset(data, data + sizeof(data));
decoder.checked_read_i32v(decoder.start(), &length);
decoder.read_i32v<true>(decoder.start(), &length);
EXPECT_EQ(5u, length);
EXPECT_TRUE(decoder.ok());
}
......@@ -450,7 +450,7 @@ TEST_F(DecoderTest, ReadI32v_extra_bits_positive) {
unsigned length = 0;
byte data[] = {0x80, 0x80, 0x80, 0x80, 0x77};
decoder.Reset(data, data + sizeof(data));
decoder.checked_read_i32v(decoder.start(), &length);
decoder.read_i32v<true>(decoder.start(), &length);
EXPECT_EQ(5u, length);
EXPECT_FALSE(decoder.ok());
}
......@@ -485,7 +485,7 @@ TEST_F(DecoderTest, ReadU32v_Bits) {
for (unsigned limit = 0; limit <= kMaxSize; limit++) {
decoder.Reset(data, data + limit);
unsigned rlen;
uint32_t result = decoder.checked_read_u32v(data, &rlen);
uint32_t result = decoder.read_u32v<true>(data, &rlen);
if (limit < length) {
EXPECT_FALSE(decoder.ok());
} else {
......@@ -541,7 +541,7 @@ TEST_F(DecoderTest, ReadU64v_PowerOf2) {
for (unsigned limit = 0; limit <= kMaxSize; limit++) {
decoder.Reset(data, data + limit);
unsigned length;
uint64_t result = decoder.checked_read_u64v(data, &length);
uint64_t result = decoder.read_u64v<true>(data, &length);
if (limit <= index) {
EXPECT_FALSE(decoder.ok());
} else {
......@@ -582,7 +582,7 @@ TEST_F(DecoderTest, ReadU64v_Bits) {
for (unsigned limit = 0; limit <= kMaxSize; limit++) {
decoder.Reset(data, data + limit);
unsigned rlen;
uint64_t result = decoder.checked_read_u64v(data, &rlen);
uint64_t result = decoder.read_u64v<true>(data, &rlen);
if (limit < length) {
EXPECT_FALSE(decoder.ok());
} else {
......@@ -624,7 +624,7 @@ TEST_F(DecoderTest, ReadI64v_Bits) {
for (unsigned limit = 0; limit <= kMaxSize; limit++) {
decoder.Reset(data, data + limit);
unsigned rlen;
int64_t result = decoder.checked_read_i64v(data, &rlen);
int64_t result = decoder.read_i64v<true>(data, &rlen);
if (limit < length) {
EXPECT_FALSE(decoder.ok());
} else {
......@@ -643,7 +643,7 @@ TEST_F(DecoderTest, ReadU64v_extra_bits) {
data[9] = static_cast<byte>(i << 1);
unsigned length = 0;
decoder.Reset(data, data + sizeof(data));
decoder.checked_read_u64v(decoder.start(), &length);
decoder.read_u64v<true>(decoder.start(), &length);
EXPECT_EQ(10u, length);
EXPECT_FALSE(decoder.ok());
}
......@@ -654,7 +654,7 @@ TEST_F(DecoderTest, ReadI64v_extra_bits_negative) {
unsigned length = 0;
byte data[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f};
decoder.Reset(data, data + sizeof(data));
decoder.checked_read_i64v(decoder.start(), &length);
decoder.read_i64v<true>(decoder.start(), &length);
EXPECT_EQ(10u, length);
EXPECT_TRUE(decoder.ok());
}
......@@ -664,7 +664,7 @@ TEST_F(DecoderTest, ReadI64v_extra_bits_positive) {
unsigned length = 0;
byte data[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x77};
decoder.Reset(data, data + sizeof(data));
decoder.checked_read_i64v(decoder.start(), &length);
decoder.read_i64v<true>(decoder.start(), &length);
EXPECT_EQ(10u, length);
EXPECT_FALSE(decoder.ok());
}
......
......@@ -2333,15 +2333,15 @@ class BranchTableIteratorTest : public TestWithZone {
BranchTableIteratorTest() : TestWithZone() {}
void CheckBrTableSize(const byte* start, const byte* end) {
Decoder decoder(start, end);
BranchTableOperand operand(&decoder, start);
BranchTableIterator iterator(&decoder, operand);
BranchTableOperand<true> operand(&decoder, start);
BranchTableIterator<true> iterator(&decoder, operand);
EXPECT_EQ(end - start - 1u, iterator.length());
EXPECT_TRUE(decoder.ok());
}
void CheckBrTableError(const byte* start, const byte* end) {
Decoder decoder(start, end);
BranchTableOperand operand(&decoder, start);
BranchTableIterator iterator(&decoder, operand);
BranchTableOperand<true> operand(&decoder, start);
BranchTableIterator<true> iterator(&decoder, operand);
iterator.length();
EXPECT_FALSE(decoder.ok());
}
......
......@@ -98,7 +98,7 @@ TEST_F(LEBHelperTest, sizeof_i32v) {
static_cast<size_t>(ptr - buffer)); \
Decoder decoder(buffer, buffer + kSize); \
unsigned length = 0; \
ctype result = decoder.checked_read_##name(buffer, &length); \
ctype result = decoder.read_##name<false>(buffer, &length); \
EXPECT_EQ(val, result); \
EXPECT_EQ(LEBHelper::sizeof_##name(val), static_cast<size_t>(length)); \
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment