// Copyright 2017 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_FRAME_CONSTANTS_H_ #define V8_EXECUTION_FRAME_CONSTANTS_H_ #include "src/common/globals.h" #include "src/flags/flags.h" namespace v8 { namespace internal { // Every pointer in a frame has a slot id. On 32-bit platforms, doubles consume // two slots. // // Stack slot indices >= 0 access the callee stack with slot 0 corresponding to // the callee's saved return address and 1 corresponding to the saved frame // pointer. Some frames have additional information stored in the fixed header, // for example JSFunctions store the function context and marker in the fixed // header, with slot index 2 corresponding to the current function context and 3 // corresponding to the frame marker/JSFunction. // // slot JS frame // +-----------------+-------------------------------- // -n-1 | parameter n | ^ // |- - - - - - - - -| | // -n | parameter n-1 | Caller // ... | ... | frame slots // -2 | parameter 1 | (slot < 0) // |- - - - - - - - -| | // -1 | parameter 0 | v // -----+-----------------+-------------------------------- // 0 | return addr | ^ ^ // |- - - - - - - - -| | | // 1 | saved frame ptr | Fixed | // |- - - - - - - - -| Header <-- frame ptr | // 2 | [Constant Pool] | | | // |- - - - - - - - -| | | // 2+cp |Context/Frm. Type| v if a constant pool | // |-----------------+---- is used, cp = 1, | // 3+cp | | ^ otherwise, cp = 0 | // |- - - - - - - - -| | | // 4+cp | | | Callee // |- - - - - - - - -| | frame slots // ... | | Frame slots (slot >= 0) // |- - - - - - - - -| | | // | | v | // -----+-----------------+----- <-- stack ptr ------------- // class CommonFrameConstants : public AllStatic { … }; // StandardFrames are used for both unoptimized and optimized JavaScript // frames. They always have a context below the saved fp/constant // pool, below that the JSFunction of the executing function and below that an // integer (not a Smi) containing the actual number of arguments passed to the // JavaScript code. // // slot JS frame // +-----------------+-------------------------------- // -n-1 | parameter n | ^ // |- - - - - - - - -| | // -n | parameter n-1 | Caller // ... | ... | frame slots // -2 | parameter 1 | (slot < 0) // |- - - - - - - - -| | // -1 | parameter 0 | v // -----+-----------------+-------------------------------- // 0 | return addr | ^ ^ // |- - - - - - - - -| | | // 1 | saved frame ptr | Fixed | // |- - - - - - - - -| Header <-- frame ptr | // 2 | [Constant Pool] | | | // |- - - - - - - - -| | | // 2+cp | Context | | if a constant pool | // |- - - - - - - - -| | is used, cp = 1, | // 3+cp | JSFunction | | otherwise, cp = 0 | // |- - - - - - - - -| | | // 4+cp | argc | v | // +-----------------+---- | // 5+cp | expressions or | ^ Callee // |- - - - - - - - -| | frame slots // ... | pushed values | Frame slots (slot >= 0) // |- - - - - - - - -| | | // | | v | // -----+-----------------+----- <-- stack ptr ------------- // class StandardFrameConstants : public CommonFrameConstants { … }; // TypedFrames have a type maker value below the saved FP/constant pool to // distinguish them from StandardFrames, which have a context in that position // instead. // // slot JS frame // +-----------------+-------------------------------- // -n-1 | parameter n | ^ // |- - - - - - - - -| | // -n | parameter n-1 | Caller // ... | ... | frame slots // -2 | parameter 1 | (slot < 0) // |- - - - - - - - -| | // -1 | parameter 0 | v // -----+-----------------+-------------------------------- // 0 | return addr | ^ ^ // |- - - - - - - - -| | | // 1 | saved frame ptr | Fixed | // |- - - - - - - - -| Header <-- frame ptr | // 2 | [Constant Pool] | | | // |- - - - - - - - -| | | // 2+cp |Frame Type Marker| v if a constant pool | // |-----------------+---- is used, cp = 1, | // 3+cp | pushed value 0 | ^ otherwise, cp = 0 | // |- - - - - - - - -| | | // 4+cp | pushed value 1 | | Callee // |- - - - - - - - -| | frame slots // ... | | Frame slots (slot >= 0) // |- - - - - - - - -| | | // | | v | // -----+-----------------+----- <-- stack ptr ------------- // class TypedFrameConstants : public CommonFrameConstants { … }; #define FRAME_PUSHED_VALUE_OFFSET(parent, x) … #define FRAME_SIZE(parent, count) … #define FRAME_SIZE_FROM_FP(parent, count) … #define DEFINE_FRAME_SIZES(parent, count) … #define STANDARD_FRAME_EXTRA_PUSHED_VALUE_OFFSET(x) … #define DEFINE_STANDARD_FRAME_SIZES(count) … #define TYPED_FRAME_PUSHED_VALUE_OFFSET(x) … #define DEFINE_TYPED_FRAME_SIZES(count) … class BuiltinFrameConstants : public TypedFrameConstants { … }; class ConstructFrameConstants : public TypedFrameConstants { … }; class FastConstructFrameConstants : public TypedFrameConstants { … }; #if V8_ENABLE_WEBASSEMBLY class CWasmEntryFrameConstants : public TypedFrameConstants { … }; class WasmFrameConstants : public TypedFrameConstants { … }; #if V8_ENABLE_DRUMBRAKE class WasmInterpreterFrameConstants : public TypedFrameConstants { public: // FP-relative. static constexpr int kWasmInstanceObjectOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0); DEFINE_TYPED_FRAME_SIZES(1); }; // Fixed frame slots shared by the interpreter wasm-to-js wrapper. class WasmToJSInterpreterFrameConstants : public TypedFrameConstants { public: // This slot contains the number of slots at the top of the frame that need to // be scanned by the GC. static constexpr int kGCScanSlotCountOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0); // The stack pointer at the moment of the JS function call. static constexpr int kGCSPOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1); }; class WasmInterpreterCWasmEntryConstants : public TypedFrameConstants { public: // FP-relative: static constexpr int kCEntryFPOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0); static constexpr int kSPFPOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1); DEFINE_TYPED_FRAME_SIZES(2); }; #endif // V8_ENABLE_DRUMBRAKE class WasmExitFrameConstants : public WasmFrameConstants { … }; // Fixed frame slots used by the js-to-wasm wrapper. class JSToWasmWrapperFrameConstants : public TypedFrameConstants { … }; // Fixed frame slots used by the ReturnPromiseOnSuspendAsm wrapper // and the WasmResume wrapper. class StackSwitchFrameConstants : public JSToWasmWrapperFrameConstants { … }; class WasmToJSWrapperConstants { … }; #if V8_ENABLE_DRUMBRAKE class BuiltinWasmInterpreterWrapperConstants : public TypedFrameConstants { public: // This slot contains the number of slots at the top of the frame that need to // be scanned by the GC. static constexpr int kGCScanSlotCountOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0); // The number of parameters passed to this function. static constexpr int kInParamCountOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1); // The number of parameters according to the signature. static constexpr int kParamCountOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(2); // The number of return values according to the siganture. static constexpr int kReturnCountOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(3); // `reps_` of wasm::FunctionSig. static constexpr int kValueTypesArrayStartOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(4); // Array of arguments/return values. static constexpr int kArgRetsAddressOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(5); // Whether the array is for arguments or return values. static constexpr int kArgRetsIsArgsOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(6); // The index of the argument or return value being converted. static constexpr int kCurrentIndexOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(7); // Precomputed signature data. static constexpr int kSignatureDataOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(8); }; #endif // V8_ENABLE_DRUMBRAKE #endif // V8_ENABLE_WEBASSEMBLY class BuiltinContinuationFrameConstants : public TypedFrameConstants { … }; class ExitFrameConstants : public TypedFrameConstants { … }; #define EXIT_FRAME_PUSHED_VALUE_OFFSET(x) … #define DEFINE_EXIT_FRAME_SIZES(x) … // Behaves like an exit frame but with target, new target and arguments count // args. class BuiltinExitFrameConstants : public ExitFrameConstants { … }; // Behaves like an exit frame but with v8::FunctionCallbackInfo's implicit // arguments (FCI), followed by JS arguments passed to the JS function // (receiver and etc.). // // slot JS frame // +-----------------+-------------------------------- // -n-1-k| parameter n | ^ // |- - - - - - - - -| | // -n-k | parameter n-1 | Caller // ... | ... | frame slots // -2-k | parameter 1 | (slot < 0) // |- - - - - - - - -| | // -1-k | receiver | v // -----+-----------------+-------------------------------- // -k | FCI slot k-1 | ^ // |- - - - - - - - -| | // -k+1 | FCI slot k-2 | v8::FunctionCallbackInfo's // ... | ... | FCI::implicit_args[k] // -2 | FCI slot 1 | k := FCI::kArgsLength // |- - - - - - - - -| | // -1 | FCI slot 0 | v // -----+-----------------+-------------------------------- // 0 | return addr | ^ ^ // |- - - - - - - - -| | | // 1 | saved frame ptr | ExitFrame | // |- - - - - - - - -| Header <-- frame ptr | // 2 | [Constant Pool] | | | // |- - - - - - - - -| | | // 2+cp |Frame Type Marker| | if a constant pool | // |- - - - - - - - -| | is used, cp = 1, | // 3+cp | caller SP | v otherwise, cp = 0 | // |-----------------+---- | // 4+cp | FCI::argc_ | ^ Callee // |- - - - - - - - -| | frame slots // 5+cp | FCI::values_ | | (slot >= 0) // |- - - - - - - - -| | | // 6+cp | FCI::imp._args_ | Frame slots | // |- - - - - - - - -| | | // ... | C function args | | | // |- - - - - - - - -| | | // | | v | // -----+-----------------+----- <-- stack ptr ------------- // class ApiCallbackExitFrameConstants : public ExitFrameConstants { … }; // Behaves like an exit frame but with v8::PropertyCallbackInfo's (PCI) // fields allocated in GC-ed area of the exit frame, followed by zero or // more parameters (required by some callback kinds). // // slot JS frame // +-----------------+-------------------------------- // -n-1-k| parameter n | ^ // |- - - - - - - - -| | // -n-k | parameter n-1 | Caller // ... | ... | frame slots // -2-k | parameter 1 | (slot < 0) // |- - - - - - - - -| | // -1-k | parameter 0 | v // -----+-----------------+-------------------------------- // -k | PCI slot k-1 | ^ // |- - - - - - - - -| | // -k+1 | PCI slot k-2 | v8::PropertyCallbackInfo's // ... | ... | PCI::args[k] // -2 | PCI slot 1 | k := PCI::kArgsLength // |- - - - - - - - -| | // -1 | PCI slot 0 | v // -----+-----------------+-------------------------------- <-- PCI object // 0 | return addr | ^ ^ // |- - - - - - - - -| | | // 1 | saved frame ptr | ExitFrame | // |- - - - - - - - -| Header <-- frame ptr | // 2 | [Constant Pool] | | | // |- - - - - - - - -| | | // 2+cp |Frame Type Marker| | if a constant pool | // |- - - - - - - - -| | is used, cp = 1, | // 3+cp | caller SP | v otherwise, cp = 0 | // |-----------------+---- | // 4+cp | | ^ Callee // |- - - - - - - - -| | frame slots // ... | C function args | Frame slots (slot >= 0) // |- - - - - - - - -| | | // | | v | // -----+-----------------+----- <-- stack ptr ------------- // class ApiAccessorExitFrameConstants : public ExitFrameConstants { … }; // Unoptimized frames are used for interpreted and baseline-compiled JavaScript // frames. They are a "standard" frame, with an additional fixed header for the // BytecodeArray, bytecode offset (if running interpreted), feedback vector (if // running baseline code), and then the interpreter register file. // // slot JS frame // +-----------------+-------------------------------- // -n-1 | parameter n | ^ // |- - - - - - - - -| | // -n | parameter n-1 | Caller // ... | ... | frame slots // -2 | parameter 1 | (slot < 0) // |- - - - - - - - -| | // -1 | parameter 0 | v // -----+-----------------+-------------------------------- // 0 | return addr | ^ ^ // |- - - - - - - - -| | | // 1 | saved frame ptr | Fixed | // |- - - - - - - - -| Header <-- frame ptr | // 2 | [Constant Pool] | | | // |- - - - - - - - -| | | // 2+cp | Context | | if a constant pool | // |- - - - - - - - -| | is used, cp = 1, | // 3+cp | JSFunction | | otherwise, cp = 0 | // |- - - - - - - - -| | | // 4+cp | argc | v | // +-----------------+---- | // 5+cp | BytecodeArray | ^ | // |- - - - - - - - -| | | // 6+cp | offset / cell | Unoptimized code header | // |- - - - - - - - -| | | // 7+cp | FBV | v | // +-----------------+---- | // 8+cp | register 0 | ^ Callee // |- - - - - - - - -| | frame slots // 9+cp | register 1 | Register file (slot >= 0) // ... | ... | | | // | register n-1 | | | // |- - - - - - - - -| | | // 9+cp+n| register n | v v // -----+-----------------+----- <-- stack ptr ------------- // class UnoptimizedFrameConstants : public StandardFrameConstants { … }; // Interpreter frames are unoptimized frames that are being executed by the // interpreter. In this case, the "offset or cell" slot contains the bytecode // offset of the currently executing bytecode. class InterpreterFrameConstants : public UnoptimizedFrameConstants { … }; // Sparkplug frames are unoptimized frames that are being executed by // sparkplug-compiled baseline code. base. In this case, the "offset or cell" // slot contains the closure feedback cell. class BaselineFrameConstants : public UnoptimizedFrameConstants { … }; inline static int FPOffsetToFrameSlot(int frame_offset) { … } inline static int FrameSlotToFPOffset(int slot) { … } } // namespace internal } // namespace v8 #if V8_TARGET_ARCH_IA32 #include "src/execution/ia32/frame-constants-ia32.h" #elif V8_TARGET_ARCH_X64 #include "src/execution/x64/frame-constants-x64.h" #elif V8_TARGET_ARCH_ARM64 #include "src/execution/arm64/frame-constants-arm64.h" #elif V8_TARGET_ARCH_ARM #include "src/execution/arm/frame-constants-arm.h" #elif V8_TARGET_ARCH_PPC64 #include "src/execution/ppc/frame-constants-ppc.h" #elif V8_TARGET_ARCH_MIPS64 #include "src/execution/mips64/frame-constants-mips64.h" #elif V8_TARGET_ARCH_LOONG64 #include "src/execution/loong64/frame-constants-loong64.h" #elif V8_TARGET_ARCH_S390 #include "src/execution/s390/frame-constants-s390.h" #elif V8_TARGET_ARCH_RISCV32 || V8_TARGET_ARCH_RISCV64 #include "src/execution/riscv/frame-constants-riscv.h" #else #error Unsupported target architecture. #endif #endif // V8_EXECUTION_FRAME_CONSTANTS_H_