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 { ...@@ -52,120 +52,86 @@ class Decoder {
return true; return true;
} }
// Reads a single 8-bit byte, reporting an error if out of bounds. // Reads an 8-bit unsigned integer.
inline uint8_t checked_read_u8(const byte* pc, template <bool checked>
const char* msg = "expected 1 byte") { inline uint8_t read_u8(const byte* pc, const char* msg = "expected 1 byte") {
return check(pc, 1, msg) ? *pc : 0; return read_little_endian<uint8_t, checked>(pc, msg);
} }
// Reads 16-bit word, reporting an error if out of bounds. // Reads a 16-bit unsigned integer (little endian).
inline uint16_t checked_read_u16(const byte* pc, template <bool checked>
inline uint16_t read_u16(const byte* pc,
const char* msg = "expected 2 bytes") { 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. // Reads a 32-bit unsigned integer (little endian).
inline uint32_t checked_read_u32(const byte* pc, template <bool checked>
inline uint32_t read_u32(const byte* pc,
const char* msg = "expected 4 bytes") { 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. // Reads a 64-bit unsigned integer (little endian).
inline uint64_t checked_read_u64(const byte* pc, template <bool checked>
inline uint64_t read_u64(const byte* pc,
const char* msg = "expected 8 bytes") { 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). // 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") { 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). // 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") { 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). // 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") { 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). // 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") { const char* name = "signed LEB64") {
return checked_read_leb<int64_t, false, false>(pc, length, name); return read_leb<int64_t, checked, 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);
} }
// Reads a 8-bit unsigned integer (byte) and advances {pc_}. // Reads a 8-bit unsigned integer (byte) and advances {pc_}.
uint8_t consume_u8(const char* name = nullptr) { uint8_t consume_u8(const char* name = "uint8_t") {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), return consume_little_endian<uint8_t>(name);
name ? name : "uint8_t");
if (checkAvailable(1)) {
byte val = *(pc_++);
TRACE("%02x = %d\n", val, val);
return val;
}
return traceOffEnd<uint8_t, true>();
} }
// Reads a 16-bit unsigned integer (little endian) and advances {pc_}. // Reads a 16-bit unsigned integer (little endian) and advances {pc_}.
uint16_t consume_u16(const char* name = nullptr) { uint16_t consume_u16(const char* name = "uint16_t") {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), return consume_little_endian<uint16_t>(name);
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>();
} }
// Reads a single 32-bit unsigned integer (little endian) and advances {pc_}. // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}.
uint32_t consume_u32(const char* name = nullptr) { uint32_t consume_u32(const char* name = "uint32_t") {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), return consume_little_endian<uint32_t>(name);
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>();
} }
// Reads a LEB128 variable-length unsigned 32-bit integer and advances {pc_}. // Reads a LEB128 variable-length unsigned 32-bit integer and advances {pc_}.
uint32_t consume_u32v(const char* name = nullptr) { uint32_t consume_u32v(const char* name = nullptr) {
unsigned length = 0; 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_}. // Reads a LEB128 variable-length signed 32-bit integer and advances {pc_}.
int32_t consume_i32v(const char* name = nullptr) { int32_t consume_i32v(const char* name = nullptr) {
unsigned length = 0; 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_}. // Consume {size} bytes and send them to the bit bucket, advancing {pc_}.
...@@ -221,15 +187,16 @@ class Decoder { ...@@ -221,15 +187,16 @@ class Decoder {
// Behavior triggered on first error, overridden in subclasses. // Behavior triggered on first error, overridden in subclasses.
virtual void onFirstError() {} virtual void onFirstError() {}
// Debugging helper to print bytes up to the end. // Debugging helper to print a bytes range as hex bytes.
template <typename T, bool update_pc> void traceByteRange(const byte* start, const byte* end) {
T traceOffEnd() { DCHECK_LE(start, end);
for (const byte* ptr = pc_; ptr < end_; ptr++) { for (const byte* p = start; p < end; ++p) TRACE("%02x ", *p);
TRACE("%02x ", *ptr);
} }
// Debugging helper to print bytes up to the end.
void traceOffEnd() {
traceByteRange(pc_, end_);
TRACE("<end>\n"); TRACE("<end>\n");
if (update_pc) pc_ = end_;
return T{0};
} }
// Converts the given value to a {Result}, copying the error if necessary. // Converts the given value to a {Result}, copying the error if necessary.
...@@ -276,8 +243,33 @@ class Decoder { ...@@ -276,8 +243,33 @@ class Decoder {
std::unique_ptr<char[]> error_msg_; std::unique_ptr<char[]> error_msg_;
private: private:
template <typename IntType, bool advance_pc, bool trace> template <typename IntType, bool checked>
inline IntType checked_read_leb(const byte* pc, unsigned* length, 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") { const char* name = "varint") {
DCHECK_IMPLIES(advance_pc, pc == pc_); DCHECK_IMPLIES(advance_pc, pc == pc_);
constexpr bool is_signed = std::is_signed<IntType>::value; constexpr bool is_signed = std::is_signed<IntType>::value;
...@@ -285,15 +277,19 @@ class Decoder { ...@@ -285,15 +277,19 @@ class Decoder {
constexpr int kMaxLength = (sizeof(IntType) * 8 + 6) / 7; constexpr int kMaxLength = (sizeof(IntType) * 8 + 6) / 7;
const byte* ptr = pc; const byte* ptr = pc;
const byte* end = Min(end_, ptr + kMaxLength); const byte* end = Min(end_, ptr + kMaxLength);
// The end variable is only used if checked == true. MSVC recognizes this.
USE(end);
int shift = 0; int shift = 0;
byte b = 0; byte b = 0;
IntType result = 0; IntType result = 0;
for (;;) { for (;;) {
if (V8_UNLIKELY(ptr >= end)) { if (checked && V8_UNLIKELY(ptr >= end)) {
TRACE_IF(trace, "<end> "); TRACE_IF(trace, "<end> ");
errorf(ptr, "expected %s", name); errorf(ptr, "expected %s", name);
result = 0;
break; break;
} }
DCHECK_GT(end, ptr);
b = *ptr++; b = *ptr++;
TRACE_IF(trace, "%02x ", b); TRACE_IF(trace, "%02x ", b);
result = result | ((static_cast<IntType>(b) & 0x7F) << shift); result = result | ((static_cast<IntType>(b) & 0x7F) << shift);
...@@ -314,10 +310,14 @@ class Decoder { ...@@ -314,10 +310,14 @@ class Decoder {
constexpr int kSignExtBits = kExtraBits - (is_signed ? 1 : 0); constexpr int kSignExtBits = kExtraBits - (is_signed ? 1 : 0);
const byte checked_bits = b & (0xFF << kSignExtBits); const byte checked_bits = b & (0xFF << kSignExtBits);
constexpr byte kSignExtendedExtraBits = 0x7f & (0xFF << kSignExtBits); constexpr byte kSignExtendedExtraBits = 0x7f & (0xFF << kSignExtBits);
if (checked_bits != 0 && bool valid_extra_bits =
(!is_signed || checked_bits != kSignExtendedExtraBits)) { 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"); error(ptr, "extra bits in varint");
return 0; result = 0;
} }
} }
if (is_signed && *length < kMaxLength) { if (is_signed && *length < kMaxLength) {
......
...@@ -14,96 +14,103 @@ namespace wasm { ...@@ -14,96 +14,103 @@ namespace wasm {
struct WasmGlobal; struct WasmGlobal;
// Use this macro to check a condition if checked == true, and DCHECK the
// condition otherwise.
#define CHECKED_COND(cond) \
(checked ? (cond) : ([&] { \
DCHECK(cond); \
return true; \
})())
// Helpers for decoding different kinds of operands which follow bytecodes. // Helpers for decoding different kinds of operands which follow bytecodes.
template <bool checked>
struct LocalIndexOperand { struct LocalIndexOperand {
uint32_t index; uint32_t index;
ValueType type; ValueType type = kWasmStmt;
unsigned length; unsigned length;
inline LocalIndexOperand(Decoder* decoder, const byte* pc) { inline LocalIndexOperand(Decoder* decoder, const byte* pc) {
index = decoder->checked_read_u32v(pc + 1, &length, "local index"); index = decoder->read_u32v<checked>(pc + 1, &length, "local index");
type = kWasmStmt;
} }
}; };
template <bool checked>
struct ImmI32Operand { struct ImmI32Operand {
int32_t value; int32_t value;
unsigned length; unsigned length;
inline ImmI32Operand(Decoder* decoder, const byte* pc) { inline ImmI32Operand(Decoder* decoder, const byte* pc) {
value = decoder->checked_read_i32v(pc + 1, &length, "immi32"); value = decoder->read_i32v<checked>(pc + 1, &length, "immi32");
} }
}; };
template <bool checked>
struct ImmI64Operand { struct ImmI64Operand {
int64_t value; int64_t value;
unsigned length; unsigned length;
inline ImmI64Operand(Decoder* decoder, const byte* pc) { inline ImmI64Operand(Decoder* decoder, const byte* pc) {
value = decoder->checked_read_i64v(pc + 1, &length, "immi64"); value = decoder->read_i64v<checked>(pc + 1, &length, "immi64");
} }
}; };
template <bool checked>
struct ImmF32Operand { struct ImmF32Operand {
float value; float value;
unsigned length; unsigned length = 4;
inline ImmF32Operand(Decoder* decoder, const byte* pc) { inline ImmF32Operand(Decoder* decoder, const byte* pc) {
// Avoid bit_cast because it might not preserve the signalling bit of a NaN. // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
uint32_t tmp = decoder->checked_read_u32(pc + 1, "immf32"); uint32_t tmp = decoder->read_u32<checked>(pc + 1, "immf32");
memcpy(&value, &tmp, sizeof(value)); memcpy(&value, &tmp, sizeof(value));
length = 4;
} }
}; };
template <bool checked>
struct ImmF64Operand { struct ImmF64Operand {
double value; double value;
unsigned length; unsigned length = 8;
inline ImmF64Operand(Decoder* decoder, const byte* pc) { inline ImmF64Operand(Decoder* decoder, const byte* pc) {
// Avoid bit_cast because it might not preserve the signalling bit of a NaN. // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
uint64_t tmp = decoder->checked_read_u64(pc + 1, "immf64"); uint64_t tmp = decoder->read_u64<checked>(pc + 1, "immf64");
memcpy(&value, &tmp, sizeof(value)); memcpy(&value, &tmp, sizeof(value));
length = 8;
} }
}; };
template <bool checked>
struct GlobalIndexOperand { struct GlobalIndexOperand {
uint32_t index; uint32_t index;
ValueType type; ValueType type = kWasmStmt;
const WasmGlobal* global; const WasmGlobal* global = nullptr;
unsigned length; unsigned length;
inline GlobalIndexOperand(Decoder* decoder, const byte* pc) { inline GlobalIndexOperand(Decoder* decoder, const byte* pc) {
index = decoder->checked_read_u32v(pc + 1, &length, "global index"); index = decoder->read_u32v<checked>(pc + 1, &length, "global index");
global = nullptr;
type = kWasmStmt;
} }
}; };
template <bool checked>
struct BlockTypeOperand { struct BlockTypeOperand {
uint32_t arity; uint32_t arity = 0;
const byte* types; // pointer to encoded types for the block. const byte* types = nullptr; // pointer to encoded types for the block.
unsigned length; unsigned length = 1;
inline BlockTypeOperand(Decoder* decoder, const byte* pc) { inline BlockTypeOperand(Decoder* decoder, const byte* pc) {
uint8_t val = decoder->checked_read_u8(pc + 1, "block type"); uint8_t val = decoder->read_u8<checked>(pc + 1, "block type");
ValueType type = kWasmStmt; ValueType type = kWasmStmt;
length = 1;
arity = 0;
types = nullptr;
if (decode_local_type(val, &type)) { if (decode_local_type(val, &type)) {
arity = type == kWasmStmt ? 0 : 1; arity = type == kWasmStmt ? 0 : 1;
types = pc + 1; types = pc + 1;
} else { } else {
// Handle multi-value blocks. // Handle multi-value blocks.
if (!FLAG_wasm_mv_prototype) { if (!CHECKED_COND(FLAG_wasm_mv_prototype)) {
decoder->error(pc + 1, "invalid block arity > 1"); decoder->error(pc + 1, "invalid block arity > 1");
return; return;
} }
if (val != kMultivalBlock) { if (!CHECKED_COND(val == kMultivalBlock)) {
decoder->error(pc + 1, "invalid block type"); decoder->error(pc + 1, "invalid block type");
return; return;
} }
// Decode and check the types vector of the block. // Decode and check the types vector of the block.
unsigned len = 0; unsigned len = 0;
uint32_t count = decoder->checked_read_u32v(pc + 2, &len, "block arity"); uint32_t count = decoder->read_u32v<checked>(pc + 2, &len, "block arity");
// {count} is encoded as {arity-2}, so that a {0} count here corresponds // {count} is encoded as {arity-2}, so that a {0} count here corresponds
// to a block with 2 values. This makes invalid/redundant encodings // to a block with 2 values. This makes invalid/redundant encodings
// impossible. // impossible.
...@@ -113,18 +120,19 @@ struct BlockTypeOperand { ...@@ -113,18 +120,19 @@ struct BlockTypeOperand {
for (uint32_t i = 0; i < arity; i++) { for (uint32_t i = 0; i < arity; i++) {
uint32_t offset = 1 + 1 + len + i; uint32_t offset = 1 + 1 + len + i;
val = decoder->checked_read_u8(pc + offset, "block type"); val = decoder->read_u8<checked>(pc + offset, "block type");
decode_local_type(val, &type); decode_local_type(val, &type);
if (type == kWasmStmt) { if (!CHECKED_COND(type != kWasmStmt)) {
decoder->error(pc + offset, "invalid block type"); decoder->error(pc + offset, "invalid block type");
return; return;
} }
} }
} }
} }
// Decode a byte representing a local type. Return {false} if the encoded // Decode a byte representing a local type. Return {false} if the encoded
// byte was invalid or {kMultivalBlock}. // byte was invalid or {kMultivalBlock}.
bool decode_local_type(uint8_t val, ValueType* result) { inline bool decode_local_type(uint8_t val, ValueType* result) {
switch (static_cast<ValueTypeCode>(val)) { switch (static_cast<ValueTypeCode>(val)) {
case kLocalVoid: case kLocalVoid:
*result = kWasmStmt; *result = kWasmStmt;
...@@ -167,74 +175,72 @@ struct BlockTypeOperand { ...@@ -167,74 +175,72 @@ struct BlockTypeOperand {
}; };
struct Control; struct Control;
template <bool checked>
struct BreakDepthOperand { struct BreakDepthOperand {
uint32_t depth; uint32_t depth;
Control* target; Control* target = nullptr;
unsigned length; unsigned length;
inline BreakDepthOperand(Decoder* decoder, const byte* pc) { inline BreakDepthOperand(Decoder* decoder, const byte* pc) {
depth = decoder->checked_read_u32v(pc + 1, &length, "break depth"); depth = decoder->read_u32v<checked>(pc + 1, &length, "break depth");
target = nullptr;
} }
}; };
template <bool checked>
struct CallIndirectOperand { struct CallIndirectOperand {
uint32_t table_index; uint32_t table_index;
uint32_t index; uint32_t index;
FunctionSig* sig; FunctionSig* sig = nullptr;
unsigned length; unsigned length;
inline CallIndirectOperand(Decoder* decoder, const byte* pc) { inline CallIndirectOperand(Decoder* decoder, const byte* pc) {
unsigned len = 0; unsigned len = 0;
index = decoder->checked_read_u32v(pc + 1, &len, "signature index"); index = decoder->read_u32v<checked>(pc + 1, &len, "signature index");
table_index = decoder->checked_read_u8(pc + 1 + len, "table index"); table_index = decoder->read_u8<checked>(pc + 1 + len, "table index");
if (table_index != 0) { if (!CHECKED_COND(table_index == 0)) {
decoder->errorf(pc + 1 + len, "expected table index 0, found %u", decoder->errorf(pc + 1 + len, "expected table index 0, found %u",
table_index); table_index);
} }
length = 1 + len; length = 1 + len;
sig = nullptr;
} }
}; };
template <bool checked>
struct CallFunctionOperand { struct CallFunctionOperand {
uint32_t index; uint32_t index;
FunctionSig* sig; FunctionSig* sig = nullptr;
unsigned length; unsigned length;
inline CallFunctionOperand(Decoder* decoder, const byte* pc) { inline CallFunctionOperand(Decoder* decoder, const byte* pc) {
index = decoder->checked_read_u32v(pc + 1, &length, "function index"); index = decoder->read_u32v<checked>(pc + 1, &length, "function index");
sig = nullptr;
} }
}; };
template <bool checked>
struct MemoryIndexOperand { struct MemoryIndexOperand {
uint32_t index; uint32_t index;
unsigned length; unsigned length = 1;
inline MemoryIndexOperand(Decoder* decoder, const byte* pc) { inline MemoryIndexOperand(Decoder* decoder, const byte* pc) {
index = decoder->checked_read_u8(pc + 1, "memory index"); index = decoder->read_u8<checked>(pc + 1, "memory index");
if (index != 0) { if (!CHECKED_COND(index == 0)) {
decoder->errorf(pc + 1, "expected memory index 0, found %u", index); decoder->errorf(pc + 1, "expected memory index 0, found %u", index);
} }
length = 1;
} }
}; };
template <bool checked>
struct BranchTableOperand { struct BranchTableOperand {
uint32_t table_count; uint32_t table_count;
const byte* start; const byte* start;
const byte* table; const byte* table;
inline BranchTableOperand(Decoder* decoder, const byte* pc) { inline BranchTableOperand(Decoder* decoder, const byte* pc) {
DCHECK_EQ(kExprBrTable, decoder->checked_read_u8(pc, "opcode")); DCHECK_EQ(kExprBrTable, decoder->read_u8<checked>(pc, "opcode"));
start = pc + 1; start = pc + 1;
unsigned len1 = 0; unsigned len = 0;
table_count = decoder->checked_read_u32v(pc + 1, &len1, "table count"); table_count = decoder->read_u32v<checked>(pc + 1, &len, "table count");
if (table_count > (UINT_MAX / sizeof(uint32_t)) - 1 || table = pc + 1 + len;
len1 > UINT_MAX - (table_count + 1) * sizeof(uint32_t)) {
decoder->error(pc, "branch table size overflow");
}
table = pc + 1 + len1;
} }
}; };
// A helper to iterate over a branch table. // A helper to iterate over a branch table.
template <bool checked>
class BranchTableIterator { class BranchTableIterator {
public: public:
unsigned cur_index() { return index_; } unsigned cur_index() { return index_; }
...@@ -242,9 +248,9 @@ class BranchTableIterator { ...@@ -242,9 +248,9 @@ class BranchTableIterator {
uint32_t next() { uint32_t next() {
DCHECK(has_next()); DCHECK(has_next());
index_++; index_++;
unsigned length = 0; unsigned length;
uint32_t result = uint32_t result =
decoder_->checked_read_u32v(pc_, &length, "branch table entry"); decoder_->read_u32v<checked>(pc_, &length, "branch table entry");
pc_ += length; pc_ += length;
return result; return result;
} }
...@@ -256,7 +262,7 @@ class BranchTableIterator { ...@@ -256,7 +262,7 @@ class BranchTableIterator {
} }
const byte* pc() { return pc_; } const byte* pc() { return pc_; }
BranchTableIterator(Decoder* decoder, BranchTableOperand& operand) BranchTableIterator(Decoder* decoder, BranchTableOperand<checked>& operand)
: decoder_(decoder), : decoder_(decoder),
start_(operand.start), start_(operand.start),
pc_(operand.table), pc_(operand.table),
...@@ -271,6 +277,7 @@ class BranchTableIterator { ...@@ -271,6 +277,7 @@ class BranchTableIterator {
uint32_t table_count_; // the count of entries, not including default. uint32_t table_count_; // the count of entries, not including default.
}; };
template <bool checked>
struct MemoryAccessOperand { struct MemoryAccessOperand {
uint32_t alignment; uint32_t alignment;
uint32_t offset; uint32_t offset;
...@@ -279,42 +286,44 @@ struct MemoryAccessOperand { ...@@ -279,42 +286,44 @@ struct MemoryAccessOperand {
uint32_t max_alignment) { uint32_t max_alignment) {
unsigned alignment_length; unsigned alignment_length;
alignment = alignment =
decoder->checked_read_u32v(pc + 1, &alignment_length, "alignment"); decoder->read_u32v<checked>(pc + 1, &alignment_length, "alignment");
if (max_alignment < alignment) { if (!CHECKED_COND(alignment <= max_alignment)) {
decoder->errorf(pc + 1, decoder->errorf(pc + 1,
"invalid alignment; expected maximum alignment is %u, " "invalid alignment; expected maximum alignment is %u, "
"actual alignment is %u", "actual alignment is %u",
max_alignment, alignment); max_alignment, alignment);
} }
unsigned offset_length; unsigned offset_length;
offset = decoder->checked_read_u32v(pc + 1 + alignment_length, offset = decoder->read_u32v<checked>(pc + 1 + alignment_length,
&offset_length, "offset"); &offset_length, "offset");
length = alignment_length + offset_length; length = alignment_length + offset_length;
} }
}; };
// Operand for SIMD lane operations. // Operand for SIMD lane operations.
template <bool checked>
struct SimdLaneOperand { struct SimdLaneOperand {
uint8_t lane; uint8_t lane;
unsigned length; unsigned length = 1;
inline SimdLaneOperand(Decoder* decoder, const byte* pc) { inline SimdLaneOperand(Decoder* decoder, const byte* pc) {
lane = decoder->checked_read_u8(pc + 2, "lane"); lane = decoder->read_u8<checked>(pc + 2, "lane");
length = 1;
} }
}; };
// Operand for SIMD shift operations. // Operand for SIMD shift operations.
template <bool checked>
struct SimdShiftOperand { struct SimdShiftOperand {
uint8_t shift; uint8_t shift;
unsigned length; unsigned length = 1;
inline SimdShiftOperand(Decoder* decoder, const byte* pc) { inline SimdShiftOperand(Decoder* decoder, const byte* pc) {
shift = decoder->checked_read_u8(pc + 2, "shift"); shift = decoder->read_u8<checked>(pc + 2, "shift");
length = 1;
} }
}; };
#undef CHECKED_COND
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -252,7 +252,7 @@ class WasmDecoder : public Decoder { ...@@ -252,7 +252,7 @@ class WasmDecoder : public Decoder {
break; break;
case kExprSetLocal: // fallthru case kExprSetLocal: // fallthru
case kExprTeeLocal: { case kExprTeeLocal: {
LocalIndexOperand operand(decoder, pc); LocalIndexOperand<true> operand(decoder, pc);
if (assigned->length() > 0 && if (assigned->length() > 0 &&
operand.index < static_cast<uint32_t>(assigned->length())) { operand.index < static_cast<uint32_t>(assigned->length())) {
// Unverified code might have an out-of-bounds index. // Unverified code might have an out-of-bounds index.
...@@ -274,7 +274,7 @@ class WasmDecoder : public Decoder { ...@@ -274,7 +274,7 @@ class WasmDecoder : public Decoder {
return decoder->ok() ? assigned : nullptr; return decoder->ok() ? assigned : nullptr;
} }
inline bool Validate(const byte* pc, LocalIndexOperand& operand) { inline bool Validate(const byte* pc, LocalIndexOperand<true>& operand) {
if (operand.index < total_locals()) { if (operand.index < total_locals()) {
if (local_types_) { if (local_types_) {
operand.type = local_types_->at(operand.index); operand.type = local_types_->at(operand.index);
...@@ -287,7 +287,7 @@ class WasmDecoder : public Decoder { ...@@ -287,7 +287,7 @@ class WasmDecoder : public Decoder {
return false; return false;
} }
inline bool Validate(const byte* pc, GlobalIndexOperand& operand) { inline bool Validate(const byte* pc, GlobalIndexOperand<true>& operand) {
if (module_ != nullptr && operand.index < module_->globals.size()) { if (module_ != nullptr && operand.index < module_->globals.size()) {
operand.global = &module_->globals[operand.index]; operand.global = &module_->globals[operand.index];
operand.type = operand.global->type; operand.type = operand.global->type;
...@@ -297,7 +297,7 @@ class WasmDecoder : public Decoder { ...@@ -297,7 +297,7 @@ class WasmDecoder : public Decoder {
return false; return false;
} }
inline bool Complete(const byte* pc, CallFunctionOperand& operand) { inline bool Complete(const byte* pc, CallFunctionOperand<true>& operand) {
if (module_ != nullptr && operand.index < module_->functions.size()) { if (module_ != nullptr && operand.index < module_->functions.size()) {
operand.sig = module_->functions[operand.index].sig; operand.sig = module_->functions[operand.index].sig;
return true; return true;
...@@ -305,7 +305,7 @@ class WasmDecoder : public Decoder { ...@@ -305,7 +305,7 @@ class WasmDecoder : public Decoder {
return false; return false;
} }
inline bool Validate(const byte* pc, CallFunctionOperand& operand) { inline bool Validate(const byte* pc, CallFunctionOperand<true>& operand) {
if (Complete(pc, operand)) { if (Complete(pc, operand)) {
return true; return true;
} }
...@@ -313,7 +313,7 @@ class WasmDecoder : public Decoder { ...@@ -313,7 +313,7 @@ class WasmDecoder : public Decoder {
return false; return false;
} }
inline bool Complete(const byte* pc, CallIndirectOperand& operand) { inline bool Complete(const byte* pc, CallIndirectOperand<true>& operand) {
if (module_ != nullptr && operand.index < module_->signatures.size()) { if (module_ != nullptr && operand.index < module_->signatures.size()) {
operand.sig = module_->signatures[operand.index]; operand.sig = module_->signatures[operand.index];
return true; return true;
...@@ -321,7 +321,7 @@ class WasmDecoder : public Decoder { ...@@ -321,7 +321,7 @@ class WasmDecoder : public Decoder {
return false; return false;
} }
inline bool Validate(const byte* pc, CallIndirectOperand& operand) { inline bool Validate(const byte* pc, CallIndirectOperand<true>& operand) {
if (module_ == nullptr || module_->function_tables.empty()) { if (module_ == nullptr || module_->function_tables.empty()) {
error("function table has to exist to execute call_indirect"); error("function table has to exist to execute call_indirect");
return false; return false;
...@@ -333,7 +333,7 @@ class WasmDecoder : public Decoder { ...@@ -333,7 +333,7 @@ class WasmDecoder : public Decoder {
return false; return false;
} }
inline bool Validate(const byte* pc, BreakDepthOperand& operand, inline bool Validate(const byte* pc, BreakDepthOperand<true>& operand,
ZoneVector<Control>& control) { ZoneVector<Control>& control) {
if (operand.depth < control.size()) { if (operand.depth < control.size()) {
operand.target = &control[control.size() - operand.depth - 1]; operand.target = &control[control.size() - operand.depth - 1];
...@@ -343,14 +343,14 @@ class WasmDecoder : public Decoder { ...@@ -343,14 +343,14 @@ class WasmDecoder : public Decoder {
return false; return false;
} }
bool Validate(const byte* pc, BranchTableOperand& operand, bool Validate(const byte* pc, BranchTableOperand<true>& operand,
size_t block_depth) { size_t block_depth) {
// TODO(titzer): add extra redundant validation for br_table here? // TODO(titzer): add extra redundant validation for br_table here?
return true; return true;
} }
inline bool Validate(const byte* pc, WasmOpcode opcode, inline bool Validate(const byte* pc, WasmOpcode opcode,
SimdLaneOperand& operand) { SimdLaneOperand<true>& operand) {
uint8_t num_lanes = 0; uint8_t num_lanes = 0;
switch (opcode) { switch (opcode) {
case kExprF32x4ExtractLane: case kExprF32x4ExtractLane:
...@@ -380,7 +380,7 @@ class WasmDecoder : public Decoder { ...@@ -380,7 +380,7 @@ class WasmDecoder : public Decoder {
} }
inline bool Validate(const byte* pc, WasmOpcode opcode, inline bool Validate(const byte* pc, WasmOpcode opcode,
SimdShiftOperand& operand) { SimdShiftOperand<true>& operand) {
uint8_t max_shift = 0; uint8_t max_shift = 0;
switch (opcode) { switch (opcode) {
case kExprI32x4Shl: case kExprI32x4Shl:
...@@ -417,26 +417,26 @@ class WasmDecoder : public Decoder { ...@@ -417,26 +417,26 @@ class WasmDecoder : public Decoder {
FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE #undef DECLARE_OPCODE_CASE
{ {
MemoryAccessOperand operand(decoder, pc, UINT32_MAX); MemoryAccessOperand<true> operand(decoder, pc, UINT32_MAX);
return 1 + operand.length; return 1 + operand.length;
} }
case kExprBr: case kExprBr:
case kExprBrIf: { case kExprBrIf: {
BreakDepthOperand operand(decoder, pc); BreakDepthOperand<true> operand(decoder, pc);
return 1 + operand.length; return 1 + operand.length;
} }
case kExprSetGlobal: case kExprSetGlobal:
case kExprGetGlobal: { case kExprGetGlobal: {
GlobalIndexOperand operand(decoder, pc); GlobalIndexOperand<true> operand(decoder, pc);
return 1 + operand.length; return 1 + operand.length;
} }
case kExprCallFunction: { case kExprCallFunction: {
CallFunctionOperand operand(decoder, pc); CallFunctionOperand<true> operand(decoder, pc);
return 1 + operand.length; return 1 + operand.length;
} }
case kExprCallIndirect: { case kExprCallIndirect: {
CallIndirectOperand operand(decoder, pc); CallIndirectOperand<true> operand(decoder, pc);
return 1 + operand.length; return 1 + operand.length;
} }
...@@ -444,7 +444,7 @@ class WasmDecoder : public Decoder { ...@@ -444,7 +444,7 @@ class WasmDecoder : public Decoder {
case kExprIf: // fall thru case kExprIf: // fall thru
case kExprLoop: case kExprLoop:
case kExprBlock: { case kExprBlock: {
BlockTypeOperand operand(decoder, pc); BlockTypeOperand<true> operand(decoder, pc);
return 1 + operand.length; return 1 + operand.length;
} }
...@@ -452,25 +452,25 @@ class WasmDecoder : public Decoder { ...@@ -452,25 +452,25 @@ class WasmDecoder : public Decoder {
case kExprTeeLocal: case kExprTeeLocal:
case kExprGetLocal: case kExprGetLocal:
case kExprCatch: { case kExprCatch: {
LocalIndexOperand operand(decoder, pc); LocalIndexOperand<true> operand(decoder, pc);
return 1 + operand.length; return 1 + operand.length;
} }
case kExprBrTable: { case kExprBrTable: {
BranchTableOperand operand(decoder, pc); BranchTableOperand<true> operand(decoder, pc);
BranchTableIterator iterator(decoder, operand); BranchTableIterator<true> iterator(decoder, operand);
return 1 + iterator.length(); return 1 + iterator.length();
} }
case kExprI32Const: { case kExprI32Const: {
ImmI32Operand operand(decoder, pc); ImmI32Operand<true> operand(decoder, pc);
return 1 + operand.length; return 1 + operand.length;
} }
case kExprI64Const: { case kExprI64Const: {
ImmI64Operand operand(decoder, pc); ImmI64Operand<true> operand(decoder, pc);
return 1 + operand.length; return 1 + operand.length;
} }
case kExprGrowMemory: case kExprGrowMemory:
case kExprMemorySize: { case kExprMemorySize: {
MemoryIndexOperand operand(decoder, pc); MemoryIndexOperand<true> operand(decoder, pc);
return 1 + operand.length; return 1 + operand.length;
} }
case kExprF32Const: case kExprF32Const:
...@@ -478,7 +478,7 @@ class WasmDecoder : public Decoder { ...@@ -478,7 +478,7 @@ class WasmDecoder : public Decoder {
case kExprF64Const: case kExprF64Const:
return 9; return 9;
case kSimdPrefix: { case kSimdPrefix: {
byte simd_index = decoder->checked_read_u8(pc + 1, "simd_index"); byte simd_index = decoder->read_u8<true>(pc + 1, "simd_index");
WasmOpcode opcode = WasmOpcode opcode =
static_cast<WasmOpcode>(kSimdPrefix << 8 | simd_index); static_cast<WasmOpcode>(kSimdPrefix << 8 | simd_index);
switch (opcode) { switch (opcode) {
...@@ -733,7 +733,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -733,7 +733,7 @@ class WasmFullDecoder : public WasmDecoder {
break; break;
case kExprBlock: { case kExprBlock: {
// The break environment is the outer environment. // The break environment is the outer environment.
BlockTypeOperand operand(this, pc_); BlockTypeOperand<true> operand(this, pc_);
SsaEnv* break_env = ssa_env_; SsaEnv* break_env = ssa_env_;
PushBlock(break_env); PushBlock(break_env);
SetEnv("block:start", Steal(break_env)); SetEnv("block:start", Steal(break_env));
...@@ -753,7 +753,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -753,7 +753,7 @@ class WasmFullDecoder : public WasmDecoder {
} }
case kExprTry: { case kExprTry: {
CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype);
BlockTypeOperand operand(this, pc_); BlockTypeOperand<true> operand(this, pc_);
SsaEnv* outer_env = ssa_env_; SsaEnv* outer_env = ssa_env_;
SsaEnv* try_env = Steal(outer_env); SsaEnv* try_env = Steal(outer_env);
SsaEnv* catch_env = UnreachableEnv(); SsaEnv* catch_env = UnreachableEnv();
...@@ -765,7 +765,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -765,7 +765,7 @@ class WasmFullDecoder : public WasmDecoder {
} }
case kExprCatch: { case kExprCatch: {
CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype);
LocalIndexOperand operand(this, pc_); LocalIndexOperand<true> operand(this, pc_);
len = 1 + operand.length; len = 1 + operand.length;
if (control_.empty()) { if (control_.empty()) {
...@@ -804,7 +804,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -804,7 +804,7 @@ class WasmFullDecoder : public WasmDecoder {
break; break;
} }
case kExprLoop: { case kExprLoop: {
BlockTypeOperand operand(this, pc_); BlockTypeOperand<true> operand(this, pc_);
SsaEnv* finish_try_env = Steal(ssa_env_); SsaEnv* finish_try_env = Steal(ssa_env_);
// The continue environment is the inner environment. // The continue environment is the inner environment.
SsaEnv* loop_body_env = PrepareForLoop(pc_, finish_try_env); SsaEnv* loop_body_env = PrepareForLoop(pc_, finish_try_env);
...@@ -817,7 +817,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -817,7 +817,7 @@ class WasmFullDecoder : public WasmDecoder {
} }
case kExprIf: { case kExprIf: {
// Condition on top of stack. Split environments for branches. // Condition on top of stack. Split environments for branches.
BlockTypeOperand operand(this, pc_); BlockTypeOperand<true> operand(this, pc_);
Value cond = Pop(0, kWasmI32); Value cond = Pop(0, kWasmI32);
TFNode* if_true = nullptr; TFNode* if_true = nullptr;
TFNode* if_false = nullptr; TFNode* if_false = nullptr;
...@@ -935,7 +935,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -935,7 +935,7 @@ class WasmFullDecoder : public WasmDecoder {
break; break;
} }
case kExprBr: { case kExprBr: {
BreakDepthOperand operand(this, pc_); BreakDepthOperand<true> operand(this, pc_);
if (Validate(pc_, operand, control_)) { if (Validate(pc_, operand, control_)) {
BreakTo(operand.depth); BreakTo(operand.depth);
} }
...@@ -944,7 +944,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -944,7 +944,7 @@ class WasmFullDecoder : public WasmDecoder {
break; break;
} }
case kExprBrIf: { case kExprBrIf: {
BreakDepthOperand operand(this, pc_); BreakDepthOperand<true> operand(this, pc_);
Value cond = Pop(0, kWasmI32); Value cond = Pop(0, kWasmI32);
if (ok() && Validate(pc_, operand, control_)) { if (ok() && Validate(pc_, operand, control_)) {
SsaEnv* fenv = ssa_env_; SsaEnv* fenv = ssa_env_;
...@@ -959,8 +959,8 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -959,8 +959,8 @@ class WasmFullDecoder : public WasmDecoder {
break; break;
} }
case kExprBrTable: { case kExprBrTable: {
BranchTableOperand operand(this, pc_); BranchTableOperand<true> operand(this, pc_);
BranchTableIterator iterator(this, operand); BranchTableIterator<true> iterator(this, operand);
if (Validate(pc_, operand, control_.size())) { if (Validate(pc_, operand, control_.size())) {
Value key = Pop(0, kWasmI32); Value key = Pop(0, kWasmI32);
if (failed()) break; if (failed()) break;
...@@ -1036,31 +1036,31 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1036,31 +1036,31 @@ class WasmFullDecoder : public WasmDecoder {
break; break;
} }
case kExprI32Const: { case kExprI32Const: {
ImmI32Operand operand(this, pc_); ImmI32Operand<true> operand(this, pc_);
Push(kWasmI32, BUILD(Int32Constant, operand.value)); Push(kWasmI32, BUILD(Int32Constant, operand.value));
len = 1 + operand.length; len = 1 + operand.length;
break; break;
} }
case kExprI64Const: { case kExprI64Const: {
ImmI64Operand operand(this, pc_); ImmI64Operand<true> operand(this, pc_);
Push(kWasmI64, BUILD(Int64Constant, operand.value)); Push(kWasmI64, BUILD(Int64Constant, operand.value));
len = 1 + operand.length; len = 1 + operand.length;
break; break;
} }
case kExprF32Const: { case kExprF32Const: {
ImmF32Operand operand(this, pc_); ImmF32Operand<true> operand(this, pc_);
Push(kWasmF32, BUILD(Float32Constant, operand.value)); Push(kWasmF32, BUILD(Float32Constant, operand.value));
len = 1 + operand.length; len = 1 + operand.length;
break; break;
} }
case kExprF64Const: { case kExprF64Const: {
ImmF64Operand operand(this, pc_); ImmF64Operand<true> operand(this, pc_);
Push(kWasmF64, BUILD(Float64Constant, operand.value)); Push(kWasmF64, BUILD(Float64Constant, operand.value));
len = 1 + operand.length; len = 1 + operand.length;
break; break;
} }
case kExprGetLocal: { case kExprGetLocal: {
LocalIndexOperand operand(this, pc_); LocalIndexOperand<true> operand(this, pc_);
if (Validate(pc_, operand)) { if (Validate(pc_, operand)) {
if (build()) { if (build()) {
Push(operand.type, ssa_env_->locals[operand.index]); Push(operand.type, ssa_env_->locals[operand.index]);
...@@ -1072,7 +1072,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1072,7 +1072,7 @@ class WasmFullDecoder : public WasmDecoder {
break; break;
} }
case kExprSetLocal: { case kExprSetLocal: {
LocalIndexOperand operand(this, pc_); LocalIndexOperand<true> operand(this, pc_);
if (Validate(pc_, operand)) { if (Validate(pc_, operand)) {
Value val = Pop(0, local_type_vec_[operand.index]); Value val = Pop(0, local_type_vec_[operand.index]);
if (ssa_env_->locals) ssa_env_->locals[operand.index] = val.node; if (ssa_env_->locals) ssa_env_->locals[operand.index] = val.node;
...@@ -1081,7 +1081,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1081,7 +1081,7 @@ class WasmFullDecoder : public WasmDecoder {
break; break;
} }
case kExprTeeLocal: { case kExprTeeLocal: {
LocalIndexOperand operand(this, pc_); LocalIndexOperand<true> operand(this, pc_);
if (Validate(pc_, operand)) { if (Validate(pc_, operand)) {
Value val = Pop(0, local_type_vec_[operand.index]); Value val = Pop(0, local_type_vec_[operand.index]);
if (ssa_env_->locals) ssa_env_->locals[operand.index] = val.node; if (ssa_env_->locals) ssa_env_->locals[operand.index] = val.node;
...@@ -1095,7 +1095,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1095,7 +1095,7 @@ class WasmFullDecoder : public WasmDecoder {
break; break;
} }
case kExprGetGlobal: { case kExprGetGlobal: {
GlobalIndexOperand operand(this, pc_); GlobalIndexOperand<true> operand(this, pc_);
if (Validate(pc_, operand)) { if (Validate(pc_, operand)) {
Push(operand.type, BUILD(GetGlobal, operand.index)); Push(operand.type, BUILD(GetGlobal, operand.index));
} }
...@@ -1103,7 +1103,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1103,7 +1103,7 @@ class WasmFullDecoder : public WasmDecoder {
break; break;
} }
case kExprSetGlobal: { case kExprSetGlobal: {
GlobalIndexOperand operand(this, pc_); GlobalIndexOperand<true> operand(this, pc_);
if (Validate(pc_, operand)) { if (Validate(pc_, operand)) {
if (operand.global->mutability) { if (operand.global->mutability) {
Value val = Pop(0, operand.type); Value val = Pop(0, operand.type);
...@@ -1195,7 +1195,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1195,7 +1195,7 @@ class WasmFullDecoder : public WasmDecoder {
break; break;
case kExprGrowMemory: { case kExprGrowMemory: {
if (!CheckHasMemory()) break; if (!CheckHasMemory()) break;
MemoryIndexOperand operand(this, pc_); MemoryIndexOperand<true> operand(this, pc_);
DCHECK_NOT_NULL(module_); DCHECK_NOT_NULL(module_);
if (module_->is_wasm()) { if (module_->is_wasm()) {
Value val = Pop(0, kWasmI32); Value val = Pop(0, kWasmI32);
...@@ -1208,13 +1208,13 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1208,13 +1208,13 @@ class WasmFullDecoder : public WasmDecoder {
} }
case kExprMemorySize: { case kExprMemorySize: {
if (!CheckHasMemory()) break; if (!CheckHasMemory()) break;
MemoryIndexOperand operand(this, pc_); MemoryIndexOperand<true> operand(this, pc_);
Push(kWasmI32, BUILD(CurrentMemoryPages)); Push(kWasmI32, BUILD(CurrentMemoryPages));
len = 1 + operand.length; len = 1 + operand.length;
break; break;
} }
case kExprCallFunction: { case kExprCallFunction: {
CallFunctionOperand operand(this, pc_); CallFunctionOperand<true> operand(this, pc_);
if (Validate(pc_, operand)) { if (Validate(pc_, operand)) {
TFNode** buffer = PopArgs(operand.sig); TFNode** buffer = PopArgs(operand.sig);
TFNode** rets = nullptr; TFNode** rets = nullptr;
...@@ -1225,7 +1225,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1225,7 +1225,7 @@ class WasmFullDecoder : public WasmDecoder {
break; break;
} }
case kExprCallIndirect: { case kExprCallIndirect: {
CallIndirectOperand operand(this, pc_); CallIndirectOperand<true> operand(this, pc_);
if (Validate(pc_, operand)) { if (Validate(pc_, operand)) {
Value index = Pop(0, kWasmI32); Value index = Pop(0, kWasmI32);
TFNode** buffer = PopArgs(operand.sig); TFNode** buffer = PopArgs(operand.sig);
...@@ -1240,7 +1240,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1240,7 +1240,7 @@ class WasmFullDecoder : public WasmDecoder {
case kSimdPrefix: { case kSimdPrefix: {
CHECK_PROTOTYPE_OPCODE(wasm_simd_prototype); CHECK_PROTOTYPE_OPCODE(wasm_simd_prototype);
len++; len++;
byte simd_index = checked_read_u8(pc_ + 1, "simd index"); byte simd_index = read_u8<true>(pc_ + 1, "simd index");
opcode = static_cast<WasmOpcode>(opcode << 8 | simd_index); opcode = static_cast<WasmOpcode>(opcode << 8 | simd_index);
TRACE(" @%-4d #%-20s|", startrel(pc_), TRACE(" @%-4d #%-20s|", startrel(pc_),
WasmOpcodes::OpcodeName(opcode)); WasmOpcodes::OpcodeName(opcode));
...@@ -1257,7 +1257,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1257,7 +1257,7 @@ class WasmFullDecoder : public WasmDecoder {
break; break;
} }
len = 2; len = 2;
byte atomic_opcode = checked_read_u8(pc_ + 1, "atomic index"); byte atomic_opcode = read_u8<true>(pc_ + 1, "atomic index");
opcode = static_cast<WasmOpcode>(opcode << 8 | atomic_opcode); opcode = static_cast<WasmOpcode>(opcode << 8 | atomic_opcode);
sig = WasmOpcodes::AtomicSignature(opcode); sig = WasmOpcodes::AtomicSignature(opcode);
if (sig) { if (sig) {
...@@ -1322,18 +1322,18 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1322,18 +1322,18 @@ class WasmFullDecoder : public WasmDecoder {
WasmOpcodes::OpcodeName(opcode)); WasmOpcodes::OpcodeName(opcode));
switch (opcode) { switch (opcode) {
case kExprI32Const: { case kExprI32Const: {
ImmI32Operand operand(this, val.pc); ImmI32Operand<true> operand(this, val.pc);
PrintF("[%d]", operand.value); PrintF("[%d]", operand.value);
break; break;
} }
case kExprGetLocal: { case kExprGetLocal: {
LocalIndexOperand operand(this, val.pc); LocalIndexOperand<true> operand(this, val.pc);
PrintF("[%u]", operand.index); PrintF("[%u]", operand.index);
break; break;
} }
case kExprSetLocal: // fallthru case kExprSetLocal: // fallthru
case kExprTeeLocal: { case kExprTeeLocal: {
LocalIndexOperand operand(this, val.pc); LocalIndexOperand<true> operand(this, val.pc);
PrintF("[%u]", operand.index); PrintF("[%u]", operand.index);
break; break;
} }
...@@ -1358,7 +1358,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1358,7 +1358,7 @@ class WasmFullDecoder : public WasmDecoder {
} }
} }
void SetBlockType(Control* c, BlockTypeOperand& operand) { void SetBlockType(Control* c, BlockTypeOperand<true>& operand) {
c->merge.arity = operand.arity; c->merge.arity = operand.arity;
if (c->merge.arity == 1) { if (c->merge.arity == 1) {
c->merge.vals.first = {pc_, nullptr, operand.read_entry(0)}; c->merge.vals.first = {pc_, nullptr, operand.read_entry(0)};
...@@ -1417,8 +1417,8 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1417,8 +1417,8 @@ class WasmFullDecoder : public WasmDecoder {
int DecodeLoadMem(ValueType type, MachineType mem_type) { int DecodeLoadMem(ValueType type, MachineType mem_type) {
if (!CheckHasMemory()) return 0; if (!CheckHasMemory()) return 0;
MemoryAccessOperand operand(this, pc_, MemoryAccessOperand<true> operand(
ElementSizeLog2Of(mem_type.representation())); this, pc_, ElementSizeLog2Of(mem_type.representation()));
Value index = Pop(0, kWasmI32); Value index = Pop(0, kWasmI32);
TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset, TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset,
...@@ -1429,8 +1429,8 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1429,8 +1429,8 @@ class WasmFullDecoder : public WasmDecoder {
int DecodeStoreMem(ValueType type, MachineType mem_type) { int DecodeStoreMem(ValueType type, MachineType mem_type) {
if (!CheckHasMemory()) return 0; if (!CheckHasMemory()) return 0;
MemoryAccessOperand operand(this, pc_, MemoryAccessOperand<true> operand(
ElementSizeLog2Of(mem_type.representation())); this, pc_, ElementSizeLog2Of(mem_type.representation()));
Value val = Pop(1, type); Value val = Pop(1, type);
Value index = Pop(0, kWasmI32); Value index = Pop(0, kWasmI32);
BUILD(StoreMem, mem_type, index.node, operand.offset, operand.alignment, BUILD(StoreMem, mem_type, index.node, operand.offset, operand.alignment,
...@@ -1439,7 +1439,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1439,7 +1439,7 @@ class WasmFullDecoder : public WasmDecoder {
} }
unsigned SimdExtractLane(WasmOpcode opcode, ValueType type) { unsigned SimdExtractLane(WasmOpcode opcode, ValueType type) {
SimdLaneOperand operand(this, pc_); SimdLaneOperand<true> operand(this, pc_);
if (Validate(pc_, opcode, operand)) { if (Validate(pc_, opcode, operand)) {
compiler::NodeVector inputs(1, zone_); compiler::NodeVector inputs(1, zone_);
inputs[0] = Pop(0, ValueType::kSimd128).node; inputs[0] = Pop(0, ValueType::kSimd128).node;
...@@ -1450,7 +1450,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1450,7 +1450,7 @@ class WasmFullDecoder : public WasmDecoder {
} }
unsigned SimdReplaceLane(WasmOpcode opcode, ValueType type) { unsigned SimdReplaceLane(WasmOpcode opcode, ValueType type) {
SimdLaneOperand operand(this, pc_); SimdLaneOperand<true> operand(this, pc_);
if (Validate(pc_, opcode, operand)) { if (Validate(pc_, opcode, operand)) {
compiler::NodeVector inputs(2, zone_); compiler::NodeVector inputs(2, zone_);
inputs[1] = Pop(1, type).node; inputs[1] = Pop(1, type).node;
...@@ -1462,7 +1462,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1462,7 +1462,7 @@ class WasmFullDecoder : public WasmDecoder {
} }
unsigned SimdShiftOp(WasmOpcode opcode) { unsigned SimdShiftOp(WasmOpcode opcode) {
SimdShiftOperand operand(this, pc_); SimdShiftOperand<true> operand(this, pc_);
if (Validate(pc_, opcode, operand)) { if (Validate(pc_, opcode, operand)) {
compiler::NodeVector inputs(1, zone_); compiler::NodeVector inputs(1, zone_);
inputs[0] = Pop(0, ValueType::kSimd128).node; inputs[0] = Pop(0, ValueType::kSimd128).node;
...@@ -2116,7 +2116,7 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, ...@@ -2116,7 +2116,7 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
case kExprIf: case kExprIf:
case kExprBlock: case kExprBlock:
case kExprTry: { case kExprTry: {
BlockTypeOperand operand(&i, i.pc()); BlockTypeOperand<true> operand(&i, i.pc());
os << " // @" << i.pc_offset(); os << " // @" << i.pc_offset();
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));
...@@ -2129,22 +2129,22 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, ...@@ -2129,22 +2129,22 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
control_depth--; control_depth--;
break; break;
case kExprBr: { case kExprBr: {
BreakDepthOperand operand(&i, i.pc()); BreakDepthOperand<true> operand(&i, i.pc());
os << " // depth=" << operand.depth; os << " // depth=" << operand.depth;
break; break;
} }
case kExprBrIf: { case kExprBrIf: {
BreakDepthOperand operand(&i, i.pc()); BreakDepthOperand<true> operand(&i, i.pc());
os << " // depth=" << operand.depth; os << " // depth=" << operand.depth;
break; break;
} }
case kExprBrTable: { case kExprBrTable: {
BranchTableOperand operand(&i, i.pc()); BranchTableOperand<true> operand(&i, i.pc());
os << " // entries=" << operand.table_count; os << " // entries=" << operand.table_count;
break; break;
} }
case kExprCallIndirect: { case kExprCallIndirect: {
CallIndirectOperand operand(&i, i.pc()); CallIndirectOperand<true> operand(&i, i.pc());
os << " // sig #" << operand.index; os << " // sig #" << operand.index;
if (decoder.Complete(i.pc(), operand)) { if (decoder.Complete(i.pc(), operand)) {
os << ": " << *operand.sig; os << ": " << *operand.sig;
...@@ -2152,7 +2152,7 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, ...@@ -2152,7 +2152,7 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
break; break;
} }
case kExprCallFunction: { case kExprCallFunction: {
CallFunctionOperand operand(&i, i.pc()); CallFunctionOperand<true> operand(&i, i.pc());
os << " // function #" << operand.index; os << " // function #" << operand.index;
if (decoder.Complete(i.pc(), operand)) { if (decoder.Complete(i.pc(), operand)) {
os << ": " << *operand.sig; os << ": " << *operand.sig;
......
...@@ -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;
......
...@@ -25,7 +25,7 @@ class DecoderTest : public TestWithZone { ...@@ -25,7 +25,7 @@ class DecoderTest : public TestWithZone {
decoder.Reset(data, data + sizeof(data)); \ decoder.Reset(data, data + sizeof(data)); \
unsigned length; \ unsigned length; \
EXPECT_EQ(static_cast<uint32_t>(expected), \ 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(static_cast<unsigned>(expected_length), length); \
EXPECT_EQ(data, decoder.pc()); \ EXPECT_EQ(data, decoder.pc()); \
EXPECT_TRUE(decoder.ok()); \ EXPECT_TRUE(decoder.ok()); \
...@@ -38,7 +38,7 @@ class DecoderTest : public TestWithZone { ...@@ -38,7 +38,7 @@ class DecoderTest : public TestWithZone {
const byte data[] = {__VA_ARGS__}; \ const byte data[] = {__VA_ARGS__}; \
decoder.Reset(data, data + sizeof(data)); \ decoder.Reset(data, data + sizeof(data)); \
unsigned length; \ 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(static_cast<unsigned>(expected_length), length); \
EXPECT_EQ(data, decoder.pc()); \ EXPECT_EQ(data, decoder.pc()); \
EXPECT_TRUE(decoder.ok()); \ EXPECT_TRUE(decoder.ok()); \
...@@ -52,7 +52,7 @@ class DecoderTest : public TestWithZone { ...@@ -52,7 +52,7 @@ class DecoderTest : public TestWithZone {
decoder.Reset(data, data + sizeof(data)); \ decoder.Reset(data, data + sizeof(data)); \
unsigned length; \ unsigned length; \
EXPECT_EQ(static_cast<uint64_t>(expected), \ 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); \ EXPECT_EQ(static_cast<unsigned>(expected_length), length); \
} while (false) } while (false)
...@@ -61,7 +61,7 @@ class DecoderTest : public TestWithZone { ...@@ -61,7 +61,7 @@ class DecoderTest : public TestWithZone {
const byte data[] = {__VA_ARGS__}; \ const byte data[] = {__VA_ARGS__}; \
decoder.Reset(data, data + sizeof(data)); \ decoder.Reset(data, data + sizeof(data)); \
unsigned length; \ 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); \ EXPECT_EQ(static_cast<unsigned>(expected_length), length); \
} while (false) } while (false)
...@@ -374,7 +374,7 @@ TEST_F(DecoderTest, ReadU32v_off_end1) { ...@@ -374,7 +374,7 @@ TEST_F(DecoderTest, ReadU32v_off_end1) {
static const byte data[] = {U32V_1(11)}; static const byte data[] = {U32V_1(11)};
unsigned length = 0; unsigned length = 0;
decoder.Reset(data, data); decoder.Reset(data, data);
decoder.checked_read_u32v(decoder.start(), &length); decoder.read_u32v<true>(decoder.start(), &length);
EXPECT_EQ(0u, length); EXPECT_EQ(0u, length);
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
} }
...@@ -384,7 +384,7 @@ TEST_F(DecoderTest, ReadU32v_off_end2) { ...@@ -384,7 +384,7 @@ TEST_F(DecoderTest, ReadU32v_off_end2) {
for (size_t i = 0; i < sizeof(data); i++) { for (size_t i = 0; i < sizeof(data); i++) {
unsigned length = 0; unsigned length = 0;
decoder.Reset(data, data + i); decoder.Reset(data, data + i);
decoder.checked_read_u32v(decoder.start(), &length); decoder.read_u32v<true>(decoder.start(), &length);
EXPECT_EQ(i, length); EXPECT_EQ(i, length);
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
} }
...@@ -395,7 +395,7 @@ TEST_F(DecoderTest, ReadU32v_off_end3) { ...@@ -395,7 +395,7 @@ TEST_F(DecoderTest, ReadU32v_off_end3) {
for (size_t i = 0; i < sizeof(data); i++) { for (size_t i = 0; i < sizeof(data); i++) {
unsigned length = 0; unsigned length = 0;
decoder.Reset(data, data + i); decoder.Reset(data, data + i);
decoder.checked_read_u32v(decoder.start(), &length); decoder.read_u32v<true>(decoder.start(), &length);
EXPECT_EQ(i, length); EXPECT_EQ(i, length);
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
} }
...@@ -406,7 +406,7 @@ TEST_F(DecoderTest, ReadU32v_off_end4) { ...@@ -406,7 +406,7 @@ TEST_F(DecoderTest, ReadU32v_off_end4) {
for (size_t i = 0; i < sizeof(data); i++) { for (size_t i = 0; i < sizeof(data); i++) {
unsigned length = 0; unsigned length = 0;
decoder.Reset(data, data + i); decoder.Reset(data, data + i);
decoder.checked_read_u32v(decoder.start(), &length); decoder.read_u32v<true>(decoder.start(), &length);
EXPECT_EQ(i, length); EXPECT_EQ(i, length);
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
} }
...@@ -417,7 +417,7 @@ TEST_F(DecoderTest, ReadU32v_off_end5) { ...@@ -417,7 +417,7 @@ TEST_F(DecoderTest, ReadU32v_off_end5) {
for (size_t i = 0; i < sizeof(data); i++) { for (size_t i = 0; i < sizeof(data); i++) {
unsigned length = 0; unsigned length = 0;
decoder.Reset(data, data + i); decoder.Reset(data, data + i);
decoder.checked_read_u32v(decoder.start(), &length); decoder.read_u32v<true>(decoder.start(), &length);
EXPECT_EQ(i, length); EXPECT_EQ(i, length);
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
} }
...@@ -429,7 +429,7 @@ TEST_F(DecoderTest, ReadU32v_extra_bits) { ...@@ -429,7 +429,7 @@ TEST_F(DecoderTest, ReadU32v_extra_bits) {
data[4] = static_cast<byte>(i << 4); data[4] = static_cast<byte>(i << 4);
unsigned length = 0; unsigned length = 0;
decoder.Reset(data, data + sizeof(data)); 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_EQ(5u, length);
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
} }
...@@ -440,7 +440,7 @@ TEST_F(DecoderTest, ReadI32v_extra_bits_negative) { ...@@ -440,7 +440,7 @@ TEST_F(DecoderTest, ReadI32v_extra_bits_negative) {
unsigned length = 0; unsigned length = 0;
byte data[] = {0xff, 0xff, 0xff, 0xff, 0x7f}; byte data[] = {0xff, 0xff, 0xff, 0xff, 0x7f};
decoder.Reset(data, data + sizeof(data)); 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_EQ(5u, length);
EXPECT_TRUE(decoder.ok()); EXPECT_TRUE(decoder.ok());
} }
...@@ -450,7 +450,7 @@ TEST_F(DecoderTest, ReadI32v_extra_bits_positive) { ...@@ -450,7 +450,7 @@ TEST_F(DecoderTest, ReadI32v_extra_bits_positive) {
unsigned length = 0; unsigned length = 0;
byte data[] = {0x80, 0x80, 0x80, 0x80, 0x77}; byte data[] = {0x80, 0x80, 0x80, 0x80, 0x77};
decoder.Reset(data, data + sizeof(data)); 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_EQ(5u, length);
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
} }
...@@ -485,7 +485,7 @@ TEST_F(DecoderTest, ReadU32v_Bits) { ...@@ -485,7 +485,7 @@ TEST_F(DecoderTest, ReadU32v_Bits) {
for (unsigned limit = 0; limit <= kMaxSize; limit++) { for (unsigned limit = 0; limit <= kMaxSize; limit++) {
decoder.Reset(data, data + limit); decoder.Reset(data, data + limit);
unsigned rlen; unsigned rlen;
uint32_t result = decoder.checked_read_u32v(data, &rlen); uint32_t result = decoder.read_u32v<true>(data, &rlen);
if (limit < length) { if (limit < length) {
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
} else { } else {
...@@ -541,7 +541,7 @@ TEST_F(DecoderTest, ReadU64v_PowerOf2) { ...@@ -541,7 +541,7 @@ TEST_F(DecoderTest, ReadU64v_PowerOf2) {
for (unsigned limit = 0; limit <= kMaxSize; limit++) { for (unsigned limit = 0; limit <= kMaxSize; limit++) {
decoder.Reset(data, data + limit); decoder.Reset(data, data + limit);
unsigned length; unsigned length;
uint64_t result = decoder.checked_read_u64v(data, &length); uint64_t result = decoder.read_u64v<true>(data, &length);
if (limit <= index) { if (limit <= index) {
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
} else { } else {
...@@ -582,7 +582,7 @@ TEST_F(DecoderTest, ReadU64v_Bits) { ...@@ -582,7 +582,7 @@ TEST_F(DecoderTest, ReadU64v_Bits) {
for (unsigned limit = 0; limit <= kMaxSize; limit++) { for (unsigned limit = 0; limit <= kMaxSize; limit++) {
decoder.Reset(data, data + limit); decoder.Reset(data, data + limit);
unsigned rlen; unsigned rlen;
uint64_t result = decoder.checked_read_u64v(data, &rlen); uint64_t result = decoder.read_u64v<true>(data, &rlen);
if (limit < length) { if (limit < length) {
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
} else { } else {
...@@ -624,7 +624,7 @@ TEST_F(DecoderTest, ReadI64v_Bits) { ...@@ -624,7 +624,7 @@ TEST_F(DecoderTest, ReadI64v_Bits) {
for (unsigned limit = 0; limit <= kMaxSize; limit++) { for (unsigned limit = 0; limit <= kMaxSize; limit++) {
decoder.Reset(data, data + limit); decoder.Reset(data, data + limit);
unsigned rlen; unsigned rlen;
int64_t result = decoder.checked_read_i64v(data, &rlen); int64_t result = decoder.read_i64v<true>(data, &rlen);
if (limit < length) { if (limit < length) {
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
} else { } else {
...@@ -643,7 +643,7 @@ TEST_F(DecoderTest, ReadU64v_extra_bits) { ...@@ -643,7 +643,7 @@ TEST_F(DecoderTest, ReadU64v_extra_bits) {
data[9] = static_cast<byte>(i << 1); data[9] = static_cast<byte>(i << 1);
unsigned length = 0; unsigned length = 0;
decoder.Reset(data, data + sizeof(data)); 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_EQ(10u, length);
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
} }
...@@ -654,7 +654,7 @@ TEST_F(DecoderTest, ReadI64v_extra_bits_negative) { ...@@ -654,7 +654,7 @@ TEST_F(DecoderTest, ReadI64v_extra_bits_negative) {
unsigned length = 0; unsigned length = 0;
byte data[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}; byte data[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f};
decoder.Reset(data, data + sizeof(data)); 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_EQ(10u, length);
EXPECT_TRUE(decoder.ok()); EXPECT_TRUE(decoder.ok());
} }
...@@ -664,7 +664,7 @@ TEST_F(DecoderTest, ReadI64v_extra_bits_positive) { ...@@ -664,7 +664,7 @@ TEST_F(DecoderTest, ReadI64v_extra_bits_positive) {
unsigned length = 0; unsigned length = 0;
byte data[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x77}; byte data[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x77};
decoder.Reset(data, data + sizeof(data)); 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_EQ(10u, length);
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
} }
......
...@@ -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