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_; |