1 // Copyright 2012 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_ARM_FRAME_CONSTANTS_ARM_H_
6 #define V8_EXECUTION_ARM_FRAME_CONSTANTS_ARM_H_
7 
8 #include "src/base/bits.h"
9 #include "src/base/macros.h"
10 #include "src/codegen/arm/register-arm.h"
11 #include "src/execution/frame-constants.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 // The layout of an EntryFrame is as follows:
17 //            TOP OF THE STACK     LOWEST ADDRESS
18 //         +---------------------+-----------------------
19 //   0     |   saved fp (r11)    |  <-- frame ptr
20 //         |- - - - - - - - - - -|
21 //   1     |   saved lr (r14)    |
22 //         |- - - - - - - - - - -|
23 //  2..3   | saved register d8   |
24 //  ...    |        ...          |
25 //  16..17 | saved register d15  |
26 //         |- - - - - - - - - - -|
27 //  18     | saved register r4   |
28 //  ...    |        ...          |
29 //  24     | saved register r10  |
30 //    -----+---------------------+-----------------------
31 //           BOTTOM OF THE STACK   HIGHEST ADDRESS
32 class EntryFrameConstants : public AllStatic {
33  public:
34   // This is the offset to where JSEntry pushes the current value of
35   // Isolate::c_entry_fp onto the stack.
36   static constexpr int kCallerFPOffset = -3 * kSystemPointerSize;
37 
38   // Stack offsets for arguments passed to JSEntry.
39   static constexpr int kArgcOffset = +0 * kSystemPointerSize;
40   static constexpr int kArgvOffset = +1 * kSystemPointerSize;
41 
42   // These offsets refer to the immediate caller (i.e a native frame).
43   static constexpr int kDirectCallerFPOffset = 0;
44   static constexpr int kDirectCallerPCOffset =
45       kDirectCallerFPOffset + 1 * kSystemPointerSize;
46   static constexpr int kDirectCallerGeneralRegistersOffset =
47       kDirectCallerPCOffset +
48       /* saved caller PC */
49       kSystemPointerSize +
50       /* d8...d15 */
51       kNumDoubleCalleeSaved * kDoubleSize;
52   static constexpr int kDirectCallerSPOffset =
53       kDirectCallerGeneralRegistersOffset +
54       /* r4...r10 (i.e. callee saved without fp) */
55       (kNumCalleeSaved - 1) * kSystemPointerSize;
56 };
57 
58 class WasmCompileLazyFrameConstants : public TypedFrameConstants {
59  public:
60   static constexpr int kNumberOfSavedGpParamRegs = 4;
61   static constexpr int kNumberOfSavedFpParamRegs = 8;
62 
63   // FP-relative.
64   // The instance is pushed as part of the saved registers. Being in {r3}, it is
65   // at position 1 in the list [r0, r2, r3, r6] (kGpParamRegisters sorted by
66   // number and indexed zero-based from the back).
67   static constexpr int kWasmInstanceOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1);
68   static constexpr int kFixedFrameSizeFromFp =
69       TypedFrameConstants::kFixedFrameSizeFromFp +
70       kNumberOfSavedGpParamRegs * kPointerSize +
71       kNumberOfSavedFpParamRegs * kDoubleSize;
72 };
73 
74 // Frame constructed by the {WasmDebugBreak} builtin.
75 // After pushing the frame type marker, the builtin pushes all Liftoff cache
76 // registers (see liftoff-assembler-defs.h).
77 class WasmDebugBreakFrameConstants : public TypedFrameConstants {
78  public:
79   // r10: root, r11: fp, r12: ip, r13: sp, r14: lr, r15: pc.
80   static constexpr RegList kPushedGpRegs =
81       Register::ListOf(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9);
82 
83   // d13: zero, d14-d15: scratch
84   static constexpr RegList kPushedFpRegs = LowDwVfpRegister::ListOf(
85       d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12);
86 
87   static constexpr int kNumPushedGpRegisters =
88       base::bits::CountPopulation(kPushedGpRegs);
89   static constexpr int kNumPushedFpRegisters =
90       base::bits::CountPopulation(kPushedFpRegs);
91 
92   static constexpr int kLastPushedGpRegisterOffset =
93       -TypedFrameConstants::kFixedFrameSizeFromFp -
94       kSystemPointerSize * kNumPushedGpRegisters;
95   static constexpr int kLastPushedFpRegisterOffset =
96       kLastPushedGpRegisterOffset - kDoubleSize * kNumPushedFpRegisters;
97 
98   // Offsets are fp-relative.
GetPushedGpRegisterOffset(int reg_code)99   static int GetPushedGpRegisterOffset(int reg_code) {
100     DCHECK_NE(0, kPushedGpRegs & (1 << reg_code));
101     uint32_t lower_regs = kPushedGpRegs & ((uint32_t{1} << reg_code) - 1);
102     return kLastPushedGpRegisterOffset +
103            base::bits::CountPopulation(lower_regs) * kSystemPointerSize;
104   }
105 
GetPushedFpRegisterOffset(int reg_code)106   static int GetPushedFpRegisterOffset(int reg_code) {
107     DCHECK_NE(0, kPushedFpRegs & (1 << reg_code));
108     uint32_t lower_regs = kPushedFpRegs & ((uint32_t{1} << reg_code) - 1);
109     return kLastPushedFpRegisterOffset +
110            base::bits::CountPopulation(lower_regs) * kDoubleSize;
111   }
112 };
113 
114 }  // namespace internal
115 }  // namespace v8
116 
117 #endif  // V8_EXECUTION_ARM_FRAME_CONSTANTS_ARM_H_
118