summaryrefslogtreecommitdiff
path: root/deps/v8/src/wasm/decoder.h
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/wasm/decoder.h')
-rw-r--r--deps/v8/src/wasm/decoder.h128
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) {