diff options
Diffstat (limited to 'deps/v8/src/wasm/decoder.h')
-rw-r--r-- | deps/v8/src/wasm/decoder.h | 128 |
1 files changed, 75 insertions, 53 deletions
diff --git a/deps/v8/src/wasm/decoder.h b/deps/v8/src/wasm/decoder.h index d9d25175ef..5f242ac1aa 100644 --- a/deps/v8/src/wasm/decoder.h +++ b/deps/v8/src/wasm/decoder.h @@ -37,14 +37,15 @@ namespace wasm { // a buffer of bytes. class Decoder { public: - Decoder(const byte* start, const byte* end) - : start_(start), pc_(start), end_(end), error_pc_(nullptr) {} - Decoder(const byte* start, const byte* pc, const byte* end) - : start_(start), pc_(pc), end_(end), error_pc_(nullptr) {} + Decoder(const byte* start, const byte* end, uint32_t buffer_offset = 0) + : start_(start), pc_(start), end_(end), buffer_offset_(buffer_offset) {} + Decoder(const byte* start, const byte* pc, const byte* end, + uint32_t buffer_offset = 0) + : start_(start), pc_(pc), end_(end), buffer_offset_(buffer_offset) {} virtual ~Decoder() {} - inline bool check(const byte* pc, unsigned length, const char* msg) { + inline bool check(const byte* pc, uint32_t length, const char* msg) { DCHECK_LE(start_, pc); if (V8_UNLIKELY(pc + length > end_)) { error(pc, msg); @@ -82,28 +83,28 @@ class Decoder { // Reads a variable-length unsigned integer (little endian). template <bool checked> - uint32_t read_u32v(const byte* pc, unsigned* length, + uint32_t read_u32v(const byte* pc, uint32_t* length, const char* name = "LEB32") { return read_leb<uint32_t, checked, false, false>(pc, length, name); } // Reads a variable-length signed integer (little endian). template <bool checked> - int32_t read_i32v(const byte* pc, unsigned* length, + int32_t read_i32v(const byte* pc, uint32_t* length, const char* name = "signed LEB32") { return read_leb<int32_t, checked, false, false>(pc, length, name); } // Reads a variable-length unsigned integer (little endian). template <bool checked> - uint64_t read_u64v(const byte* pc, unsigned* length, + uint64_t read_u64v(const byte* pc, uint32_t* length, const char* name = "LEB64") { return read_leb<uint64_t, checked, false, false>(pc, length, name); } // Reads a variable-length signed integer (little endian). template <bool checked> - int64_t read_i64v(const byte* pc, unsigned* length, + int64_t read_i64v(const byte* pc, uint32_t* length, const char* name = "signed LEB64") { return read_leb<int64_t, checked, false, false>(pc, length, name); } @@ -125,13 +126,13 @@ class Decoder { // Reads a LEB128 variable-length unsigned 32-bit integer and advances {pc_}. uint32_t consume_u32v(const char* name = nullptr) { - unsigned length = 0; + uint32_t length = 0; return read_leb<uint32_t, true, true, true>(pc_, &length, name); } // Reads a LEB128 variable-length signed 32-bit integer and advances {pc_}. int32_t consume_i32v(const char* name = nullptr) { - unsigned length = 0; + uint32_t length = 0; return read_leb<int32_t, true, true, true>(pc_, &length, name); } @@ -182,7 +183,8 @@ class Decoder { CHECK_LT(0, len); va_end(arguments); error_msg_.assign(buffer.start(), len); - error_pc_ = pc; + DCHECK_GE(pc, start_); + error_offset_ = static_cast<uint32_t>(pc - start_) + buffer_offset_; onFirstError(); } @@ -206,40 +208,51 @@ class Decoder { Result<U> toResult(T&& val) { Result<U> result(std::forward<T>(val)); if (failed()) { - // The error message must not be empty, otherwise Result::failed() will be - // false. - DCHECK(!error_msg_.empty()); TRACE("Result error: %s\n", error_msg_.c_str()); - DCHECK_GE(error_pc_, start_); - result.error_offset = static_cast<uint32_t>(error_pc_ - start_); - result.error_msg = std::move(error_msg_); + result.error(error_offset_, std::move(error_msg_)); } return result; } // Resets the boundaries of this decoder. - void Reset(const byte* start, const byte* end) { + void Reset(const byte* start, const byte* end, uint32_t buffer_offset = 0) { start_ = start; pc_ = start; end_ = end; - error_pc_ = nullptr; + buffer_offset_ = buffer_offset; + error_offset_ = 0; error_msg_.clear(); } + void Reset(Vector<const uint8_t> bytes, uint32_t buffer_offset = 0) { + Reset(bytes.begin(), bytes.end(), buffer_offset); + } + bool ok() const { return error_msg_.empty(); } bool failed() const { return !ok(); } bool more() const { return pc_ < end_; } const byte* start() const { return start_; } const byte* pc() const { return pc_; } - uint32_t pc_offset() const { return static_cast<uint32_t>(pc_ - start_); } + uint32_t pc_offset() const { + return static_cast<uint32_t>(pc_ - start_) + buffer_offset_; + } + uint32_t buffer_offset() const { return buffer_offset_; } + // Takes an offset relative to the module start and returns an offset relative + // to the current buffer of the decoder. + uint32_t GetBufferRelativeOffset(uint32_t offset) const { + DCHECK_LE(buffer_offset_, offset); + return offset - buffer_offset_; + } const byte* end() const { return end_; } protected: const byte* start_; const byte* pc_; const byte* end_; - const byte* error_pc_; + // The offset of the current buffer in the module. Needed for streaming. + uint32_t buffer_offset_; + uint32_t error_offset_ = 0; std::string error_msg_; private: @@ -269,37 +282,47 @@ class Decoder { } template <typename IntType, bool checked, bool advance_pc, bool trace> - inline IntType read_leb(const byte* pc, unsigned* length, + inline IntType read_leb(const byte* pc, uint32_t* length, const char* name = "varint") { DCHECK_IMPLIES(advance_pc, pc == pc_); - constexpr bool is_signed = std::is_signed<IntType>::value; TRACE_IF(trace, " +%d %-20s: ", static_cast<int>(pc - start_), name); + return read_leb_tail<IntType, checked, advance_pc, trace, 0>(pc, length, + name, 0); + } + + template <typename IntType, bool checked, bool advance_pc, bool trace, + int byte_index> + IntType read_leb_tail(const byte* pc, uint32_t* length, const char* name, + IntType result) { + constexpr bool is_signed = std::is_signed<IntType>::value; constexpr int kMaxLength = (sizeof(IntType) * 8 + 6) / 7; - const byte* ptr = pc; - const byte* end = Min(end_, ptr + kMaxLength); - // The end variable is only used if checked == true. MSVC recognizes this. - USE(end); - int shift = 0; + static_assert(byte_index < kMaxLength, "invalid template instantiation"); + constexpr int shift = byte_index * 7; + constexpr bool is_last_byte = byte_index == kMaxLength - 1; + const bool at_end = checked && pc >= end_; byte b = 0; - IntType result = 0; - do { - if (checked && V8_UNLIKELY(ptr >= end)) { - TRACE_IF(trace, - ptr == pc + kMaxLength ? "<length overflow> " : "<end> "); - errorf(ptr, "expected %s", name); - result = 0; - break; - } - DCHECK_GT(end, ptr); - b = *ptr++; + if (!at_end) { + DCHECK_LT(pc_, end_); + b = *pc; TRACE_IF(trace, "%02x ", b); - result = result | ((static_cast<IntType>(b) & 0x7F) << shift); - shift += 7; - } while (b & 0x80); - DCHECK_LE(ptr - pc, kMaxLength); - *length = static_cast<unsigned>(ptr - pc); - if (advance_pc) pc_ = ptr; - if (*length == kMaxLength) { + result = result | ((static_cast<IntType>(b) & 0x7f) << shift); + } + if (!is_last_byte && (b & 0x80)) { + // Make sure that we only instantiate the template for valid byte indexes. + // Compilers are not smart enough to figure out statically that the + // following call is unreachable if is_last_byte is false. + constexpr int next_byte_index = byte_index + (is_last_byte ? 0 : 1); + return read_leb_tail<IntType, checked, advance_pc, trace, + next_byte_index>(pc + 1, length, name, result); + } + if (advance_pc) pc_ = pc + (at_end ? 0 : 1); + *length = byte_index + (at_end ? 0 : 1); + if (checked && (at_end || (b & 0x80))) { + TRACE_IF(trace, at_end ? "<end> " : "<length overflow> "); + errorf(pc, "expected %s", name); + result = 0; + } + if (is_last_byte) { // A signed-LEB128 must sign-extend the final byte, excluding its // most-significant bit; e.g. for a 32-bit LEB128: // kExtraBits = 4 (== 32 - (5-1) * 7) @@ -316,15 +339,14 @@ class Decoder { if (!checked) { DCHECK(valid_extra_bits); } else if (!valid_extra_bits) { - error(ptr, "extra bits in varint"); + error(pc, "extra bits in varint"); result = 0; } } - if (is_signed && *length < kMaxLength) { - int sign_ext_shift = 8 * sizeof(IntType) - shift; - // Perform sign extension. - result = (result << sign_ext_shift) >> sign_ext_shift; - } + constexpr int sign_ext_shift = + is_signed && !is_last_byte ? 8 * sizeof(IntType) - shift - 7 : 0; + // Perform sign extension. + result = (result << sign_ext_shift) >> sign_ext_shift; if (trace && is_signed) { TRACE("= %" PRIi64 "\n", static_cast<int64_t>(result)); } else if (trace) { |