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
11 namespace v8 {
12 namespace 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 //
51 class 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 //
109 class 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 //
158 class 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
199 class 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.
209 class 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
221 class 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
234 class 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
241 class 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
248 class 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
256 class 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
278 class 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.
290 class 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 //
345 class 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.
374 class 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.
386 class BaselineFrameConstants : public UnoptimizedFrameConstants {
387 public:
388 static constexpr int kFeedbackVectorExpressionIndex =
389 kBytecodeOffsetOrFeedbackVectorExpressionIndex;
390
391 static constexpr int kFeedbackVectorFromFp =
392 kBytecodeOffsetOrFeedbackVectorFromFp;
393 };
394
FPOffsetToFrameSlot(int frame_offset)395 inline static int FPOffsetToFrameSlot(int frame_offset) {
396 return StandardFrameConstants::kFixedSlotCountAboveFp - 1 -
397 frame_offset / kSystemPointerSize;
398 }
399
FrameSlotToFPOffset(int slot)400 inline 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