1// Copyright 2017 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_EXECUTION_FRAME_CONSTANTS_H_
6#define V8_EXECUTION_FRAME_CONSTANTS_H_
7
8#include "src/common/globals.h"
9#include "src/flags/flags.h"
10
11namespace v8 {
12namespace internal {
13
14// Every pointer in a frame has a slot id. On 32-bit platforms, doubles consume
15// two slots.
16//
17// Stack slot indices >= 0 access the callee stack with slot 0 corresponding to
18// the callee's saved return address and 1 corresponding to the saved frame
19// pointer. Some frames have additional information stored in the fixed header,
20// for example JSFunctions store the function context and marker in the fixed
21// header, with slot index 2 corresponding to the current function context and 3
22// corresponding to the frame marker/JSFunction.
23//
24//  slot      JS frame
25//       +-----------------+--------------------------------
26//  -n-1 |   parameter n   |                            ^
27//       |- - - - - - - - -|                            |
28//  -n   |  parameter n-1  |                          Caller
29//  ...  |       ...       |                       frame slots
30//  -2   |   parameter 1   |                       (slot < 0)
31//       |- - - - - - - - -|                            |
32//  -1   |   parameter 0   |                            v
33//  -----+-----------------+--------------------------------
34//   0   |   return addr   |   ^                        ^
35//       |- - - - - - - - -|   |                        |
36//   1   | saved frame ptr | Fixed                      |
37//       |- - - - - - - - -| Header <-- frame ptr       |
38//   2   | [Constant Pool] |   |                        |
39//       |- - - - - - - - -|   |                        |
40// 2+cp  |Context/Frm. Type|   v   if a constant pool   |
41//       |-----------------+----    is used, cp = 1,    |
42// 3+cp  |                 |   ^   otherwise, cp = 0    |
43//       |- - - - - - - - -|   |                        |
44// 4+cp  |                 |   |                      Callee
45//       |- - - - - - - - -|   |                   frame slots
46//  ...  |                 | Frame slots           (slot >= 0)
47//       |- - - - - - - - -|   |                        |
48//       |                 |   v                        |
49//  -----+-----------------+----- <-- stack ptr -------------
50//
51class CommonFrameConstants : public AllStatic {
52 public:
53  static constexpr int kCallerFPOffset = 0 * kSystemPointerSize;
54  static constexpr int kCallerPCOffset = kCallerFPOffset + 1 * kFPOnStackSize;
55  static constexpr int kCallerSPOffset = kCallerPCOffset + 1 * kPCOnStackSize;
56
57  // Fixed part of the frame consists of return address, caller fp,
58  // constant pool (if FLAG_enable_embedded_constant_pool), context, and
59  // function. CommonFrame::IterateExpressions assumes that kLastObjectOffset
60  // is the last object pointer.
61  static constexpr int kFixedFrameSizeAboveFp = kPCOnStackSize + kFPOnStackSize;
62  static constexpr int kFixedSlotCountAboveFp =
63      kFixedFrameSizeAboveFp / kSystemPointerSize;
64  static constexpr int kCPSlotSize =
65      FLAG_enable_embedded_constant_pool ? kSystemPointerSize : 0;
66  static constexpr int kCPSlotCount = kCPSlotSize / kSystemPointerSize;
67  static constexpr int kConstantPoolOffset =
68      kCPSlotSize ? -1 * kSystemPointerSize : 0;
69  static constexpr int kContextOrFrameTypeSize = kSystemPointerSize;
70  static constexpr int kContextOrFrameTypeOffset =
71      -(kCPSlotSize + kContextOrFrameTypeSize);
72};
73
74// StandardFrames are used for both unoptimized and optimized JavaScript
75// frames. They always have a context below the saved fp/constant
76// pool, below that the JSFunction of the executing function and below that an
77// integer (not a Smi) containing the actual number of arguments passed to the
78// JavaScript code.
79//
80//  slot      JS frame
81//       +-----------------+--------------------------------
82//  -n-1 |   parameter n   |                            ^
83//       |- - - - - - - - -|                            |
84//  -n   |  parameter n-1  |                          Caller
85//  ...  |       ...       |                       frame slots
86//  -2   |   parameter 1   |                       (slot < 0)
87//       |- - - - - - - - -|                            |
88//  -1   |   parameter 0   |                            v
89//  -----+-----------------+--------------------------------
90//   0   |   return addr   |   ^                        ^
91//       |- - - - - - - - -|   |                        |
92//   1   | saved frame ptr | Fixed                      |
93//       |- - - - - - - - -| Header <-- frame ptr       |
94//   2   | [Constant Pool] |   |                        |
95//       |- - - - - - - - -|   |                        |
96// 2+cp  |     Context     |   |   if a constant pool   |
97//       |- - - - - - - - -|   |    is used, cp = 1,    |
98// 3+cp  |    JSFunction   |   |   otherwise, cp = 0    |
99//       |- - - - - - - - -|   |                        |
100// 4+cp  |      argc       |   v                        |
101//       +-----------------+----                        |
102// 5+cp  |  expressions or |   ^                      Callee
103//       |- - - - - - - - -|   |                   frame slots
104//  ...  |  pushed values  | Frame slots           (slot >= 0)
105//       |- - - - - - - - -|   |                        |
106//       |                 |   v                        |
107//  -----+-----------------+----- <-- stack ptr -------------
108//
109class StandardFrameConstants : public CommonFrameConstants {
110 public:
111  static constexpr int kFixedFrameSizeFromFp =
112      3 * kSystemPointerSize + kCPSlotSize;
113  static constexpr int kFixedFrameSize =
114      kFixedFrameSizeAboveFp + kFixedFrameSizeFromFp;
115  static constexpr int kFixedSlotCountFromFp =
116      kFixedFrameSizeFromFp / kSystemPointerSize;
117  static constexpr int kFixedSlotCount = kFixedFrameSize / kSystemPointerSize;
118  static constexpr int kContextOffset = kContextOrFrameTypeOffset;
119  static constexpr int kFunctionOffset = -2 * kSystemPointerSize - kCPSlotSize;
120  static constexpr int kArgCOffset = -3 * kSystemPointerSize - kCPSlotSize;
121  static constexpr int kExpressionsOffset =
122      -4 * kSystemPointerSize - kCPSlotSize;
123  static constexpr int kFirstPushedFrameValueOffset = kExpressionsOffset;
124  static constexpr int kLastObjectOffset = kContextOffset;
125};
126
127// TypedFrames have a type maker value below the saved FP/constant pool to
128// distinguish them from StandardFrames, which have a context in that position
129// instead.
130//
131//  slot      JS frame
132//       +-----------------+--------------------------------
133//  -n-1 |   parameter n   |                            ^
134//       |- - - - - - - - -|                            |
135//  -n   |  parameter n-1  |                          Caller
136//  ...  |       ...       |                       frame slots
137//  -2   |   parameter 1   |                       (slot < 0)
138//       |- - - - - - - - -|                            |
139//  -1   |   parameter 0   |                            v
140//  -----+-----------------+--------------------------------
141//   0   |   return addr   |   ^                        ^
142//       |- - - - - - - - -|   |                        |
143//   1   | saved frame ptr | Fixed                      |
144//       |- - - - - - - - -| Header <-- frame ptr       |
145//   2   | [Constant Pool] |   |                        |
146//       |- - - - - - - - -|   |                        |
147// 2+cp  |Frame Type Marker|   v   if a constant pool   |
148//       |-----------------+----    is used, cp = 1,    |
149// 3+cp  |  pushed value 0 |   ^   otherwise, cp = 0    |
150//       |- - - - - - - - -|   |                        |
151// 4+cp  |  pushed value 1 |   |                      Callee
152//       |- - - - - - - - -|   |                   frame slots
153//  ...  |                 | Frame slots           (slot >= 0)
154//       |- - - - - - - - -|   |                        |
155//       |                 |   v                        |
156//  -----+-----------------+----- <-- stack ptr -------------
157//
158class TypedFrameConstants : public CommonFrameConstants {
159 public:
160  static constexpr int kFrameTypeSize = kContextOrFrameTypeSize;
161  static constexpr int kFrameTypeOffset = kContextOrFrameTypeOffset;
162  static constexpr int kFixedFrameSizeFromFp = kCPSlotSize + kFrameTypeSize;
163  static constexpr int kFixedSlotCountFromFp =
164      kFixedFrameSizeFromFp / kSystemPointerSize;
165  static constexpr int kFixedFrameSize =
166      StandardFrameConstants::kFixedFrameSizeAboveFp + kFixedFrameSizeFromFp;
167  static constexpr int kFixedSlotCount = kFixedFrameSize / kSystemPointerSize;
168  static constexpr int kFirstPushedFrameValueOffset =
169      -kFixedFrameSizeFromFp - kSystemPointerSize;
170};
171
172#define FRAME_PUSHED_VALUE_OFFSET(parent, x) \
173  (parent::kFirstPushedFrameValueOffset - (x)*kSystemPointerSize)
174#define FRAME_SIZE(parent, count) \
175  (parent::kFixedFrameSize + (count)*kSystemPointerSize)
176#define FRAME_SIZE_FROM_FP(parent, count) \
177  (parent::kFixedFrameSizeFromFp + (count)*kSystemPointerSize)
178#define DEFINE_FRAME_SIZES(parent, count)                                      \
179  static constexpr int kFixedFrameSize = FRAME_SIZE(parent, count);            \
180  static constexpr int kFixedSlotCount = kFixedFrameSize / kSystemPointerSize; \
181  static constexpr int kFixedFrameSizeFromFp =                                 \
182      FRAME_SIZE_FROM_FP(parent, count);                                       \
183  static constexpr int kFixedSlotCountFromFp =                                 \
184      kFixedFrameSizeFromFp / kSystemPointerSize;                              \
185  static constexpr int kExtraSlotCount =                                       \
186      kFixedFrameSize / kSystemPointerSize -                                   \
187      parent::kFixedFrameSize / kSystemPointerSize
188
189#define STANDARD_FRAME_EXTRA_PUSHED_VALUE_OFFSET(x) \
190  FRAME_PUSHED_VALUE_OFFSET(StandardFrameConstants, x)
191#define DEFINE_STANDARD_FRAME_SIZES(count) \
192  DEFINE_FRAME_SIZES(StandardFrameConstants, count)
193
194#define TYPED_FRAME_PUSHED_VALUE_OFFSET(x) \
195  FRAME_PUSHED_VALUE_OFFSET(TypedFrameConstants, x)
196#define DEFINE_TYPED_FRAME_SIZES(count) \
197  DEFINE_FRAME_SIZES(TypedFrameConstants, count)
198
199class BuiltinFrameConstants : public TypedFrameConstants {
200 public:
201  // FP-relative.
202  static constexpr int kFunctionOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0);
203  static constexpr int kLengthOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1);
204  DEFINE_TYPED_FRAME_SIZES(2);
205};
206
207// Fixed frame slots shared by the js-to-wasm wrapper, the
208// ReturnPromiseOnSuspend wrapper and the WasmResume wrapper.
209class BuiltinWasmWrapperConstants : public TypedFrameConstants {
210 public:
211  // This slot contains the number of slots at the top of the frame that need to
212  // be scanned by the GC.
213  static constexpr int kGCScanSlotCountOffset =
214      TYPED_FRAME_PUSHED_VALUE_OFFSET(0);
215  // The number of parameters passed to this function.
216  static constexpr int kInParamCountOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1);
217  // The number of parameters according to the signature.
218  static constexpr int kParamCountOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(2);
219};
220
221class ConstructFrameConstants : public TypedFrameConstants {
222 public:
223  // FP-relative.
224  static constexpr int kContextOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0);
225  static constexpr int kLengthOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1);
226  static constexpr int kConstructorOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(2);
227  static constexpr int kPaddingOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(3);
228  static constexpr int kNewTargetOrImplicitReceiverOffset =
229      TYPED_FRAME_PUSHED_VALUE_OFFSET(4);
230  DEFINE_TYPED_FRAME_SIZES(5);
231};
232
233#if V8_ENABLE_WEBASSEMBLY
234class CWasmEntryFrameConstants : public TypedFrameConstants {
235 public:
236  // FP-relative:
237  static constexpr int kCEntryFPOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0);
238  DEFINE_TYPED_FRAME_SIZES(1);
239};
240
241class WasmFrameConstants : public TypedFrameConstants {
242 public:
243  // FP-relative.
244  static constexpr int kWasmInstanceOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0);
245  DEFINE_TYPED_FRAME_SIZES(1);
246};
247
248class WasmExitFrameConstants : public WasmFrameConstants {
249 public:
250  // FP-relative.
251  static const int kCallingPCOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1);
252  DEFINE_TYPED_FRAME_SIZES(2);
253};
254#endif  // V8_ENABLE_WEBASSEMBLY
255
256class BuiltinContinuationFrameConstants : public TypedFrameConstants {
257 public:
258  // FP-relative.
259  static constexpr int kFunctionOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0);
260  static constexpr int kFrameSPtoFPDeltaAtDeoptimize =
261      TYPED_FRAME_PUSHED_VALUE_OFFSET(1);
262  static constexpr int kBuiltinContextOffset =
263      TYPED_FRAME_PUSHED_VALUE_OFFSET(2);
264  static constexpr int kBuiltinIndexOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(3);
265
266  // The argument count is in the first allocatable register, stored below the
267  // fixed part of the frame and therefore is not part of the fixed frame size.
268  static constexpr int kArgCOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(4);
269  DEFINE_TYPED_FRAME_SIZES(4);
270
271  // Returns the number of padding stack slots needed when we have
272  // 'register_count' register slots.
273  // This is needed on some architectures to ensure the stack pointer is
274  // aligned.
275  static int PaddingSlotCount(int register_count);
276};
277
278class ExitFrameConstants : public TypedFrameConstants {
279 public:
280  static constexpr int kSPOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0);
281  static constexpr int kLastExitFrameField = kSPOffset;
282  DEFINE_TYPED_FRAME_SIZES(1);
283
284  // FP-relative displacement of the caller's SP.  It points just
285  // below the saved PC.
286  static constexpr int kCallerSPDisplacement = kCallerSPOffset;
287};
288
289// Behaves like an exit frame but with target and new target args.
290class BuiltinExitFrameConstants : public ExitFrameConstants {
291 public:
292  static constexpr int kNewTargetOffset =
293      kCallerPCOffset + 1 * kSystemPointerSize;
294  static constexpr int kTargetOffset =
295      kNewTargetOffset + 1 * kSystemPointerSize;
296  static constexpr int kArgcOffset = kTargetOffset + 1 * kSystemPointerSize;
297  static constexpr int kPaddingOffset = kArgcOffset + 1 * kSystemPointerSize;
298  static constexpr int kFirstArgumentOffset =
299      kPaddingOffset + 1 * kSystemPointerSize;
300  static constexpr int kNumExtraArgsWithoutReceiver = 4;
301  static constexpr int kNumExtraArgsWithReceiver =
302      kNumExtraArgsWithoutReceiver + 1;
303};
304
305// Unoptimized frames are used for interpreted and baseline-compiled JavaScript
306// frames. They are a "standard" frame, with an additional fixed header for the
307// BytecodeArray, bytecode offset (if running interpreted), feedback vector (if
308// running baseline code), and then the interpreter register file.
309//
310//  slot      JS frame
311//       +-----------------+--------------------------------
312//  -n-1 |   parameter n   |                            ^
313//       |- - - - - - - - -|                            |
314//  -n   |  parameter n-1  |                          Caller
315//  ...  |       ...       |                       frame slots
316//  -2   |   parameter 1   |                       (slot < 0)
317//       |- - - - - - - - -|                            |
318//  -1   |   parameter 0   |                            v
319//  -----+-----------------+--------------------------------
320//   0   |   return addr   |   ^                        ^
321//       |- - - - - - - - -|   |                        |
322//   1   | saved frame ptr | Fixed                      |
323//       |- - - - - - - - -| Header <-- frame ptr       |
324//   2   | [Constant Pool] |   |                        |
325//       |- - - - - - - - -|   |                        |
326// 2+cp  |     Context     |   |   if a constant pool   |
327//       |- - - - - - - - -|   |    is used, cp = 1,    |
328// 3+cp  |    JSFunction   |   |   otherwise, cp = 0    |
329//       |- - - - - - - - -|   |                        |
330// 4+cp  |      argc       |   v                        |
331//       +-----------------+----                        |
332// 5+cp  |  BytecodeArray  |   ^                        |
333//       |- - - - - - - - -| Unoptimized code header    |
334// 6+cp  |  offset or FBV  |   v                        |
335//       +-----------------+----                        |
336// 7+cp  |   register 0    |   ^                     Callee
337//       |- - - - - - - - -|   |                   frame slots
338// 8+cp  |   register 1    | Register file         (slot >= 0)
339//  ...  |       ...       |   |                        |
340//       |  register n-1   |   |                        |
341//       |- - - - - - - - -|   |                        |
342// 8+cp+n|   register n    |   v                        v
343//  -----+-----------------+----- <-- stack ptr -------------
344//
345class UnoptimizedFrameConstants : public StandardFrameConstants {
346 public:
347  // FP-relative.
348  static constexpr int kBytecodeArrayFromFp =
349      STANDARD_FRAME_EXTRA_PUSHED_VALUE_OFFSET(0);
350  static constexpr int kBytecodeOffsetOrFeedbackVectorFromFp =
351      STANDARD_FRAME_EXTRA_PUSHED_VALUE_OFFSET(1);
352  DEFINE_STANDARD_FRAME_SIZES(2);
353
354  static constexpr int kFirstParamFromFp =
355      StandardFrameConstants::kCallerSPOffset;
356  static constexpr int kRegisterFileFromFp =
357      -kFixedFrameSizeFromFp - kSystemPointerSize;
358  static constexpr int kExpressionsOffset = kRegisterFileFromFp;
359
360  // Expression index for {JavaScriptFrame::GetExpressionAddress}.
361  static constexpr int kBytecodeArrayExpressionIndex = -2;
362  static constexpr int kBytecodeOffsetOrFeedbackVectorExpressionIndex = -1;
363  static constexpr int kRegisterFileExpressionIndex = 0;
364
365  // Returns the number of stack slots needed for 'register_count' registers.
366  // This is needed because some architectures must pad the stack frame with
367  // additional stack slots to ensure the stack pointer is aligned.
368  static int RegisterStackSlotCount(int register_count);
369};
370
371// Interpreter frames are unoptimized frames that are being executed by the
372// interpreter. In this case, the "offset or FBV" slot contains the bytecode
373// offset of the currently executing bytecode.
374class InterpreterFrameConstants : public UnoptimizedFrameConstants {
375 public:
376  static constexpr int kBytecodeOffsetExpressionIndex =
377      kBytecodeOffsetOrFeedbackVectorExpressionIndex;
378
379  static constexpr int kBytecodeOffsetFromFp =
380      kBytecodeOffsetOrFeedbackVectorFromFp;
381};
382
383// Sparkplug frames are unoptimized frames that are being executed by
384// sparkplug-compiled baseline code. base. In this case, the "offset or FBV"
385// slot contains a cached pointer to the feedback vector.
386class BaselineFrameConstants : public UnoptimizedFrameConstants {
387 public:
388  static constexpr int kFeedbackVectorExpressionIndex =
389      kBytecodeOffsetOrFeedbackVectorExpressionIndex;
390
391  static constexpr int kFeedbackVectorFromFp =
392      kBytecodeOffsetOrFeedbackVectorFromFp;
393};
394
395inline static int FPOffsetToFrameSlot(int frame_offset) {
396  return StandardFrameConstants::kFixedSlotCountAboveFp - 1 -
397         frame_offset / kSystemPointerSize;
398}
399
400inline static int FrameSlotToFPOffset(int slot) {
401  return (StandardFrameConstants::kFixedSlotCountAboveFp - 1 - slot) *
402         kSystemPointerSize;
403}
404
405}  // namespace internal
406}  // namespace v8
407
408#if V8_TARGET_ARCH_IA32
409#include "src/execution/ia32/frame-constants-ia32.h"
410#elif V8_TARGET_ARCH_X64
411#include "src/execution/x64/frame-constants-x64.h"
412#elif V8_TARGET_ARCH_ARM64
413#include "src/execution/arm64/frame-constants-arm64.h"
414#elif V8_TARGET_ARCH_ARM
415#include "src/execution/arm/frame-constants-arm.h"
416#elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
417#include "src/execution/ppc/frame-constants-ppc.h"
418#elif V8_TARGET_ARCH_MIPS
419#include "src/execution/mips/frame-constants-mips.h"
420#elif V8_TARGET_ARCH_MIPS64
421#include "src/execution/mips64/frame-constants-mips64.h"
422#elif V8_TARGET_ARCH_LOONG64
423#include "src/execution/loong64/frame-constants-loong64.h"
424#elif V8_TARGET_ARCH_S390
425#include "src/execution/s390/frame-constants-s390.h"
426#elif V8_TARGET_ARCH_RISCV64
427#include "src/execution/riscv64/frame-constants-riscv64.h"
428#else
429#error Unsupported target architecture.
430#endif
431
432#endif  // V8_EXECUTION_FRAME_CONSTANTS_H_
433