5 #ifndef V8_WASM_DECODER_H_ 6 #define V8_WASM_DECODER_H_ 11 #include "src/base/compiler-specific.h" 12 #include "src/flags.h" 13 #include "src/signature.h" 14 #include "src/v8memory.h" 15 #include "src/wasm/wasm-result.h" 16 #include "src/zone/zone-containers.h" 24 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ 26 #define TRACE_IF(cond, ...) \ 28 if (FLAG_trace_wasm_decoder && (cond)) PrintF(__VA_ARGS__); \ 32 using DecodeResult = VoidResult;
38 enum ValidateFlag :
bool { kValidate =
true, kNoValidate =
false };
40 enum AdvancePCFlag :
bool { kAdvancePc =
true, kNoAdvancePc =
false };
42 enum TraceFlag :
bool { kTrace =
true, kNoTrace =
false };
45 :
Decoder(start, start, end, buffer_offset) {}
47 :
Decoder(bytes.start(), bytes.start() + bytes.length(), buffer_offset) {}
48 Decoder(
const byte* start,
const byte* pc,
const byte* end,
50 : start_(start), pc_(pc), end_(end), buffer_offset_(buffer_offset) {
53 DCHECK_EQ(static_cast<uint32_t>(end - start), end - start);
58 inline bool validate_size(
const byte* pc,
uint32_t length,
const char* msg) {
59 DCHECK_LE(start_, pc);
61 if (V8_UNLIKELY(length > static_cast<uint32_t>(end_ - pc))) {
69 template <Val
idateFlag val
idate>
70 inline uint8_t read_u8(
const byte* pc,
const char* msg =
"expected 1 byte") {
71 return read_little_endian<uint8_t, validate>(pc, msg);
75 template <Val
idateFlag val
idate>
76 inline uint16_t read_u16(
const byte* pc,
77 const char* msg =
"expected 2 bytes") {
78 return read_little_endian<uint16_t, validate>(pc, msg);
82 template <Val
idateFlag val
idate>
83 inline uint32_t read_u32(
const byte* pc,
84 const char* msg =
"expected 4 bytes") {
85 return read_little_endian<uint32_t, validate>(pc, msg);
89 template <Val
idateFlag val
idate>
90 inline uint64_t read_u64(
const byte* pc,
91 const char* msg =
"expected 8 bytes") {
92 return read_little_endian<uint64_t, validate>(pc, msg);
96 template <Val
idateFlag val
idate>
98 const char* name =
"LEB32") {
99 return read_leb<uint32_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
104 template <Val
idateFlag val
idate>
105 int32_t read_i32v(
const byte* pc,
uint32_t* length,
106 const char* name =
"signed LEB32") {
107 return read_leb<int32_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
112 template <Val
idateFlag val
idate>
113 uint64_t read_u64v(
const byte* pc,
uint32_t* length,
114 const char* name =
"LEB64") {
115 return read_leb<uint64_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
120 template <Val
idateFlag val
idate>
122 const char* name =
"signed LEB64") {
123 return read_leb<int64_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
128 uint8_t consume_u8(
const char* name =
"uint8_t") {
129 return consume_little_endian<uint8_t>(name);
133 uint16_t consume_u16(
const char* name =
"uint16_t") {
134 return consume_little_endian<uint16_t>(name);
138 uint32_t consume_u32(
const char* name =
"uint32_t") {
139 return consume_little_endian<uint32_t>(name);
143 uint32_t consume_u32v(
const char* name =
nullptr) {
145 return read_leb<uint32_t, kValidate, kAdvancePc, kTrace>(pc_, &length,
150 int32_t consume_i32v(
const char* name =
nullptr) {
152 return read_leb<int32_t, kValidate, kAdvancePc, kTrace>(pc_, &length, name);
156 void consume_bytes(
uint32_t size,
const char* name =
"skip") {
158 TRACE_IF(name,
" +%u %-20s: %u bytes\n", pc_offset(), name, size);
159 if (checkAvailable(size)) {
167 bool checkAvailable(
uint32_t size) {
168 DCHECK_LE(pc_, end_);
169 if (V8_UNLIKELY(size > static_cast<uint32_t>(end_ - pc_))) {
170 errorf(pc_,
"expected %u bytes, fell off end", size);
176 void error(
const char* msg) { errorf(pc_,
"%s", msg); }
178 void error(
const byte* pc,
const char* msg) { errorf(pc,
"%s", msg); }
181 void PRINTF_FORMAT(3, 4) errorf(
const byte* pc,
const char* format, ...) {
185 if (FLAG_wasm_break_on_decoder_error) {
186 base::OS::DebugBreak();
189 constexpr
int kMaxErrorMsg = 256;
192 va_start(arguments, format);
193 int len = VSNPrintF(buffer, format, arguments);
196 error_msg_.assign(buffer.start(), len);
197 DCHECK_GE(pc, start_);
198 error_offset_ =
static_cast<uint32_t>(pc - start_) + buffer_offset_;
203 virtual void onFirstError() {}
206 void traceByteRange(
const byte* start,
const byte* end) {
207 DCHECK_LE(start, end);
208 for (
const byte* p = start; p < end; ++p) TRACE(
"%02x ", *p);
213 traceByteRange(pc_, end_);
218 template <typename T, typename U = typename std::remove_reference<T>::type>
221 TRACE(
"Result error: %s\n", error_msg_.c_str());
228 void Reset(
const byte* start,
const byte* end,
uint32_t buffer_offset = 0) {
229 DCHECK_LE(start, end);
230 DCHECK_EQ(static_cast<uint32_t>(end - start), end - start);
234 buffer_offset_ = buffer_offset;
240 Reset(bytes.begin(), bytes.end(), buffer_offset);
243 bool ok()
const {
return error_msg_.empty(); }
244 bool failed()
const {
return !ok(); }
245 bool more()
const {
return pc_ < end_; }
247 const byte* start()
const {
return start_; }
248 const byte* pc()
const {
return pc_; }
251 return static_cast<uint32_t>(pc_ - start_) + buffer_offset_;
253 uint32_t buffer_offset()
const {
return buffer_offset_; }
257 DCHECK_LE(buffer_offset_, offset);
258 return offset - buffer_offset_;
260 const byte* end()
const {
return end_; }
269 std::string error_msg_;
272 template <
typename IntType,
bool val
idate>
273 inline IntType read_little_endian(
const byte* pc,
const char* msg) {
275 DCHECK(validate_size(pc,
sizeof(IntType), msg));
276 }
else if (!validate_size(pc,
sizeof(IntType), msg)) {
279 return ReadLittleEndianValue<IntType>(
reinterpret_cast<Address>(pc));
282 template <
typename IntType>
283 inline IntType consume_little_endian(
const char* name) {
284 TRACE(
" +%u %-20s: ", pc_offset(), name);
285 if (!checkAvailable(
sizeof(IntType))) {
290 IntType val = read_little_endian<IntType, false>(pc_, name);
291 traceByteRange(pc_, pc_ +
sizeof(IntType));
292 TRACE(
"= %d\n", val);
293 pc_ +=
sizeof(IntType);
297 template <
typename IntType, ValidateFlag validate, AdvancePCFlag advance_pc,
299 inline IntType read_leb(
const byte* pc,
uint32_t* length,
300 const char* name =
"varint") {
301 DCHECK_IMPLIES(advance_pc, pc == pc_);
302 TRACE_IF(trace,
" +%u %-20s: ", pc_offset(), name);
303 return read_leb_tail<IntType, validate, advance_pc, trace, 0>(pc, length,
307 template <
typename IntType, ValidateFlag validate, AdvancePCFlag advance_pc,
308 TraceFlag trace,
int byte_index>
309 IntType read_leb_tail(
const byte* pc,
uint32_t* length,
const char* name,
311 constexpr
bool is_signed = std::is_signed<IntType>::value;
312 constexpr
int kMaxLength = (
sizeof(IntType) * 8 + 6) / 7;
313 static_assert(byte_index < kMaxLength,
"invalid template instantiation");
314 constexpr
int shift = byte_index * 7;
315 constexpr
bool is_last_byte = byte_index == kMaxLength - 1;
317 const bool at_end = validate && pc == end_;
322 TRACE_IF(trace,
"%02x ", b);
323 result = result | ((
static_cast<IntType
>(b) & 0x7f) << shift);
325 if (!is_last_byte && (b & 0x80)) {
329 constexpr
int next_byte_index = byte_index + (is_last_byte ? 0 : 1);
330 return read_leb_tail<IntType, validate, advance_pc, trace,
331 next_byte_index>(pc + 1, length, name, result);
333 if (advance_pc) pc_ = pc + (at_end ? 0 : 1);
334 *length = byte_index + (at_end ? 0 : 1);
335 if (validate && (at_end || (b & 0x80))) {
336 TRACE_IF(trace, at_end ?
"<end> " :
"<length overflow> ");
337 errorf(pc,
"expected %s", name);
347 constexpr
int kExtraBits = (
sizeof(IntType) * 8) - ((kMaxLength - 1) * 7);
348 constexpr
int kSignExtBits = kExtraBits - (is_signed ? 1 : 0);
349 const byte checked_bits = b & (0xFF << kSignExtBits);
350 constexpr byte kSignExtendedExtraBits = 0x7f & (0xFF << kSignExtBits);
351 bool valid_extra_bits =
353 (is_signed && checked_bits == kSignExtendedExtraBits);
355 DCHECK(valid_extra_bits);
356 }
else if (!valid_extra_bits) {
357 error(pc,
"extra bits in varint");
361 constexpr
int sign_ext_shift =
362 is_signed ? Max(0,
int{8 *
sizeof(IntType)} - shift - 7) : 0;
364 result = (result << sign_ext_shift) >> sign_ext_shift;
365 if (trace && is_signed) {
366 TRACE(
"= %" PRIi64
"\n", static_cast<int64_t>(result));
368 TRACE(
"= %" PRIu64
"\n", static_cast<uint64_t>(result));
379 #endif // V8_WASM_DECODER_H_