| Index: src/wasm/decoder.h
|
| diff --git a/src/wasm/decoder.h b/src/wasm/decoder.h
|
| index 698919d6a024eea189aa6efbf0a660cd14d716b6..433e80a186a7f616d5cee2376a0af0e269a7b3b6 100644
|
| --- a/src/wasm/decoder.h
|
| +++ b/src/wasm/decoder.h
|
| @@ -24,6 +24,12 @@ namespace wasm {
|
| #define TRACE(...)
|
| #endif
|
|
|
| +#if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM)
|
| +#define UNALIGNED_ACCESS_OK 1
|
| +#else
|
| +#define UNALIGNED_ACCESS_OK 0
|
| +#endif
|
| +
|
| // A helper utility to decode bytes, integers, fields, varints, etc, from
|
| // a buffer of bytes.
|
| class Decoder {
|
| @@ -32,107 +38,126 @@ class Decoder {
|
| : start_(start),
|
| pc_(start),
|
| limit_(end),
|
| + end_(end),
|
| error_pc_(nullptr),
|
| error_pt_(nullptr) {}
|
|
|
| virtual ~Decoder() {}
|
|
|
| + // Reads a single 16-bit unsigned integer (little endian).
|
| + inline uint16_t read_u16(const byte* ptr) {
|
| + DCHECK(ptr >= start_ && (ptr + 2) <= end_);
|
| +#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
|
| + return *reinterpret_cast<const uint16_t*>(ptr);
|
| +#else
|
| + uint16_t b0 = ptr[0];
|
| + uint16_t b1 = ptr[1];
|
| + return (b1 << 8) | b0;
|
| +#endif
|
| + }
|
| +
|
| + // Reads a single 32-bit unsigned integer (little endian).
|
| + inline uint32_t read_u32(const byte* ptr) {
|
| + DCHECK(ptr >= start_ && (ptr + 4) <= end_);
|
| +#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
|
| + return *reinterpret_cast<const uint32_t*>(ptr);
|
| +#else
|
| + uint32_t b0 = ptr[0];
|
| + uint32_t b1 = ptr[1];
|
| + uint32_t b2 = ptr[2];
|
| + uint32_t b3 = ptr[3];
|
| + return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
|
| +#endif
|
| + }
|
| +
|
| + // Reads a single 64-bit unsigned integer (little endian).
|
| + inline uint64_t read_u64(const byte* ptr) {
|
| + DCHECK(ptr >= start_ && (ptr + 8) <= end_);
|
| +#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
|
| + return *reinterpret_cast<const uint64_t*>(ptr);
|
| +#else
|
| + uint32_t b0 = ptr[0];
|
| + uint32_t b1 = ptr[1];
|
| + uint32_t b2 = ptr[2];
|
| + uint32_t b3 = ptr[3];
|
| + uint32_t low = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
|
| + uint32_t b4 = ptr[4];
|
| + uint32_t b5 = ptr[5];
|
| + uint32_t b6 = ptr[6];
|
| + uint32_t b7 = ptr[7];
|
| + uint64_t high = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4;
|
| + return (high << 32) | low;
|
| +#endif
|
| + }
|
| +
|
| // Reads a 8-bit unsigned integer (byte) and advances {pc_}.
|
| - uint8_t u8(const char* name = nullptr) {
|
| + uint8_t consume_u8(const char* name = nullptr) {
|
| TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
|
| name ? name : "uint8_t");
|
| if (checkAvailable(1)) {
|
| byte val = *(pc_++);
|
| TRACE("%02x = %d\n", val, val);
|
| return val;
|
| - } else {
|
| - error("expected 1 byte, but fell off end");
|
| - return traceOffEnd<uint8_t>();
|
| }
|
| + return traceOffEnd<uint8_t>();
|
| }
|
|
|
| // Reads a 16-bit unsigned integer (little endian) and advances {pc_}.
|
| - uint16_t u16(const char* name = nullptr) {
|
| + uint16_t consume_u16(const char* name = nullptr) {
|
| TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
|
| name ? name : "uint16_t");
|
| if (checkAvailable(2)) {
|
| -#ifdef V8_TARGET_LITTLE_ENDIAN
|
| - byte b0 = pc_[0];
|
| - byte b1 = pc_[1];
|
| -#else
|
| - byte b1 = pc_[0];
|
| - byte b0 = pc_[1];
|
| -#endif
|
| - uint16_t val = static_cast<uint16_t>(b1 << 8) | b0;
|
| + uint16_t val = read_u16(pc_);
|
| TRACE("%02x %02x = %d\n", pc_[0], pc_[1], val);
|
| pc_ += 2;
|
| return val;
|
| - } else {
|
| - error("expected 2 bytes, but fell off end");
|
| - return traceOffEnd<uint16_t>();
|
| }
|
| + return traceOffEnd<uint16_t>();
|
| }
|
|
|
| // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}.
|
| - uint32_t u32(const char* name = nullptr) {
|
| + uint32_t consume_u32(const char* name = nullptr) {
|
| TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
|
| name ? name : "uint32_t");
|
| if (checkAvailable(4)) {
|
| -#ifdef V8_TARGET_LITTLE_ENDIAN
|
| - byte b0 = pc_[0];
|
| - byte b1 = pc_[1];
|
| - byte b2 = pc_[2];
|
| - byte b3 = pc_[3];
|
| -#else
|
| - byte b3 = pc_[0];
|
| - byte b2 = pc_[1];
|
| - byte b1 = pc_[2];
|
| - byte b0 = pc_[3];
|
| -#endif
|
| - uint32_t val = static_cast<uint32_t>(b3 << 24) |
|
| - static_cast<uint32_t>(b2 << 16) |
|
| - static_cast<uint32_t>(b1 << 8) | b0;
|
| + 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;
|
| - } else {
|
| - error("expected 4 bytes, but fell off end");
|
| - return traceOffEnd<uint32_t>();
|
| }
|
| + return traceOffEnd<uint32_t>();
|
| }
|
|
|
| // Reads a LEB128 variable-length 32-bit integer and advances {pc_}.
|
| - uint32_t u32v(int* length, const char* name = nullptr) {
|
| + uint32_t consume_u32v(int* length, const char* name = nullptr) {
|
| TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
|
| name ? name : "varint");
|
|
|
| - if (!checkAvailable(1)) {
|
| - error("expected at least 1 byte, but fell off end");
|
| - return traceOffEnd<uint32_t>();
|
| - }
|
| + if (checkAvailable(1)) {
|
| + const byte* pos = pc_;
|
| + const byte* end = pc_ + 5;
|
| + if (end > limit_) end = limit_;
|
|
|
| - const byte* pos = pc_;
|
| - const byte* end = pc_ + 5;
|
| - if (end > limit_) end = limit_;
|
| -
|
| - uint32_t result = 0;
|
| - int shift = 0;
|
| - byte b = 0;
|
| - while (pc_ < end) {
|
| - b = *pc_++;
|
| - TRACE("%02x ", b);
|
| - result = result | ((b & 0x7F) << shift);
|
| - if ((b & 0x80) == 0) break;
|
| - shift += 7;
|
| - }
|
| + uint32_t result = 0;
|
| + int shift = 0;
|
| + byte b = 0;
|
| + while (pc_ < end) {
|
| + b = *pc_++;
|
| + TRACE("%02x ", b);
|
| + result = result | ((b & 0x7F) << shift);
|
| + if ((b & 0x80) == 0) break;
|
| + shift += 7;
|
| + }
|
|
|
| - *length = static_cast<int>(pc_ - pos);
|
| - if (pc_ == end && (b & 0x80)) {
|
| - error(pc_ - 1, "varint too large");
|
| - } else {
|
| - TRACE("= %u\n", result);
|
| + *length = static_cast<int>(pc_ - pos);
|
| + if (pc_ == end && (b & 0x80)) {
|
| + error(pc_ - 1, "varint too large");
|
| + } else {
|
| + TRACE("= %u\n", result);
|
| + }
|
| + return result;
|
| }
|
| - return result;
|
| + return traceOffEnd<uint32_t>();
|
| }
|
|
|
| // Check that at least {size} bytes exist between {pc_} and {limit_}.
|
| @@ -208,6 +233,7 @@ class Decoder {
|
| start_ = start;
|
| pc_ = start;
|
| limit_ = end;
|
| + end_ = end;
|
| error_pc_ = nullptr;
|
| error_pt_ = nullptr;
|
| error_msg_.Reset(nullptr);
|
| @@ -220,6 +246,7 @@ class Decoder {
|
| const byte* start_;
|
| const byte* pc_;
|
| const byte* limit_;
|
| + const byte* end_;
|
| const byte* error_pc_;
|
| const byte* error_pt_;
|
| base::SmartArrayPointer<char> error_msg_;
|
|
|