1 // Copyright 2013 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_ARM64_FRAME_CONSTANTS_ARM64_H_ 6 #define V8_EXECUTION_ARM64_FRAME_CONSTANTS_ARM64_H_ 7 8 #include "src/base/bits.h" 9 #include "src/base/macros.h" 10 #include "src/codegen/register.h" 11 #include "src/codegen/reglist.h" 12 #include "src/common/globals.h" 13 #include "src/execution/frame-constants.h" 14 15 namespace v8 { 16 namespace internal { 17 18 // The layout of an EntryFrame is as follows: 19 // 20 // BOTTOM OF THE STACK HIGHEST ADDRESS 21 // slot Entry frame 22 // +---------------------+----------------------- 23 // -19 | saved register d15 | 24 // ... | ... | 25 // -12 | saved register d8 | 26 // |- - - - - - - - - - -| 27 // -11 | saved register x28 | 28 // ... | ... | 29 // -2 | saved register x19 | 30 // |- - - - - - - - - - -| 31 // -1 | saved lr (x30) | 32 // |- - - - - - - - - - -| 33 // 0 | saved fp (x29) | <-- frame ptr 34 // |- - - - - - - - - - -| 35 // 1 | stack frame marker | 36 // | (ENTRY) | 37 // |- - - - - - - - - - -| 38 // 2 | stack frame marker | 39 // | (0) | 40 // |- - - - - - - - - - -| 41 // 3 | C entry FP | 42 // |- - - - - - - - - - -| 43 // 4 | JS entry frame | <-- stack ptr 44 // | marker | 45 // -----+---------------------+----------------------- 46 // TOP OF THE STACK LOWEST ADDRESS 47 // 48 class EntryFrameConstants : public AllStatic { 49 public: 50 // This is the offset to where JSEntry pushes the current value of 51 // Isolate::c_entry_fp onto the stack. 52 static constexpr int kCallerFPOffset = -3 * kSystemPointerSize; 53 static constexpr int kFixedFrameSize = 4 * kSystemPointerSize; 54 55 // The following constants are defined so we can static-assert their values 56 // near the relevant JSEntry assembly code, not because they're actually very 57 // useful. 58 static constexpr int kCalleeSavedRegisterBytesPushedBeforeFpLrPair = 59 18 * kSystemPointerSize; 60 static constexpr int kCalleeSavedRegisterBytesPushedAfterFpLrPair = 0; 61 static constexpr int kOffsetToCalleeSavedRegisters = 0; 62 63 // These offsets refer to the immediate caller (a native frame), not to the 64 // previous JS exit frame like kCallerFPOffset above. 65 static constexpr int kDirectCallerFPOffset = 66 kCalleeSavedRegisterBytesPushedAfterFpLrPair + 67 kOffsetToCalleeSavedRegisters; 68 static constexpr int kDirectCallerPCOffset = 69 kDirectCallerFPOffset + 1 * kSystemPointerSize; 70 static constexpr int kDirectCallerSPOffset = 71 kDirectCallerPCOffset + 1 * kSystemPointerSize + 72 kCalleeSavedRegisterBytesPushedBeforeFpLrPair; 73 }; 74 75 class WasmCompileLazyFrameConstants : public TypedFrameConstants { 76 public: 77 static constexpr int kNumberOfSavedGpParamRegs = 8; 78 static constexpr int kNumberOfSavedFpParamRegs = 8; 79 80 // FP-relative. 81 // The instance is pushed as part of the saved registers. Being in {r7}, it is 82 // the first register pushed (highest register code in 83 // {wasm::kGpParamRegisters}). Because of padding of the frame header, it is 84 // actually one word further down the stack though (thus at position {1}). 85 static constexpr int kWasmInstanceOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1); 86 static constexpr int kFixedFrameSizeFromFp = 87 // Header is padded to 16 byte (see {MacroAssembler::EnterFrame}). 88 RoundUp<16>(TypedFrameConstants::kFixedFrameSizeFromFp) + 89 kNumberOfSavedGpParamRegs * kSystemPointerSize + 90 kNumberOfSavedFpParamRegs * kSimd128Size; 91 }; 92 93 // Frame constructed by the {WasmDebugBreak} builtin. 94 // After pushing the frame type marker, the builtin pushes all Liftoff cache 95 // registers (see liftoff-assembler-defs.h). 96 class WasmDebugBreakFrameConstants : public TypedFrameConstants { 97 public: 98 // x16: ip0, x17: ip1, x18: platform register, x26: root, x28: base, x29: fp, 99 // x30: lr, x31: xzr. 100 static constexpr RegList kPushedGpRegs = { 101 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, 102 x12, x13, x14, x15, x19, x20, x21, x22, x23, x24, x25, x27}; 103 104 // We push FpRegs as 128-bit SIMD registers, so 16-byte frame alignment 105 // is guaranteed regardless of register count. 106 static constexpr DoubleRegList kPushedFpRegs = { 107 d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, 108 d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29}; 109 110 static constexpr int kNumPushedGpRegisters = kPushedGpRegs.Count(); 111 static_assert(kNumPushedGpRegisters % 2 == 0, 112 "stack frames need to be 16-byte aligned"); 113 114 static constexpr int kNumPushedFpRegisters = kPushedFpRegs.Count(); 115 116 static constexpr int kLastPushedGpRegisterOffset = 117 // Header is padded to 16 byte (see {MacroAssembler::EnterFrame}). 118 -RoundUp<16>(TypedFrameConstants::kFixedFrameSizeFromFp) - 119 kSystemPointerSize * kNumPushedGpRegisters; 120 static constexpr int kLastPushedFpRegisterOffset = 121 kLastPushedGpRegisterOffset - kSimd128Size * kNumPushedFpRegisters; 122 123 // Offsets are fp-relative. GetPushedGpRegisterOffset(int reg_code)124 static int GetPushedGpRegisterOffset(int reg_code) { 125 DCHECK_NE(0, kPushedGpRegs.bits() & (1 << reg_code)); 126 uint32_t lower_regs = 127 kPushedGpRegs.bits() & ((uint32_t{1} << reg_code) - 1); 128 return kLastPushedGpRegisterOffset + 129 base::bits::CountPopulation(lower_regs) * kSystemPointerSize; 130 } 131 GetPushedFpRegisterOffset(int reg_code)132 static int GetPushedFpRegisterOffset(int reg_code) { 133 DCHECK_NE(0, kPushedFpRegs.bits() & (1 << reg_code)); 134 uint32_t lower_regs = 135 kPushedFpRegs.bits() & ((uint32_t{1} << reg_code) - 1); 136 return kLastPushedFpRegisterOffset + 137 base::bits::CountPopulation(lower_regs) * kSimd128Size; 138 } 139 }; 140 141 } // namespace internal 142 } // namespace v8 143 144 #endif // V8_EXECUTION_ARM64_FRAME_CONSTANTS_ARM64_H_ 145