5#ifndef V8_WASM_INTERPRETER_WASM_INTERPRETER_H_
6#define V8_WASM_INTERPRETER_WASM_INTERPRETER_H_
8#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
37#ifdef V8_HOST_ARCH_ARM64
39#elif !defined(__clang__)
41#elif defined(V8_DRUMBRAKE_BOUNDS_CHECKS)
44#define VECTORCALL __vectorcall
47#define INSTRUCTION_HANDLER_FUNC \
48 __attribute__((noinline)) static DISABLE_CFI_ICALL void VECTORCALL
55class WasmInstanceObject;
61struct InterpreterCode;
62class InterpreterHandle;
63struct ModuleWireBytes;
65class WasmBytecodeGenerator;
69class WasmInterpreterRuntime;
70class WasmInterpreterThread;
83 const uint8_t*
start,
const uint8_t*
end)
104#ifdef V8_ENABLE_DRUMBRAKE_TRACING
106 current_stack_height_(0),
107 current_stack_start_args_(0),
108 current_stack_start_locals_(0),
109 current_stack_start_stack_(0)
126 uint32_t catch_block_index)
const;
132#ifdef V8_ENABLE_DRUMBRAKE_TRACING
133 uint32_t current_stack_height_;
134 uint32_t current_stack_start_args_;
135 uint32_t current_stack_start_locals_;
136 uint32_t current_stack_start_stack_;
190 void NotifyIsolateDisposal(
Isolate* isolate);
193 typedef std::unordered_map<int, std::unique_ptr<WasmInterpreterThread>>
276 enum State { STOPPED, RUNNING, FINISHED, TRAPPED, EH_UNWINDING };
290 uint8_t* start_fp,
const FrameState& callee_frame_state)
293 frame_pointer_(frame_pointer),
294 current_frame_size_(0),
295 current_ref_stack_fp_(0),
296 current_ref_stack_frame_size_(0),
297 current_fp_(start_fp),
298 current_frame_state_(callee_frame_state)
299#ifdef V8_ENABLE_DRUMBRAKE_TRACING
301 current_stack_start_(callee_frame_state.current_stack_start_args_ +
302 thread->CurrentStackFrameSize()),
303 current_stack_size_(0)
310 inline Isolate* GetIsolate()
const;
315 current_frame_state_ = frame_state;
320 uint32_t current_frame_size,
321 uint32_t current_stack_size,
322 uint32_t current_ref_stack_fp,
323 uint32_t current_ref_stack_frame_size) {
324 current_fp_ = current_fp;
325 current_frame_size_ = current_frame_size;
326 current_ref_stack_fp_ = current_ref_stack_fp;
327 current_ref_stack_frame_size_ = current_ref_stack_frame_size;
329#ifdef V8_ENABLE_DRUMBRAKE_TRACING
330 current_stack_size_ = current_stack_size;
335 return current_fp_ + current_frame_size_;
339 return current_ref_stack_fp_ + current_ref_stack_frame_size_;
347 TrapStatus trap_status{trap_function_index, trap_pc};
349 std::make_unique<std::vector<WasmInterpreterStackEntry>>(
350 CaptureStackTrace(&trap_status));
354 if (trap_stack_trace_) {
355 return *trap_stack_trace_;
360 return CaptureStackTrace();
363 int GetFunctionIndex(
int index)
const;
366 return wasm_runtime_;
369#ifdef V8_ENABLE_DRUMBRAKE_TRACING
370 uint32_t CurrentStackFrameStart()
const {
return current_stack_start_; }
371 uint32_t CurrentStackFrameSize()
const {
return current_stack_size_; }
375 std::vector<WasmInterpreterStackEntry> CaptureStackTrace(
376 const TrapStatus* trap_status =
nullptr)
const;
387#ifdef V8_ENABLE_DRUMBRAKE_TRACING
388 uint32_t current_stack_start_;
389 uint32_t current_stack_size_;
399 if (current_stack_size_ + additional_required_size > kMaxStackSize) {
403 uint32_t new_size = current_stack_size_;
404 while (new_size < current_stack_size_ + additional_required_size) {
405 new_size = std::min(new_size + kStackSizeIncrement, kMaxStackSize);
409 PageAllocator::Permission::kReadWrite)) {
410 current_stack_size_ = new_size;
418 if (thread_interpreter_map_s)
return;
423 delete thread_interpreter_map_s;
424 thread_interpreter_map_s =
nullptr;
428 thread_interpreter_map_s->NotifyIsolateDisposal(isolate);
433 return thread_interpreter_map_s->GetCurrentInterpreterThread(isolate);
441 if (!trap_handler::IsThreadInWasm()) {
442 trap_handler::SetThreadInWasm();
451 trap_reason_ = trap_reason;
453 DCHECK(!activations_.empty());
454 activations_.back()->SetCurrentFrame(current_frame);
455 activations_.back()->SetTrapped(trap_function_index, trap_pc);
463 uint8_t* interpreter_fp,
const FrameState& frame_state);
464 inline void FinishActivation();
465 inline const FrameState* GetCurrentActivationFor(
469 DCHECK(!activations_.empty());
470 activations_.back()->SetCurrentFrame(frame_state);
474 uint32_t current_frame_size,
475 uint32_t current_stack_size,
476 uint32_t current_ref_stack_fp,
477 uint32_t current_ref_stack_frame_size) {
478 DCHECK(!activations_.empty());
479 activations_.back()->SetCurrentActivationFrame(
480 reinterpret_cast<uint8_t*
>(fp), current_frame_size, current_stack_size,
481 current_ref_stack_fp, current_ref_stack_frame_size);
485 Address frame_pointer)
const {
486 for (
size_t i = 0;
i < activations_.
size();
i++) {
487 if (activations_[
i]->GetFramePointer() == frame_pointer) {
488 return activations_[
i].get();
495 if (activations_.empty()) {
498 return activations_.back()->NextFrameAddress();
503 if (activations_.empty()) {
506 return activations_.back()->NextRefStackOffset();
510 return stack_mem() + current_stack_size_;
513 void EnsureRefStackSpace(
size_t new_size);
514 void ClearRefStackValues(
size_t index,
size_t count);
516 void StartExecutionTimer();
517 void StopExecutionTimer();
518 void TerminateExecutionTimers();
520 static void SetRuntimeLastWasmError(
Isolate* isolate,
524#ifdef V8_ENABLE_DRUMBRAKE_TRACING
525 uint32_t CurrentStackFrameStart()
const {
526 if (activations_.empty()) {
529 return activations_.back()->CurrentStackFrameStart();
533 uint32_t CurrentStackFrameSize()
const {
534 if (activations_.empty()) {
537 return activations_.back()->CurrentStackFrameSize();
542 void RaiseException(Isolate* isolate, MessageTemplate message);
548 return reinterpret_cast<uint8_t*
>(stack_mem_);
557 static constexpr uint32_t kInitialStackSize = 1 *
MB;
558 static constexpr uint32_t kStackSizeIncrement = 1 *
MB;
559 static constexpr uint32_t kMaxStackSize = 32 *
MB;
591 const uint8_t* module_start,
Zone* zone);
597 inline WasmBytecode* GetFunctionBytecode(uint32_t func_index);
600 const uint8_t* code_start,
const uint8_t* code_end);
603 return generated_code_size_.load(std::memory_order_relaxed);
607 void Preprocess(uint32_t function_index);
622 static void InitializeOncePerProcess();
623 static void GlobalTearDown();
624 static void NotifyIsolateDisposal(
Isolate* isolate);
627 uint32_t function_index, Address frame_pointer,
628 uint8_t* interpreter_fp, uint32_t ref_stack_offset,
629 const std::vector<WasmValue>& argument_values);
631 uint32_t function_index, Address frame_pointer,
632 uint8_t* interpreter_fp);
635 bool called_from_js);
637 inline WasmValue GetReturnValue(
int index)
const;
639 inline std::vector<WasmInterpreterStackEntry> GetInterpretedStack(
640 Address frame_pointer);
642 inline int GetFunctionIndex(Address frame_pointer,
int index)
const;
644 inline void SetTrapFunctionIndex(int32_t func_index);
647 return wasm_runtime_.get();
676#define MUSTTAIL [[clang::musttail]]
683#ifdef V8_ENABLE_DRUMBRAKE_TRACING
684extern char const* kInstructionHandlerNames[];
688template <
bool compact_handler>
1152 operator bool()
const {
return length > 0; }
1173template <
typename T>
1176 int64_t
r0,
double fp0);
1178template <
typename T>
1218#define DEFINE_INSTR_HANDLER(name) k_##name,
1221#ifdef V8_ENABLE_DRUMBRAKE_TRACING
1226#undef DEFINE_INSTR_HANDLER
1230 reinterpret_cast<Address>(code));
1231#ifdef V8_ENABLE_DRUMBRAKE_TRACING
1232 if (
v8_flags.trace_drumbrake_compact_bytecode) {
1233 printf(
"* ReadFnId %04x %s%s\n",
result,
1324 BlockIndex parent_or_matching_try_block_index,
1327 uint32_t first_param_slot_offset,
1328 uint32_t first_param_ref_stack_index,
1345 WasmBytecode(
int func_index,
const uint8_t* code_data,
size_t code_length,
1346 uint32_t stack_frame_size,
const FunctionSig* signature,
1349 const uint8_t* const_slots_data,
size_t const_slots_length,
1351 const std::map<CodeOffset, pc_t>&& code_pc_map);
1416 uint32_t catch_block_index)
const {
1468 int32_t parent_block_index, uint32_t stack_size,
1470 uint32_t first_block_index, uint32_t rets_slots_count,
1471 uint32_t params_slots_count, int32_t parent_try_block_index)
1498 for (
size_t i = 0;
i < params_count;
i++) {
1531 return static_cast<uint32_t
>(
code_.size());
1563 void Emit(
const void* buff,
size_t len) {
1564 code_.insert(
code_.end(),
static_cast<const uint8_t*
>(buff),
1565 static_cast<const uint8_t*
>(buff) + len);
1568 inline void I32Push(
bool emit =
true);
1569 inline void I64Push(
bool emit =
true);
1572 inline void F32Push(
bool emit =
true);
1573 inline void F64Push(
bool emit =
true);
1574 inline void S128Push(
bool emit =
true);
1599 }
else if (value_kind ==
kI8 || value_kind ==
kI16) {
1600 return stack_slot_kind ==
kI32;
1602 return value_kind == stack_slot_kind;
1613 uint32_t slot_offset =
PopSlot();
1623#ifdef V8_ENABLE_DRUMBRAKE_TRACING
1624 if (
v8_flags.trace_drumbrake_compact_bytecode) {
1625 printf(
"EmitSlotOffset %d\n", value);
1633 uint16_t u16 =
static_cast<uint16_t
>(
value);
1634 Emit(&u16,
sizeof(u16));
1639 Emit(&value,
sizeof(value));
1643#ifdef V8_ENABLE_DRUMBRAKE_TRACING
1644 if (
v8_flags.trace_drumbrake_compact_bytecode) {
1645 printf(
"EmitMemoryOffset %llu\n", value);
1653 uint32_t u32 =
static_cast<uint32_t
>(
value);
1654 Emit(&u32,
sizeof(u32));
1659 Emit(&value,
sizeof(value));
1667 Emit(&value,
sizeof(value));
1675 if (
pc != UINT_MAX) {
1681 int16_t
id = func_id;
1687 Emit(&
id,
sizeof(
id));
1689#ifdef V8_ENABLE_DRUMBRAKE_TRACING
1690 if (
v8_flags.trace_drumbrake_compact_bytecode) {
1691 printf(
"* EmitFnId %04x %s%s\n",
id, kInstructionHandlerNames[func_id],
1698 uint32_t to_slot_index,
bool copy_from_reg =
false);
1708 size_t* rets_slots_count,
1709 size_t* params_slots_count);
1746 bool FindSharedSlot(uint32_t stack_index, uint32_t* new_slot_index);
1776 template <
typename T>
1781 if constexpr (std::is_same_v<T, WasmRef>) {
1784 uint32_t slot_index =
static_cast<uint32_t
>(
slots_.size());
1790 uint32_t slot_index =
static_cast<uint32_t
>(
slots_.size());
1797 template <
typename T>
1799 if constexpr (std::is_same_v<T, int32_t>) {
1802 if constexpr (std::is_same_v<T, int64_t>) {
1805 if constexpr (std::is_same_v<T, float>) {
1808 if constexpr (std::is_same_v<T, double>) {
1811 if constexpr (std::is_same_v<T, Simd128>) {
1852 template <
typename T>
1854 if constexpr (std::is_same_v<T, WasmRef>) {
1858 if (slot_index == UINT_MAX) {
1862 slot_index =
static_cast<uint32_t
>(
slots_.size());
1873 template <
typename T>
1877 return new_slot_index;
1880#ifdef V8_ENABLE_DRUMBRAKE_TRACING
1881 void TracePushConstSlot(uint32_t slot_index);
1885#ifdef V8_ENABLE_DRUMBRAKE_TRACING
1886 if (
v8_flags.trace_drumbrake_bytecode_generator &&
1887 v8_flags.trace_drumbrake_execution_verbose) {
1888 printf(
" push - slot[%d] = %d\n",
stack_size(), slot_index);
1901#ifdef V8_ENABLE_DRUMBRAKE_TRACING
1902 void TracePushCopySlot(uint32_t from_stack_index);
1912#ifdef V8_ENABLE_DRUMBRAKE_TRACING
1913 if (
v8_flags.trace_drumbrake_bytecode_generator &&
1914 v8_flags.trace_drumbrake_execution_verbose) {
1924 uint32_t to_stack_index,
bool copy_from_reg);
1926 bool copy_from_reg);
1931 uint32_t slot_index =
stack_[stack_index];
1934#ifdef V8_ENABLE_DRUMBRAKE_TRACING
1935 TraceSetSlotType(stack_index, type);
1939#ifdef V8_ENABLE_DRUMBRAKE_TRACING
1940 void TraceSetSlotType(uint32_t stack_index,
ValueType typo);
1956 return static_cast<uint32_t
>(
stack_.
size() - 1);
1981 static bool HasSideEffects(
WasmOpcode opcode);
2068 bool was_current_instruction_reachable_;
2113#ifdef V8_ENABLE_DRUMBRAKE_TRACING
2114class InterpreterTracer final :
public Malloced {
2116 explicit InterpreterTracer(
int isolate_id)
2117 : isolate_id_(isolate_id),
2119 current_chunk_index_(0),
2121 if (0 != strcmp(
v8_flags.trace_drumbrake_filter.value(),
"*")) {
2122 std::stringstream
s(
v8_flags.trace_drumbrake_filter.value());
2123 for (
int i; s >>
i;) {
2124 traced_functions_.insert(
i);
2125 if (s.peek() ==
',') s.ignore();
2132 ~InterpreterTracer() { CloseFile(); }
2135 if (!ShouldRedirect()) {
2140 if (isolate_id_ >= 0) {
2141 base::SNPrintF(filename_,
"trace-%d-%d-%d.dbt",
2142 base::OS::GetCurrentProcessId(), isolate_id_,
2143 current_chunk_index_);
2145 base::SNPrintF(filename_,
"trace-%d-%d.dbt",
2146 base::OS::GetCurrentProcessId(), current_chunk_index_);
2150 if (file_ ==
nullptr) {
2151 file_ = base::OS::FOpen(filename_.begin(),
"w");
2157 if (!ShouldRedirect()) {
2162 base::Fclose(file_);
2166 bool ShouldTraceFunction(
int function_index)
const {
2167 return traced_functions_.empty() ||
2168 traced_functions_.find(function_index) != traced_functions_.end();
2171 void PrintF(
const char* format, ...);
2173 void CheckFileSize() {
2174 if (!ShouldRedirect()) {
2179 if (++write_count_ >= kWriteCountCheckInterval) {
2181 ::fseek(file_, 0L, SEEK_END);
2182 if (::ftell(file_) > kMaxFileSize) {
2184 current_chunk_index_ = (current_chunk_index_ + 1) % kFileChunksCount;
2190 FILE*
file()
const {
return file_; }
2193 static bool ShouldRedirect() {
return v8_flags.redirect_drumbrake_traces; }
2196 base::EmbeddedVector<char, 128> filename_;
2198 std::unordered_set<int> traced_functions_;
2199 int current_chunk_index_;
2200 int64_t write_count_;
2202 static const int64_t kWriteCountCheckInterval = 1000;
2203 static const int kFileChunksCount = 10;
2204 static const int64_t kMaxFileSize = 100 *
MB;
2209 void TracePop() { stack_.pop_back(); }
2211 void TraceSetSlotType(uint32_t index, uint32_t type) {
2212 if (stack_.size() <= index) stack_.resize(index + 1);
2213 stack_[
index].type_ = ValueType::FromRawBitField(type);
2216 template <
typename T>
2217 void TracePush(uint32_t slot_offset) {
2218 stack_.push_back({value_type<T>(), slot_offset});
2221 void TracePushCopy(uint32_t index) { stack_.push_back(stack_[index]); }
2223 void TraceUpdate(uint32_t stack_index, uint32_t slot_offset) {
2224 if (stack_.size() <= stack_index) stack_.resize(stack_index + 1);
2225 stack_[stack_index].slot_offset_ = slot_offset;
2228 void Print(WasmInterpreterRuntime* wasm_runtime,
const uint32_t* sp,
2229 size_t start_params,
size_t start_locals,
size_t start_stack,
2230 RegMode reg_mode, int64_t r0,
double fp0)
const;
2233 static void Print(WasmInterpreterRuntime* wasm_runtime, ValueType type,
2234 size_t index,
char kind,
const uint8_t* addr);
2235 void Print(WasmInterpreterRuntime* wasm_runtime,
size_t index,
char kind,
2236 const uint8_t* addr)
const {
2237 return Print(wasm_runtime,
type_, index,
kind, addr);
2241 uint32_t slot_offset_;
2245 std::vector<Slot> stack_;
static constexpr HeapType FromBits(uint32_t bits)
constexpr bool is_bottom() const
constexpr ValueKind kind() const
constexpr bool is_object_reference() const
static constexpr ValueType FromRawBitField(uint32_t bits)
std::vector< uint32_t > Stack
void resize(Stack::size_type count)
Stack::const_reference operator[](Stack::size_type pos) const
Stack::const_reference back() const
void reserve(Stack::size_type new_cap)
void push_back(const uint32_t &value)
Stack::reference operator[](Stack::size_type pos)
std::vector< Entry > history_
bool IsMultiMemory() const
uint32_t GetS128ConstSlot(Simd128 value)
static void PrintBytecodeCompressionStats()
void EmitI32Const(int32_t value)
static std::atomic< size_t > emitted_short_memory_offset_count_
int32_t EndBlock(WasmOpcode opcode)
ValueType GetParamType(const WasmBytecodeGenerator::BlockData &block_data, size_t index) const
uint32_t const_slots_start() const
void BeginElseBlock(uint32_t if_block_index, bool dummy)
void Pop(ValueKind kind, bool emit=true)
void EmitFnId(InstructionHandler func_id, uint32_t pc=UINT_MAX)
void CopyToSlotAndPop(ValueType value_type, uint32_t to, bool is_tee, bool copy_from_reg)
void(WasmBytecodeGenerator::*) MemIndexPopFunc(bool emit)
void EmitBranchOffset(uint32_t delta)
void EmitStackIndex(int32_t value)
std::vector< uint8_t > code_
uint32_t rets_slots_size_
void EmitBranchTableOffset(uint32_t delta, uint32_t code_pos)
void EmitCopySlot(ValueType value_type, uint32_t from_slot_index, uint32_t to_slot_index, bool copy_from_reg=false)
uint32_t _PushSlot(ValueType value_type)
std::vector< Simd128 > simd_immediates_
void SetSlotType(uint32_t stack_index, ValueType type)
base::SmallVector< uint32_t, 8 > br_table_labels_
bool TypeCheckAlwaysSucceeds(ValueType obj_type, HeapType type) const
const FunctionSig * GetFunctionSignature(uint32_t function_index) const
uint32_t GetF64ConstSlot(double value)
bool no_nested_emit_instr_handler_guard_
WasmEHDataGenerator eh_data_
void ITableIndexPush(bool is_table64, bool emit=true)
void PushSlot(uint32_t slot_index)
bool HasVoidSignature(const WasmBytecodeGenerator::BlockData &block_data) const
uint32_t function_index() const
std::unordered_map< float, uint32_t > f32_const_cache_
WasmBytecodeGenerator(const WasmBytecodeGenerator &)=delete
void(WasmBytecodeGenerator::*) MemIndexPushFunc(bool emit)
void EmitMemoryOffset(uint64_t value)
uint32_t CurrentCodePos() const
uint32_t CreateWasmRefSlot(ValueType value_type)
uint32_t CreateConstSlot(T value)
uint32_t CreateSlot(ValueType value_type)
uint32_t stack_top_index() const
void DecodeAtomicOp(WasmOpcode opcode, WasmInstruction::Optional *optional, Decoder *decoder, InterpreterCode *code, pc_t pc, int *const len)
base::SmallVector< uint32_t, 16 > loop_begin_code_offsets_
void Push(ValueType type)
uint32_t GetI32ConstSlot(int32_t value)
ValueKind GetTopStackType(RegMode reg_mode) const
uint32_t GetConstSlot(T value)
RegMode DoEncodeInstruction(const WasmInstruction &instr, RegMode curr_reg_mode, RegMode next_reg_mode)
void DecodeGCOp(WasmOpcode opcode, WasmInstruction::Optional *optional, Decoder *decoder, InterpreterCode *code, pc_t pc, int *const len)
void PushCopySlot(uint32_t from_stack_index)
std::map< CodeOffset, pc_t > code_pc_map_
ValueType GetReturnType(const WasmBytecodeGenerator::BlockData &block_data, size_t index) const
std::unordered_map< Simd128, uint32_t, Simd128Hash > s128_const_cache_
void I32Pop(bool emit=true)
uint32_t GetStackFrameSize() const
void EmitI16Const(int16_t value)
uint32_t const_slot_offset_
static const CodeOffset kInvalidCodeOffset
void StoreBlockParamsAndResultsIntoSlots(uint32_t target_block_index, WasmOpcode opcode)
void EmitTryCatchBranchOffset()
std::unordered_map< double, uint32_t > f64_const_cache_
static std::atomic< size_t > total_bytecode_size_
uint32_t ReturnsCount(const WasmBytecodeGenerator::BlockData &block_data) const
WasmBytecodeGenerator(uint32_t function_index, InterpreterCode *wasm_code, const WasmModule *module)
uint32_t ParamsCount(const WasmBytecodeGenerator::BlockData &block_data) const
std::unordered_map< int64_t, uint32_t > i64_const_cache_
bool DoEncodeSuperInstruction(RegMode ®_mode, const WasmInstruction &curr_instr, const WasmInstruction &next_instr)
void F32Push(bool emit=true)
int GetCurrentTryBlockIndex(bool return_matching_try_for_catch_blocks) const
uint32_t GetI64ConstSlot(int64_t value)
void EmitGlobalIndex(uint32_t index)
void RestoreIfElseParams(uint32_t if_block_index)
void MemIndexPop(bool emit=true)
uint32_t PushConstSlot(T value)
WasmInstruction DecodeInstruction(pc_t pc, Decoder &decoder)
std::unordered_map< int32_t, uint32_t > i32_const_cache_
void EmitF64Const(double value)
void S128Pop(bool emit=true)
void StoreBlockParamsIntoSlots(uint32_t target_block_index, bool update_stack)
void UpdateStack(uint32_t index, uint32_t slot_index)
uint32_t GetCurrentBranchDepth() const
bool EncodeSuperInstruction(RegMode ®_mode, const WasmInstruction &curr_instr, const WasmInstruction &next_instr)
bool HasSharedSlot(uint32_t stack_index) const
InterpreterCode * wasm_code_
ValueKind GetGlobalType(uint32_t index) const
void InitSlotsForFunctionArgs(const FunctionSig *sig, bool is_indirect_call)
uint32_t unreachable_block_count_
CodeOffset last_instr_offset_
MemIndexPushFunc int_mem_push_
uint32_t ReserveBlockSlots(uint8_t opcode, const WasmInstruction::Optional::Block &block_data, size_t *rets_slots_count, size_t *params_slots_count)
void PreserveArgsAndLocals()
void EmitRefStackIndex(int32_t value)
bool TypeCheckAlwaysFails(ValueType obj_type, HeapType expected_type, bool null_succeeds) const
void F64Push(bool emit=true)
void I64Push(bool emit=true)
int32_t current_block_index_
void EmitSlotOffset(uint32_t value)
int32_t BeginBlock(WasmOpcode opcode, const WasmInstruction::Optional::Block signature)
bool DecodeSimdOp(WasmOpcode opcode, WasmInstruction::Optional *optional, Decoder *decoder, InterpreterCode *code, pc_t pc, int *const len)
ValueType RefPop(bool emit=true)
void RefPush(ValueType type, bool emit=true)
void EmitIfElseBranchOffset()
uint32_t CreateSlot(ValueType value_type)
uint32_t ScanConstInstructions() const
bool TryCompactInstructionHandler(InstructionHandler func_addr)
InstrHandlerSize handler_size_
void EmitF32Const(float value)
void F64Pop(bool emit=true)
bool current_instr_encoding_failed_
void I32Push(bool emit=true)
RegMode EncodeInstruction(const WasmInstruction &instr, RegMode curr_reg_mode, RegMode next_reg_mode)
void EmitStructFieldOffset(int32_t value)
MemIndexPopFunc int_mem_pop_
const WasmModule * module_
void DecodeNumericOp(WasmOpcode opcode, WasmInstruction::Optional *optional, Decoder *decoder, InterpreterCode *code, pc_t pc, int *const len)
int32_t GetTargetBranch(uint32_t delta) const
uint32_t args_slots_size_
void UpdateStack(uint32_t index, uint32_t slot_index, ValueType value_type)
uint32_t GetF32ConstSlot(float value)
void EmitRefValueType(int32_t value)
bool FindSharedSlot(uint32_t stack_index, uint32_t *new_slot_index)
static std::atomic< size_t > emitted_short_slot_offset_count_
bool is_instruction_reachable_
uint32_t ref_slots_count_
void I64Pop(bool emit=true)
void SetUnreachableMode()
void Emit(const void *buff, size_t len)
std::vector< Slot > slots_
bool ToRegisterIsAllowed(const WasmInstruction &instr)
uint32_t stack_size() const
void F32Pop(bool emit=true)
WasmBytecodeGenerator & operator=(const WasmBytecodeGenerator &)=delete
void PatchBranchOffsets()
void S128Push(bool emit=true)
void CopyToSlot(ValueType value_type, uint32_t from_slot_index, uint32_t to_stack_index, bool copy_from_reg)
void PatchLoopBeginInstructions()
std::vector< BlockData > blocks_
std::vector< uint8_t > const_slots_values_
std::unique_ptr< WasmBytecode > GenerateBytecode()
void MemIndexPush(bool emit=true)
uint32_t args_slots_size_
static bool HasRefOrSimdArgs(const FunctionSig *sig)
uint32_t return_count() const
uint32_t args_count() const
ValueType return_type(size_t index) const
static uint32_t RefLocalsCount(const InterpreterCode *wasm_code)
std::vector< uint8_t > code_
uint32_t locals_slots_size_
const FunctionSig * GetFunctionSignature() const
static uint32_t JSToWasmWrapperPackedArraySize(const FunctionSig *sig)
uint32_t ref_slots_count_
WasmEHData::ExceptionPayloadSlotOffsets GetExceptionPayloadStartSlotOffsets(WasmEHData::BlockIndex catch_block_index) const
uint32_t total_frame_size_in_bytes_
bool InitializeSlots(uint8_t *sp, size_t stack_space) const
uint32_t locals_count() const
uint32_t ref_slots_count() const
size_t GetCodeSize() const
uint32_t locals_slots_size() const
uint32_t internal_ref_slots_count() const
uint32_t GetBlocksCount() const
WasmBytecode(int func_index, const uint8_t *code_data, size_t code_length, uint32_t stack_frame_size, const FunctionSig *signature, const CanonicalSig *canonical_signature, const InterpreterCode *interpreter_code, size_t blocks_count, const uint8_t *const_slots_data, size_t const_slots_length, uint32_t ref_slots_count, const WasmEHData &&eh_data, const std::map< CodeOffset, pc_t > &&code_pc_map)
static uint32_t RetsSizeInSlots(const FunctionSig *sig)
pc_t GetPcFromTrapCode(const uint8_t *current_code) const
const InterpreterCode * interpreter_code_
int GetFunctionIndex() const
const FunctionSig * signature_
const uint8_t * code_bytes_
DirectHandle< Object > GetCaughtException(Isolate *isolate, uint32_t catch_block_index) const
uint32_t ref_locals_count_
static uint32_t ArgsSizeInSlots(const FunctionSig *sig)
ValueType local_type(size_t index) const
const WasmEHData::TryBlock * GetParentTryBlock(const WasmEHData::TryBlock *try_block) const
uint32_t ref_rets_count() const
static bool ContainsSimd(const FunctionSig *sig)
static uint32_t LocalsSizeInSlots(const InterpreterCode *wasm_code)
ValueType arg_type(size_t index) const
uint32_t rets_slots_size() const
uint32_t ref_args_count() const
const CanonicalSig * canonical_signature_
uint32_t const_slots_size_in_bytes() const
uint32_t rets_slots_size_
std::map< CodeOffset, pc_t > code_pc_map_
std::vector< uint8_t > const_slots_values_
const CanonicalSig * GetCanonicalFunctionSignature() const
const uint8_t * GetCode() const
uint32_t ref_locals_count() const
static uint32_t RefArgsCount(const FunctionSig *sig)
static uint32_t RefRetsCount(const FunctionSig *sig)
uint32_t args_slots_size() const
const WasmEHData::TryBlock * GetTryBlock(CodeOffset code_offset) const
void AddCatchBlock(BlockIndex catch_block_index, int tag_index, uint32_t first_param_slot_offset, uint32_t first_param_ref_stack_index, CodeOffset code_offset)
BlockIndex current_try_block_index_
void AddTryBlock(BlockIndex try_block_index, BlockIndex parent_or_matching_try_block_index, BlockIndex ancestor_try_block_index)
void AddDelegatedBlock(BlockIndex delegated_try_block_index)
BlockIndex GetCurrentTryBlockIndex() const
void RecordPotentialExceptionThrowingInstruction(WasmOpcode opcode, CodeOffset code_offset)
BlockIndex EndTryCatchBlocks(BlockIndex block_index, CodeOffset code_offset)
ExceptionPayloadSlotOffsets GetExceptionPayloadStartSlotOffsets(BlockIndex catch_block_index) const
static const int kCatchAllTagIndex
std::unordered_map< BlockIndex, CatchBlock > catch_blocks_
void SetCaughtException(Isolate *isolate, BlockIndex catch_block_index, DirectHandle< Object > exception)
DirectHandle< Object > GetCaughtException(Isolate *isolate, BlockIndex catch_block_index) const
std::unordered_map< CodeOffset, BlockIndex > code_trycatch_map_
const TryBlock * GetTryBlock(CodeOffset code_offset) const
std::unordered_map< BlockIndex, TryBlock > try_blocks_
static const int kDelegateToCallerIndex
size_t GetEndInstructionOffsetFor(BlockIndex catch_block_index) const
BlockIndex GetTryBranchOf(BlockIndex catch_block_index) const
const TryBlock * GetParentTryBlock(const TryBlock *try_block) const
const TryBlock * GetDelegateTryBlock(const TryBlock *try_block) const
base::TimeTicks start_interval_time_
base::TimeTicks next_interval_time_
base::TimeDelta window_running_time_
const size_t slow_threshold_samples_count_
base::TimeDelta cooldown_interval_
std::vector< int > samples_
Histogram * slow_wasm_histogram_
base::ElapsedTimer window_execute_timer_
const int slow_threshold_
void BeginInterval(bool start_timer)
static const int kMaxPercentValue
const base::TimeDelta sample_duration_
Histogram * execute_ratio_histogram_
void AddSample(int running_ratio)
WasmExecutionTimer(Isolate *isolate, bool track_jitless_wasm)
std::unordered_map< int, std::unique_ptr< WasmInterpreterThread > > ThreadInterpreterMap
ThreadInterpreterMap map_
void SetCurrentActivationFrame(uint8_t *current_fp, uint32_t current_frame_size, uint32_t current_stack_size, uint32_t current_ref_stack_fp, uint32_t current_ref_stack_frame_size)
void SetCurrentFrame(const FrameState &frame_state)
uint32_t current_ref_stack_fp_
std::unique_ptr< std::vector< WasmInterpreterStackEntry > > trap_stack_trace_
const FrameState & GetCurrentFrame() const
WasmInterpreterThread * thread() const
WasmInterpreterRuntime * wasm_runtime_
Activation(WasmInterpreterThread *thread, WasmInterpreterRuntime *wasm_runtime, Address frame_pointer, uint8_t *start_fp, const FrameState &callee_frame_state)
uint32_t current_ref_stack_frame_size_
uint32_t current_frame_size_
void SetTrapped(int trap_function_index, int trap_pc)
WasmInterpreterThread * thread_
FrameState current_frame_state_
uint32_t NextRefStackOffset() const
Address GetFramePointer() const
std::vector< WasmInterpreterStackEntry > GetStackTrace()
uint8_t * NextFrameAddress() const
const WasmInterpreterRuntime * GetWasmRuntime() const
void Trap(TrapReason trap_reason, int trap_function_index, int trap_pc, const FrameState ¤t_frame)
bool ExpandStack(size_t additional_required_size)
TrapReason GetTrapReason() const
static void NotifyIsolateDisposal(Isolate *isolate)
void SetCurrentActivationFrame(uint32_t *fp, uint32_t current_frame_size, uint32_t current_stack_size, uint32_t current_ref_stack_fp, uint32_t current_ref_stack_frame_size)
static WasmInterpreterThreadMap * thread_interpreter_map_s
WasmInterpreterThread::Activation * GetActivation(Address frame_pointer) const
Handle< FixedArray > reference_stack() const
std::vector< std::unique_ptr< Activation > > activations_
uint32_t NextRefStackOffset() const
const uint8_t * StackLimitAddress() const
Handle< FixedArray > reference_stack_
uint8_t * stack_mem() const
size_t current_ref_stack_size_
WasmExecutionTimer execution_timer_
static WasmInterpreterThread * GetCurrentInterpreterThread(Isolate *isolate)
uint32_t current_stack_size_
const Isolate * GetIsolate() const
void SetCurrentFrame(const FrameState &frame_state)
uint8_t * NextFrameAddress() const
size_t TotalBytecodeSize()
std::atomic< size_t > generated_code_size_
const WasmModule * module() const
base::TimeDelta bytecode_generation_time_
const WasmModule * module_
ZoneVector< InterpreterCode > interpreter_code_
WasmInterpreter & operator=(const WasmInterpreter &)=delete
WasmInterpreterRuntime * GetWasmRuntime()
std::shared_ptr< WasmInterpreterRuntime > wasm_runtime_
IndirectHandle< WasmInstanceObject > instance_object_
const ZoneVector< uint8_t > module_bytes_
WasmInterpreter(const WasmInterpreter &)=delete
enum v8::internal::@1270::DeoptimizableCodeIterator::@67 state_
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 allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage * MB
#define FOREACH_INSTR_HANDLER(V)
ZoneVector< RpoNumber > & result
static V ReadUnalignedValue(Address p)
static void WriteUnalignedValue(Address p, V value)
RegMode GetRegMode(ValueKind kind)
ValueType value_type< int64_t >()
static ValueType value_type()
static const size_t kSlotSize
ValueType value_type< uint64_t >()
PWasmOp * kInstructionTable[kInstructionTableSize]
static const RegModeTransform kRegModes[256]
constexpr uint32_t kBranchOnCastDataTargetTypeBitSize
static const size_t kOperatorModeCount
InstructionHandler ReadFnId(const uint8_t *&code)
ValueType value_type< Simd128 >()
uint32_t WasmInterpreterRuntime int64_t r0
ValueType value_type< double >()
constexpr IndependentValueType kWasmF32
constexpr IndependentHeapType kWasmAnyRef
uint32_t WasmInterpreterRuntime * wasm_runtime
constexpr IndependentValueType kWasmI32
ValueType value_type< uint32_t >()
uint32_t WasmInterpreterRuntime int64_t double fp0
DirectHandle< Object > WasmRef
INSTRUCTION_HANDLER_FUNC trace_PushSlot(const uint8_t *code, uint32_t *sp, WasmInterpreterRuntime *wasm_runtime, int64_t r0, double fp0)
static const ptrdiff_t kCodeOffsetSize
static constexpr uint32_t kInstructionTableMask
InstructionHandler s_unwind_code
ValueType value_type< WasmRef >()
ValueType value_type< int32_t >()
typedef void(VECTORCALL PWasmOp)(const uint8_t *code
static constexpr uint32_t kInstructionTableSize
constexpr IndependentValueType kWasmS128
constexpr IndependentValueType kWasmF64
constexpr bool is_reference(ValueKind kind)
constexpr IndependentValueType kWasmI64
ValueType value_type< float >()
bool SetPermissions(v8::PageAllocator *page_allocator, void *address, size_t size, PageAllocator::Permission access)
v8::PageAllocator * GetPlatformPageAllocator()
void PrintF(const char *format,...)
wasm::WasmModule WasmModule
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
constexpr int kSystemPointerSize
int WriteChars(const char *filename, const char *str, int size, bool verbose)
V8_EXPORT_PRIVATE FlagValues v8_flags
wasm::WasmFunction WasmFunction
#define DCHECK_LE(v1, v2)
#define CHECK_GE(lhs, rhs)
#define CHECK_WITH_MSG(condition, message)
#define DCHECK_NOT_NULL(val)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
#define V8_EXPORT_PRIVATE
uint32_t target_type_bit_fields
WasmInterpreterThread * thread_
DirectHandle< Object > GetCaughtException(Isolate *isolate, uint32_t catch_block_index) const
void ResetHandleScope(Isolate *isolate)
const FrameState * previous_frame_
HandleScope * handle_scope_
void SetCaughtException(Isolate *isolate, uint32_t catch_block_index, DirectHandle< Object > exception)
const WasmBytecode * current_function_
Handle< FixedArray > caught_exceptions_
const uint8_t * current_bytecode_
uint32_t ref_array_current_sp_
void DisposeCaughtExceptionsArray(Isolate *isolate)
std::unique_ptr< WasmBytecode > bytecode
InterpreterCode(const WasmFunction *function, BodyLocalDecls locals, const uint8_t *start, const uint8_t *end)
const WasmFunction * function
const uint8_t * at(pc_t pc)
constexpr ValueKind kind() const
int32_t parent_block_index_
BlockData(WasmOpcode opcode, uint32_t begin_code_offset, int32_t parent_block_index, uint32_t stack_size, WasmInstruction::Optional::Block signature, uint32_t first_block_index, uint32_t rets_slots_count, uint32_t params_slots_count, int32_t parent_try_block_index)
uint32_t end_code_offset_
base::SmallVector< uint32_t, 4 > branch_code_offsets_
base::SmallVector< uint32_t, 4 > if_block_params_
uint32_t params_slots_count_
int32_t parent_try_block_index_
void SaveParams(uint32_t *from, size_t params_count)
WasmInstruction::Optional::Block signature_
uint32_t begin_code_offset_
uint32_t rets_slots_count_
uint32_t first_block_index_
int32_t if_else_block_index_
bool HasElseBranch() const
uint32_t GetParam(size_t index) const
size_t operator()(const Simd128 &s128) const
BlockIndex try_block_index
uint32_t first_param_ref_stack_index
uint32_t first_param_slot_offset
BlockIndex catch_block_index
uint32_t first_param_ref_stack_index
uint32_t first_param_slot_offset
TryBlock(BlockIndex parent_or_matching_try_block, BlockIndex ancestor_try_index)
BlockIndex delegate_try_index
void SetDelegated(BlockIndex delegate_try_idx)
std::vector< CatchHandler > catch_handlers
BlockIndex ancestor_try_index
bool IsTryDelegate() const
size_t end_instruction_code_offset
BlockIndex parent_or_matching_try_block
constexpr ValueType value_type() const
ModuleTypeIndex sig_index
uint32_t value_type_bitfield
constexpr bool is_bottom() const
uint32_t dest_array_index
uint32_t element_segment_index
WasmInstruction(uint8_t orig, WasmOpcode opcode, int length, uint32_t pc, Optional optional)
RegMode InputRegMode() const
bool SupportsToRegister() const
uint64_t memory_offset32_t
uint64_t memory_offset64_t
uint32_t memory_offset64_t
uint32_t memory_offset32_t
BranchOnCastData br_on_cast_data
struct v8::internal::wasm::WasmInstruction::Optional::Block block
struct v8::internal::wasm::WasmInstruction::Optional::BrTable br_table
struct v8::internal::wasm::WasmInstruction::Optional::SimdLaneLoad simd_loadstore_lane
struct v8::internal::wasm::WasmInstruction::Optional::TableInit table_init
struct v8::internal::wasm::WasmInstruction::Optional::GC_ArrayNewFixed gc_array_new_fixed
struct v8::internal::wasm::WasmInstruction::Optional::IndirectCall indirect_call
struct v8::internal::wasm::WasmInstruction::Optional::GC_FieldImmediate gc_field_immediate
uint32_t ref_type_bit_field
struct v8::internal::wasm::WasmInstruction::Optional::GC_ArrayCopy gc_array_copy
struct v8::internal::wasm::WasmInstruction::Optional::GC_MemoryImmediate gc_memory_immediate
struct v8::internal::wasm::WasmInstruction::Optional::GC_HeapTypeImmediate gc_heap_type_immediate
struct v8::internal::wasm::WasmInstruction::Optional::TableCopy table_copy
struct v8::internal::wasm::WasmInstruction::Optional::GC_ArrayNewOrInitData gc_array_new_or_init_data
size_t simd_immediate_index
#define V8_UNLIKELY(condition)
const wasm::WasmModule * module_
#define DEFINE_INSTR_HANDLER(name)
#define INSTRUCTION_HANDLER_FUNC