Index: src/wasm/decoder.h |
diff --git a/src/wasm/decoder.h b/src/wasm/decoder.h |
index d5c9f43c570f3b4ff7d8382d0fb684e3d603ee14..b556f932badd25f22215950ed8784568e76731b3 100644 |
--- a/src/wasm/decoder.h |
+++ b/src/wasm/decoder.h |
@@ -173,48 +173,14 @@ class Decoder { |
return traceOffEnd<uint32_t>(); |
} |
- // Reads a LEB128 variable-length 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) { |
- TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), |
- name ? name : "varint"); |
- if (checkAvailable(1)) { |
- 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; |
- } |
- |
- int length = static_cast<int>(pc_ - pos); |
- if (pc_ == end && (b & 0x80)) { |
- error(pc_ - 1, "varint too large"); |
- } else if (length == 0) { |
- error(pc_, "varint of length 0"); |
- } else { |
- TRACE("= %u\n", result); |
- } |
- return result; |
- } |
- return traceOffEnd<uint32_t>(); |
+ return consume_leb<uint32_t, false>(name); |
} |
- // Consume {size} bytes and send them to the bit bucket, advancing {pc_}. |
- void consume_bytes(int size) { |
- TRACE(" +%d %-20s: %d bytes\n", static_cast<int>(pc_ - start_), "skip", |
- size); |
- if (checkAvailable(size)) { |
- pc_ += size; |
- } else { |
- pc_ = limit_; |
- } |
+ // Reads a LEB128 variable-length signed 32-bit integer and advances {pc_}. |
+ int32_t consume_i32v(const char* name = nullptr) { |
+ return consume_leb<int32_t, true>(name); |
} |
// Consume {size} bytes and send them to the bit bucket, advancing {pc_}. |
@@ -383,6 +349,47 @@ class Decoder { |
} |
return result; |
} |
+ |
+ template <typename IntType, bool is_signed> |
+ IntType consume_leb(const char* name = nullptr) { |
+ TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), |
+ name ? name : "varint"); |
+ if (checkAvailable(1)) { |
+ const int kMaxLength = (sizeof(IntType) * 8 + 6) / 7; |
+ const byte* pos = pc_; |
+ const byte* end = pc_ + kMaxLength; |
+ if (end > limit_) end = limit_; |
+ |
+ IntType result = 0; |
+ int shift = 0; |
+ byte b = 0; |
+ while (pc_ < end) { |
+ b = *pc_++; |
+ TRACE("%02x ", b); |
+ result = result | (static_cast<IntType>(b & 0x7F) << shift); |
+ shift += 7; |
+ if ((b & 0x80) == 0) break; |
+ } |
+ |
+ int length = static_cast<int>(pc_ - pos); |
+ if (pc_ == end && (b & 0x80)) { |
+ error(pc_ - 1, "varint too large"); |
+ } else if (length == 0) { |
+ error(pc_, "varint of length 0"); |
+ } else if (is_signed) { |
+ if (length < kMaxLength) { |
+ int sign_ext_shift = 8 * sizeof(IntType) - shift; |
+ // Perform sign extension. |
+ result = (result << sign_ext_shift) >> sign_ext_shift; |
+ } |
+ TRACE("= %" PRIi64 "\n", static_cast<int64_t>(result)); |
+ } else { |
+ TRACE("= %" PRIu64 "\n", static_cast<uint64_t>(result)); |
+ } |
+ return result; |
+ } |
+ return traceOffEnd<uint32_t>(); |
+ } |
}; |
#undef TRACE |