#ifndef V8_DEOPTIMIZER_DEOPTIMIZER_H_
#define V8_DEOPTIMIZER_DEOPTIMIZER_H_
#include <optional>
#include <vector>
#include "src/builtins/builtins.h"
#include "src/codegen/source-position.h"
#include "src/deoptimizer/deoptimize-reason.h"
#include "src/deoptimizer/frame-description.h"
#include "src/deoptimizer/translated-state.h"
#include "src/diagnostics/code-tracer.h"
#include "src/objects/js-function.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/sandbox/hardware-support.h"
#include "src/wasm/value-type.h"
#endif
namespace v8 {
namespace internal {
namespace wasm {
class WasmCode;
}
enum class BuiltinContinuationMode;
class DeoptimizedFrameInfo;
class Isolate;
class Deoptimizer : public Malloced {
public:
enum class CodeValidity : uint8_t {
kUnknown,
kInvalidated,
kInvalidatedOsr,
kUnaffected
};
struct DeoptInfo {
static constexpr int kUninitilizedDeoptId = std::numeric_limits<int>::min();
SourcePosition position;
int deopt_id = kUninitilizedDeoptId;
#ifdef DEBUG
uint32_t node_id;
#endif
DeoptimizeReason deopt_reason;
};
static DeoptInfo ComputeDeoptInfo(Tagged<Code> code, Address pc);
DeoptInfo GetDeoptInfo() {
if (deopt_info_.deopt_id == DeoptInfo::kUninitilizedDeoptId) {
deopt_info_ = ComputeDeoptInfo(compiled_code_, from_);
}
return deopt_info_;
}
static bool GetOutermostOuterLoopWithCodeKind(
Isolate* isolate, Tagged<JSFunction> function, BytecodeOffset osr_offset,
CodeKind outer_loop_code_kind, BytecodeOffset* outer_loop_osr_offset);
static const char* MessageFor(DeoptimizeKind kind);
DirectHandle<JSFunction> function() const;
DirectHandle<Code> compiled_code() const;
DeoptimizeKind deopt_kind() const { return deopt_kind_; }
CodeValidity code_validity() const {
DCHECK_NE(code_validity_, CodeValidity::kUnknown);
return code_validity_;
}
int output_count() const { return output_count_; }
BytecodeOffset bytecode_offset_in_outermost_frame() const {
return bytecode_offset_in_outermost_frame_;
}
static Deoptimizer* New(Address raw_function, DeoptimizeKind kind,
Address from, int fp_to_sp_delta, Isolate* isolate);
static Deoptimizer* Grab(Isolate* isolate);
static size_t DeleteForWasm(Isolate* isolate);
static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
int jsframe_index,
Isolate* isolate);
static void DeoptimizeFunction(Tagged<JSFunction> function,
LazyDeoptimizeReason reason,
Tagged<Code> code = {});
V8_EXPORT_PRIVATE static void DeoptimizeAll(Isolate* isolate);
static void DeoptimizeMarkedCode(Isolate* isolate);
static void DeoptimizeAllOptimizedCodeWithFunction(
Isolate* isolate, DirectHandle<SharedFunctionInfo> function);
static Address EnsureValidReturnAddress(Isolate* isolate, Address address);
~Deoptimizer();
void MaterializeHeapObjects();
void ProcessDeoptReason(DeoptimizeReason reason);
static void ComputeOutputFrames(Deoptimizer* deoptimizer);
V8_EXPORT_PRIVATE static Builtin GetDeoptimizationEntry(DeoptimizeKind kind);
static int input_offset() { return offsetof(Deoptimizer, input_); }
static int output_count_offset() {
return offsetof(Deoptimizer, output_count_);
}
static int output_offset() { return offsetof(Deoptimizer, output_); }
static int caller_frame_top_offset() {
return offsetof(Deoptimizer, caller_frame_top_);
}
#ifdef V8_ENABLE_CET_SHADOW_STACK
static constexpr int shadow_stack_offset() {
return offsetof(Deoptimizer, shadow_stack_);
}
static constexpr int shadow_stack_count_offset() {
return offsetof(Deoptimizer, shadow_stack_count_);
}
#endif
Isolate* isolate() const { return isolate_; }
static constexpr int kMaxNumberOfEntries = 16384;
static constexpr unsigned kFixedExitSizeMarker = kMaxUInt32;
V8_EXPORT_PRIVATE static const int kEagerDeoptExitSize;
V8_EXPORT_PRIVATE static const int kLazyDeoptExitSize;
V8_EXPORT_PRIVATE static const int kAdaptShadowStackOffsetToSubtract;
static void TraceMarkForDeoptimization(Isolate* isolate, Tagged<Code> code,
LazyDeoptimizeReason reason);
static void TraceEvictFromOptimizedCodeCache(Isolate* isolate,
Tagged<SharedFunctionInfo> sfi,
const char* reason);
static void PatchToJump(Address pc, Address new_pc);
static void ZapCode(Address start, Address end, RelocIterator& it);
private:
static bool DeoptExitIsInsideOsrLoop(Isolate* isolate,
Tagged<JSFunction> function,
BytecodeOffset deopt_exit_offset,
BytecodeOffset osr_offset,
CodeKind code_kind);
void QueueValueForMaterialization(Address output_address, Tagged<Object> obj,
const TranslatedFrame::iterator& iterator);
void QueueFeedbackVectorForMaterialization(
Address output_address, const TranslatedFrame::iterator& iterator);
Deoptimizer(Isolate* isolate, Tagged<JSFunction> function,
DeoptimizeKind kind, Address from, int fp_to_sp_delta);
void DeleteFrameDescriptions();
void DoComputeOutputFrames();
#if V8_ENABLE_WEBASSEMBLY
void DoComputeOutputFramesWasmImpl();
FrameDescription* DoComputeWasmLiftoffFrame(
TranslatedFrame& frame, wasm::NativeModule* native_module,
Tagged<WasmTrustedInstanceData> wasm_trusted_instance, int frame_index,
std::stack<intptr_t>& shadow_stack);
void GetWasmStackSlotsCounts(const wasm::FunctionSig* sig,
int* parameter_stack_slots,
int* return_stack_slots);
#endif
void DoComputeUnoptimizedFrame(TranslatedFrame* translated_frame,
int frame_index, bool goto_catch_handler);
void DoComputeInlinedExtraArguments(TranslatedFrame* translated_frame,
int frame_index);
void DoComputeConstructCreateStubFrame(TranslatedFrame* translated_frame,
int frame_index);
void DoComputeConstructInvokeStubFrame(TranslatedFrame* translated_frame,
int frame_index);
static Builtin TrampolineForBuiltinContinuation(BuiltinContinuationMode mode,
bool must_handle_result);
#if V8_ENABLE_WEBASSEMBLY
TranslatedValue TranslatedValueForWasmReturnKind(
std::optional<wasm::ValueKind> wasm_call_return_kind);
#endif
void DoComputeBuiltinContinuation(TranslatedFrame* translated_frame,
int frame_index,
BuiltinContinuationMode mode);
unsigned ComputeInputFrameAboveFpFixedSize() const;
unsigned ComputeInputFrameSize() const;
static unsigned ComputeIncomingArgumentSize(Tagged<Code> code);
bool tracing_enabled() const { return trace_scope_ != nullptr; }
bool verbose_tracing_enabled() const {
return v8_flags.trace_deopt_verbose && tracing_enabled();
}
CodeTracer::Scope* trace_scope() const { return trace_scope_; }
CodeTracer::Scope* verbose_trace_scope() const {
return v8_flags.trace_deopt_verbose ? trace_scope() : nullptr;
}
void TraceDeoptBegin(int optimization_id, BytecodeOffset bytecode_offset);
void TraceDeoptEnd(double deopt_duration);
#ifdef DEBUG
static void TraceFoundActivation(Isolate* isolate,
Tagged<JSFunction> function);
#endif
static void TraceDeoptAll(Isolate* isolate);
bool is_restart_frame() const { return restart_frame_index_ >= 0; }
Isolate* isolate_;
Tagged<JSFunction> function_;
Tagged<Code> compiled_code_;
#if V8_ENABLE_WEBASSEMBLY
wasm::WasmCode* compiled_optimized_wasm_code_ = nullptr;
#endif
unsigned deopt_exit_index_;
BytecodeOffset bytecode_offset_in_outermost_frame_ = BytecodeOffset::None();
DeoptimizeKind deopt_kind_;
Address from_;
int fp_to_sp_delta_;
bool deoptimizing_throw_;
int catch_handler_data_;
int catch_handler_pc_offset_;
int restart_frame_index_;
FrameDescription* input_;
int output_count_;
FrameDescription** output_;
intptr_t caller_frame_top_;
intptr_t caller_fp_;
intptr_t caller_pc_;
intptr_t caller_constant_pool_;
int actual_argument_count_;
intptr_t stack_fp_;
DeoptInfo deopt_info_;
CodeValidity code_validity_ = CodeValidity::kUnknown;
TranslatedState translated_state_;
struct ValueToMaterialize {
Address output_slot_address_;
TranslatedFrame::iterator value_;
};
std::vector<ValueToMaterialize> values_to_materialize_;
std::vector<ValueToMaterialize> feedback_vector_to_materialize_;
#ifdef V8_ENABLE_CET_SHADOW_STACK
intptr_t* shadow_stack_ = nullptr;
size_t shadow_stack_count_ = 0;
#endif
#ifdef DEBUG
DisallowGarbageCollection* disallow_garbage_collection_;
#endif
CodeTracer::Scope* const trace_scope_;
#if V8_ENABLE_WEBASSEMBLY && V8_TARGET_ARCH_32_BIT
std::optional<AccountingAllocator> alloc_;
std::optional<Zone> zone_;
#endif
#if V8_ENABLE_WEBASSEMBLY
std::optional<DisallowSandboxAccess> no_sandbox_access_during_wasm_deopt_;
#endif
friend class DeoptimizedFrameInfo;
friend class FrameDescription;
friend class FrameWriter;
};
}
}
#endif