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
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -170,7 +170,7 @@ class V8_EXPORT_PRIVATE BytecodeIterator : public NON_EXPORTED_BASE(Decoder) { ...@@ -170,7 +170,7 @@ class V8_EXPORT_PRIVATE BytecodeIterator : public NON_EXPORTED_BASE(Decoder) {
} }
WasmOpcode current() { WasmOpcode current() {
return static_cast<WasmOpcode>(checked_read_u8(pc_, "expected bytecode")); return static_cast<WasmOpcode>(read_u8<false>(pc_, "expected bytecode"));
} }
void next() { void next() {
......
...@@ -976,7 +976,7 @@ class ModuleDecoder : public Decoder { ...@@ -976,7 +976,7 @@ class ModuleDecoder : public Decoder {
unsigned len = 0; unsigned len = 0;
switch (opcode) { switch (opcode) {
case kExprGetGlobal: { case kExprGetGlobal: {
GlobalIndexOperand operand(this, pc() - 1); GlobalIndexOperand<true> operand(this, pc() - 1);
if (module->globals.size() <= operand.index) { if (module->globals.size() <= operand.index) {
error("global index is out of bounds"); error("global index is out of bounds");
expr.kind = WasmInitExpr::kNone; expr.kind = WasmInitExpr::kNone;
...@@ -998,28 +998,28 @@ class ModuleDecoder : public Decoder { ...@@ -998,28 +998,28 @@ class ModuleDecoder : public Decoder {
break; break;
} }
case kExprI32Const: { case kExprI32Const: {
ImmI32Operand operand(this, pc() - 1); ImmI32Operand<true> operand(this, pc() - 1);
expr.kind = WasmInitExpr::kI32Const; expr.kind = WasmInitExpr::kI32Const;
expr.val.i32_const = operand.value; expr.val.i32_const = operand.value;
len = operand.length; len = operand.length;
break; break;
} }
case kExprF32Const: { case kExprF32Const: {
ImmF32Operand operand(this, pc() - 1); ImmF32Operand<true> operand(this, pc() - 1);
expr.kind = WasmInitExpr::kF32Const; expr.kind = WasmInitExpr::kF32Const;
expr.val.f32_const = operand.value; expr.val.f32_const = operand.value;
len = operand.length; len = operand.length;
break; break;
} }
case kExprI64Const: { case kExprI64Const: {
ImmI64Operand operand(this, pc() - 1); ImmI64Operand<true> operand(this, pc() - 1);
expr.kind = WasmInitExpr::kI64Const; expr.kind = WasmInitExpr::kI64Const;
expr.val.i64_const = operand.value; expr.val.i64_const = operand.value;
len = operand.length; len = operand.length;
break; break;
} }
case kExprF64Const: { case kExprF64Const: {
ImmF64Operand operand(this, pc() - 1); ImmF64Operand<true> operand(this, pc() - 1);
expr.kind = WasmInitExpr::kF64Const; expr.kind = WasmInitExpr::kF64Const;
expr.val.f64_const = operand.value; expr.val.f64_const = operand.value;
len = operand.length; len = operand.length;
......
...@@ -808,22 +808,22 @@ class ControlTransfers : public ZoneObject { ...@@ -808,22 +808,22 @@ class ControlTransfers : public ZoneObject {
break; break;
} }
case kExprBr: { 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); TRACE("control @%u: Br[depth=%u]\n", i.pc_offset(), operand.depth);
Control* c = &control_stack[control_stack.size() - operand.depth - 1]; Control* c = &control_stack[control_stack.size() - operand.depth - 1];
c->Ref(&map_, start, i.pc()); c->Ref(&map_, start, i.pc());
break; break;
} }
case kExprBrIf: { 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); TRACE("control @%u: BrIf[depth=%u]\n", i.pc_offset(), operand.depth);
Control* c = &control_stack[control_stack.size() - operand.depth - 1]; Control* c = &control_stack[control_stack.size() - operand.depth - 1];
c->Ref(&map_, start, i.pc()); c->Ref(&map_, start, i.pc());
break; break;
} }
case kExprBrTable: { case kExprBrTable: {
BranchTableOperand operand(&i, i.pc()); BranchTableOperand<false> operand(&i, i.pc());
BranchTableIterator iterator(&i, operand); BranchTableIterator<false> iterator(&i, operand);
TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(), TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(),
operand.table_count); operand.table_count);
while (iterator.has_next()) { while (iterator.has_next()) {
...@@ -1385,11 +1385,11 @@ class ThreadImpl { ...@@ -1385,11 +1385,11 @@ class ThreadImpl {
pc_t ReturnPc(Decoder* decoder, InterpreterCode* code, pc_t pc) { pc_t ReturnPc(Decoder* decoder, InterpreterCode* code, pc_t pc) {
switch (code->orig_start[pc]) { switch (code->orig_start[pc]) {
case kExprCallFunction: { case kExprCallFunction: {
CallFunctionOperand operand(decoder, code->at(pc)); CallFunctionOperand<false> operand(decoder, code->at(pc));
return pc + 1 + operand.length; return pc + 1 + operand.length;
} }
case kExprCallIndirect: { case kExprCallIndirect: {
CallIndirectOperand operand(decoder, code->at(pc)); CallIndirectOperand<false> operand(decoder, code->at(pc));
return pc + 1 + operand.length; return pc + 1 + operand.length;
} }
default: default:
...@@ -1466,7 +1466,7 @@ class ThreadImpl { ...@@ -1466,7 +1466,7 @@ class ThreadImpl {
template <typename ctype, typename mtype> template <typename ctype, typename mtype>
bool ExecuteLoad(Decoder* decoder, InterpreterCode* code, pc_t pc, int& len) { 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>(); uint32_t index = Pop().to<uint32_t>();
if (!BoundsCheck<mtype>(instance()->mem_size, operand.offset, index)) { if (!BoundsCheck<mtype>(instance()->mem_size, operand.offset, index)) {
DoTrap(kTrapMemOutOfBounds, pc); DoTrap(kTrapMemOutOfBounds, pc);
...@@ -1483,7 +1483,7 @@ class ThreadImpl { ...@@ -1483,7 +1483,7 @@ class ThreadImpl {
template <typename ctype, typename mtype> template <typename ctype, typename mtype>
bool ExecuteStore(Decoder* decoder, InterpreterCode* code, pc_t pc, bool ExecuteStore(Decoder* decoder, InterpreterCode* code, pc_t pc,
int& len) { int& len) {
MemoryAccessOperand operand(decoder, code->at(pc), sizeof(ctype)); MemoryAccessOperand<false> operand(decoder, code->at(pc), sizeof(ctype));
WasmVal val = Pop(); WasmVal val = Pop();
uint32_t index = Pop().to<uint32_t>(); uint32_t index = Pop().to<uint32_t>();
...@@ -1574,19 +1574,19 @@ class ThreadImpl { ...@@ -1574,19 +1574,19 @@ class ThreadImpl {
case kExprNop: case kExprNop:
break; break;
case kExprBlock: { 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}); blocks_.push_back({pc, stack_.size(), frames_.size(), operand.arity});
len = 1 + operand.length; len = 1 + operand.length;
break; break;
} }
case kExprLoop: { case kExprLoop: {
BlockTypeOperand operand(&decoder, code->at(pc)); BlockTypeOperand<false> operand(&decoder, code->at(pc));
blocks_.push_back({pc, stack_.size(), frames_.size(), 0}); blocks_.push_back({pc, stack_.size(), frames_.size(), 0});
len = 1 + operand.length; len = 1 + operand.length;
break; break;
} }
case kExprIf: { case kExprIf: {
BlockTypeOperand operand(&decoder, code->at(pc)); BlockTypeOperand<false> operand(&decoder, code->at(pc));
WasmVal cond = Pop(); WasmVal cond = Pop();
bool is_true = cond.to<uint32_t>() != 0; bool is_true = cond.to<uint32_t>() != 0;
blocks_.push_back({pc, stack_.size(), frames_.size(), operand.arity}); blocks_.push_back({pc, stack_.size(), frames_.size(), operand.arity});
...@@ -1614,13 +1614,13 @@ class ThreadImpl { ...@@ -1614,13 +1614,13 @@ class ThreadImpl {
break; break;
} }
case kExprBr: { case kExprBr: {
BreakDepthOperand operand(&decoder, code->at(pc)); BreakDepthOperand<false> operand(&decoder, code->at(pc));
len = DoBreak(code, pc, operand.depth); len = DoBreak(code, pc, operand.depth);
TRACE(" br => @%zu\n", pc + len); TRACE(" br => @%zu\n", pc + len);
break; break;
} }
case kExprBrIf: { case kExprBrIf: {
BreakDepthOperand operand(&decoder, code->at(pc)); BreakDepthOperand<false> operand(&decoder, code->at(pc));
WasmVal cond = Pop(); WasmVal cond = Pop();
bool is_true = cond.to<uint32_t>() != 0; bool is_true = cond.to<uint32_t>() != 0;
if (is_true) { if (is_true) {
...@@ -1633,8 +1633,8 @@ class ThreadImpl { ...@@ -1633,8 +1633,8 @@ class ThreadImpl {
break; break;
} }
case kExprBrTable: { case kExprBrTable: {
BranchTableOperand operand(&decoder, code->at(pc)); BranchTableOperand<false> operand(&decoder, code->at(pc));
BranchTableIterator iterator(&decoder, operand); BranchTableIterator<false> iterator(&decoder, operand);
uint32_t key = Pop().to<uint32_t>(); uint32_t key = Pop().to<uint32_t>();
uint32_t depth = 0; uint32_t depth = 0;
if (key >= operand.table_count) key = operand.table_count; if (key >= operand.table_count) key = operand.table_count;
...@@ -1660,44 +1660,44 @@ class ThreadImpl { ...@@ -1660,44 +1660,44 @@ class ThreadImpl {
break; break;
} }
case kExprI32Const: { case kExprI32Const: {
ImmI32Operand operand(&decoder, code->at(pc)); ImmI32Operand<false> operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value)); Push(pc, WasmVal(operand.value));
len = 1 + operand.length; len = 1 + operand.length;
break; break;
} }
case kExprI64Const: { case kExprI64Const: {
ImmI64Operand operand(&decoder, code->at(pc)); ImmI64Operand<false> operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value)); Push(pc, WasmVal(operand.value));
len = 1 + operand.length; len = 1 + operand.length;
break; break;
} }
case kExprF32Const: { case kExprF32Const: {
ImmF32Operand operand(&decoder, code->at(pc)); ImmF32Operand<false> operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value)); Push(pc, WasmVal(operand.value));
len = 1 + operand.length; len = 1 + operand.length;
break; break;
} }
case kExprF64Const: { case kExprF64Const: {
ImmF64Operand operand(&decoder, code->at(pc)); ImmF64Operand<false> operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value)); Push(pc, WasmVal(operand.value));
len = 1 + operand.length; len = 1 + operand.length;
break; break;
} }
case kExprGetLocal: { case kExprGetLocal: {
LocalIndexOperand operand(&decoder, code->at(pc)); LocalIndexOperand<false> operand(&decoder, code->at(pc));
Push(pc, stack_[frames_.back().sp + operand.index]); Push(pc, stack_[frames_.back().sp + operand.index]);
len = 1 + operand.length; len = 1 + operand.length;
break; break;
} }
case kExprSetLocal: { case kExprSetLocal: {
LocalIndexOperand operand(&decoder, code->at(pc)); LocalIndexOperand<false> operand(&decoder, code->at(pc));
WasmVal val = Pop(); WasmVal val = Pop();
stack_[frames_.back().sp + operand.index] = val; stack_[frames_.back().sp + operand.index] = val;
len = 1 + operand.length; len = 1 + operand.length;
break; break;
} }
case kExprTeeLocal: { case kExprTeeLocal: {
LocalIndexOperand operand(&decoder, code->at(pc)); LocalIndexOperand<false> operand(&decoder, code->at(pc));
WasmVal val = Pop(); WasmVal val = Pop();
stack_[frames_.back().sp + operand.index] = val; stack_[frames_.back().sp + operand.index] = val;
Push(pc, val); Push(pc, val);
...@@ -1709,7 +1709,7 @@ class ThreadImpl { ...@@ -1709,7 +1709,7 @@ class ThreadImpl {
break; break;
} }
case kExprCallFunction: { case kExprCallFunction: {
CallFunctionOperand operand(&decoder, code->at(pc)); CallFunctionOperand<false> operand(&decoder, code->at(pc));
InterpreterCode* target = codemap()->GetCode(operand.index); InterpreterCode* target = codemap()->GetCode(operand.index);
if (target->function->imported) { if (target->function->imported) {
CommitPc(pc); CommitPc(pc);
...@@ -1741,7 +1741,7 @@ class ThreadImpl { ...@@ -1741,7 +1741,7 @@ class ThreadImpl {
continue; // don't bump pc continue; // don't bump pc
} break; } break;
case kExprCallIndirect: { case kExprCallIndirect: {
CallIndirectOperand operand(&decoder, code->at(pc)); CallIndirectOperand<false> operand(&decoder, code->at(pc));
uint32_t entry_index = Pop().to<uint32_t>(); uint32_t entry_index = Pop().to<uint32_t>();
// Assume only one table for now. // Assume only one table for now.
DCHECK_LE(module()->function_tables.size(), 1u); DCHECK_LE(module()->function_tables.size(), 1u);
...@@ -1768,7 +1768,7 @@ class ThreadImpl { ...@@ -1768,7 +1768,7 @@ class ThreadImpl {
} }
} break; } break;
case kExprGetGlobal: { case kExprGetGlobal: {
GlobalIndexOperand operand(&decoder, code->at(pc)); GlobalIndexOperand<false> operand(&decoder, code->at(pc));
const WasmGlobal* global = &module()->globals[operand.index]; const WasmGlobal* global = &module()->globals[operand.index];
byte* ptr = instance()->globals_start + global->offset; byte* ptr = instance()->globals_start + global->offset;
WasmVal val; WasmVal val;
...@@ -1787,7 +1787,7 @@ class ThreadImpl { ...@@ -1787,7 +1787,7 @@ class ThreadImpl {
break; break;
} }
case kExprSetGlobal: { case kExprSetGlobal: {
GlobalIndexOperand operand(&decoder, code->at(pc)); GlobalIndexOperand<false> operand(&decoder, code->at(pc));
const WasmGlobal* global = &module()->globals[operand.index]; const WasmGlobal* global = &module()->globals[operand.index];
byte* ptr = instance()->globals_start + global->offset; byte* ptr = instance()->globals_start + global->offset;
WasmVal val = Pop(); WasmVal val = Pop();
...@@ -1889,7 +1889,7 @@ class ThreadImpl { ...@@ -1889,7 +1889,7 @@ class ThreadImpl {
ASMJS_STORE_CASE(F64AsmjsStoreMem, double, double); ASMJS_STORE_CASE(F64AsmjsStoreMem, double, double);
#undef ASMJS_STORE_CASE #undef ASMJS_STORE_CASE
case kExprGrowMemory: { case kExprGrowMemory: {
MemoryIndexOperand operand(&decoder, code->at(pc)); MemoryIndexOperand<false> operand(&decoder, code->at(pc));
uint32_t delta_pages = Pop().to<uint32_t>(); uint32_t delta_pages = Pop().to<uint32_t>();
Push(pc, WasmVal(ExecuteGrowMemory( Push(pc, WasmVal(ExecuteGrowMemory(
delta_pages, codemap_->maybe_instance(), instance()))); delta_pages, codemap_->maybe_instance(), instance())));
...@@ -1897,7 +1897,7 @@ class ThreadImpl { ...@@ -1897,7 +1897,7 @@ class ThreadImpl {
break; break;
} }
case kExprMemorySize: { 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 / Push(pc, WasmVal(static_cast<uint32_t>(instance()->mem_size /
WasmModule::kPageSize))); WasmModule::kPageSize)));
len = 1 + operand.length; len = 1 + operand.length;
......
...@@ -102,7 +102,7 @@ void wasm::PrintWasmText(const WasmModule *module, ...@@ -102,7 +102,7 @@ void wasm::PrintWasmText(const WasmModule *module,
case kExprIf: case kExprIf:
case kExprBlock: case kExprBlock:
case kExprTry: { case kExprTry: {
BlockTypeOperand operand(&i, i.pc()); BlockTypeOperand<false> operand(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode); os << WasmOpcodes::OpcodeName(opcode);
for (unsigned i = 0; i < operand.arity; i++) { for (unsigned i = 0; i < operand.arity; i++) {
os << " " << WasmOpcodes::TypeName(operand.read_entry(i)); os << " " << WasmOpcodes::TypeName(operand.read_entry(i));
...@@ -112,7 +112,7 @@ void wasm::PrintWasmText(const WasmModule *module, ...@@ -112,7 +112,7 @@ void wasm::PrintWasmText(const WasmModule *module,
} }
case kExprBr: case kExprBr:
case kExprBrIf: { case kExprBrIf: {
BreakDepthOperand operand(&i, i.pc()); BreakDepthOperand<false> operand(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.depth; os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.depth;
break; break;
} }
...@@ -124,20 +124,20 @@ void wasm::PrintWasmText(const WasmModule *module, ...@@ -124,20 +124,20 @@ void wasm::PrintWasmText(const WasmModule *module,
os << "end"; os << "end";
break; break;
case kExprBrTable: { case kExprBrTable: {
BranchTableOperand operand(&i, i.pc()); BranchTableOperand<false> operand(&i, i.pc());
BranchTableIterator iterator(&i, operand); BranchTableIterator<false> iterator(&i, operand);
os << "br_table"; os << "br_table";
while (iterator.has_next()) os << ' ' << iterator.next(); while (iterator.has_next()) os << ' ' << iterator.next();
break; break;
} }
case kExprCallIndirect: { case kExprCallIndirect: {
CallIndirectOperand operand(&i, i.pc()); CallIndirectOperand<false> operand(&i, i.pc());
DCHECK_EQ(0, operand.table_index); DCHECK_EQ(0, operand.table_index);
os << "call_indirect " << operand.index; os << "call_indirect " << operand.index;
break; break;
} }
case kExprCallFunction: { case kExprCallFunction: {
CallFunctionOperand operand(&i, i.pc()); CallFunctionOperand<false> operand(&i, i.pc());
os << "call " << operand.index; os << "call " << operand.index;
break; break;
} }
...@@ -145,19 +145,19 @@ void wasm::PrintWasmText(const WasmModule *module, ...@@ -145,19 +145,19 @@ void wasm::PrintWasmText(const WasmModule *module,
case kExprSetLocal: case kExprSetLocal:
case kExprTeeLocal: case kExprTeeLocal:
case kExprCatch: { case kExprCatch: {
LocalIndexOperand operand(&i, i.pc()); LocalIndexOperand<false> operand(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.index; os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.index;
break; break;
} }
case kExprGetGlobal: case kExprGetGlobal:
case kExprSetGlobal: { case kExprSetGlobal: {
GlobalIndexOperand operand(&i, i.pc()); GlobalIndexOperand<false> operand(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.index; os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.index;
break; break;
} }
#define CASE_CONST(type, str, cast_type) \ #define CASE_CONST(type, str, cast_type) \
case kExpr##type##Const: { \ 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); \ os << #str ".const " << static_cast<cast_type>(operand.value); \
break; \ break; \
} }
...@@ -169,7 +169,7 @@ void wasm::PrintWasmText(const WasmModule *module, ...@@ -169,7 +169,7 @@ void wasm::PrintWasmText(const WasmModule *module,
#define CASE_OPCODE(opcode, _, __) case kExpr##opcode: #define CASE_OPCODE(opcode, _, __) case kExpr##opcode:
FOREACH_LOAD_MEM_OPCODE(CASE_OPCODE) FOREACH_LOAD_MEM_OPCODE(CASE_OPCODE)
FOREACH_STORE_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 os << WasmOpcodes::OpcodeName(opcode) << " offset=" << operand.offset
<< " align=" << (1ULL << operand.alignment); << " align=" << (1ULL << operand.alignment);
break; break;
......
This diff is collapsed.
...@@ -2333,15 +2333,15 @@ class BranchTableIteratorTest : public TestWithZone { ...@@ -2333,15 +2333,15 @@ class BranchTableIteratorTest : public TestWithZone {
BranchTableIteratorTest() : TestWithZone() {} BranchTableIteratorTest() : TestWithZone() {}
void CheckBrTableSize(const byte* start, const byte* end) { void CheckBrTableSize(const byte* start, const byte* end) {
Decoder decoder(start, end); Decoder decoder(start, end);
BranchTableOperand operand(&decoder, start); BranchTableOperand<true> operand(&decoder, start);
BranchTableIterator iterator(&decoder, operand); BranchTableIterator<true> iterator(&decoder, operand);
EXPECT_EQ(end - start - 1u, iterator.length()); EXPECT_EQ(end - start - 1u, iterator.length());
EXPECT_TRUE(decoder.ok()); EXPECT_TRUE(decoder.ok());
} }
void CheckBrTableError(const byte* start, const byte* end) { void CheckBrTableError(const byte* start, const byte* end) {
Decoder decoder(start, end); Decoder decoder(start, end);
BranchTableOperand operand(&decoder, start); BranchTableOperand<true> operand(&decoder, start);
BranchTableIterator iterator(&decoder, operand); BranchTableIterator<true> iterator(&decoder, operand);
iterator.length(); iterator.length();
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
} }
......
...@@ -98,7 +98,7 @@ TEST_F(LEBHelperTest, sizeof_i32v) { ...@@ -98,7 +98,7 @@ TEST_F(LEBHelperTest, sizeof_i32v) {
static_cast<size_t>(ptr - buffer)); \ static_cast<size_t>(ptr - buffer)); \
Decoder decoder(buffer, buffer + kSize); \ Decoder decoder(buffer, buffer + kSize); \
unsigned length = 0; \ 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(val, result); \
EXPECT_EQ(LEBHelper::sizeof_##name(val), static_cast<size_t>(length)); \ 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