| 1 | /* |
| 2 | * Copyright (C) 2013-2019 Apple Inc. All rights reserved. |
| 3 | * |
| 4 | * Redistribution and use in source and binary forms, with or without |
| 5 | * modification, are permitted provided that the following conditions |
| 6 | * are met: |
| 7 | * 1. Redistributions of source code must retain the above copyright |
| 8 | * notice, this list of conditions and the following disclaimer. |
| 9 | * 2. Redistributions in binary form must reproduce the above copyright |
| 10 | * notice, this list of conditions and the following disclaimer in the |
| 11 | * documentation and/or other materials provided with the distribution. |
| 12 | * |
| 13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| 14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| 17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 24 | */ |
| 25 | |
| 26 | #include "config.h" |
| 27 | |
| 28 | #if ENABLE(ASSEMBLER) && CPU(ARM64) |
| 29 | #include "MacroAssembler.h" |
| 30 | |
| 31 | #include "ProbeContext.h" |
| 32 | #include <wtf/InlineASM.h> |
| 33 | |
| 34 | #if OS(LINUX) |
| 35 | #include <asm/hwcap.h> |
| 36 | #include <sys/auxv.h> |
| 37 | #endif |
| 38 | |
| 39 | namespace JSC { |
| 40 | |
| 41 | #if ENABLE(MASM_PROBE) |
| 42 | |
| 43 | extern "C" void ctiMasmProbeTrampoline(); |
| 44 | |
| 45 | using namespace ARM64Registers; |
| 46 | |
| 47 | #if COMPILER(GCC_COMPATIBLE) |
| 48 | |
| 49 | // The following are offsets for Probe::State fields accessed |
| 50 | // by the ctiMasmProbeTrampoline stub. |
| 51 | #if CPU(ADDRESS64) |
| 52 | #define PTR_SIZE 8 |
| 53 | #else |
| 54 | #define PTR_SIZE 4 |
| 55 | #endif |
| 56 | |
| 57 | #define PROBE_PROBE_FUNCTION_OFFSET (0 * PTR_SIZE) |
| 58 | #define PROBE_ARG_OFFSET (1 * PTR_SIZE) |
| 59 | #define PROBE_INIT_STACK_FUNCTION_OFFSET (2 * PTR_SIZE) |
| 60 | #define PROBE_INIT_STACK_ARG_OFFSET (3 * PTR_SIZE) |
| 61 | |
| 62 | #define PROBE_FIRST_GPREG_OFFSET (4 * PTR_SIZE) |
| 63 | |
| 64 | #define GPREG_SIZE 8 |
| 65 | #define PROBE_CPU_X0_OFFSET (PROBE_FIRST_GPREG_OFFSET + (0 * GPREG_SIZE)) |
| 66 | #define PROBE_CPU_X1_OFFSET (PROBE_FIRST_GPREG_OFFSET + (1 * GPREG_SIZE)) |
| 67 | #define PROBE_CPU_X2_OFFSET (PROBE_FIRST_GPREG_OFFSET + (2 * GPREG_SIZE)) |
| 68 | #define PROBE_CPU_X3_OFFSET (PROBE_FIRST_GPREG_OFFSET + (3 * GPREG_SIZE)) |
| 69 | #define PROBE_CPU_X4_OFFSET (PROBE_FIRST_GPREG_OFFSET + (4 * GPREG_SIZE)) |
| 70 | #define PROBE_CPU_X5_OFFSET (PROBE_FIRST_GPREG_OFFSET + (5 * GPREG_SIZE)) |
| 71 | #define PROBE_CPU_X6_OFFSET (PROBE_FIRST_GPREG_OFFSET + (6 * GPREG_SIZE)) |
| 72 | #define PROBE_CPU_X7_OFFSET (PROBE_FIRST_GPREG_OFFSET + (7 * GPREG_SIZE)) |
| 73 | #define PROBE_CPU_X8_OFFSET (PROBE_FIRST_GPREG_OFFSET + (8 * GPREG_SIZE)) |
| 74 | #define PROBE_CPU_X9_OFFSET (PROBE_FIRST_GPREG_OFFSET + (9 * GPREG_SIZE)) |
| 75 | #define PROBE_CPU_X10_OFFSET (PROBE_FIRST_GPREG_OFFSET + (10 * GPREG_SIZE)) |
| 76 | #define PROBE_CPU_X11_OFFSET (PROBE_FIRST_GPREG_OFFSET + (11 * GPREG_SIZE)) |
| 77 | #define PROBE_CPU_X12_OFFSET (PROBE_FIRST_GPREG_OFFSET + (12 * GPREG_SIZE)) |
| 78 | #define PROBE_CPU_X13_OFFSET (PROBE_FIRST_GPREG_OFFSET + (13 * GPREG_SIZE)) |
| 79 | #define PROBE_CPU_X14_OFFSET (PROBE_FIRST_GPREG_OFFSET + (14 * GPREG_SIZE)) |
| 80 | #define PROBE_CPU_X15_OFFSET (PROBE_FIRST_GPREG_OFFSET + (15 * GPREG_SIZE)) |
| 81 | #define PROBE_CPU_X16_OFFSET (PROBE_FIRST_GPREG_OFFSET + (16 * GPREG_SIZE)) |
| 82 | #define PROBE_CPU_X17_OFFSET (PROBE_FIRST_GPREG_OFFSET + (17 * GPREG_SIZE)) |
| 83 | #define PROBE_CPU_X18_OFFSET (PROBE_FIRST_GPREG_OFFSET + (18 * GPREG_SIZE)) |
| 84 | #define PROBE_CPU_X19_OFFSET (PROBE_FIRST_GPREG_OFFSET + (19 * GPREG_SIZE)) |
| 85 | #define PROBE_CPU_X20_OFFSET (PROBE_FIRST_GPREG_OFFSET + (20 * GPREG_SIZE)) |
| 86 | #define PROBE_CPU_X21_OFFSET (PROBE_FIRST_GPREG_OFFSET + (21 * GPREG_SIZE)) |
| 87 | #define PROBE_CPU_X22_OFFSET (PROBE_FIRST_GPREG_OFFSET + (22 * GPREG_SIZE)) |
| 88 | #define PROBE_CPU_X23_OFFSET (PROBE_FIRST_GPREG_OFFSET + (23 * GPREG_SIZE)) |
| 89 | #define PROBE_CPU_X24_OFFSET (PROBE_FIRST_GPREG_OFFSET + (24 * GPREG_SIZE)) |
| 90 | #define PROBE_CPU_X25_OFFSET (PROBE_FIRST_GPREG_OFFSET + (25 * GPREG_SIZE)) |
| 91 | #define PROBE_CPU_X26_OFFSET (PROBE_FIRST_GPREG_OFFSET + (26 * GPREG_SIZE)) |
| 92 | #define PROBE_CPU_X27_OFFSET (PROBE_FIRST_GPREG_OFFSET + (27 * GPREG_SIZE)) |
| 93 | #define PROBE_CPU_X28_OFFSET (PROBE_FIRST_GPREG_OFFSET + (28 * GPREG_SIZE)) |
| 94 | #define PROBE_CPU_FP_OFFSET (PROBE_FIRST_GPREG_OFFSET + (29 * GPREG_SIZE)) |
| 95 | #define PROBE_CPU_LR_OFFSET (PROBE_FIRST_GPREG_OFFSET + (30 * GPREG_SIZE)) |
| 96 | #define PROBE_CPU_SP_OFFSET (PROBE_FIRST_GPREG_OFFSET + (31 * GPREG_SIZE)) |
| 97 | |
| 98 | #define PROBE_CPU_PC_OFFSET (PROBE_FIRST_GPREG_OFFSET + (32 * GPREG_SIZE)) |
| 99 | #define PROBE_CPU_NZCV_OFFSET (PROBE_FIRST_GPREG_OFFSET + (33 * GPREG_SIZE)) |
| 100 | #define PROBE_CPU_FPSR_OFFSET (PROBE_FIRST_GPREG_OFFSET + (34 * GPREG_SIZE)) |
| 101 | |
| 102 | #define PROBE_FIRST_FPREG_OFFSET (PROBE_FIRST_GPREG_OFFSET + (35 * GPREG_SIZE)) |
| 103 | |
| 104 | #define FPREG_SIZE 8 |
| 105 | #define PROBE_CPU_Q0_OFFSET (PROBE_FIRST_FPREG_OFFSET + (0 * FPREG_SIZE)) |
| 106 | #define PROBE_CPU_Q1_OFFSET (PROBE_FIRST_FPREG_OFFSET + (1 * FPREG_SIZE)) |
| 107 | #define PROBE_CPU_Q2_OFFSET (PROBE_FIRST_FPREG_OFFSET + (2 * FPREG_SIZE)) |
| 108 | #define PROBE_CPU_Q3_OFFSET (PROBE_FIRST_FPREG_OFFSET + (3 * FPREG_SIZE)) |
| 109 | #define PROBE_CPU_Q4_OFFSET (PROBE_FIRST_FPREG_OFFSET + (4 * FPREG_SIZE)) |
| 110 | #define PROBE_CPU_Q5_OFFSET (PROBE_FIRST_FPREG_OFFSET + (5 * FPREG_SIZE)) |
| 111 | #define PROBE_CPU_Q6_OFFSET (PROBE_FIRST_FPREG_OFFSET + (6 * FPREG_SIZE)) |
| 112 | #define PROBE_CPU_Q7_OFFSET (PROBE_FIRST_FPREG_OFFSET + (7 * FPREG_SIZE)) |
| 113 | #define PROBE_CPU_Q8_OFFSET (PROBE_FIRST_FPREG_OFFSET + (8 * FPREG_SIZE)) |
| 114 | #define PROBE_CPU_Q9_OFFSET (PROBE_FIRST_FPREG_OFFSET + (9 * FPREG_SIZE)) |
| 115 | #define PROBE_CPU_Q10_OFFSET (PROBE_FIRST_FPREG_OFFSET + (10 * FPREG_SIZE)) |
| 116 | #define PROBE_CPU_Q11_OFFSET (PROBE_FIRST_FPREG_OFFSET + (11 * FPREG_SIZE)) |
| 117 | #define PROBE_CPU_Q12_OFFSET (PROBE_FIRST_FPREG_OFFSET + (12 * FPREG_SIZE)) |
| 118 | #define PROBE_CPU_Q13_OFFSET (PROBE_FIRST_FPREG_OFFSET + (13 * FPREG_SIZE)) |
| 119 | #define PROBE_CPU_Q14_OFFSET (PROBE_FIRST_FPREG_OFFSET + (14 * FPREG_SIZE)) |
| 120 | #define PROBE_CPU_Q15_OFFSET (PROBE_FIRST_FPREG_OFFSET + (15 * FPREG_SIZE)) |
| 121 | #define PROBE_CPU_Q16_OFFSET (PROBE_FIRST_FPREG_OFFSET + (16 * FPREG_SIZE)) |
| 122 | #define PROBE_CPU_Q17_OFFSET (PROBE_FIRST_FPREG_OFFSET + (17 * FPREG_SIZE)) |
| 123 | #define PROBE_CPU_Q18_OFFSET (PROBE_FIRST_FPREG_OFFSET + (18 * FPREG_SIZE)) |
| 124 | #define PROBE_CPU_Q19_OFFSET (PROBE_FIRST_FPREG_OFFSET + (19 * FPREG_SIZE)) |
| 125 | #define PROBE_CPU_Q20_OFFSET (PROBE_FIRST_FPREG_OFFSET + (20 * FPREG_SIZE)) |
| 126 | #define PROBE_CPU_Q21_OFFSET (PROBE_FIRST_FPREG_OFFSET + (21 * FPREG_SIZE)) |
| 127 | #define PROBE_CPU_Q22_OFFSET (PROBE_FIRST_FPREG_OFFSET + (22 * FPREG_SIZE)) |
| 128 | #define PROBE_CPU_Q23_OFFSET (PROBE_FIRST_FPREG_OFFSET + (23 * FPREG_SIZE)) |
| 129 | #define PROBE_CPU_Q24_OFFSET (PROBE_FIRST_FPREG_OFFSET + (24 * FPREG_SIZE)) |
| 130 | #define PROBE_CPU_Q25_OFFSET (PROBE_FIRST_FPREG_OFFSET + (25 * FPREG_SIZE)) |
| 131 | #define PROBE_CPU_Q26_OFFSET (PROBE_FIRST_FPREG_OFFSET + (26 * FPREG_SIZE)) |
| 132 | #define PROBE_CPU_Q27_OFFSET (PROBE_FIRST_FPREG_OFFSET + (27 * FPREG_SIZE)) |
| 133 | #define PROBE_CPU_Q28_OFFSET (PROBE_FIRST_FPREG_OFFSET + (28 * FPREG_SIZE)) |
| 134 | #define PROBE_CPU_Q29_OFFSET (PROBE_FIRST_FPREG_OFFSET + (29 * FPREG_SIZE)) |
| 135 | #define PROBE_CPU_Q30_OFFSET (PROBE_FIRST_FPREG_OFFSET + (30 * FPREG_SIZE)) |
| 136 | #define PROBE_CPU_Q31_OFFSET (PROBE_FIRST_FPREG_OFFSET + (31 * FPREG_SIZE)) |
| 137 | #define PROBE_SIZE (PROBE_FIRST_FPREG_OFFSET + (32 * FPREG_SIZE)) |
| 138 | |
| 139 | #define SAVED_PROBE_RETURN_PC_OFFSET (PROBE_SIZE + (0 * GPREG_SIZE)) |
| 140 | #define PROBE_SIZE_PLUS_EXTRAS (PROBE_SIZE + (3 * GPREG_SIZE)) |
| 141 | |
| 142 | // These ASSERTs remind you that if you change the layout of Probe::State, |
| 143 | // you need to change ctiMasmProbeTrampoline offsets above to match. |
| 144 | #define PROBE_OFFSETOF(x) offsetof(struct Probe::State, x) |
| 145 | static_assert(PROBE_OFFSETOF(probeFunction) == PROBE_PROBE_FUNCTION_OFFSET, "Probe::State::probeFunction's offset matches ctiMasmProbeTrampoline" ); |
| 146 | static_assert(PROBE_OFFSETOF(arg) == PROBE_ARG_OFFSET, "Probe::State::arg's offset matches ctiMasmProbeTrampoline" ); |
| 147 | static_assert(PROBE_OFFSETOF(initializeStackFunction) == PROBE_INIT_STACK_FUNCTION_OFFSET, "Probe::State::initializeStackFunction's offset matches ctiMasmProbeTrampoline" ); |
| 148 | static_assert(PROBE_OFFSETOF(initializeStackArg) == PROBE_INIT_STACK_ARG_OFFSET, "Probe::State::initializeStackArg's offset matches ctiMasmProbeTrampoline" ); |
| 149 | |
| 150 | static_assert(!(PROBE_CPU_X0_OFFSET & 0x7), "Probe::State::cpu.gprs[x0]'s offset should be 8 byte aligned" ); |
| 151 | |
| 152 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x0]) == PROBE_CPU_X0_OFFSET, "Probe::State::cpu.gprs[x0]'s offset matches ctiMasmProbeTrampoline" ); |
| 153 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x1]) == PROBE_CPU_X1_OFFSET, "Probe::State::cpu.gprs[x1]'s offset matches ctiMasmProbeTrampoline" ); |
| 154 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x2]) == PROBE_CPU_X2_OFFSET, "Probe::State::cpu.gprs[x2]'s offset matches ctiMasmProbeTrampoline" ); |
| 155 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x3]) == PROBE_CPU_X3_OFFSET, "Probe::State::cpu.gprs[x3]'s offset matches ctiMasmProbeTrampoline" ); |
| 156 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x4]) == PROBE_CPU_X4_OFFSET, "Probe::State::cpu.gprs[x4]'s offset matches ctiMasmProbeTrampoline" ); |
| 157 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x5]) == PROBE_CPU_X5_OFFSET, "Probe::State::cpu.gprs[x5]'s offset matches ctiMasmProbeTrampoline" ); |
| 158 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x6]) == PROBE_CPU_X6_OFFSET, "Probe::State::cpu.gprs[x6]'s offset matches ctiMasmProbeTrampoline" ); |
| 159 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x7]) == PROBE_CPU_X7_OFFSET, "Probe::State::cpu.gprs[x7]'s offset matches ctiMasmProbeTrampoline" ); |
| 160 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x8]) == PROBE_CPU_X8_OFFSET, "Probe::State::cpu.gprs[x8]'s offset matches ctiMasmProbeTrampoline" ); |
| 161 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x9]) == PROBE_CPU_X9_OFFSET, "Probe::State::cpu.gprs[x9]'s offset matches ctiMasmProbeTrampoline" ); |
| 162 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x10]) == PROBE_CPU_X10_OFFSET, "Probe::State::cpu.gprs[x10]'s offset matches ctiMasmProbeTrampoline" ); |
| 163 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x11]) == PROBE_CPU_X11_OFFSET, "Probe::State::cpu.gprs[x11]'s offset matches ctiMasmProbeTrampoline" ); |
| 164 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x12]) == PROBE_CPU_X12_OFFSET, "Probe::State::cpu.gprs[x12]'s offset matches ctiMasmProbeTrampoline" ); |
| 165 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x13]) == PROBE_CPU_X13_OFFSET, "Probe::State::cpu.gprs[x13]'s offset matches ctiMasmProbeTrampoline" ); |
| 166 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x14]) == PROBE_CPU_X14_OFFSET, "Probe::State::cpu.gprs[x14]'s offset matches ctiMasmProbeTrampoline" ); |
| 167 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x15]) == PROBE_CPU_X15_OFFSET, "Probe::State::cpu.gprs[x15]'s offset matches ctiMasmProbeTrampoline" ); |
| 168 | |
| 169 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x16]) == PROBE_CPU_X16_OFFSET, "Probe::State::cpu.gprs[x16]'s offset matches ctiMasmProbeTrampoline" ); |
| 170 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x17]) == PROBE_CPU_X17_OFFSET, "Probe::State::cpu.gprs[x17]'s offset matches ctiMasmProbeTrampoline" ); |
| 171 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x18]) == PROBE_CPU_X18_OFFSET, "Probe::State::cpu.gprs[x18]'s offset matches ctiMasmProbeTrampoline" ); |
| 172 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x19]) == PROBE_CPU_X19_OFFSET, "Probe::State::cpu.gprs[x19]'s offset matches ctiMasmProbeTrampoline" ); |
| 173 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x20]) == PROBE_CPU_X20_OFFSET, "Probe::State::cpu.gprs[x20]'s offset matches ctiMasmProbeTrampoline" ); |
| 174 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x21]) == PROBE_CPU_X21_OFFSET, "Probe::State::cpu.gprs[x21]'s offset matches ctiMasmProbeTrampoline" ); |
| 175 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x22]) == PROBE_CPU_X22_OFFSET, "Probe::State::cpu.gprs[x22]'s offset matches ctiMasmProbeTrampoline" ); |
| 176 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x23]) == PROBE_CPU_X23_OFFSET, "Probe::State::cpu.gprs[x23]'s offset matches ctiMasmProbeTrampoline" ); |
| 177 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x24]) == PROBE_CPU_X24_OFFSET, "Probe::State::cpu.gprs[x24]'s offset matches ctiMasmProbeTrampoline" ); |
| 178 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x25]) == PROBE_CPU_X25_OFFSET, "Probe::State::cpu.gprs[x25]'s offset matches ctiMasmProbeTrampoline" ); |
| 179 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x26]) == PROBE_CPU_X26_OFFSET, "Probe::State::cpu.gprs[x26]'s offset matches ctiMasmProbeTrampoline" ); |
| 180 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x27]) == PROBE_CPU_X27_OFFSET, "Probe::State::cpu.gprs[x27]'s offset matches ctiMasmProbeTrampoline" ); |
| 181 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::x28]) == PROBE_CPU_X28_OFFSET, "Probe::State::cpu.gprs[x28]'s offset matches ctiMasmProbeTrampoline" ); |
| 182 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::fp]) == PROBE_CPU_FP_OFFSET, "Probe::State::cpu.gprs[fp]'s offset matches ctiMasmProbeTrampoline" ); |
| 183 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::lr]) == PROBE_CPU_LR_OFFSET, "Probe::State::cpu.gprs[lr]'s offset matches ctiMasmProbeTrampoline" ); |
| 184 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARM64Registers::sp]) == PROBE_CPU_SP_OFFSET, "Probe::State::cpu.gprs[sp]'s offset matches ctiMasmProbeTrampoline" ); |
| 185 | |
| 186 | static_assert(PROBE_OFFSETOF(cpu.sprs[ARM64Registers::pc]) == PROBE_CPU_PC_OFFSET, "Probe::State::cpu.sprs[pc]'s offset matches ctiMasmProbeTrampoline" ); |
| 187 | static_assert(PROBE_OFFSETOF(cpu.sprs[ARM64Registers::nzcv]) == PROBE_CPU_NZCV_OFFSET, "Probe::State::cpu.sprs[nzcv]'s offset matches ctiMasmProbeTrampoline" ); |
| 188 | static_assert(PROBE_OFFSETOF(cpu.sprs[ARM64Registers::fpsr]) == PROBE_CPU_FPSR_OFFSET, "Probe::State::cpu.sprs[fpsr]'s offset matches ctiMasmProbeTrampoline" ); |
| 189 | |
| 190 | static_assert(!(PROBE_CPU_Q0_OFFSET & 0x7), "Probe::State::cpu.fprs[q0]'s offset should be 8 byte aligned" ); |
| 191 | |
| 192 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q0]) == PROBE_CPU_Q0_OFFSET, "Probe::State::cpu.fprs[q0]'s offset matches ctiMasmProbeTrampoline" ); |
| 193 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q1]) == PROBE_CPU_Q1_OFFSET, "Probe::State::cpu.fprs[q1]'s offset matches ctiMasmProbeTrampoline" ); |
| 194 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q2]) == PROBE_CPU_Q2_OFFSET, "Probe::State::cpu.fprs[q2]'s offset matches ctiMasmProbeTrampoline" ); |
| 195 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q3]) == PROBE_CPU_Q3_OFFSET, "Probe::State::cpu.fprs[q3]'s offset matches ctiMasmProbeTrampoline" ); |
| 196 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q4]) == PROBE_CPU_Q4_OFFSET, "Probe::State::cpu.fprs[q4]'s offset matches ctiMasmProbeTrampoline" ); |
| 197 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q5]) == PROBE_CPU_Q5_OFFSET, "Probe::State::cpu.fprs[q5]'s offset matches ctiMasmProbeTrampoline" ); |
| 198 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q6]) == PROBE_CPU_Q6_OFFSET, "Probe::State::cpu.fprs[q6]'s offset matches ctiMasmProbeTrampoline" ); |
| 199 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q7]) == PROBE_CPU_Q7_OFFSET, "Probe::State::cpu.fprs[q7]'s offset matches ctiMasmProbeTrampoline" ); |
| 200 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q8]) == PROBE_CPU_Q8_OFFSET, "Probe::State::cpu.fprs[q8]'s offset matches ctiMasmProbeTrampoline" ); |
| 201 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q9]) == PROBE_CPU_Q9_OFFSET, "Probe::State::cpu.fprs[q9]'s offset matches ctiMasmProbeTrampoline" ); |
| 202 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q10]) == PROBE_CPU_Q10_OFFSET, "Probe::State::cpu.fprs[q10]'s offset matches ctiMasmProbeTrampoline" ); |
| 203 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q11]) == PROBE_CPU_Q11_OFFSET, "Probe::State::cpu.fprs[q11]'s offset matches ctiMasmProbeTrampoline" ); |
| 204 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q12]) == PROBE_CPU_Q12_OFFSET, "Probe::State::cpu.fprs[q12]'s offset matches ctiMasmProbeTrampoline" ); |
| 205 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q13]) == PROBE_CPU_Q13_OFFSET, "Probe::State::cpu.fprs[q13]'s offset matches ctiMasmProbeTrampoline" ); |
| 206 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q14]) == PROBE_CPU_Q14_OFFSET, "Probe::State::cpu.fprs[q14]'s offset matches ctiMasmProbeTrampoline" ); |
| 207 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q15]) == PROBE_CPU_Q15_OFFSET, "Probe::State::cpu.fprs[q15]'s offset matches ctiMasmProbeTrampoline" ); |
| 208 | |
| 209 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q16]) == PROBE_CPU_Q16_OFFSET, "Probe::State::cpu.fprs[q16]'s offset matches ctiMasmProbeTrampoline" ); |
| 210 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q17]) == PROBE_CPU_Q17_OFFSET, "Probe::State::cpu.fprs[q17]'s offset matches ctiMasmProbeTrampoline" ); |
| 211 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q18]) == PROBE_CPU_Q18_OFFSET, "Probe::State::cpu.fprs[q18]'s offset matches ctiMasmProbeTrampoline" ); |
| 212 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q19]) == PROBE_CPU_Q19_OFFSET, "Probe::State::cpu.fprs[q19]'s offset matches ctiMasmProbeTrampoline" ); |
| 213 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q20]) == PROBE_CPU_Q20_OFFSET, "Probe::State::cpu.fprs[q20]'s offset matches ctiMasmProbeTrampoline" ); |
| 214 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q21]) == PROBE_CPU_Q21_OFFSET, "Probe::State::cpu.fprs[q21]'s offset matches ctiMasmProbeTrampoline" ); |
| 215 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q22]) == PROBE_CPU_Q22_OFFSET, "Probe::State::cpu.fprs[q22]'s offset matches ctiMasmProbeTrampoline" ); |
| 216 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q23]) == PROBE_CPU_Q23_OFFSET, "Probe::State::cpu.fprs[q23]'s offset matches ctiMasmProbeTrampoline" ); |
| 217 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q24]) == PROBE_CPU_Q24_OFFSET, "Probe::State::cpu.fprs[q24]'s offset matches ctiMasmProbeTrampoline" ); |
| 218 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q25]) == PROBE_CPU_Q25_OFFSET, "Probe::State::cpu.fprs[q25]'s offset matches ctiMasmProbeTrampoline" ); |
| 219 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q26]) == PROBE_CPU_Q26_OFFSET, "Probe::State::cpu.fprs[q26]'s offset matches ctiMasmProbeTrampoline" ); |
| 220 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q27]) == PROBE_CPU_Q27_OFFSET, "Probe::State::cpu.fprs[q27]'s offset matches ctiMasmProbeTrampoline" ); |
| 221 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q28]) == PROBE_CPU_Q28_OFFSET, "Probe::State::cpu.fprs[q28]'s offset matches ctiMasmProbeTrampoline" ); |
| 222 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q29]) == PROBE_CPU_Q29_OFFSET, "Probe::State::cpu.fprs[q29]'s offset matches ctiMasmProbeTrampoline" ); |
| 223 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q30]) == PROBE_CPU_Q30_OFFSET, "Probe::State::cpu.fprs[q30]'s offset matches ctiMasmProbeTrampoline" ); |
| 224 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARM64Registers::q31]) == PROBE_CPU_Q31_OFFSET, "Probe::State::cpu.fprs[q31]'s offset matches ctiMasmProbeTrampoline" ); |
| 225 | |
| 226 | static_assert(sizeof(Probe::State) == PROBE_SIZE, "Probe::State's size matches ctiMasmProbeTrampoline" ); |
| 227 | |
| 228 | // Conditions for using ldp and stp. |
| 229 | static_assert(PROBE_CPU_PC_OFFSET == PROBE_CPU_SP_OFFSET + GPREG_SIZE, "PROBE_CPU_SP_OFFSET and PROBE_CPU_PC_OFFSET must be adjacent" ); |
| 230 | static_assert(!(PROBE_SIZE_PLUS_EXTRAS & 0xf), "PROBE_SIZE_PLUS_EXTRAS should be 16 byte aligned" ); // the Probe::State copying code relies on this. |
| 231 | |
| 232 | #undef PROBE_OFFSETOF |
| 233 | |
| 234 | #define FPR_OFFSET(fpr) (PROBE_CPU_##fpr##_OFFSET - PROBE_CPU_Q0_OFFSET) |
| 235 | |
| 236 | struct IncomingProbeRecord { |
| 237 | UCPURegister x24; |
| 238 | UCPURegister x25; |
| 239 | UCPURegister x26; |
| 240 | UCPURegister x27; |
| 241 | UCPURegister x28; |
| 242 | UCPURegister x30; // lr |
| 243 | }; |
| 244 | |
| 245 | #define IN_X24_OFFSET (0 * GPREG_SIZE) |
| 246 | #define IN_X25_OFFSET (1 * GPREG_SIZE) |
| 247 | #define IN_X26_OFFSET (2 * GPREG_SIZE) |
| 248 | #define IN_X27_OFFSET (3 * GPREG_SIZE) |
| 249 | #define IN_X28_OFFSET (4 * GPREG_SIZE) |
| 250 | #define IN_X30_OFFSET (5 * GPREG_SIZE) |
| 251 | #define IN_SIZE (6 * GPREG_SIZE) |
| 252 | |
| 253 | static_assert(IN_X24_OFFSET == offsetof(IncomingProbeRecord, x24), "IN_X24_OFFSET is incorrect" ); |
| 254 | static_assert(IN_X25_OFFSET == offsetof(IncomingProbeRecord, x25), "IN_X25_OFFSET is incorrect" ); |
| 255 | static_assert(IN_X26_OFFSET == offsetof(IncomingProbeRecord, x26), "IN_X26_OFFSET is incorrect" ); |
| 256 | static_assert(IN_X27_OFFSET == offsetof(IncomingProbeRecord, x27), "IN_X27_OFFSET is incorrect" ); |
| 257 | static_assert(IN_X28_OFFSET == offsetof(IncomingProbeRecord, x28), "IN_X22_OFFSET is incorrect" ); |
| 258 | static_assert(IN_X30_OFFSET == offsetof(IncomingProbeRecord, x30), "IN_X23_OFFSET is incorrect" ); |
| 259 | static_assert(IN_SIZE == sizeof(IncomingProbeRecord), "IN_SIZE is incorrect" ); |
| 260 | static_assert(!(sizeof(IncomingProbeRecord) & 0xf), "IncomingProbeStack must be 16-byte aligned" ); |
| 261 | |
| 262 | struct OutgoingProbeRecord { |
| 263 | UCPURegister nzcv; |
| 264 | UCPURegister fpsr; |
| 265 | UCPURegister x27; |
| 266 | UCPURegister x28; |
| 267 | UCPURegister fp; |
| 268 | UCPURegister lr; |
| 269 | }; |
| 270 | |
| 271 | #define OUT_NZCV_OFFSET (0 * GPREG_SIZE) |
| 272 | #define OUT_FPSR_OFFSET (1 * GPREG_SIZE) |
| 273 | #define OUT_X27_OFFSET (2 * GPREG_SIZE) |
| 274 | #define OUT_X28_OFFSET (3 * GPREG_SIZE) |
| 275 | #define OUT_FP_OFFSET (4 * GPREG_SIZE) |
| 276 | #define OUT_LR_OFFSET (5 * GPREG_SIZE) |
| 277 | #define OUT_SIZE (6 * GPREG_SIZE) |
| 278 | |
| 279 | static_assert(OUT_NZCV_OFFSET == offsetof(OutgoingProbeRecord, nzcv), "OUT_NZCV_OFFSET is incorrect" ); |
| 280 | static_assert(OUT_FPSR_OFFSET == offsetof(OutgoingProbeRecord, fpsr), "OUT_FPSR_OFFSET is incorrect" ); |
| 281 | static_assert(OUT_X27_OFFSET == offsetof(OutgoingProbeRecord, x27), "OUT_X27_OFFSET is incorrect" ); |
| 282 | static_assert(OUT_X28_OFFSET == offsetof(OutgoingProbeRecord, x28), "OUT_X28_OFFSET is incorrect" ); |
| 283 | static_assert(OUT_FP_OFFSET == offsetof(OutgoingProbeRecord, fp), "OUT_FP_OFFSET is incorrect" ); |
| 284 | static_assert(OUT_LR_OFFSET == offsetof(OutgoingProbeRecord, lr), "OUT_LR_OFFSET is incorrect" ); |
| 285 | static_assert(OUT_SIZE == sizeof(OutgoingProbeRecord), "OUT_SIZE is incorrect" ); |
| 286 | static_assert(!(sizeof(OutgoingProbeRecord) & 0xf), "OutgoingProbeStack must be 16-byte aligned" ); |
| 287 | |
| 288 | struct LRRestorationRecord { |
| 289 | UCPURegister lr; |
| 290 | UCPURegister unusedDummyToEnsureSizeIs16ByteAligned; |
| 291 | }; |
| 292 | |
| 293 | #define LR_RESTORATION_LR_OFFSET (0 * GPREG_SIZE) |
| 294 | #define LR_RESTORATION_SIZE (2 * GPREG_SIZE) |
| 295 | |
| 296 | static_assert(LR_RESTORATION_LR_OFFSET == offsetof(LRRestorationRecord, lr), "LR_RESTORATION_LR_OFFSET is incorrect" ); |
| 297 | static_assert(LR_RESTORATION_SIZE == sizeof(LRRestorationRecord), "LR_RESTORATION_SIZE is incorrect" ); |
| 298 | static_assert(!(sizeof(LRRestorationRecord) & 0xf), "LRRestorationRecord must be 16-byte aligned" ); |
| 299 | |
| 300 | // We use x29 and x30 instead of fp and lr because GCC's inline assembler does not recognize fp and lr. |
| 301 | // See https://bugs.webkit.org/show_bug.cgi?id=175512 for details. |
| 302 | asm ( |
| 303 | ".text" "\n" |
| 304 | ".balign 16" "\n" |
| 305 | ".globl " SYMBOL_STRING(ctiMasmProbeTrampoline) "\n" |
| 306 | HIDE_SYMBOL(ctiMasmProbeTrampoline) "\n" |
| 307 | SYMBOL_STRING(ctiMasmProbeTrampoline) ":" "\n" |
| 308 | |
| 309 | // MacroAssemblerARM64::probe() has already generated code to store some values in an |
| 310 | // IncomingProbeRecord. sp points to the IncomingProbeRecord. |
| 311 | // |
| 312 | // Incoming register values: |
| 313 | // x24: probe function |
| 314 | // x25: probe arg |
| 315 | // x26: scratch, was ctiMasmProbeTrampoline |
| 316 | // x27: scratch |
| 317 | // x28: Probe::executeProbe |
| 318 | // x30: return address |
| 319 | |
| 320 | "mov x26, sp" "\n" |
| 321 | "mov x27, sp" "\n" |
| 322 | |
| 323 | "sub x27, x27, #" STRINGIZE_VALUE_OF(PROBE_SIZE_PLUS_EXTRAS + OUT_SIZE) "\n" |
| 324 | "bic x27, x27, #0xf" "\n" // The ARM EABI specifies that the stack needs to be 16 byte aligned. |
| 325 | "mov sp, x27" "\n" // Set the sp to protect the Probe::State from interrupts before we initialize it. |
| 326 | |
| 327 | "stp x24, x25, [sp, #" STRINGIZE_VALUE_OF(PROBE_PROBE_FUNCTION_OFFSET) "]" "\n" // Store the probe handler function and arg (preloaded into x24 and x25 |
| 328 | |
| 329 | "stp x0, x1, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X0_OFFSET) "]" "\n" |
| 330 | "mrs x0, nzcv" "\n" // Preload nzcv. |
| 331 | "stp x2, x3, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X2_OFFSET) "]" "\n" |
| 332 | "stp x4, x5, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X4_OFFSET) "]" "\n" |
| 333 | "mrs x1, fpsr" "\n" // Preload fpsr. |
| 334 | "stp x6, x7, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X6_OFFSET) "]" "\n" |
| 335 | "stp x8, x9, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X8_OFFSET) "]" "\n" |
| 336 | |
| 337 | "ldp x2, x3, [x26, #" STRINGIZE_VALUE_OF(IN_X24_OFFSET) "]" "\n" // Preload saved x24 and x25. |
| 338 | "ldp x4, x5, [x26, #" STRINGIZE_VALUE_OF(IN_X26_OFFSET) "]" "\n" // Preload saved x26 and x27. |
| 339 | "ldp x6, x7, [x26, #" STRINGIZE_VALUE_OF(IN_X28_OFFSET) "]" "\n" // Preload saved x28 and lr. |
| 340 | "add x26, x26, #" STRINGIZE_VALUE_OF(IN_SIZE) "\n" // Compute the sp before the probe. |
| 341 | |
| 342 | "stp x10, x11, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X10_OFFSET) "]" "\n" |
| 343 | "stp x12, x13, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X12_OFFSET) "]" "\n" |
| 344 | "stp x14, x15, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X14_OFFSET) "]" "\n" |
| 345 | "stp x16, x17, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X16_OFFSET) "]" "\n" |
| 346 | "stp x18, x19, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X18_OFFSET) "]" "\n" |
| 347 | "stp x20, x21, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X20_OFFSET) "]" "\n" |
| 348 | "stp x22, x23, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X22_OFFSET) "]" "\n" |
| 349 | "stp x2, x3, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X24_OFFSET) "]" "\n" // Store saved r24 and r25 (preloaded into x2 and x3 above). |
| 350 | "stp x4, x5, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X26_OFFSET) "]" "\n" // Store saved r26 and r27 (preloaded into x4 and x5 above). |
| 351 | "stp x6, x29, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X28_OFFSET) "]" "\n" |
| 352 | "stp x7, x26, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_LR_OFFSET) "]" "\n" // Save values lr and sp (original sp value computed into x26 above). |
| 353 | |
| 354 | "str x30, [sp, #" STRINGIZE_VALUE_OF(SAVED_PROBE_RETURN_PC_OFFSET) "]" "\n" // Save a duplicate copy of return pc (in lr). |
| 355 | |
| 356 | "add x30, x30, #" STRINGIZE_VALUE_OF(2 * GPREG_SIZE) "\n" // The PC after the probe is at 2 instructions past the return point. |
| 357 | "str x30, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_PC_OFFSET) "]" "\n" |
| 358 | |
| 359 | "stp x0, x1, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_NZCV_OFFSET) "]" "\n" // Store nzcv and fpsr (preloaded into x0 and x1 above). |
| 360 | |
| 361 | "add x9, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_Q0_OFFSET) "\n" |
| 362 | "stp d0, d1, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q0)) "]" "\n" |
| 363 | "stp d2, d3, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q2)) "]" "\n" |
| 364 | "stp d4, d5, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q4)) "]" "\n" |
| 365 | "stp d6, d7, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q6)) "]" "\n" |
| 366 | "stp d8, d9, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q8)) "]" "\n" |
| 367 | "stp d10, d11, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q10)) "]" "\n" |
| 368 | "stp d12, d13, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q12)) "]" "\n" |
| 369 | "stp d14, d15, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q14)) "]" "\n" |
| 370 | "stp d16, d17, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q16)) "]" "\n" |
| 371 | "stp d18, d19, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q18)) "]" "\n" |
| 372 | "stp d20, d21, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q20)) "]" "\n" |
| 373 | "stp d22, d23, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q22)) "]" "\n" |
| 374 | "stp d24, d25, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q24)) "]" "\n" |
| 375 | "stp d26, d27, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q26)) "]" "\n" |
| 376 | "stp d28, d29, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q28)) "]" "\n" |
| 377 | "stp d30, d31, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q30)) "]" "\n" |
| 378 | |
| 379 | "mov x27, sp" "\n" // Save the Probe::State* in a callee saved register. |
| 380 | |
| 381 | // Note: we haven't changed the value of fp. Hence, it is still pointing to the frame of |
| 382 | // the caller of the probe (which is what we want in order to play nice with debuggers e.g. lldb). |
| 383 | "mov x0, sp" "\n" // Set the Probe::State* arg. |
| 384 | #if CPU(ARM64E) |
| 385 | "blraaz x28" "\n" // Call the probe handler. |
| 386 | #else |
| 387 | "blr x28" "\n" // Call the probe handler. |
| 388 | #endif |
| 389 | |
| 390 | // Make sure the Probe::State is entirely below the result stack pointer so |
| 391 | // that register values are still preserved when we call the initializeStack |
| 392 | // function. |
| 393 | "ldr x1, [x27, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n" // Result sp. |
| 394 | "add x2, x27, #" STRINGIZE_VALUE_OF(PROBE_SIZE_PLUS_EXTRAS + OUT_SIZE) "\n" // End of Probe::State + buffer. |
| 395 | "cmp x1, x2" "\n" |
| 396 | "bge " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineProbeStateIsSafe) "\n" |
| 397 | |
| 398 | // Allocate a safe place on the stack below the result stack pointer to stash the Probe::State. |
| 399 | "sub x1, x1, #" STRINGIZE_VALUE_OF(PROBE_SIZE_PLUS_EXTRAS + OUT_SIZE) "\n" |
| 400 | "bic x1, x1, #0xf" "\n" // The ARM EABI specifies that the stack needs to be 16 byte aligned. |
| 401 | "mov sp, x1" "\n" // Set the new sp to protect that memory from interrupts before we copy the Probe::State. |
| 402 | |
| 403 | // Copy the Probe::State to the safe place. |
| 404 | // Note: we have to copy from low address to higher address because we're moving the |
| 405 | // Probe::State to a lower address. |
| 406 | "mov x5, x27" "\n" |
| 407 | "mov x6, x1" "\n" |
| 408 | "add x7, x27, #" STRINGIZE_VALUE_OF(PROBE_SIZE_PLUS_EXTRAS) "\n" |
| 409 | |
| 410 | LOCAL_LABEL_STRING(ctiMasmProbeTrampolineCopyLoop) ":" "\n" |
| 411 | "ldp x3, x4, [x5], #16" "\n" |
| 412 | "stp x3, x4, [x6], #16" "\n" |
| 413 | "cmp x5, x7" "\n" |
| 414 | "blt " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineCopyLoop) "\n" |
| 415 | |
| 416 | "mov x27, x1" "\n" |
| 417 | |
| 418 | // Call initializeStackFunction if present. |
| 419 | LOCAL_LABEL_STRING(ctiMasmProbeTrampolineProbeStateIsSafe) ":" "\n" |
| 420 | "ldr x2, [x27, #" STRINGIZE_VALUE_OF(PROBE_INIT_STACK_FUNCTION_OFFSET) "]" "\n" |
| 421 | "cbz x2, " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineRestoreRegisters) "\n" |
| 422 | |
| 423 | "mov x0, x27" "\n" // Set the Probe::State* arg. |
| 424 | #if CPU(ARM64E) |
| 425 | "blraaz x2" "\n" // Call the initializeStackFunction (loaded into x2 above). |
| 426 | #else |
| 427 | "blr x2" "\n" // Call the initializeStackFunction (loaded into x2 above). |
| 428 | #endif |
| 429 | |
| 430 | LOCAL_LABEL_STRING(ctiMasmProbeTrampolineRestoreRegisters) ":" "\n" |
| 431 | |
| 432 | "mov sp, x27" "\n" |
| 433 | |
| 434 | // To enable probes to modify register state, we copy all registers |
| 435 | // out of the Probe::State before returning. That is except for x18. |
| 436 | // x18 is "reserved for the platform. Conforming software should not make use of it." |
| 437 | // Hence, the JITs would not be using it, and the probe should also not be modifying it. |
| 438 | // See https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html. |
| 439 | |
| 440 | "add x9, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_Q0_OFFSET) "\n" |
| 441 | "ldp d0, d1, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q0)) "]" "\n" |
| 442 | "ldp d2, d3, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q2)) "]" "\n" |
| 443 | "ldp d4, d5, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q4)) "]" "\n" |
| 444 | "ldp d6, d7, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q6)) "]" "\n" |
| 445 | "ldp d8, d9, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q8)) "]" "\n" |
| 446 | "ldp d10, d11, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q10)) "]" "\n" |
| 447 | "ldp d12, d13, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q12)) "]" "\n" |
| 448 | "ldp d14, d15, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q14)) "]" "\n" |
| 449 | "ldp d16, d17, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q16)) "]" "\n" |
| 450 | "ldp d18, d19, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q18)) "]" "\n" |
| 451 | "ldp d20, d21, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q20)) "]" "\n" |
| 452 | "ldp d22, d23, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q22)) "]" "\n" |
| 453 | "ldp d24, d25, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q24)) "]" "\n" |
| 454 | "ldp d26, d27, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q26)) "]" "\n" |
| 455 | "ldp d28, d29, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q28)) "]" "\n" |
| 456 | "ldp d30, d31, [x9, #" STRINGIZE_VALUE_OF(FPR_OFFSET(Q30)) "]" "\n" |
| 457 | |
| 458 | "ldp x0, x1, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X0_OFFSET) "]" "\n" |
| 459 | "ldp x2, x3, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X2_OFFSET) "]" "\n" |
| 460 | "ldp x4, x5, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X4_OFFSET) "]" "\n" |
| 461 | "ldp x6, x7, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X6_OFFSET) "]" "\n" |
| 462 | "ldp x8, x9, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X8_OFFSET) "]" "\n" |
| 463 | "ldp x10, x11, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X10_OFFSET) "]" "\n" |
| 464 | "ldp x12, x13, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X12_OFFSET) "]" "\n" |
| 465 | "ldp x14, x15, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X14_OFFSET) "]" "\n" |
| 466 | "ldp x16, x17, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X16_OFFSET) "]" "\n" |
| 467 | // x18 should not be modified by the probe. See comment above for details. |
| 468 | "ldp x19, x20, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X19_OFFSET) "]" "\n" |
| 469 | "ldp x21, x22, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X21_OFFSET) "]" "\n" |
| 470 | "ldp x23, x24, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X23_OFFSET) "]" "\n" |
| 471 | "ldp x25, x26, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X25_OFFSET) "]" "\n" |
| 472 | |
| 473 | // Remaining registers to restore are: fpsr, nzcv, x27, x28, fp, lr, sp, and pc. |
| 474 | |
| 475 | // The only way to set the pc on ARM64 (from user space) is via an indirect branch |
| 476 | // or a ret, which means we'll need a free register to do so. For our purposes, lr |
| 477 | // happens to be available in applications of the probe where we may want to |
| 478 | // continue executing at a different location (i.e. change the pc) after the probe |
| 479 | // returns. So, the ARM64 probe implementation will allow the probe handler to |
| 480 | // either modify lr or pc, but not both in the same probe invocation. The probe |
| 481 | // mechanism ensures that we never try to modify both lr and pc with a RELEASE_ASSERT |
| 482 | // in Probe::executeProbe(). |
| 483 | |
| 484 | // Determine if the probe handler changed the pc. |
| 485 | "ldr x30, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n" // preload the target sp. |
| 486 | "ldr x27, [sp, #" STRINGIZE_VALUE_OF(SAVED_PROBE_RETURN_PC_OFFSET) "]" "\n" |
| 487 | "ldr x28, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_PC_OFFSET) "]" "\n" |
| 488 | "add x27, x27, #" STRINGIZE_VALUE_OF(2 * GPREG_SIZE) "\n" |
| 489 | "cmp x27, x28" "\n" |
| 490 | "bne " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineEnd) "\n" |
| 491 | |
| 492 | // We didn't change the PC. So, let's prepare for setting a potentially new lr value. |
| 493 | |
| 494 | // 1. Make room for the LRRestorationRecord. The probe site will pop this off later. |
| 495 | "sub x30, x30, #" STRINGIZE_VALUE_OF(LR_RESTORATION_SIZE) "\n" |
| 496 | // 2. Store the lp value to restore at the probe return site. |
| 497 | "ldr x27, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_LR_OFFSET) "]" "\n" |
| 498 | "str x27, [x30, #" STRINGIZE_VALUE_OF(LR_RESTORATION_LR_OFFSET) "]" "\n" |
| 499 | // 3. Force the return ramp to return to the probe return site. |
| 500 | "ldr x27, [sp, #" STRINGIZE_VALUE_OF(SAVED_PROBE_RETURN_PC_OFFSET) "]" "\n" |
| 501 | "str x27, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_PC_OFFSET) "]" "\n" |
| 502 | |
| 503 | LOCAL_LABEL_STRING(ctiMasmProbeTrampolineEnd) ":" "\n" |
| 504 | |
| 505 | // Fill in the OutgoingProbeRecord. |
| 506 | "sub x30, x30, #" STRINGIZE_VALUE_OF(OUT_SIZE) "\n" |
| 507 | |
| 508 | "ldp x27, x28, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_NZCV_OFFSET) "]" "\n" |
| 509 | "stp x27, x28, [x30, #" STRINGIZE_VALUE_OF(OUT_NZCV_OFFSET) "]" "\n" |
| 510 | "ldp x27, x28, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_X27_OFFSET) "]" "\n" |
| 511 | "stp x27, x28, [x30, #" STRINGIZE_VALUE_OF(OUT_X27_OFFSET) "]" "\n" |
| 512 | "ldr x27, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_FP_OFFSET) "]" "\n" |
| 513 | "ldr x28, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_PC_OFFSET) "]" "\n" // Set up the outgoing record so that we'll jump to the new PC. |
| 514 | "stp x27, x28, [x30, #" STRINGIZE_VALUE_OF(OUT_FP_OFFSET) "]" "\n" |
| 515 | "mov sp, x30" "\n" |
| 516 | |
| 517 | // Restore the remaining registers and pop the OutgoingProbeRecord. |
| 518 | "ldp x27, x28, [sp], #" STRINGIZE_VALUE_OF(2 * GPREG_SIZE) "\n" |
| 519 | "msr nzcv, x27" "\n" |
| 520 | "msr fpsr, x28" "\n" |
| 521 | "ldp x27, x28, [sp], #" STRINGIZE_VALUE_OF(2 * GPREG_SIZE) "\n" |
| 522 | "ldp x29, x30, [sp], #" STRINGIZE_VALUE_OF(2 * GPREG_SIZE) "\n" |
| 523 | "ret" "\n" |
| 524 | ); |
| 525 | #endif // COMPILER(GCC_COMPATIBLE) |
| 526 | |
| 527 | void MacroAssembler::probe(Probe::Function function, void* arg) |
| 528 | { |
| 529 | sub64(TrustedImm32(sizeof(IncomingProbeRecord)), sp); |
| 530 | |
| 531 | storePair64(x24, x25, sp, TrustedImm32(offsetof(IncomingProbeRecord, x24))); |
| 532 | storePair64(x26, x27, sp, TrustedImm32(offsetof(IncomingProbeRecord, x26))); |
| 533 | storePair64(x28, x30, sp, TrustedImm32(offsetof(IncomingProbeRecord, x28))); // Note: x30 is lr. |
| 534 | move(TrustedImmPtr(reinterpret_cast<void*>(ctiMasmProbeTrampoline)), x26); |
| 535 | move(TrustedImmPtr(reinterpret_cast<void*>(Probe::executeProbe)), x28); |
| 536 | move(TrustedImmPtr(reinterpret_cast<void*>(function)), x24); |
| 537 | move(TrustedImmPtr(arg), x25); |
| 538 | call(x26, CFunctionPtrTag); |
| 539 | |
| 540 | // ctiMasmProbeTrampoline should have restored every register except for lr and the sp. |
| 541 | load64(Address(sp, offsetof(LRRestorationRecord, lr)), lr); |
| 542 | add64(TrustedImm32(sizeof(LRRestorationRecord)), sp); |
| 543 | } |
| 544 | |
| 545 | #endif // ENABLE(MASM_PROBE) |
| 546 | |
| 547 | void MacroAssemblerARM64::collectCPUFeatures() |
| 548 | { |
| 549 | #if OS(LINUX) |
| 550 | static std::once_flag onceKey; |
| 551 | std::call_once(onceKey, [] { |
| 552 | // A register for describing ARM64 CPU features are only accessible in kernel mode. |
| 553 | // Thus, some kernel support is necessary to collect CPU features. In Linux, the |
| 554 | // kernel passes CPU feature flags in AT_HWCAP auxiliary vector which is passed |
| 555 | // when the process starts. While this may pose a bit conservative information |
| 556 | // (for example, the Linux kernel may add a flag for a feature after the feature |
| 557 | // is shipped and implemented in some CPUs. In that case, even if the CPU has |
| 558 | // that feature, the kernel does not tell it to users.), it is a stable approach. |
| 559 | // https://www.kernel.org/doc/Documentation/arm64/elf_hwcaps.txt |
| 560 | uint64_t hwcaps = getauxval(AT_HWCAP); |
| 561 | |
| 562 | #if !defined(HWCAP_JSCVT) |
| 563 | #define HWCAP_JSCVT (1 << 13) |
| 564 | #endif |
| 565 | |
| 566 | s_jscvtCheckState = (hwcaps & HWCAP_JSCVT) ? CPUIDCheckState::Set : CPUIDCheckState::Clear; |
| 567 | }); |
| 568 | #elif HAVE(FJCVTZS_INSTRUCTION) |
| 569 | s_jscvtCheckState = CPUIDCheckState::Set; |
| 570 | #else |
| 571 | s_jscvtCheckState = CPUIDCheckState::Clear; |
| 572 | #endif |
| 573 | } |
| 574 | |
| 575 | MacroAssemblerARM64::CPUIDCheckState MacroAssemblerARM64::s_jscvtCheckState = CPUIDCheckState::NotChecked; |
| 576 | |
| 577 | } // namespace JSC |
| 578 | |
| 579 | #endif // ENABLE(ASSEMBLER) && CPU(ARM64) |
| 580 | |
| 581 | |