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/register.h"
11#include "src/execution/frame-constants.h"
12
13namespace v8 {
14namespace 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
32class 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
58class 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).
77class WasmDebugBreakFrameConstants : public TypedFrameConstants {
78 public:
79  // r10: root, r11: fp, r12: ip, r13: sp, r14: lr, r15: pc.
80  static constexpr RegList kPushedGpRegs = {r0, r1, r2, r3, r4,
81                                            r5, r6, r7, r8, r9};
82
83  // d13: zero, d14-d15: scratch
84  static constexpr DoubleRegList kPushedFpRegs = {d0, d1, d2, d3,  d4,  d5, d6,
85                                                  d7, d8, d9, d10, d11, d12};
86
87  static constexpr int kNumPushedGpRegisters = kPushedGpRegs.Count();
88  static constexpr int kNumPushedFpRegisters = kPushedFpRegs.Count();
89
90  static constexpr int kLastPushedGpRegisterOffset =
91      -TypedFrameConstants::kFixedFrameSizeFromFp -
92      kSystemPointerSize * kNumPushedGpRegisters;
93  static constexpr int kLastPushedFpRegisterOffset =
94      kLastPushedGpRegisterOffset - kDoubleSize * kNumPushedFpRegisters;
95
96  // Offsets are fp-relative.
97  static int GetPushedGpRegisterOffset(int reg_code) {
98    DCHECK_NE(0, kPushedGpRegs.bits() & (1 << reg_code));
99    uint32_t lower_regs =
100        kPushedGpRegs.bits() & ((uint32_t{1} << reg_code) - 1);
101    return kLastPushedGpRegisterOffset +
102           base::bits::CountPopulation(lower_regs) * kSystemPointerSize;
103  }
104
105  static int GetPushedFpRegisterOffset(int reg_code) {
106    DCHECK_NE(0, kPushedFpRegs.bits() & (1 << reg_code));
107    uint32_t lower_regs =
108        kPushedFpRegs.bits() & ((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