5#ifndef V8_WASM_DECODER_H_
6#define V8_WASM_DECODER_H_
8#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
31 if (v8_flags.trace_wasm_decoder) PrintF(__VA_ARGS__); \
33#define TRACE_IF(cond, ...) \
35 if (v8_flags.trace_wasm_decoder && (cond)) PrintF(__VA_ARGS__); \
65 virtual void Description(
const char* desc,
size_t length) = 0;
106 template <
typename Val
idationTag>
107 using Name =
const char*;
109 template <
typename Val
idationTag>
110 using Name = std::conditional_t<ValidationTag::validate, const char*, NoName>;
131 template <
typename Val
idationTag>
138 template <
typename Val
idationTag>
145 template <
typename Val
idationTag>
152 template <
typename Val
idationTag>
160 template <
typename Val
idationTag>
168 template <
typename Val
idationTag>
176 template <
typename Val
idationTag>
184 template <
typename Val
idationTag>
192 template <
typename Val
idationTag>
201 template <
typename Val
idationTag>
205 auto [
index, index_length] =
207 uint32_t length = index_length + 1;
210 if (ValidationTag::validate &&
V8_UNLIKELY(index > 0xfff)) {
211 errorf(
pc,
"Invalid prefixed opcode %d", index);
213 static_assert(kExprUnreachable == 0);
214 return {kExprUnreachable, 0};
230 tracer->
Bytes(
pc_,
sizeof(uint8_t));
244 tracer->
Bytes(
pc_,
sizeof(uint32_t));
317 return static_cast<uint32_t
>(
end_ -
pc_);
323 errorf(
pc_,
"expected %u bytes, fell off end", size);
341 template <
typename... Args>
346 template <
typename... Args>
348 const char* format, Args...
args) {
352 template <
typename... Args>
357 "Use error instead of errorf if the format string has no placeholders");
367 for (
const uint8_t* p =
start; p <
end; ++p)
TRACE(
"%02x ", *p);
377 template <
typename T,
typename R = std::decay_t<T>>
408 const uint8_t*
pc()
const {
return pc_; }
410 return static_cast<uint32_t
>(
pc_ -
start_);
445 verrorf(uint32_t
offset, const
char* format, ...) {
459 template <
typename IntType,
typename Val
idationTag>
463 if (!ValidationTag::validate) {
473 template <
typename IntType, TraceFlag trace>
484 pc_ +=
sizeof(IntType);
490 template <
typename IntType,
typename ValidationTag,
TraceFlag trace,
491 size_t size_in_bits = 8 *
sizeof(IntType)>
494 static_assert(size_in_bits <= 8 *
sizeof(IntType),
495 "leb does not fit in type");
502 if (std::is_signed<IntType>::value) {
504 constexpr int sign_ext_shift =
int{8 *
sizeof(IntType)} - 7;
508 TRACE_IF(trace,
"= %" PRIu64
"\n",
static_cast<uint64_t
>(
result));
515 V8_ASSUME(length >= 0 && length <= (size_in_bits + 6) / 7);
516 V8_ASSUME(ValidationTag::validate || length >= 1);
520 template <
typename IntType,
typename ValidationTag,
TraceFlag trace,
521 size_t size_in_bits = 8 *
sizeof(IntType)>
529 template <
typename IntType,
typename ValidationTag,
TraceFlag trace,
530 size_t size_in_bits,
int byte_index>
533 IntType intermediate_result) {
534 constexpr bool is_signed = std::is_signed<IntType>::value;
535 constexpr int kMaxLength = (size_in_bits + 6) / 7;
536 static_assert(byte_index < kMaxLength,
"invalid template instantiation");
537 constexpr int shift = byte_index * 7;
538 constexpr bool is_last_byte = byte_index == kMaxLength - 1;
539 const bool at_end = ValidationTag::validate &&
pc >=
end_;
545 using Unsigned =
typename std::make_unsigned<IntType>::type;
546 intermediate_result |=
547 (
static_cast<Unsigned
>(
static_cast<IntType
>(b) & 0x7f) << shift);
549 if (!is_last_byte && (b & 0x80)) {
553 constexpr int next_byte_index = byte_index + (is_last_byte ? 0 : 1);
554 return read_leb_tail<IntType, ValidationTag, trace, size_in_bits,
555 next_byte_index>(
pc + 1,
name, intermediate_result);
557 if (ValidationTag::validate &&
V8_UNLIKELY(at_end || (b & 0x80))) {
558 TRACE_IF(trace, at_end ?
"<end> " :
"<length overflow> ");
560 at_end ?
"reached end" :
"length overflow", name);
563 if constexpr (is_last_byte) {
570 constexpr int kExtraBits = size_in_bits - ((kMaxLength - 1) * 7);
571 constexpr int kSignExtBits = kExtraBits - (
is_signed ? 1 : 0);
572 const uint8_t checked_bits = b & (0xFF << kSignExtBits);
573 constexpr uint8_t kSignExtendedExtraBits = 0x7f & (0xFF << kSignExtBits);
574 const bool valid_extra_bits =
576 (
is_signed && checked_bits == kSignExtendedExtraBits);
577 if (!ValidationTag::validate) {
580 error(
pc,
"extra bits in varint");
584 constexpr int sign_ext_shift =
585 is_signed ? std::max(0,
int{8 *
sizeof(IntType)} - shift - 7) : 0;
587 intermediate_result =
588 (intermediate_result << sign_ext_shift) >> sign_ext_shift;
590 TRACE(
"= %" PRIi64
"\n",
static_cast<int64_t
>(intermediate_result));
592 TRACE(
"= %" PRIu64
"\n",
static_cast<uint64_t
>(intermediate_result));
594 const uint32_t length = byte_index + 1;
595 return {intermediate_result, length};
constexpr T * begin() const
uint64_t read_u64(const uint8_t *pc, Name< ValidationTag > msg="expected 8 bytes")
void V8_NOINLINE V8_PRESERVE_MOST errorf(const uint8_t *pc, const char *format, Args... args)
void V8_NOINLINE PRINTF_FORMAT(3, 4) verrorf(uint32_t offset
const uint8_t * start() const
Result< R > toResult(T &&val)
std::pair< int64_t, uint32_t > read_i64v(const uint8_t *pc, Name< ValidationTag > name="signed LEB64")
uint32_t read_u32(const uint8_t *pc, Name< ValidationTag > msg="expected 4 bytes")
int32_t consume_i32v(const char *name="var_int32")
std::pair< int64_t, uint32_t > read_i33v(const uint8_t *pc, Name< ValidationTag > name="signed LEB33")
uint32_t consume_u32(const char *name, ITracer *tracer)
uint16_t read_u16(const uint8_t *pc, Name< ValidationTag > msg="expected 2 bytes")
uint32_t available_bytes() const
std::conditional_t< ValidationTag::validate, const char *, NoName > Name
std::pair< uint64_t, uint32_t > read_u64v(const uint8_t *pc, Name< ValidationTag > name="LEB64")
void V8_NOINLINE V8_PRESERVE_MOST errorf(const char *format, Args... args)
const WasmError & error() const
V8_INLINE std::pair< IntType, uint32_t > read_leb(const uint8_t *pc, Name< ValidationTag > name="varint")
uint8_t consume_u8(const char *name, ITracer *tracer)
IntType read_little_endian(const uint8_t *pc, Name< ValidationTag > msg)
Decoder(const uint8_t *start, const uint8_t *end, uint32_t buffer_offset=0)
const uint8_t * pc() const
V8_INLINE std::pair< IntType, uint32_t > read_leb_tail(const uint8_t *pc, Name< ValidationTag > name, IntType intermediate_result)
Decoder(const uint8_t *start, const uint8_t *pc, const uint8_t *end, uint32_t buffer_offset=0)
void Reset(base::Vector< const uint8_t > bytes, uint32_t buffer_offset=0)
void Reset(const uint8_t *start, const uint8_t *end, uint32_t buffer_offset=0)
void V8_NOINLINE const char constexpr int kMaxErrorMsg
IntType consume_little_endian(const char *name)
void set_end(const uint8_t *end)
uint16_t consume_u16(const char *name="uint16_t")
void V8_NOINLINE V8_PRESERVE_MOST errorf(uint32_t offset, const char *format, Args... args)
base::EmbeddedVector< char, kMaxErrorMsg > buffer
bool checkAvailable(uint32_t size)
bool lookahead(int offset, uint8_t expected)
uint32_t GetBufferRelativeOffset(uint32_t offset) const
uint8_t read_u8(const uint8_t *pc, Name< ValidationTag > msg="expected 1 byte")
uint64_t consume_u64v(const char *name, ITracer *tracer)
uint32_t consume_u32v(const char *name, ITracer *tracer)
void consume_bytes(uint32_t size, const char *name, ITracer *tracer)
virtual ~Decoder()=default
void V8_NOINLINE V8_PRESERVE_MOST error(uint32_t offset, const char *msg)
std::pair< uint32_t, uint32_t > read_u32v(const uint8_t *pc, Name< ValidationTag > name="LEB32")
void consume_bytes(uint32_t size, const char *name="skip")
uint32_t pc_offset() const
uint32_t consume_u32v(const char *name="var_uint32")
Decoder(const base::Vector< const uint8_t > bytes, uint32_t buffer_offset=0)
std::pair< int32_t, uint32_t > read_i32v(const uint8_t *pc, Name< ValidationTag > name="signed LEB32")
uint32_t V8_INLINE pc_offset(const uint8_t *pc) const
void V8_NOINLINE V8_PRESERVE_MOST error(const uint8_t *pc, const char *msg)
uint8_t consume_u8(const char *name="uint8_t")
const uint8_t * end() const
std::pair< WasmOpcode, uint32_t > read_prefixed_opcode(const uint8_t *pc, Name< ValidationTag > name="prefixed opcode")
uint32_t V8_INLINE position() const
void traceByteRange(const uint8_t *start, const uint8_t *end)
void V8_NOINLINE V8_PRESERVE_MOST error(const char *msg)
V8_NOINLINE V8_PRESERVE_MOST std::pair< IntType, uint32_t > read_leb_slowpath(const uint8_t *pc, Name< ValidationTag > name)
static constexpr struct v8::internal::wasm::Decoder::NoValidationTag kNoValidation
virtual void onFirstError()
static constexpr struct v8::internal::wasm::Decoder::FullValidationTag kFullValidation
uint32_t buffer_offset() const
int64_t consume_i64v(const char *name="var_int64")
virtual void StringOffset(uint32_t offset)=0
virtual void InitializerExpression(const uint8_t *start, const uint8_t *end, ValueType expected_type)=0
virtual void Description(HeapType type)=0
virtual void NextLineIfNonEmpty()=0
static constexpr ITracer * NoTrace
virtual void RecGroupOffset(uint32_t offset, uint32_t group_size)=0
virtual void GlobalOffset(uint32_t offset)=0
virtual ~ITracer()=default
virtual void TypeOffset(uint32_t offset)=0
virtual void Description(uint32_t number)=0
virtual void ImportOffset(uint32_t offset)=0
virtual void Bytes(const uint8_t *start, uint32_t count)=0
virtual void Description(uint64_t number)=0
virtual void Description(const char *desc, size_t length)=0
virtual void FunctionBody(const WasmFunction *func, const uint8_t *start)=0
virtual void ImportsDone(const WasmModule *module)=0
virtual void ElementOffset(uint32_t offset)=0
virtual void Description(const FunctionSig *sig)=0
virtual void Description(const char *desc)=0
virtual void TableOffset(uint32_t offset)=0
virtual void MemoryOffset(uint32_t offset)=0
virtual void FunctionName(uint32_t func_index)=0
virtual void DataOffset(uint32_t offset)=0
virtual void TagOffset(uint32_t offset)=0
virtual void StartOffset(uint32_t offset)=0
virtual void NextLine()=0
virtual void NameSection(const uint8_t *start, const uint8_t *end, uint32_t offset)=0
virtual void NextLineIfFull()=0
virtual void Description(ValueType type)=0
const std::string & message() const &
#define TRACE_IF(cond,...)
ZoneVector< RpoNumber > & result
static V ReadLittleEndianValue(Address p)
int VSNPrintF(Vector< char > str, const char *format, va_list args)
Result< std::nullptr_t > VoidResult
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
constexpr uint32_t kMaxUInt32
bool is_signed(Condition cond)
#define DCHECK_LE(v1, v2)
#define DCHECK_GE(v1, v2)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
V8_INLINE A implicit_cast(A x)
static constexpr bool validate
constexpr NoName(const char *)
static constexpr bool validate
#define V8_LIKELY(condition)
#define V8_UNLIKELY(condition)