#ifndef V8_EXECUTION_FRAMES_H_
#define V8_EXECUTION_FRAMES_H_
#include "include/v8-initialization.h"
#include "src/base/bounds.h"
#include "src/codegen/handler-table.h"
#include "src/codegen/safepoint-table.h"
#include "src/common/assert-scope.h"
#include "src/common/globals.h"
#include "src/objects/code.h"
#include "src/objects/deoptimization-data.h"
#include "src/objects/objects.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/wasm/stacks.h"
#include "src/wasm/wasm-code-manager.h"
#endif
namespace v8 {
namespace internal {
namespace wasm {
class WasmCode;
struct JumpBuffer;
class StackMemory;
}
class AbstractCode;
class Debug;
class ExternalCallbackScope;
class InnerPointerToCodeCache;
class Isolate;
class ObjectVisitor;
class Register;
class RootVisitor;
class StackFrameInfo;
class StackFrameIteratorBase;
class StringStream;
class ThreadLocalTop;
class WasmInstanceObject;
class WasmModuleObject;
#if V8_ENABLE_DRUMBRAKE
class Tuple2;
#endif
class StackHandlerConstants : public AllStatic {
public:
static const int kNextOffset = 0 * kSystemPointerSize;
static const int kPaddingOffset = 1 * kSystemPointerSize;
static const int kSize = kPaddingOffset + kSystemPointerSize;
static const int kSlotCount = kSize >> kSystemPointerSizeLog2;
};
class StackHandler {
public:
inline Address address() const;
inline StackHandler* next() const;
inline Address next_address() const;
static inline StackHandler* FromAddress(Address address);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler);
};
#define STACK_FRAME_TYPE_LIST(V) \
V(ENTRY, EntryFrame) \
V(CONSTRUCT_ENTRY, ConstructEntryFrame) \
V(EXIT, ExitFrame) \
IF_WASM(V, WASM, WasmFrame) \
IF_WASM(V, WASM_TO_JS, WasmToJsFrame) \
IF_WASM(V, JS_TO_WASM, JsToWasmFrame) \
IF_WASM(V, WASM_JSPI, WasmJspiFrame) \
IF_WASM_DRUMBRAKE(V, WASM_INTERPRETER_ENTRY, WasmInterpreterEntryFrame) \
IF_WASM(V, WASM_DEBUG_BREAK, WasmDebugBreakFrame) \
IF_WASM(V, C_WASM_ENTRY, CWasmEntryFrame) \
\
IF_WASM(V, WASM_STACK_ENTRY, WasmStackEntryFrame) \
IF_WASM(V, WASM_STACK_EXIT, WasmStackExitFrame) \
IF_WASM(V, WASM_EXIT, WasmExitFrame) \
IF_WASM(V, WASM_LIFTOFF_SETUP, WasmLiftoffSetupFrame) \
IF_WASM(V, WASM_SEGMENT_START, WasmSegmentStartFrame) \
V(INTERPRETED, InterpretedFrame) \
V(BASELINE, BaselineFrame) \
V(MAGLEV, MaglevFrame) \
V(TURBOFAN_JS, TurbofanJSFrame) \
V(STUB, StubFrame) \
V(TURBOFAN_STUB_WITH_CONTEXT, TurbofanStubWithContextFrame) \
V(BUILTIN_CONTINUATION, BuiltinContinuationFrame) \
V(JAVASCRIPT_BUILTIN_CONTINUATION, JavaScriptBuiltinContinuationFrame) \
V(JAVASCRIPT_BUILTIN_CONTINUATION_WITH_CATCH, \
JavaScriptBuiltinContinuationWithCatchFrame) \
V(INTERNAL, InternalFrame) \
V(CONSTRUCT, ConstructFrame) \
V(FAST_CONSTRUCT, FastConstructFrame) \
V(BUILTIN, BuiltinFrame) \
V(BUILTIN_EXIT, BuiltinExitFrame) \
V(API_CALLBACK_EXIT, ApiCallbackExitFrame) \
V(API_ACCESSOR_EXIT, ApiAccessorExitFrame) \
V(NATIVE, NativeFrame) \
V(IRREGEXP, IrregexpFrame)
class StackFrame {
public:
#define DECLARE_TYPE(type, ignore) type,
enum Type {
NO_FRAME_TYPE = 0,
STACK_FRAME_TYPE_LIST(DECLARE_TYPE) NUMBER_OF_TYPES,
MANUAL
};
#undef DECLARE_TYPE
enum JsFrameMarker {
INNER_JSENTRY_FRAME = (0 << kSmiTagSize) | kSmiTag,
OUTERMOST_JSENTRY_FRAME = (1 << kSmiTagSize) | kSmiTag
};
static_assert((INNER_JSENTRY_FRAME & kHeapObjectTagMask) != kHeapObjectTag);
static_assert((OUTERMOST_JSENTRY_FRAME & kHeapObjectTagMask) !=
kHeapObjectTag);
struct State {
Address sp = kNullAddress;
Address fp = kNullAddress;
Address* pc_address = nullptr;
Address callee_fp = kNullAddress;
Address callee_pc = kNullAddress;
Address* constant_pool_address = nullptr;
bool is_profiler_entry_frame = false;
bool is_stack_exit_frame = false;
};
static constexpr int32_t TypeToMarker(Type type) {
DCHECK_GE(type, 0);
return (type << kSmiTagSize) | kSmiTag;
}
static constexpr Type MarkerToType(intptr_t marker) {
DCHECK(IsTypeMarker(marker));
return static_cast<Type>(marker >> kSmiTagSize);
}
static constexpr bool IsTypeMarker(uintptr_t function_or_marker) {
static_assert(kSmiTag == 0);
static_assert((std::numeric_limits<uintptr_t>::max() >> kSmiTagSize) >
Type::NUMBER_OF_TYPES);
return (function_or_marker & kSmiTagMask) == kSmiTag &&
function_or_marker < (Type::NUMBER_OF_TYPES << kSmiTagSize);
}
StackFrame(const StackFrame& original) V8_NOEXCEPT
: iterator_(nullptr),
isolate_(original.isolate_),
state_(original.state_) {}
bool is_entry() const { return type() == ENTRY; }
bool is_construct_entry() const { return type() == CONSTRUCT_ENTRY; }
bool is_exit() const { return type() == EXIT; }
bool is_optimized_js() const {
static_assert(TURBOFAN_JS == MAGLEV + 1);
return base::IsInRange(type(), MAGLEV, TURBOFAN_JS);
}
bool is_unoptimized_js() const {
static_assert(BASELINE == INTERPRETED + 1);
return base::IsInRange(type(), INTERPRETED, BASELINE);
}
bool is_interpreted() const { return type() == INTERPRETED; }
bool is_baseline() const { return type() == BASELINE; }
bool is_maglev() const { return type() == MAGLEV; }
bool is_turbofan_js() const { return type() == TURBOFAN_JS; }
#if V8_ENABLE_WEBASSEMBLY
bool is_wasm() const {
return this->type() == WASM || this->type() == WASM_SEGMENT_START
#ifdef V8_ENABLE_DRUMBRAKE
|| this->type() == WASM_INTERPRETER_ENTRY
#endif
;
}
bool is_c_wasm_entry() const { return type() == C_WASM_ENTRY; }
bool is_wasm_liftoff_setup() const { return type() == WASM_LIFTOFF_SETUP; }
#if V8_ENABLE_DRUMBRAKE
bool is_wasm_interpreter_entry() const {
return type() == WASM_INTERPRETER_ENTRY;
}
#endif
bool is_wasm_debug_break() const { return type() == WASM_DEBUG_BREAK; }
bool is_wasm_to_js() const { return type() == WASM_TO_JS; }
bool is_js_to_wasm() const { return type() == JS_TO_WASM; }
#endif
bool is_builtin() const { return type() == BUILTIN; }
bool is_internal() const { return type() == INTERNAL; }
bool is_builtin_continuation() const {
return type() == BUILTIN_CONTINUATION;
}
bool is_javascript_builtin_continuation() const {
return type() == JAVASCRIPT_BUILTIN_CONTINUATION;
}
bool is_javascript_builtin_with_catch_continuation() const {
return type() == JAVASCRIPT_BUILTIN_CONTINUATION_WITH_CATCH;
}
bool is_construct() const { return type() == CONSTRUCT; }
bool is_fast_construct() const { return type() == FAST_CONSTRUCT; }
bool is_builtin_exit() const { return type() == BUILTIN_EXIT; }
bool is_api_accessor_exit() const { return type() == API_ACCESSOR_EXIT; }
bool is_api_callback_exit() const { return type() == API_CALLBACK_EXIT; }
bool is_irregexp() const { return type() == IRREGEXP; }
static bool IsJavaScript(Type t) {
static_assert(INTERPRETED + 1 == BASELINE);
static_assert(BASELINE + 1 == MAGLEV);
static_assert(MAGLEV + 1 == TURBOFAN_JS);
return t >= INTERPRETED && t <= TURBOFAN_JS;
}
bool is_javascript() const { return IsJavaScript(type()); }
Address sp() const {
DCHECK(!InFastCCall());
return state_.sp;
}
Address fp() const { return state_.fp; }
Address callee_fp() const { return state_.callee_fp; }
Address callee_pc() const { return state_.callee_pc; }
Address caller_sp() const { return GetCallerStackPointer(); }
inline Address pc() const;
bool is_profiler_entry_frame() const {
return state_.is_profiler_entry_frame;
}
bool is_stack_exit_frame() const { return state_.is_stack_exit_frame; }
inline Address unauthenticated_pc() const;
static inline Address unauthenticated_pc(Address* pc_address);
inline Address maybe_unauthenticated_pc() const;
static inline Address maybe_unauthenticated_pc(Address* pc_address);
bool InFastCCall() const { return state_.sp == kNullAddress; }
Address constant_pool() const { return *constant_pool_address(); }
void set_constant_pool(Address constant_pool) {
*constant_pool_address() = constant_pool;
}
Address* pc_address() const { return state_.pc_address; }
Address* constant_pool_address() const {
return state_.constant_pool_address;
}
StackFrameId id() const { return static_cast<StackFrameId>(caller_sp()); }
inline StackHandler* top_handler() const;
virtual Type type() const = 0;
virtual Tagged<HeapObject> unchecked_code() const = 0;
V8_EXPORT_PRIVATE Tagged<Code> LookupCode() const;
V8_EXPORT_PRIVATE std::pair<Tagged<Code>, int> LookupCodeAndOffset() const;
V8_EXPORT_PRIVATE Tagged<GcSafeCode> GcSafeLookupCode() const;
V8_EXPORT_PRIVATE std::pair<Tagged<GcSafeCode>, int>
GcSafeLookupCodeAndOffset() const;
virtual void Iterate(RootVisitor* v) const = 0;
void IteratePc(RootVisitor* v, Address* constant_pool_address,
Tagged<GcSafeCode> holder) const;
static void SetReturnAddressLocationResolver(
ReturnAddressLocationResolver resolver);
static inline Address ReadPC(Address* pc_address);
static inline Address* ResolveReturnAddressLocation(Address* pc_address);
enum PrintMode { OVERVIEW, DETAILS };
virtual void Print(StringStream* accumulator, PrintMode mode,
int index) const;
Isolate* isolate() const { return isolate_; }
void operator=(const StackFrame& original) = delete;
protected:
inline explicit StackFrame(StackFrameIteratorBase* iterator);
virtual Address GetCallerStackPointer() const = 0;
const StackFrameIteratorBase* const iterator_;
private:
Isolate* const isolate_;
State state_;
static ReturnAddressLocationResolver return_address_location_resolver_;
virtual void ComputeCallerState(State* state) const = 0;
virtual Type GetCallerState(State* state) const;
static const intptr_t kIsolateTag = 1;
friend class StackFrameIterator;
friend class StackFrameIteratorBase;
friend class StackHandlerIterator;
friend class StackFrameIteratorForProfiler;
};
class CommonFrame;
class V8_EXPORT_PRIVATE FrameSummary {
public:
#define FRAME_SUMMARY_VARIANTS(F) \
F(JAVASCRIPT, JavaScriptFrameSummary, javascript_summary_, JavaScript) \
IF_WASM(F, BUILTIN, BuiltinFrameSummary, builtin_summary_, Builtin) \
IF_WASM(F, WASM, WasmFrameSummary, wasm_summary_, Wasm) \
IF_WASM_DRUMBRAKE(F, WASM_INTERPRETED, WasmInterpretedFrameSummary, \
wasm_interpreted_summary_, WasmInterpreted) \
IF_WASM(F, WASM_INLINED, WasmInlinedFrameSummary, wasm_inlined_summary_, \
WasmInlined)
#define FRAME_SUMMARY_KIND(kind, type, field, desc) kind,
enum Kind { FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_KIND) };
#undef FRAME_SUMMARY_KIND
class FrameSummaryBase {
public:
FrameSummaryBase(Isolate* isolate, Kind kind)
: isolate_(isolate), kind_(kind) {}
Isolate* isolate() const { return isolate_; }
Kind kind() const { return kind_; }
private:
Isolate* isolate_;
Kind kind_;
};
class JavaScriptFrameSummary : public FrameSummaryBase {
public:
JavaScriptFrameSummary(Isolate* isolate, Tagged<Object> receiver,
Tagged<JSFunction> function,
Tagged<AbstractCode> abstract_code, int code_offset,
bool is_constructor, Tagged<FixedArray> parameters);
void EnsureSourcePositionsAvailable();
bool AreSourcePositionsAvailable() const;
Handle<Object> receiver() const { return receiver_; }
Handle<JSFunction> function() const { return function_; }
Handle<AbstractCode> abstract_code() const { return abstract_code_; }
int code_offset() const { return code_offset_; }
bool is_constructor() const { return is_constructor_; }
DirectHandle<FixedArray> parameters() const { return parameters_; }
bool is_subject_to_debugging() const;
int SourcePosition() const;
int SourceStatementPosition() const;
Handle<Object> script() const;
DirectHandle<Context> native_context() const;
DirectHandle<StackFrameInfo> CreateStackFrameInfo() const;
private:
Handle<Object> receiver_;
Handle<JSFunction> function_;
Handle<AbstractCode> abstract_code_;
int code_offset_;
bool is_constructor_;
Handle<FixedArray> parameters_;
};
#if V8_ENABLE_WEBASSEMBLY
class WasmFrameSummary : public FrameSummaryBase {
public:
WasmFrameSummary(Isolate* isolate,
Handle<WasmTrustedInstanceData> instance_data,
wasm::WasmCode* code, int byte_offset, int function_index,
bool at_to_number_conversion);
Handle<Object> receiver() const;
uint32_t function_index() const;
wasm::WasmCode* code() const { return code_; }
int code_offset() const { return byte_offset_; }
bool is_constructor() const { return false; }
bool is_subject_to_debugging() const { return true; }
int SourcePosition() const;
int SourceStatementPosition() const { return SourcePosition(); }
Handle<Script> script() const;
DirectHandle<WasmInstanceObject> wasm_instance() const;
DirectHandle<WasmTrustedInstanceData> wasm_trusted_instance_data() const {
return instance_data_;
}
DirectHandle<Context> native_context() const;
bool at_to_number_conversion() const { return at_to_number_conversion_; }
DirectHandle<StackFrameInfo> CreateStackFrameInfo() const;
private:
Handle<WasmTrustedInstanceData> instance_data_;
bool at_to_number_conversion_;
wasm::WasmCode* code_;
int byte_offset_;
int function_index_;
};
class WasmInlinedFrameSummary : public FrameSummaryBase {
public:
WasmInlinedFrameSummary(Isolate* isolate,
Handle<WasmTrustedInstanceData> instance_data,
int function_index, int op_wire_bytes_offset);
DirectHandle<WasmInstanceObject> wasm_instance() const;
DirectHandle<WasmTrustedInstanceData> wasm_trusted_instance_data() const {
return instance_data_;
}
Handle<Object> receiver() const;
uint32_t function_index() const;
int code_offset() const { return op_wire_bytes_offset_; }
bool is_constructor() const { return false; }
bool is_subject_to_debugging() const { return true; }
Handle<Script> script() const;
int SourcePosition() const;
int SourceStatementPosition() const { return SourcePosition(); }
DirectHandle<Context> native_context() const;
DirectHandle<StackFrameInfo> CreateStackFrameInfo() const;
private:
Handle<WasmTrustedInstanceData> instance_data_;
int function_index_;
int op_wire_bytes_offset_;
};
class BuiltinFrameSummary : public FrameSummaryBase {
public:
BuiltinFrameSummary(Isolate*, Builtin);
Builtin builtin() const { return builtin_; }
Handle<Object> receiver() const;
int code_offset() const { return 0; }
bool is_constructor() const { return false; }
bool is_subject_to_debugging() const { return false; }
Handle<Object> script() const;
int SourcePosition() const { return kNoSourcePosition; }
int SourceStatementPosition() const { return 0; }
DirectHandle<Context> native_context() const;
DirectHandle<StackFrameInfo> CreateStackFrameInfo() const;
private:
Builtin builtin_;
};
#if V8_ENABLE_DRUMBRAKE
class WasmInterpretedFrameSummary : public FrameSummaryBase {
public:
WasmInterpretedFrameSummary(Isolate*, Handle<WasmInstanceObject>,
uint32_t function_index, int byte_offset);
Handle<WasmInstanceObject> wasm_instance() const { return wasm_instance_; }
Handle<WasmTrustedInstanceData> instance_data() const;
uint32_t function_index() const { return function_index_; }
int byte_offset() const { return byte_offset_; }
Handle<Object> receiver() const;
int code_offset() const { return byte_offset_; }
bool is_constructor() const { return false; }
bool is_subject_to_debugging() const { return true; }
int SourcePosition() const;
int SourceStatementPosition() const { return SourcePosition(); }
Handle<Script> script() const;
DirectHandle<Context> native_context() const;
DirectHandle<StackFrameInfo> CreateStackFrameInfo() const;
private:
Handle<WasmInstanceObject> wasm_instance_;
uint32_t function_index_;
int byte_offset_;
};
#endif
#endif
#define FRAME_SUMMARY_CONS(kind, type, field, desc) \
FrameSummary(type summ) : field(summ) {}
FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_CONS)
#undef FRAME_SUMMARY_CONS
~FrameSummary();
static FrameSummary GetTop(const CommonFrame* frame);
static FrameSummary GetBottom(const CommonFrame* frame);
static FrameSummary GetSingle(const CommonFrame* frame);
static FrameSummary Get(const CommonFrame* frame, int index);
void EnsureSourcePositionsAvailable();
bool AreSourcePositionsAvailable() const;
Handle<Object> receiver() const;
int code_offset() const;
bool is_constructor() const;
bool is_subject_to_debugging() const;
Handle<Object> script() const;
int SourcePosition() const;
int SourceStatementPosition() const;
DirectHandle<Context> native_context() const;
DirectHandle<StackFrameInfo> CreateStackFrameInfo() const;
#define FRAME_SUMMARY_CAST(kind_, type, field, desc) \
bool Is##desc() const { return base_.kind() == kind_; } \
const type& As##desc() const { \
DCHECK_EQ(base_.kind(), kind_); \
return field; \
}
FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_CAST)
#undef FRAME_SUMMARY_CAST
private:
#define FRAME_SUMMARY_FIELD(kind, type, field, desc) type field;
union {
FrameSummaryBase base_;
FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_FIELD)
};
#undef FRAME_SUMMARY_FIELD
};
struct FrameSummaries {
std::vector<FrameSummary> frames;
bool top_frame_is_construct_call = false;
FrameSummaries() = default;
explicit FrameSummaries(FrameSummary summary) : frames() {
frames.push_back(summary);
}
int size() const { return static_cast<int>(frames.size()); }
};
class CommonFrame : public StackFrame {
public:
virtual Tagged<Object> context()
const;
virtual int position() const;
inline Tagged<Object> GetExpression(int index) const;
inline void SetExpression(int index, Tagged<Object> value);
int ComputeExpressionsCount() const;
Address GetCallerStackPointer() const override;
virtual FrameSummaries Summarize() const;
static CommonFrame* cast(StackFrame* frame) {
return static_cast<CommonFrame*>(frame);
}
protected:
inline explicit CommonFrame(StackFrameIteratorBase* iterator);
bool HasTaggedOutgoingParams(Tagged<GcSafeCode> code_lookup) const;
void ComputeCallerState(State* state) const override;
inline Address caller_fp() const;
inline Address caller_pc() const;
void IterateExpressions(RootVisitor* v) const;
void IterateTurbofanJSOptimizedFrame(RootVisitor* v) const;
virtual Address GetExpressionAddress(int n) const;
};
class TurbofanStubWithContextFrame : public CommonFrame {
public:
Type type() const override { return TURBOFAN_STUB_WITH_CONTEXT; }
Tagged<HeapObject> unchecked_code() const override;
void Iterate(RootVisitor* v) const override;
protected:
inline explicit TurbofanStubWithContextFrame(
StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class TypedFrame : public CommonFrame {
public:
Tagged<HeapObject> unchecked_code() const override { return {}; }
void Iterate(RootVisitor* v) const override;
void IterateParamsOfGenericWasmToJSWrapper(RootVisitor* v) const;
protected:
inline explicit TypedFrame(StackFrameIteratorBase* iterator);
};
class CommonFrameWithJSLinkage : public CommonFrame {
public:
virtual Tagged<JSFunction> function() const = 0;
virtual Tagged<Object> receiver() const;
virtual Tagged<Object> GetParameter(int index) const;
virtual int ComputeParametersCount() const;
DirectHandle<FixedArray> GetParameters() const;
virtual int GetActualArgumentCount() const;
Tagged<HeapObject> unchecked_code() const override;
virtual int LookupExceptionHandlerInTable(
int* data, HandlerTable::CatchPrediction* prediction);
virtual bool IsConstructor() const;
FrameSummaries Summarize() const override;
protected:
inline explicit CommonFrameWithJSLinkage(StackFrameIteratorBase* iterator);
static inline bool IsConstructFrame(Address fp);
inline Address GetParameterSlot(int index) const;
};
class TypedFrameWithJSLinkage : public CommonFrameWithJSLinkage {
public:
void Iterate(RootVisitor* v) const override;
protected:
inline explicit TypedFrameWithJSLinkage(StackFrameIteratorBase* iterator);
};
class JavaScriptFrame : public CommonFrameWithJSLinkage {
public:
Type type() const override = 0;
Tagged<JSFunction> function() const override;
Tagged<Object> unchecked_function() const;
Tagged<Script> script() const;
Tagged<Object> context() const override;
int GetActualArgumentCount() const override;
inline void set_receiver(Tagged<Object> value);
void SetParameterValue(int index, Tagged<Object> value) const;
bool IsConstructor() const override;
void Iterate(RootVisitor* v) const override;
void Print(StringStream* accumulator, PrintMode mode,
int index) const override;
virtual void GetFunctions(
std::vector<Tagged<SharedFunctionInfo>>* functions) const;
void GetFunctions(std::vector<Handle<SharedFunctionInfo>>* functions) const;
std::tuple<Tagged<AbstractCode>, int> GetActiveCodeAndOffset() const;
static Register fp_register();
static Register context_register();
static Register constant_pool_pointer_register();
bool is_unoptimized() const { return is_unoptimized_js(); }
bool is_optimized() const { return is_optimized_js(); }
bool is_turbofan() const { return is_turbofan_js(); }
static JavaScriptFrame* cast(StackFrame* frame) {
DCHECK(frame->is_javascript());
return static_cast<JavaScriptFrame*>(frame);
}
static void PrintFunctionAndOffset(Isolate* isolate,
Tagged<JSFunction> function,
Tagged<AbstractCode> code, int code_offset,
FILE* file, bool print_line_number);
static void PrintTop(Isolate* isolate, FILE* file, bool print_args,
bool print_line_number);
static void CollectFunctionAndOffsetForICStats(Isolate* isolate,
Tagged<JSFunction> function,
Tagged<AbstractCode> code,
int code_offset);
protected:
inline explicit JavaScriptFrame(StackFrameIteratorBase* iterator);
Address GetCallerStackPointer() const override;
virtual void PrintFrameKind(StringStream* accumulator) const {}
private:
inline Tagged<Object> function_slot_object() const;
friend class StackFrameIteratorBase;
};
class NativeFrame : public TypedFrame {
public:
Type type() const override { return NATIVE; }
void Iterate(RootVisitor* v) const override {}
protected:
inline explicit NativeFrame(StackFrameIteratorBase* iterator);
private:
void ComputeCallerState(State* state) const override;
friend class StackFrameIteratorBase;
};
class EntryFrame : public TypedFrame {
public:
Type type() const override { return ENTRY; }
Tagged<HeapObject> unchecked_code() const override;
void Iterate(RootVisitor* v) const override;
static EntryFrame* cast(StackFrame* frame) {
DCHECK(frame->is_entry());
return static_cast<EntryFrame*>(frame);
}
protected:
inline explicit EntryFrame(StackFrameIteratorBase* iterator);
Address GetCallerStackPointer() const override { return 0; }
private:
void ComputeCallerState(State* state) const override;
Type GetCallerState(State* state) const override;
friend class StackFrameIteratorBase;
};
class ConstructEntryFrame : public EntryFrame {
public:
Type type() const override { return CONSTRUCT_ENTRY; }
Tagged<HeapObject> unchecked_code() const override;
static ConstructEntryFrame* cast(StackFrame* frame) {
DCHECK(frame->is_construct_entry());
return static_cast<ConstructEntryFrame*>(frame);
}
protected:
inline explicit ConstructEntryFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class ExitFrame : public TypedFrame {
public:
Type type() const override { return EXIT; }
void Iterate(RootVisitor* v) const override;
static ExitFrame* cast(StackFrame* frame) {
DCHECK(frame->is_exit());
return static_cast<ExitFrame*>(frame);
}
static Type GetStateForFramePointer(Address fp, State* state);
static Address ComputeStackPointer(Address fp);
static StackFrame::Type ComputeFrameType(Address fp);
static void FillState(Address fp, Address sp, State* state);
protected:
inline explicit ExitFrame(StackFrameIteratorBase* iterator);
private:
void ComputeCallerState(State* state) const override;
friend class StackFrameIteratorBase;
};
class BuiltinExitFrame : public ExitFrame {
public:
Type type() const override { return BUILTIN_EXIT; }
Tagged<JSFunction> function() const;
Tagged<Object> receiver() const;
Tagged<Object> GetParameter(int i) const;
int ComputeParametersCount() const;
DirectHandle<FixedArray> GetParameters() const;
bool IsConstructor() const;
void Print(StringStream* accumulator, PrintMode mode,
int index) const override;
FrameSummaries Summarize() const override;
protected:
inline explicit BuiltinExitFrame(StackFrameIteratorBase* iterator);
private:
inline Tagged<Object> receiver_slot_object() const;
inline Tagged<Object> argc_slot_object() const;
inline Tagged<Object> target_slot_object() const;
inline Tagged<Object> new_target_slot_object() const;
friend class StackFrameIteratorBase;
};
class ApiCallbackExitFrame : public ExitFrame {
public:
Type type() const override { return API_CALLBACK_EXIT; }
DirectHandle<JSFunction> GetFunction() const;
DirectHandle<FunctionTemplateInfo> GetFunctionTemplateInfo() const;
inline Tagged<Object> receiver() const;
inline Tagged<Object> GetParameter(int i) const;
inline int ComputeParametersCount() const;
DirectHandle<FixedArray> GetParameters() const;
inline Tagged<Object> context() const override;
inline bool IsConstructor() const;
void Print(StringStream* accumulator, PrintMode mode,
int index) const override;
FrameSummaries Summarize() const override;
static ApiCallbackExitFrame* cast(StackFrame* frame) {
DCHECK(frame->is_api_callback_exit());
return static_cast<ApiCallbackExitFrame*>(frame);
}
protected:
inline explicit ApiCallbackExitFrame(StackFrameIteratorBase* iterator);
private:
inline Tagged<HeapObject> target() const;
inline void set_target(Tagged<HeapObject> function) const;
inline FullObjectSlot target_slot() const;
friend class StackFrameIteratorBase;
};
class ApiAccessorExitFrame : public ExitFrame {
public:
Type type() const override { return API_ACCESSOR_EXIT; }
inline Tagged<Name> property_name() const;
inline Tagged<Object> receiver() const;
inline Tagged<Object> holder() const;
void Print(StringStream* accumulator, PrintMode mode,
int index) const override;
FrameSummaries Summarize() const override;
static ApiAccessorExitFrame* cast(StackFrame* frame) {
DCHECK(frame->is_api_accessor_exit());
return static_cast<ApiAccessorExitFrame*>(frame);
}
protected:
inline explicit ApiAccessorExitFrame(StackFrameIteratorBase* iterator);
private:
inline FullObjectSlot property_name_slot() const;
inline FullObjectSlot receiver_slot() const;
inline FullObjectSlot holder_slot() const;
friend class StackFrameIteratorBase;
};
class StubFrame : public TypedFrame {
public:
Type type() const override { return STUB; }
Tagged<HeapObject> unchecked_code() const override;
int LookupExceptionHandlerInTable();
FrameSummaries Summarize() const override;
protected:
inline explicit StubFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class OptimizedJSFrame : public JavaScriptFrame {
public:
void GetFunctions(
std::vector<Tagged<SharedFunctionInfo>>* functions) const override;
FrameSummaries Summarize() const override;
Tagged<DeoptimizationData> GetDeoptimizationData(Tagged<Code> code,
int* deopt_index) const;
static int StackSlotOffsetRelativeToFp(int slot_index);
int LookupExceptionHandlerInTable(
int* data, HandlerTable::CatchPrediction* prediction) override;
virtual int FindReturnPCForTrampoline(Tagged<Code> code,
int trampoline_pc) const = 0;
protected:
inline explicit OptimizedJSFrame(StackFrameIteratorBase* iterator);
};
class UnoptimizedJSFrame : public JavaScriptFrame {
public:
int position() const override;
int LookupExceptionHandlerInTable(
int* data, HandlerTable::CatchPrediction* prediction) override;
virtual int GetBytecodeOffset() const = 0;
Tagged<BytecodeArray> GetBytecodeArray() const;
Tagged<Object> ReadInterpreterRegister(int register_index) const;
inline void SetFeedbackVector(Tagged<FeedbackVector> feedback_vector);
FrameSummaries Summarize() const override;
static UnoptimizedJSFrame* cast(StackFrame* frame) {
DCHECK(frame->is_unoptimized_js());
return static_cast<UnoptimizedJSFrame*>(frame);
}
protected:
inline explicit UnoptimizedJSFrame(StackFrameIteratorBase* iterator);
Address GetExpressionAddress(int n) const override;
private:
friend class StackFrameIteratorBase;
};
class InterpretedFrame : public UnoptimizedJSFrame {
public:
Type type() const override { return INTERPRETED; }
int GetBytecodeOffset() const override;
void PatchBytecodeOffset(int new_offset);
void PatchBytecodeArray(Tagged<BytecodeArray> bytecode_array);
static InterpretedFrame* cast(StackFrame* frame) {
DCHECK(frame->is_interpreted());
return static_cast<InterpretedFrame*>(frame);
}
static const InterpretedFrame* cast(const StackFrame* frame) {
DCHECK(frame->is_interpreted());
return static_cast<const InterpretedFrame*>(frame);
}
protected:
inline explicit InterpretedFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class BaselineFrame : public UnoptimizedJSFrame {
public:
Type type() const override { return BASELINE; }
int GetBytecodeOffset() const override;
intptr_t GetPCForBytecodeOffset(int lookup_offset) const;
void PatchContext(Tagged<Context> value);
static BaselineFrame* cast(StackFrame* frame) {
DCHECK(frame->is_baseline());
return static_cast<BaselineFrame*>(frame);
}
static const BaselineFrame* cast(const StackFrame* frame) {
DCHECK(frame->is_baseline());
return static_cast<const BaselineFrame*>(frame);
}
protected:
inline explicit BaselineFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class MaglevFrame : public OptimizedJSFrame {
public:
Type type() const override { return MAGLEV; }
static MaglevFrame* cast(StackFrame* frame) {
DCHECK(frame->is_maglev());
return static_cast<MaglevFrame*>(frame);
}
void Iterate(RootVisitor* v) const override;
int FindReturnPCForTrampoline(Tagged<Code> code,
int trampoline_pc) const override;
DirectHandle<JSFunction> GetInnermostFunction() const;
BytecodeOffset GetBytecodeOffsetForOSR() const;
static intptr_t StackGuardFrameSize(int register_input_count);
protected:
inline explicit MaglevFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class TurbofanJSFrame : public OptimizedJSFrame {
public:
Type type() const override { return TURBOFAN_JS; }
int ComputeParametersCount() const override;
void Iterate(RootVisitor* v) const override;
int FindReturnPCForTrampoline(Tagged<Code> code,
int trampoline_pc) const override;
protected:
inline explicit TurbofanJSFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
Tagged<Object> StackSlotAt(int index) const;
};
class BuiltinFrame final : public TypedFrameWithJSLinkage {
public:
Type type() const final { return BUILTIN; }
static BuiltinFrame* cast(StackFrame* frame) {
DCHECK(frame->is_builtin());
return static_cast<BuiltinFrame*>(frame);
}
Tagged<JSFunction> function() const override;
int ComputeParametersCount() const override;
protected:
inline explicit BuiltinFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
#if V8_ENABLE_WEBASSEMBLY
class WasmFrame : public TypedFrame {
public:
Type type() const override { return WASM; }
void Print(StringStream* accumulator, PrintMode mode,
int index) const override;
int LookupExceptionHandlerInTable();
void Iterate(RootVisitor* v) const override;
virtual V8_EXPORT_PRIVATE Tagged<WasmInstanceObject> wasm_instance() const;
virtual Tagged<WasmTrustedInstanceData> trusted_instance_data() const;
V8_EXPORT_PRIVATE wasm::NativeModule* native_module() const;
virtual wasm::WasmCode* wasm_code() const;
int function_index() const;
Tagged<Script> script() const;
int position() const override;
Tagged<Object> context() const override;
bool at_to_number_conversion() const;
int generated_code_offset() const;
bool is_inspectable() const;
FrameSummaries Summarize() const override;
static WasmFrame* cast(StackFrame* frame) {
DCHECK(frame->is_wasm()
#ifdef V8_ENABLE_DRUMBRAKE
&& !frame->is_wasm_interpreter_entry()
#endif
);
return static_cast<WasmFrame*>(frame);
}
protected:
inline explicit WasmFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
Tagged<WasmModuleObject> module_object() const;
};
class WasmSegmentStartFrame : public WasmFrame {
public:
Type type() const override { return WASM; }
protected:
inline explicit WasmSegmentStartFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class WasmExitFrame : public WasmFrame {
public:
Type type() const override { return WASM_EXIT; }
static Address ComputeStackPointer(Address fp);
protected:
inline explicit WasmExitFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
#if V8_ENABLE_DRUMBRAKE
class WasmInterpreterEntryFrame final : public WasmFrame {
public:
Type type() const override { return WASM_INTERPRETER_ENTRY; }
void Iterate(RootVisitor* v) const override;
void Print(StringStream* accumulator, PrintMode mode,
int index) const override;
FrameSummaries Summarize() const override;
Tagged<HeapObject> unchecked_code() const override;
Tagged<Tuple2> interpreter_object() const;
V8_EXPORT_PRIVATE Tagged<WasmInstanceObject> wasm_instance() const override;
Tagged<WasmTrustedInstanceData> trusted_instance_data() const override;
wasm::WasmCode* wasm_code() const override { UNREACHABLE(); }
int function_index(int inlined_function_index) const;
int position() const override;
Tagged<Object> context() const override;
static WasmInterpreterEntryFrame* cast(StackFrame* frame) {
DCHECK(frame->is_wasm_interpreter_entry());
return static_cast<WasmInterpreterEntryFrame*>(frame);
}
protected:
inline explicit WasmInterpreterEntryFrame(StackFrameIteratorBase* iterator);
Address GetCallerStackPointer() const override;
private:
friend class StackFrameIteratorBase;
Tagged<WasmModuleObject> module_object() const;
};
#endif
class WasmDebugBreakFrame final : public TypedFrame {
public:
Type type() const override { return WASM_DEBUG_BREAK; }
void Iterate(RootVisitor* v) const override;
void Print(StringStream* accumulator, PrintMode mode,
int index) const override;
static WasmDebugBreakFrame* cast(StackFrame* frame) {
DCHECK(frame->is_wasm_debug_break());
return static_cast<WasmDebugBreakFrame*>(frame);
}
protected:
inline explicit WasmDebugBreakFrame(StackFrameIteratorBase*);
private:
friend class StackFrameIteratorBase;
};
class WasmToJsFrame : public WasmFrame {
public:
Type type() const override { return WASM_TO_JS; }
#if V8_ENABLE_DRUMBRAKE
void Iterate(RootVisitor* v) const override;
#endif
int position() const override { return 0; }
Tagged<WasmInstanceObject> wasm_instance() const override;
Tagged<WasmTrustedInstanceData> trusted_instance_data() const override;
protected:
inline explicit WasmToJsFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class JsToWasmFrame : public StubFrame {
public:
Type type() const override { return JS_TO_WASM; }
void Iterate(RootVisitor* v) const override;
protected:
inline explicit JsToWasmFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class WasmJspiFrame : public ExitFrame {
public:
Type type() const override { return WASM_JSPI; }
void Iterate(RootVisitor* v) const override;
static void GetStateForJumpBuffer(wasm::JumpBuffer* jmpbuf, State* state);
protected:
inline explicit WasmJspiFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class WasmStackEntryFrame : public TypedFrame {
public:
Type type() const override { return WASM_STACK_ENTRY; }
void Iterate(RootVisitor* v) const override {}
protected:
inline explicit WasmStackEntryFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class WasmStackExitFrame : public TypedFrame {
public:
Type type() const override { return WASM_STACK_EXIT; }
void Iterate(RootVisitor* v) const override {}
protected:
inline explicit WasmStackExitFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class CWasmEntryFrame : public StubFrame {
public:
Type type() const override { return C_WASM_ENTRY; }
#if V8_ENABLE_DRUMBRAKE
void Iterate(RootVisitor* v) const override;
#endif
protected:
inline explicit CWasmEntryFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
Type GetCallerState(State* state) const override;
};
class WasmLiftoffSetupFrame : public TypedFrame {
public:
Type type() const override { return WASM_LIFTOFF_SETUP; }
FullObjectSlot wasm_instance_data_slot() const;
int GetDeclaredFunctionIndex() const;
wasm::NativeModule* GetNativeModule() const;
void Iterate(RootVisitor* v) const override;
static WasmLiftoffSetupFrame* cast(StackFrame* frame) {
DCHECK(frame->is_wasm_liftoff_setup());
return static_cast<WasmLiftoffSetupFrame*>(frame);
}
protected:
inline explicit WasmLiftoffSetupFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
#endif
class InternalFrame : public TypedFrame {
public:
Type type() const override { return INTERNAL; }
void Iterate(RootVisitor* v) const override;
static InternalFrame* cast(StackFrame* frame) {
DCHECK(frame->is_internal());
return static_cast<InternalFrame*>(frame);
}
protected:
inline explicit InternalFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class ConstructFrame : public InternalFrame {
public:
Type type() const override { return CONSTRUCT; }
static ConstructFrame* cast(StackFrame* frame) {
DCHECK(frame->is_construct());
return static_cast<ConstructFrame*>(frame);
}
void Iterate(RootVisitor* v) const override;
protected:
inline explicit ConstructFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class FastConstructFrame : public InternalFrame {
public:
Type type() const override { return FAST_CONSTRUCT; }
static FastConstructFrame* cast(StackFrame* frame) {
DCHECK(frame->is_fast_construct());
return static_cast<FastConstructFrame*>(frame);
}
protected:
inline explicit FastConstructFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class BuiltinContinuationFrame : public InternalFrame {
public:
Type type() const override { return BUILTIN_CONTINUATION; }
static BuiltinContinuationFrame* cast(StackFrame* frame) {
DCHECK(frame->is_builtin_continuation());
return static_cast<BuiltinContinuationFrame*>(frame);
}
protected:
inline explicit BuiltinContinuationFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class JavaScriptBuiltinContinuationFrame : public TypedFrameWithJSLinkage {
public:
Type type() const override { return JAVASCRIPT_BUILTIN_CONTINUATION; }
static JavaScriptBuiltinContinuationFrame* cast(StackFrame* frame) {
DCHECK(frame->is_javascript_builtin_continuation());
return static_cast<JavaScriptBuiltinContinuationFrame*>(frame);
}
Tagged<JSFunction> function() const override;
int ComputeParametersCount() const override;
intptr_t GetSPToFPDelta() const;
Tagged<Object> context() const override;
protected:
inline explicit JavaScriptBuiltinContinuationFrame(
StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class JavaScriptBuiltinContinuationWithCatchFrame
: public JavaScriptBuiltinContinuationFrame {
public:
Type type() const override {
return JAVASCRIPT_BUILTIN_CONTINUATION_WITH_CATCH;
}
static JavaScriptBuiltinContinuationWithCatchFrame* cast(StackFrame* frame) {
DCHECK(frame->is_javascript_builtin_with_catch_continuation());
return static_cast<JavaScriptBuiltinContinuationWithCatchFrame*>(frame);
}
void SetException(Tagged<Object> exception);
protected:
inline explicit JavaScriptBuiltinContinuationWithCatchFrame(
StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class IrregexpFrame : public TypedFrame {
public:
Type type() const override { return IRREGEXP; }
void Iterate(RootVisitor* v) const override {
UNREACHABLE();
}
static IrregexpFrame* cast(StackFrame* frame) {
DCHECK(frame->is_irregexp());
return static_cast<IrregexpFrame*>(frame);
}
protected:
inline explicit IrregexpFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class StackFrameIteratorBase {
public:
StackFrameIteratorBase(const StackFrameIteratorBase&) = delete;
StackFrameIteratorBase& operator=(const StackFrameIteratorBase&) = delete;
Isolate* isolate() const { return isolate_; }
#if V8_ENABLE_WEBASSEMBLY
wasm::StackMemory* wasm_stack() const { return wasm_stack_; }
#endif
bool done() const { return frame_ == nullptr; }
#ifdef DEBUG
virtual bool IsStackFrameIteratorForProfiler() const = 0;
#endif
virtual StackFrame::Type ComputeStackFrameType(
StackFrame::State* state) const = 0;
protected:
explicit StackFrameIteratorBase(Isolate* isolate);
Isolate* const isolate_;
union {
char uninitialized_;
#define DECLARE_SINGLETON(ignore, type) type type##_;
STACK_FRAME_TYPE_LIST(DECLARE_SINGLETON)
#undef DECLARE_SINGLETON
};
StackFrame* frame_;
StackHandler* handler_;
#if V8_ENABLE_WEBASSEMBLY
bool first_stack_only_ = false;
wasm::StackMemory* wasm_stack_ = nullptr;
#endif
StackHandler* handler() const {
DCHECK(!done());
return handler_;
}
void SetNewFrame(StackFrame::Type type, StackFrame::State* state);
void SetNewFrame(StackFrame::Type type);
private:
friend class StackFrame;
};
class StackFrameIterator : public StackFrameIteratorBase {
public:
V8_EXPORT_PRIVATE explicit StackFrameIterator(Isolate* isolate);
V8_EXPORT_PRIVATE StackFrameIterator(Isolate* isolate, ThreadLocalTop* t);
#if V8_ENABLE_WEBASSEMBLY
struct FirstStackOnly {};
V8_EXPORT_PRIVATE StackFrameIterator(Isolate* isolate, ThreadLocalTop* t,
FirstStackOnly);
V8_EXPORT_PRIVATE StackFrameIterator(Isolate* isolate,
wasm::StackMemory* stack);
#endif
StackFrameIterator(const StackFrameIterator&) = delete;
StackFrameIterator& operator=(const StackFrameIterator&) = delete;
StackFrame* frame() const {
DCHECK(!done());
return frame_;
}
V8_EXPORT_PRIVATE void Advance();
StackFrame* Reframe();
#if V8_ENABLE_WEBASSEMBLY
void Reset(ThreadLocalTop* top, wasm::StackMemory* stack);
#endif
#ifdef DEBUG
bool IsStackFrameIteratorForProfiler() const override { return false; }
#endif
StackFrame::Type ComputeStackFrameType(
StackFrame::State* state) const override;
private:
void Reset(ThreadLocalTop* top);
};
class JavaScriptStackFrameIterator final {
public:
explicit JavaScriptStackFrameIterator(Isolate* isolate) : iterator_(isolate) {
if (!done()) Advance();
}
JavaScriptStackFrameIterator(Isolate* isolate, ThreadLocalTop* top)
: iterator_(isolate, top) {
if (!done()) Advance();
}
JavaScriptFrame* frame() const {
return JavaScriptFrame::cast(iterator_.frame());
}
JavaScriptFrame* Reframe() {
return JavaScriptFrame::cast(iterator_.Reframe());
}
bool done() const { return iterator_.done(); }
V8_EXPORT_PRIVATE void Advance();
private:
StackFrameIterator iterator_;
};
class V8_EXPORT_PRIVATE DebuggableStackFrameIterator {
public:
explicit DebuggableStackFrameIterator(Isolate* isolate);
DebuggableStackFrameIterator(Isolate* isolate, StackFrameId id);
bool done() const { return iterator_.done(); }
void Advance();
int FrameFunctionCount() const;
inline CommonFrame* frame() const;
inline CommonFrame* Reframe();
inline bool is_javascript() const;
#if V8_ENABLE_WEBASSEMBLY
inline bool is_wasm() const;
#if V8_ENABLE_DRUMBRAKE
inline bool is_wasm_interpreter_entry() const;
#endif
#endif
inline JavaScriptFrame* javascript_frame() const;
FrameSummary GetTopValidFrame() const;
private:
StackFrameIterator iterator_;
static bool IsValidFrame(StackFrame* frame);
};
class StackFrameIteratorForProfiler : public StackFrameIteratorBase {
public:
StackFrameIteratorForProfiler(Isolate* isolate, Address pc, Address fp,
Address sp, Address lr, Address js_entry_sp);
inline StackFrame* frame() const;
void Advance();
StackFrame::Type top_frame_type() const { return top_frame_type_; }
#ifdef DEBUG
bool IsStackFrameIteratorForProfiler() const override { return true; }
#endif
StackFrame::Type ComputeStackFrameType(
StackFrame::State* state) const override;
private:
void AdvanceOneFrame();
bool IsValidStackAddress(Address addr) const {
return low_bound_ <= addr && addr <= high_bound_;
}
bool IsValidState(const StackFrame::State& frame) const;
bool HasValidExitIfEntryFrame(const StackFrame* frame) const;
bool IsValidExitFrame(Address fp) const;
bool IsValidTop(ThreadLocalTop* top) const;
static bool IsValidFrameType(StackFrame::Type type);
StackFrame::Type GetCallerIfValid(StackFrame* frame,
StackFrame::State* state);
bool IsNoFrameBytecodeHandlerPc(Isolate* isolate, Address pc,
Address fp) const;
const Address low_bound_;
const Address high_bound_;
StackFrame::Type top_frame_type_;
ExternalCallbackScope* external_callback_scope_;
Address top_link_register_;
#if V8_ENABLE_WEBASSEMBLY
std::vector<std::unique_ptr<wasm::StackMemory>>& wasm_stacks_;
#endif
};
class V8_EXPORT_PRIVATE StackFrameIteratorForProfilerForTesting
: public StackFrameIteratorForProfiler {
public:
StackFrameIteratorForProfilerForTesting(Isolate* isolate, Address pc,
Address fp, Address sp, Address lr,
Address js_entry_sp);
void Advance();
};
enum class FrameInfoKind {
kPrecise,
kConservative,
};
enum class BuiltinContinuationMode {
STUB,
JAVASCRIPT,
JAVASCRIPT_WITH_CATCH,
JAVASCRIPT_HANDLE_EXCEPTION
};
class UnoptimizedFrameInfo {
public:
static UnoptimizedFrameInfo Precise(int parameters_count_with_receiver,
int translation_height, bool is_topmost,
bool pad_arguments) {
return {parameters_count_with_receiver, translation_height, is_topmost,
pad_arguments, FrameInfoKind::kPrecise};
}
static UnoptimizedFrameInfo Conservative(int parameters_count_with_receiver,
int locals_count) {
return {parameters_count_with_receiver, locals_count, false, true,
FrameInfoKind::kConservative};
}
static uint32_t GetStackSizeForAdditionalArguments(int parameters_count);
uint32_t register_stack_slot_count() const {
return register_stack_slot_count_;
}
uint32_t frame_size_in_bytes_without_fixed() const {
return frame_size_in_bytes_without_fixed_;
}
uint32_t frame_size_in_bytes() const { return frame_size_in_bytes_; }
private:
UnoptimizedFrameInfo(int parameters_count_with_receiver,
int translation_height, bool is_topmost,
bool pad_arguments, FrameInfoKind frame_info_kind);
uint32_t register_stack_slot_count_;
uint32_t frame_size_in_bytes_without_fixed_;
uint32_t frame_size_in_bytes_;
};
class ConstructStubFrameInfo {
public:
static ConstructStubFrameInfo Precise(int translation_height,
bool is_topmost) {
return {translation_height, is_topmost, FrameInfoKind::kPrecise};
}
static ConstructStubFrameInfo Conservative(int parameters_count) {
return {parameters_count, false, FrameInfoKind::kConservative};
}
uint32_t frame_size_in_bytes_without_fixed() const {
return frame_size_in_bytes_without_fixed_;
}
uint32_t frame_size_in_bytes() const { return frame_size_in_bytes_; }
private:
ConstructStubFrameInfo(int translation_height, bool is_topmost,
FrameInfoKind frame_info_kind);
uint32_t frame_size_in_bytes_without_fixed_;
uint32_t frame_size_in_bytes_;
};
class FastConstructStubFrameInfo {
public:
static FastConstructStubFrameInfo Precise(bool is_topmost) {
return FastConstructStubFrameInfo(is_topmost);
}
static FastConstructStubFrameInfo Conservative() {
return FastConstructStubFrameInfo(true);
}
uint32_t frame_size_in_bytes_without_fixed() const {
return frame_size_in_bytes_without_fixed_;
}
uint32_t frame_size_in_bytes() const { return frame_size_in_bytes_; }
private:
explicit FastConstructStubFrameInfo(bool is_topmost);
uint32_t frame_size_in_bytes_without_fixed_;
uint32_t frame_size_in_bytes_;
};
class CallInterfaceDescriptor;
class RegisterConfiguration;
class BuiltinContinuationFrameInfo {
public:
static BuiltinContinuationFrameInfo Precise(
int translation_height,
const CallInterfaceDescriptor& continuation_descriptor,
const RegisterConfiguration* register_config, bool is_topmost,
DeoptimizeKind deopt_kind, BuiltinContinuationMode continuation_mode) {
return {translation_height,
continuation_descriptor,
register_config,
is_topmost,
deopt_kind,
continuation_mode,
FrameInfoKind::kPrecise};
}
static BuiltinContinuationFrameInfo Conservative(
int parameters_count,
const CallInterfaceDescriptor& continuation_descriptor,
const RegisterConfiguration* register_config) {
return {parameters_count,
continuation_descriptor,
register_config,
false,
DeoptimizeKind::kEager,
BuiltinContinuationMode::STUB,
FrameInfoKind::kConservative};
}
bool frame_has_result_stack_slot() const {
return frame_has_result_stack_slot_;
}
uint32_t translated_stack_parameter_count() const {
return translated_stack_parameter_count_;
}
uint32_t stack_parameter_count() const { return stack_parameter_count_; }
uint32_t frame_size_in_bytes() const { return frame_size_in_bytes_; }
uint32_t frame_size_in_bytes_above_fp() const {
return frame_size_in_bytes_above_fp_;
}
private:
BuiltinContinuationFrameInfo(
int translation_height,
const CallInterfaceDescriptor& continuation_descriptor,
const RegisterConfiguration* register_config, bool is_topmost,
DeoptimizeKind deopt_kind, BuiltinContinuationMode continuation_mode,
FrameInfoKind frame_info_kind);
bool frame_has_result_stack_slot_;
uint32_t translated_stack_parameter_count_;
uint32_t stack_parameter_count_;
uint32_t frame_size_in_bytes_;
uint32_t frame_size_in_bytes_above_fp_;
};
}
}
#endif