diff options
author | Michaël Zasso <targos@protonmail.com> | 2019-08-01 08:38:30 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2019-08-01 12:53:56 +0200 |
commit | 2dcc3665abf57c3607cebffdeeca062f5894885d (patch) | |
tree | 4f560748132edcfb4c22d6f967a7e80d23d7ea2c /deps/v8/src/execution/frames.h | |
parent | 1ee47d550c6de132f06110aa13eceb7551d643b3 (diff) | |
download | android-node-v8-2dcc3665abf57c3607cebffdeeca062f5894885d.tar.gz android-node-v8-2dcc3665abf57c3607cebffdeeca062f5894885d.tar.bz2 android-node-v8-2dcc3665abf57c3607cebffdeeca062f5894885d.zip |
deps: update V8 to 7.6.303.28
PR-URL: https://github.com/nodejs/node/pull/28016
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Refael Ackermann (רפאל פלחי) <refack@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Diffstat (limited to 'deps/v8/src/execution/frames.h')
-rw-r--r-- | deps/v8/src/execution/frames.h | 1316 |
1 files changed, 1316 insertions, 0 deletions
diff --git a/deps/v8/src/execution/frames.h b/deps/v8/src/execution/frames.h new file mode 100644 index 0000000000..982716db93 --- /dev/null +++ b/deps/v8/src/execution/frames.h @@ -0,0 +1,1316 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_EXECUTION_FRAMES_H_ +#define V8_EXECUTION_FRAMES_H_ + +#include "src/codegen/safepoint-table.h" +#include "src/handles/handles.h" +#include "src/objects/code.h" +#include "src/objects/objects.h" + +namespace v8 { +namespace internal { +namespace wasm { +class WasmCode; +} + +// Forward declarations. +class AbstractCode; +class Debug; +class ExternalCallbackScope; +class InnerPointerToCodeCache; +class Isolate; +class ObjectVisitor; +class Register; +class RootVisitor; +class StackFrameIteratorBase; +class StringStream; +class ThreadLocalTop; +class WasmDebugInfo; +class WasmInstanceObject; +class WasmModuleObject; + +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: + // Get the address of this stack handler. + inline Address address() const; + + // Get the next stack handler in the chain. + inline StackHandler* next() const; + + // Get the next stack handler, as an Address. This is safe to use even + // when the next handler is null. + inline Address next_address() const; + + // Conversion support. + 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) \ + V(OPTIMIZED, OptimizedFrame) \ + V(WASM_COMPILED, WasmCompiledFrame) \ + V(WASM_TO_JS, WasmToJsFrame) \ + V(JS_TO_WASM, JsToWasmFrame) \ + V(WASM_INTERPRETER_ENTRY, WasmInterpreterEntryFrame) \ + V(C_WASM_ENTRY, CWasmEntryFrame) \ + V(WASM_EXIT, WasmExitFrame) \ + V(WASM_COMPILE_LAZY, WasmCompileLazyFrame) \ + V(INTERPRETED, InterpretedFrame) \ + V(STUB, StubFrame) \ + V(BUILTIN_CONTINUATION, BuiltinContinuationFrame) \ + V(JAVA_SCRIPT_BUILTIN_CONTINUATION, JavaScriptBuiltinContinuationFrame) \ + V(JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH, \ + JavaScriptBuiltinContinuationWithCatchFrame) \ + V(INTERNAL, InternalFrame) \ + V(CONSTRUCT, ConstructFrame) \ + V(ARGUMENTS_ADAPTOR, ArgumentsAdaptorFrame) \ + V(BUILTIN, BuiltinFrame) \ + V(BUILTIN_EXIT, BuiltinExitFrame) \ + V(NATIVE, NativeFrame) + +// Abstract base class for all stack frames. +class StackFrame { + public: +#define DECLARE_TYPE(type, ignore) type, + enum Type { + NONE = 0, + STACK_FRAME_TYPE_LIST(DECLARE_TYPE) NUMBER_OF_TYPES, + // Used by FrameScope to indicate that the stack frame is constructed + // manually and the FrameScope does not need to emit code. + MANUAL + }; +#undef DECLARE_TYPE + + // Opaque data type for identifying stack frames. Used extensively + // by the debugger. + // ID_MIN_VALUE and ID_MAX_VALUE are specified to ensure that enumeration type + // has correct value range (see Issue 830 for more details). + enum Id { ID_MIN_VALUE = kMinInt, ID_MAX_VALUE = kMaxInt, NO_ID = 0 }; + + // Used to mark the outermost JS entry frame. + // + // The mark is an opaque value that should be pushed onto the stack directly, + // carefully crafted to not be interpreted as a tagged pointer. + 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_pc_address = nullptr; + Address* constant_pool_address = nullptr; + }; + + // Convert a stack frame type to a marker that can be stored on the stack. + // + // The marker is an opaque value, not intended to be interpreted in any way + // except being checked by IsTypeMarker or converted by MarkerToType. + // It has the same tagging as Smis, so any marker value that does not pass + // IsTypeMarker can instead be interpreted as a tagged pointer. + // + // Note that the marker is not a Smi: Smis on 64-bit architectures are stored + // in the top 32 bits of a 64-bit value, which in turn makes them expensive + // (in terms of code/instruction size) to push as immediates onto the stack. + static int32_t TypeToMarker(Type type) { + DCHECK_GE(type, 0); + return (type << kSmiTagSize) | kSmiTag; + } + + // Convert a marker back to a stack frame type. + // + // Unlike the return value of TypeToMarker, this takes an intptr_t, as that is + // the type of the value on the stack. + static Type MarkerToType(intptr_t marker) { + DCHECK(IsTypeMarker(marker)); + return static_cast<Type>(marker >> kSmiTagSize); + } + + // Check if a marker is a stack frame type marker or a tagged pointer. + // + // Returns true if the given marker is tagged as a stack frame type marker, + // and should be converted back to a stack frame type using MarkerToType. + // Otherwise, the value is a tagged function pointer. + static bool IsTypeMarker(intptr_t function_or_marker) { + return (function_or_marker & kSmiTagMask) == kSmiTag; + } + + // Copy constructor; it breaks the connection to host iterator + // (as an iterator usually lives on stack). + StackFrame(const StackFrame& original) V8_NOEXCEPT { + this->state_ = original.state_; + this->iterator_ = nullptr; + this->isolate_ = original.isolate_; + } + + // Type testers. + 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() const { return type() == OPTIMIZED; } + bool is_interpreted() const { return type() == INTERPRETED; } + bool is_wasm_compiled() const { return type() == WASM_COMPILED; } + bool is_wasm_exit() const { return type() == WASM_EXIT; } + bool is_wasm_compile_lazy() const { return type() == WASM_COMPILE_LAZY; } + bool is_wasm_to_js() const { return type() == WASM_TO_JS; } + bool is_js_to_wasm() const { return type() == JS_TO_WASM; } + bool is_wasm_interpreter_entry() const { + return type() == WASM_INTERPRETER_ENTRY; + } + bool is_arguments_adaptor() const { return type() == ARGUMENTS_ADAPTOR; } + 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_java_script_builtin_continuation() const { + return type() == JAVA_SCRIPT_BUILTIN_CONTINUATION; + } + bool is_java_script_builtin_with_catch_continuation() const { + return type() == JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH; + } + bool is_construct() const { return type() == CONSTRUCT; } + bool is_builtin_exit() const { return type() == BUILTIN_EXIT; } + virtual bool is_standard() const { return false; } + + bool is_java_script() const { + Type type = this->type(); + return (type == OPTIMIZED) || (type == INTERPRETED) || (type == BUILTIN) || + (type == JAVA_SCRIPT_BUILTIN_CONTINUATION) || + (type == JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH); + } + bool is_wasm() const { + Type type = this->type(); + return type == WASM_COMPILED || type == WASM_INTERPRETER_ENTRY; + } + + // Accessors. + Address sp() const { return state_.sp; } + Address fp() const { return state_.fp; } + Address callee_pc() const { + return state_.callee_pc_address ? *state_.callee_pc_address : kNullAddress; + } + Address caller_sp() const { return GetCallerStackPointer(); } + + // If this frame is optimized and was dynamically aligned return its old + // unaligned frame pointer. When the frame is deoptimized its FP will shift + // up one word and become unaligned. + Address UnpaddedFP() const; + + Address pc() const { return *pc_address(); } + void set_pc(Address pc) { *pc_address() = pc; } + + 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; + } + + // Get the id of this stack frame. + Id id() const { return static_cast<Id>(caller_sp()); } + + // Get the top handler from the current stack iterator. + inline StackHandler* top_handler() const; + + // Get the type of this frame. + virtual Type type() const = 0; + + // Get the code associated with this frame. + // This method could be called during marking phase of GC. + virtual Code unchecked_code() const = 0; + + // Search for the code associated with this frame. + V8_EXPORT_PRIVATE Code LookupCode() const; + + virtual void Iterate(RootVisitor* v) const = 0; + static void IteratePc(RootVisitor* v, Address* pc_address, + Address* constant_pool_address, Code holder); + + // Sets a callback function for return-address rewriting profilers + // to resolve the location of a return address to the location of the + // profiler's stashed return address. + static void SetReturnAddressLocationResolver( + ReturnAddressLocationResolver resolver); + + // Resolves pc_address through the resolution address function if one is set. + static inline Address* ResolveReturnAddressLocation(Address* pc_address); + + // Printing support. + 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 ~StackFrame() = default; + + // Compute the stack pointer for the calling frame. + virtual Address GetCallerStackPointer() const = 0; + + // Compute the stack frame type for the given state. + static Type ComputeType(const StackFrameIteratorBase* iterator, State* state); + +#ifdef DEBUG + bool can_access_heap_objects() const; +#endif + + private: + const StackFrameIteratorBase* iterator_; + Isolate* isolate_; + State state_; + + static ReturnAddressLocationResolver return_address_location_resolver_; + + // Fill in the state of the calling frame. + virtual void ComputeCallerState(State* state) const = 0; + + // Get the type and the state of the calling frame. + virtual Type GetCallerState(State* state) const; + + static const intptr_t kIsolateTag = 1; + + friend class StackFrameIterator; + friend class StackFrameIteratorBase; + friend class StackHandlerIterator; + friend class SafeStackFrameIterator; +}; + +class NativeFrame : public StackFrame { + public: + Type type() const override { return NATIVE; } + + Code unchecked_code() const override; + + // Garbage collection support. + void Iterate(RootVisitor* v) const override {} + + protected: + inline explicit NativeFrame(StackFrameIteratorBase* iterator); + + Address GetCallerStackPointer() const override; + + private: + void ComputeCallerState(State* state) const override; + + friend class StackFrameIteratorBase; +}; + +// Entry frames are used to enter JavaScript execution from C. +class EntryFrame : public StackFrame { + public: + Type type() const override { return ENTRY; } + + Code unchecked_code() const override; + + // Garbage collection support. + 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); + + // The caller stack pointer for entry frames is always zero. The + // real information about the caller frame is available through the + // link to the top exit frame. + 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; } + + Code 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; +}; + +// Exit frames are used to exit JavaScript execution and go to C. +class ExitFrame : public StackFrame { + public: + Type type() const override { return EXIT; } + + Code unchecked_code() const override; + + // Garbage collection support. + void Iterate(RootVisitor* v) const override; + + static ExitFrame* cast(StackFrame* frame) { + DCHECK(frame->is_exit()); + return static_cast<ExitFrame*>(frame); + } + + // Compute the state and type of an exit frame given a frame + // pointer. Used when constructing the first stack frame seen by an + // iterator and the frames following entry frames. + 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); + + Address GetCallerStackPointer() const override; + + private: + void ComputeCallerState(State* state) const override; + + friend class StackFrameIteratorBase; +}; + +// Builtin exit frames are a special case of exit frames, which are used +// whenever C++ builtins (e.g., Math.acos) are called. Their main purpose is +// to allow such builtins to appear in stack traces. +class BuiltinExitFrame : public ExitFrame { + public: + Type type() const override { return BUILTIN_EXIT; } + + static BuiltinExitFrame* cast(StackFrame* frame) { + DCHECK(frame->is_builtin_exit()); + return static_cast<BuiltinExitFrame*>(frame); + } + + JSFunction function() const; + Object receiver() const; + + bool IsConstructor() const; + + void Print(StringStream* accumulator, PrintMode mode, + int index) const override; + + protected: + inline explicit BuiltinExitFrame(StackFrameIteratorBase* iterator); + + private: + Object GetParameter(int i) const; + int ComputeParametersCount() const; + + inline Object receiver_slot_object() const; + inline Object argc_slot_object() const; + inline Object target_slot_object() const; + inline Object new_target_slot_object() const; + + friend class StackFrameIteratorBase; + friend class FrameArrayBuilder; +}; + +class StandardFrame; + +class V8_EXPORT_PRIVATE FrameSummary { + public: +// Subclasses for the different summary kinds: +#define FRAME_SUMMARY_VARIANTS(F) \ + F(JAVA_SCRIPT, JavaScriptFrameSummary, java_script_summary_, JavaScript) \ + F(WASM_COMPILED, WasmCompiledFrameSummary, wasm_compiled_summary_, \ + WasmCompiled) \ + F(WASM_INTERPRETED, WasmInterpretedFrameSummary, wasm_interpreted_summary_, \ + WasmInterpreted) + +#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, Object receiver, + JSFunction function, AbstractCode abstract_code, + int code_offset, bool is_constructor, + 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_; } + Handle<FixedArray> parameters() const { return parameters_; } + bool is_subject_to_debugging() const; + int SourcePosition() const; + int SourceStatementPosition() const; + Handle<Object> script() const; + Handle<String> FunctionName() const; + Handle<Context> native_context() const; + + private: + Handle<Object> receiver_; + Handle<JSFunction> function_; + Handle<AbstractCode> abstract_code_; + int code_offset_; + bool is_constructor_; + Handle<FixedArray> parameters_; + }; + + class WasmFrameSummary : public FrameSummaryBase { + protected: + WasmFrameSummary(Isolate*, Kind, Handle<WasmInstanceObject>, + bool at_to_number_conversion); + + public: + Handle<Object> receiver() const; + uint32_t function_index() const; + int byte_offset() const; + 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; + Handle<WasmInstanceObject> wasm_instance() const { return wasm_instance_; } + Handle<String> FunctionName() const; + Handle<Context> native_context() const; + bool at_to_number_conversion() const { return at_to_number_conversion_; } + + private: + Handle<WasmInstanceObject> wasm_instance_; + bool at_to_number_conversion_; + }; + + class WasmCompiledFrameSummary : public WasmFrameSummary { + public: + WasmCompiledFrameSummary(Isolate*, Handle<WasmInstanceObject>, + wasm::WasmCode*, int code_offset, + bool at_to_number_conversion); + uint32_t function_index() const; + wasm::WasmCode* code() const { return code_; } + int code_offset() const { return code_offset_; } + int byte_offset() const; + static int GetWasmSourcePosition(const wasm::WasmCode* code, int offset); + + private: + wasm::WasmCode* const code_; + int code_offset_; + }; + + class WasmInterpretedFrameSummary : public WasmFrameSummary { + public: + WasmInterpretedFrameSummary(Isolate*, Handle<WasmInstanceObject>, + uint32_t function_index, int byte_offset); + uint32_t function_index() const { return function_index_; } + int code_offset() const { return byte_offset_; } + int byte_offset() const { return byte_offset_; } + + private: + uint32_t function_index_; + int byte_offset_; + }; + +#define FRAME_SUMMARY_CONS(kind, type, field, desc) \ + FrameSummary(type summ) : field(summ) {} // NOLINT + FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_CONS) +#undef FRAME_SUMMARY_CONS + + ~FrameSummary(); + + static FrameSummary GetTop(const StandardFrame* frame); + static FrameSummary GetBottom(const StandardFrame* frame); + static FrameSummary GetSingle(const StandardFrame* frame); + static FrameSummary Get(const StandardFrame* frame, int index); + + void EnsureSourcePositionsAvailable(); + bool AreSourcePositionsAvailable() const; + + // Dispatched accessors. + 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; + Handle<String> FunctionName() const; + Handle<Context> native_context() 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 + + bool IsWasm() const { return IsWasmCompiled() || IsWasmInterpreted(); } + const WasmFrameSummary& AsWasm() const { + if (IsWasmCompiled()) return AsWasmCompiled(); + return AsWasmInterpreted(); + } + + private: +#define FRAME_SUMMARY_FIELD(kind, type, field, desc) type field; + union { + FrameSummaryBase base_; + FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_FIELD) + }; +#undef FRAME_SUMMARY_FIELD +}; + +class StandardFrame : public StackFrame { + public: + // Testers. + bool is_standard() const override { return true; } + + // Accessors. + virtual Object receiver() const; + virtual Script script() const; + virtual Object context() const; + virtual int position() const; + + // Access the expressions in the stack frame including locals. + inline Object GetExpression(int index) const; + inline void SetExpression(int index, Object value); + int ComputeExpressionsCount() const; + + // Access the parameters. + virtual Object GetParameter(int index) const; + virtual int ComputeParametersCount() const; + + // Check if this frame is a constructor frame invoked through 'new'. + virtual bool IsConstructor() const; + + // Build a list with summaries for this frame including all inlined frames. + // The functions are ordered bottom-to-top (i.e. summaries.last() is the + // top-most activation; caller comes before callee). + virtual void Summarize(std::vector<FrameSummary>* frames) const; + + static StandardFrame* cast(StackFrame* frame) { + DCHECK(frame->is_standard()); + return static_cast<StandardFrame*>(frame); + } + + protected: + inline explicit StandardFrame(StackFrameIteratorBase* iterator); + + void ComputeCallerState(State* state) const override; + + // Accessors. + inline Address caller_fp() const; + inline Address caller_pc() const; + + // Computes the address of the PC field in the standard frame given + // by the provided frame pointer. + static inline Address ComputePCAddress(Address fp); + + // Computes the address of the constant pool field in the standard + // frame given by the provided frame pointer. + static inline Address ComputeConstantPoolAddress(Address fp); + + // Iterate over expression stack including stack handlers, locals, + // and parts of the fixed part including context and code fields. + void IterateExpressions(RootVisitor* v) const; + + // Returns the address of the n'th expression stack element. + virtual Address GetExpressionAddress(int n) const; + + // Determines if the standard frame for the given frame pointer is + // an arguments adaptor frame. + static inline bool IsArgumentsAdaptorFrame(Address fp); + + // Determines if the standard frame for the given frame pointer is a + // construct frame. + static inline bool IsConstructFrame(Address fp); + + // Used by OptimizedFrames and StubFrames. + void IterateCompiledFrame(RootVisitor* v) const; + + private: + friend class StackFrame; + friend class SafeStackFrameIterator; +}; + +class JavaScriptFrame : public StandardFrame { + public: + Type type() const override = 0; + + void Summarize(std::vector<FrameSummary>* frames) const override; + + // Accessors. + virtual JSFunction function() const; + Object unchecked_function() const; + Object receiver() const override; + Object context() const override; + Script script() const override; + + inline void set_receiver(Object value); + + // Access the parameters. + inline Address GetParameterSlot(int index) const; + Object GetParameter(int index) const override; + int ComputeParametersCount() const override; + Handle<FixedArray> GetParameters() const; + + // Debugger access. + void SetParameterValue(int index, Object value) const; + + // Check if this frame is a constructor frame invoked through 'new'. + bool IsConstructor() const override; + + // Determines whether this frame includes inlined activations. To get details + // about the inlined frames use {GetFunctions} and {Summarize}. + bool HasInlinedFrames() const; + + // Check if this frame has "adapted" arguments in the sense that the + // actual passed arguments are available in an arguments adaptor + // frame below it on the stack. + inline bool has_adapted_arguments() const; + + // Garbage collection support. + void Iterate(RootVisitor* v) const override; + + // Printing support. + void Print(StringStream* accumulator, PrintMode mode, + int index) const override; + + // Determine the code for the frame. + Code unchecked_code() const override; + + // Return a list with {SharedFunctionInfo} objects of this frame. + virtual void GetFunctions(std::vector<SharedFunctionInfo>* functions) const; + + void GetFunctions(std::vector<Handle<SharedFunctionInfo>>* functions) const; + + // Lookup exception handler for current {pc}, returns -1 if none found. Also + // returns data associated with the handler site specific to the frame type: + // - OptimizedFrame : Data is the stack slot count of the entire frame. + // - InterpretedFrame: Data is the register index holding the context. + virtual int LookupExceptionHandlerInTable( + int* data, HandlerTable::CatchPrediction* prediction); + + // Architecture-specific register description. + static Register fp_register(); + static Register context_register(); + static Register constant_pool_pointer_register(); + + static JavaScriptFrame* cast(StackFrame* frame) { + DCHECK(frame->is_java_script()); + return static_cast<JavaScriptFrame*>(frame); + } + + static void PrintFunctionAndOffset(JSFunction function, 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(JSFunction function, + AbstractCode code, + int code_offset); + + protected: + inline explicit JavaScriptFrame(StackFrameIteratorBase* iterator); + + Address GetCallerStackPointer() const override; + + virtual void PrintFrameKind(StringStream* accumulator) const {} + + private: + inline Object function_slot_object() const; + + friend class StackFrameIteratorBase; +}; + +class StubFrame : public StandardFrame { + public: + Type type() const override { return STUB; } + + // GC support. + void Iterate(RootVisitor* v) const override; + + // Determine the code for the frame. + Code unchecked_code() const override; + + // Lookup exception handler for current {pc}, returns -1 if none found. Only + // TurboFan stub frames are supported. Also returns data associated with the + // handler site: + // - TurboFan stub: Data is the stack slot count of the entire frame. + int LookupExceptionHandlerInTable(int* data); + + protected: + inline explicit StubFrame(StackFrameIteratorBase* iterator); + + Address GetCallerStackPointer() const override; + + friend class StackFrameIteratorBase; +}; + +class OptimizedFrame : public JavaScriptFrame { + public: + Type type() const override { return OPTIMIZED; } + + // GC support. + void Iterate(RootVisitor* v) const override; + + // Return a list with {SharedFunctionInfo} objects of this frame. + // The functions are ordered bottom-to-top (i.e. functions.last() + // is the top-most activation) + void GetFunctions(std::vector<SharedFunctionInfo>* functions) const override; + + void Summarize(std::vector<FrameSummary>* frames) const override; + + // Lookup exception handler for current {pc}, returns -1 if none found. + int LookupExceptionHandlerInTable( + int* data, HandlerTable::CatchPrediction* prediction) override; + + DeoptimizationData GetDeoptimizationData(int* deopt_index) const; + + Object receiver() const override; + int ComputeParametersCount() const override; + + static int StackSlotOffsetRelativeToFp(int slot_index); + + protected: + inline explicit OptimizedFrame(StackFrameIteratorBase* iterator); + + private: + friend class StackFrameIteratorBase; + + Object StackSlotAt(int index) const; +}; + +class InterpretedFrame : public JavaScriptFrame { + public: + Type type() const override { return INTERPRETED; } + + // Accessors. + int position() const override; + + // Lookup exception handler for current {pc}, returns -1 if none found. + int LookupExceptionHandlerInTable( + int* data, HandlerTable::CatchPrediction* prediction) override; + + // Returns the current offset into the bytecode stream. + int GetBytecodeOffset() const; + + // Updates the current offset into the bytecode stream, mainly used for stack + // unwinding to continue execution at a different bytecode offset. + void PatchBytecodeOffset(int new_offset); + + // Returns the frame's current bytecode array. + BytecodeArray GetBytecodeArray() const; + + // Updates the frame's BytecodeArray with |bytecode_array|. Used by the + // debugger to swap execution onto a BytecodeArray patched with breakpoints. + void PatchBytecodeArray(BytecodeArray bytecode_array); + + // Access to the interpreter register file for this frame. + Object ReadInterpreterRegister(int register_index) const; + void WriteInterpreterRegister(int register_index, Object value); + + // Build a list with summaries for this frame including all inlined frames. + void Summarize(std::vector<FrameSummary>* frames) const override; + + static int GetBytecodeOffset(Address fp); + + static InterpretedFrame* cast(StackFrame* frame) { + DCHECK(frame->is_interpreted()); + return static_cast<InterpretedFrame*>(frame); + } + + protected: + inline explicit InterpretedFrame(StackFrameIteratorBase* iterator); + + Address GetExpressionAddress(int n) const override; + + private: + friend class StackFrameIteratorBase; +}; + +// Arguments adaptor frames are automatically inserted below +// JavaScript frames when the actual number of parameters does not +// match the formal number of parameters. +class ArgumentsAdaptorFrame : public JavaScriptFrame { + public: + Type type() const override { return ARGUMENTS_ADAPTOR; } + + // Determine the code for the frame. + Code unchecked_code() const override; + + static ArgumentsAdaptorFrame* cast(StackFrame* frame) { + DCHECK(frame->is_arguments_adaptor()); + return static_cast<ArgumentsAdaptorFrame*>(frame); + } + + int ComputeParametersCount() const override; + + // Printing support. + void Print(StringStream* accumulator, PrintMode mode, + int index) const override; + + protected: + inline explicit ArgumentsAdaptorFrame(StackFrameIteratorBase* iterator); + + private: + friend class StackFrameIteratorBase; +}; + +// Builtin frames are built for builtins with JavaScript linkage, such as +// various standard library functions (i.e. Math.asin, Math.floor, etc.). +class BuiltinFrame final : public JavaScriptFrame { + public: + Type type() const final { return BUILTIN; } + + static BuiltinFrame* cast(StackFrame* frame) { + DCHECK(frame->is_builtin()); + return static_cast<BuiltinFrame*>(frame); + } + int ComputeParametersCount() const final; + + protected: + inline explicit BuiltinFrame(StackFrameIteratorBase* iterator); + + void PrintFrameKind(StringStream* accumulator) const override; + + private: + friend class StackFrameIteratorBase; +}; + +class WasmCompiledFrame : public StandardFrame { + public: + Type type() const override { return WASM_COMPILED; } + + // GC support. + void Iterate(RootVisitor* v) const override; + + // Printing support. + void Print(StringStream* accumulator, PrintMode mode, + int index) const override; + + // Lookup exception handler for current {pc}, returns -1 if none found. Also + // returns the stack slot count of the entire frame. + int LookupExceptionHandlerInTable(int* data); + + // Determine the code for the frame. + Code unchecked_code() const override; + + // Accessors. + WasmInstanceObject wasm_instance() const; + wasm::WasmCode* wasm_code() const; + uint32_t function_index() const; + Script script() const override; + int position() const override; + bool at_to_number_conversion() const; + + void Summarize(std::vector<FrameSummary>* frames) const override; + + static WasmCompiledFrame* cast(StackFrame* frame) { + DCHECK(frame->is_wasm_compiled()); + return static_cast<WasmCompiledFrame*>(frame); + } + + protected: + inline explicit WasmCompiledFrame(StackFrameIteratorBase* iterator); + + Address GetCallerStackPointer() const override; + + private: + friend class StackFrameIteratorBase; + WasmModuleObject module_object() const; +}; + +class WasmExitFrame : public WasmCompiledFrame { + public: + Type type() const override { return WASM_EXIT; } + static Address ComputeStackPointer(Address fp); + + protected: + inline explicit WasmExitFrame(StackFrameIteratorBase* iterator); + + private: + friend class StackFrameIteratorBase; +}; + +class WasmInterpreterEntryFrame final : public StandardFrame { + public: + Type type() const override { return WASM_INTERPRETER_ENTRY; } + + // GC support. + void Iterate(RootVisitor* v) const override; + + // Printing support. + void Print(StringStream* accumulator, PrintMode mode, + int index) const override; + + void Summarize(std::vector<FrameSummary>* frames) const override; + + // Determine the code for the frame. + Code unchecked_code() const override; + + // Accessors. + WasmDebugInfo debug_info() const; + WasmInstanceObject wasm_instance() const; + + Script script() const override; + int position() const override; + 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; + WasmModuleObject module_object() const; +}; + +class WasmToJsFrame : public StubFrame { + public: + Type type() const override { return WASM_TO_JS; } + + protected: + inline explicit WasmToJsFrame(StackFrameIteratorBase* iterator); + + private: + friend class StackFrameIteratorBase; +}; + +class JsToWasmFrame : public StubFrame { + public: + Type type() const override { return JS_TO_WASM; } + + protected: + inline explicit JsToWasmFrame(StackFrameIteratorBase* iterator); + + private: + friend class StackFrameIteratorBase; +}; + +class CWasmEntryFrame : public StubFrame { + public: + Type type() const override { return C_WASM_ENTRY; } + + protected: + inline explicit CWasmEntryFrame(StackFrameIteratorBase* iterator); + + private: + friend class StackFrameIteratorBase; +}; + +class WasmCompileLazyFrame : public StandardFrame { + public: + Type type() const override { return WASM_COMPILE_LAZY; } + + Code unchecked_code() const override; + WasmInstanceObject wasm_instance() const; + FullObjectSlot wasm_instance_slot() const; + + // Garbage collection support. + void Iterate(RootVisitor* v) const override; + + static WasmCompileLazyFrame* cast(StackFrame* frame) { + DCHECK(frame->is_wasm_compile_lazy()); + return static_cast<WasmCompileLazyFrame*>(frame); + } + + protected: + inline explicit WasmCompileLazyFrame(StackFrameIteratorBase* iterator); + + Address GetCallerStackPointer() const override; + + private: + friend class StackFrameIteratorBase; +}; + +class InternalFrame : public StandardFrame { + public: + Type type() const override { return INTERNAL; } + + // Garbage collection support. + void Iterate(RootVisitor* v) const override; + + // Determine the code for the frame. + Code unchecked_code() const override; + + static InternalFrame* cast(StackFrame* frame) { + DCHECK(frame->is_internal()); + return static_cast<InternalFrame*>(frame); + } + + protected: + inline explicit InternalFrame(StackFrameIteratorBase* iterator); + + Address GetCallerStackPointer() const override; + + private: + friend class StackFrameIteratorBase; +}; + +// Construct frames are special trampoline frames introduced to handle +// function invocations through 'new'. +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); + } + + protected: + inline explicit ConstructFrame(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 JavaScriptFrame { + public: + Type type() const override { return JAVA_SCRIPT_BUILTIN_CONTINUATION; } + + static JavaScriptBuiltinContinuationFrame* cast(StackFrame* frame) { + DCHECK(frame->is_java_script_builtin_continuation()); + return static_cast<JavaScriptBuiltinContinuationFrame*>(frame); + } + + int ComputeParametersCount() const override; + intptr_t GetSPToFPDelta() const; + + Object context() const override; + + protected: + inline explicit JavaScriptBuiltinContinuationFrame( + StackFrameIteratorBase* iterator); + + private: + friend class StackFrameIteratorBase; +}; + +class JavaScriptBuiltinContinuationWithCatchFrame + : public JavaScriptBuiltinContinuationFrame { + public: + Type type() const override { + return JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH; + } + + static JavaScriptBuiltinContinuationWithCatchFrame* cast(StackFrame* frame) { + DCHECK(frame->is_java_script_builtin_with_catch_continuation()); + return static_cast<JavaScriptBuiltinContinuationWithCatchFrame*>(frame); + } + + // Patch in the exception object at the appropriate location into the stack + // frame. + void SetException(Object exception); + + protected: + inline explicit JavaScriptBuiltinContinuationWithCatchFrame( + StackFrameIteratorBase* iterator); + + private: + friend class StackFrameIteratorBase; +}; + +class StackFrameIteratorBase { + public: + Isolate* isolate() const { return isolate_; } + + bool done() const { return frame_ == nullptr; } + + protected: + // An iterator that iterates over a given thread's stack. + StackFrameIteratorBase(Isolate* isolate, bool can_access_heap_objects); + + Isolate* isolate_; +#define DECLARE_SINGLETON(ignore, type) type type##_; + STACK_FRAME_TYPE_LIST(DECLARE_SINGLETON) +#undef DECLARE_SINGLETON + StackFrame* frame_; + StackHandler* handler_; + const bool can_access_heap_objects_; + + StackHandler* handler() const { + DCHECK(!done()); + return handler_; + } + + // Get the type-specific frame singleton in a given state. + StackFrame* SingletonFor(StackFrame::Type type, StackFrame::State* state); + // A helper function, can return a nullptr pointer. + StackFrame* SingletonFor(StackFrame::Type type); + + private: + friend class StackFrame; + DISALLOW_COPY_AND_ASSIGN(StackFrameIteratorBase); +}; + +class StackFrameIterator : public StackFrameIteratorBase { + public: + // An iterator that iterates over the isolate's current thread's stack, + V8_EXPORT_PRIVATE explicit StackFrameIterator(Isolate* isolate); + // An iterator that iterates over a given thread's stack. + V8_EXPORT_PRIVATE StackFrameIterator(Isolate* isolate, ThreadLocalTop* t); + + StackFrame* frame() const { + DCHECK(!done()); + return frame_; + } + V8_EXPORT_PRIVATE void Advance(); + + private: + // Go back to the first frame. + void Reset(ThreadLocalTop* top); + + DISALLOW_COPY_AND_ASSIGN(StackFrameIterator); +}; + +// Iterator that supports iterating through all JavaScript frames. +class JavaScriptFrameIterator { + public: + inline explicit JavaScriptFrameIterator(Isolate* isolate); + inline JavaScriptFrameIterator(Isolate* isolate, ThreadLocalTop* top); + + inline JavaScriptFrame* frame() const; + + bool done() const { return iterator_.done(); } + V8_EXPORT_PRIVATE void Advance(); + void AdvanceOneFrame() { iterator_.Advance(); } + + private: + StackFrameIterator iterator_; +}; + +// NOTE: The stack trace frame iterator is an iterator that only traverse proper +// JavaScript frames that have proper JavaScript functions and WebAssembly +// frames. +class V8_EXPORT_PRIVATE StackTraceFrameIterator { + public: + explicit StackTraceFrameIterator(Isolate* isolate); + // Skip frames until the frame with the given id is reached. + StackTraceFrameIterator(Isolate* isolate, StackFrame::Id id); + bool done() const { return iterator_.done(); } + void Advance(); + void AdvanceOneFrame() { iterator_.Advance(); } + + inline StandardFrame* frame() const; + + inline bool is_javascript() const; + inline bool is_wasm() const; + inline JavaScriptFrame* javascript_frame() const; + + private: + StackFrameIterator iterator_; + bool IsValidFrame(StackFrame* frame) const; +}; + +class SafeStackFrameIterator : public StackFrameIteratorBase { + public: + SafeStackFrameIterator(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_; } + + private: + void AdvanceOneFrame(); + + bool IsValidStackAddress(Address addr) const { + return low_bound_ <= addr && addr <= high_bound_; + } + bool IsValidFrame(StackFrame* frame) const; + bool IsValidCaller(StackFrame* frame); + bool IsValidExitFrame(Address fp) const; + bool IsValidTop(ThreadLocalTop* top) const; + + // Returns true if the pc points to a bytecode handler and the frame pointer + // doesn't seem to be a bytecode handler's frame, which implies that the + // bytecode handler has an elided frame. This is not precise and might give + // false negatives since it relies on checks to the frame's type marker, + // which might be uninitialized. + 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_; +}; +} // namespace internal +} // namespace v8 + +#endif // V8_EXECUTION_FRAMES_H_ |