| 1 | /* |
| 2 | * Copyright (C) 2013-2017 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(ARM_THUMB2) |
| 29 | #include "MacroAssembler.h" |
| 30 | |
| 31 | #include "ProbeContext.h" |
| 32 | #include <wtf/InlineASM.h> |
| 33 | |
| 34 | namespace JSC { |
| 35 | |
| 36 | #if ENABLE(MASM_PROBE) |
| 37 | |
| 38 | extern "C" void ctiMasmProbeTrampoline(); |
| 39 | |
| 40 | using namespace ARMRegisters; |
| 41 | |
| 42 | #if COMPILER(GCC_COMPATIBLE) |
| 43 | |
| 44 | // The following are offsets for Probe::State fields accessed |
| 45 | // by the ctiMasmProbeTrampoline stub. |
| 46 | |
| 47 | #define PTR_SIZE 4 |
| 48 | #define PROBE_PROBE_FUNCTION_OFFSET (0 * PTR_SIZE) |
| 49 | #define PROBE_ARG_OFFSET (1 * PTR_SIZE) |
| 50 | #define PROBE_INIT_STACK_FUNCTION_OFFSET (2 * PTR_SIZE) |
| 51 | #define PROBE_INIT_STACK_ARG_OFFSET (3 * PTR_SIZE) |
| 52 | |
| 53 | #define PROBE_FIRST_GPREG_OFFSET (4 * PTR_SIZE) |
| 54 | |
| 55 | #define GPREG_SIZE 4 |
| 56 | #define PROBE_CPU_R0_OFFSET (PROBE_FIRST_GPREG_OFFSET + (0 * GPREG_SIZE)) |
| 57 | #define PROBE_CPU_R1_OFFSET (PROBE_FIRST_GPREG_OFFSET + (1 * GPREG_SIZE)) |
| 58 | #define PROBE_CPU_R2_OFFSET (PROBE_FIRST_GPREG_OFFSET + (2 * GPREG_SIZE)) |
| 59 | #define PROBE_CPU_R3_OFFSET (PROBE_FIRST_GPREG_OFFSET + (3 * GPREG_SIZE)) |
| 60 | #define PROBE_CPU_R4_OFFSET (PROBE_FIRST_GPREG_OFFSET + (4 * GPREG_SIZE)) |
| 61 | #define PROBE_CPU_R5_OFFSET (PROBE_FIRST_GPREG_OFFSET + (5 * GPREG_SIZE)) |
| 62 | #define PROBE_CPU_R6_OFFSET (PROBE_FIRST_GPREG_OFFSET + (6 * GPREG_SIZE)) |
| 63 | #define PROBE_CPU_R7_OFFSET (PROBE_FIRST_GPREG_OFFSET + (7 * GPREG_SIZE)) |
| 64 | #define PROBE_CPU_R8_OFFSET (PROBE_FIRST_GPREG_OFFSET + (8 * GPREG_SIZE)) |
| 65 | #define PROBE_CPU_R9_OFFSET (PROBE_FIRST_GPREG_OFFSET + (9 * GPREG_SIZE)) |
| 66 | #define PROBE_CPU_R10_OFFSET (PROBE_FIRST_GPREG_OFFSET + (10 * GPREG_SIZE)) |
| 67 | #define PROBE_CPU_R11_OFFSET (PROBE_FIRST_GPREG_OFFSET + (11 * GPREG_SIZE)) |
| 68 | #define PROBE_CPU_IP_OFFSET (PROBE_FIRST_GPREG_OFFSET + (12 * GPREG_SIZE)) |
| 69 | #define PROBE_CPU_SP_OFFSET (PROBE_FIRST_GPREG_OFFSET + (13 * GPREG_SIZE)) |
| 70 | #define PROBE_CPU_LR_OFFSET (PROBE_FIRST_GPREG_OFFSET + (14 * GPREG_SIZE)) |
| 71 | #define PROBE_CPU_PC_OFFSET (PROBE_FIRST_GPREG_OFFSET + (15 * GPREG_SIZE)) |
| 72 | |
| 73 | #define PROBE_CPU_APSR_OFFSET (PROBE_FIRST_GPREG_OFFSET + (16 * GPREG_SIZE)) |
| 74 | #define PROBE_CPU_FPSCR_OFFSET (PROBE_FIRST_GPREG_OFFSET + (17 * GPREG_SIZE)) |
| 75 | |
| 76 | #define PROBE_FIRST_FPREG_OFFSET (PROBE_FIRST_GPREG_OFFSET + (18 * GPREG_SIZE)) |
| 77 | |
| 78 | #define FPREG_SIZE 8 |
| 79 | #define PROBE_CPU_D0_OFFSET (PROBE_FIRST_FPREG_OFFSET + (0 * FPREG_SIZE)) |
| 80 | #define PROBE_CPU_D1_OFFSET (PROBE_FIRST_FPREG_OFFSET + (1 * FPREG_SIZE)) |
| 81 | #define PROBE_CPU_D2_OFFSET (PROBE_FIRST_FPREG_OFFSET + (2 * FPREG_SIZE)) |
| 82 | #define PROBE_CPU_D3_OFFSET (PROBE_FIRST_FPREG_OFFSET + (3 * FPREG_SIZE)) |
| 83 | #define PROBE_CPU_D4_OFFSET (PROBE_FIRST_FPREG_OFFSET + (4 * FPREG_SIZE)) |
| 84 | #define PROBE_CPU_D5_OFFSET (PROBE_FIRST_FPREG_OFFSET + (5 * FPREG_SIZE)) |
| 85 | #define PROBE_CPU_D6_OFFSET (PROBE_FIRST_FPREG_OFFSET + (6 * FPREG_SIZE)) |
| 86 | #define PROBE_CPU_D7_OFFSET (PROBE_FIRST_FPREG_OFFSET + (7 * FPREG_SIZE)) |
| 87 | #define PROBE_CPU_D8_OFFSET (PROBE_FIRST_FPREG_OFFSET + (8 * FPREG_SIZE)) |
| 88 | #define PROBE_CPU_D9_OFFSET (PROBE_FIRST_FPREG_OFFSET + (9 * FPREG_SIZE)) |
| 89 | #define PROBE_CPU_D10_OFFSET (PROBE_FIRST_FPREG_OFFSET + (10 * FPREG_SIZE)) |
| 90 | #define PROBE_CPU_D11_OFFSET (PROBE_FIRST_FPREG_OFFSET + (11 * FPREG_SIZE)) |
| 91 | #define PROBE_CPU_D12_OFFSET (PROBE_FIRST_FPREG_OFFSET + (12 * FPREG_SIZE)) |
| 92 | #define PROBE_CPU_D13_OFFSET (PROBE_FIRST_FPREG_OFFSET + (13 * FPREG_SIZE)) |
| 93 | #define PROBE_CPU_D14_OFFSET (PROBE_FIRST_FPREG_OFFSET + (14 * FPREG_SIZE)) |
| 94 | #define PROBE_CPU_D15_OFFSET (PROBE_FIRST_FPREG_OFFSET + (15 * FPREG_SIZE)) |
| 95 | |
| 96 | #if CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32) |
| 97 | #define PROBE_CPU_D16_OFFSET (PROBE_FIRST_FPREG_OFFSET + (16 * FPREG_SIZE)) |
| 98 | #define PROBE_CPU_D17_OFFSET (PROBE_FIRST_FPREG_OFFSET + (17 * FPREG_SIZE)) |
| 99 | #define PROBE_CPU_D18_OFFSET (PROBE_FIRST_FPREG_OFFSET + (18 * FPREG_SIZE)) |
| 100 | #define PROBE_CPU_D19_OFFSET (PROBE_FIRST_FPREG_OFFSET + (19 * FPREG_SIZE)) |
| 101 | #define PROBE_CPU_D20_OFFSET (PROBE_FIRST_FPREG_OFFSET + (20 * FPREG_SIZE)) |
| 102 | #define PROBE_CPU_D21_OFFSET (PROBE_FIRST_FPREG_OFFSET + (21 * FPREG_SIZE)) |
| 103 | #define PROBE_CPU_D22_OFFSET (PROBE_FIRST_FPREG_OFFSET + (22 * FPREG_SIZE)) |
| 104 | #define PROBE_CPU_D23_OFFSET (PROBE_FIRST_FPREG_OFFSET + (23 * FPREG_SIZE)) |
| 105 | #define PROBE_CPU_D24_OFFSET (PROBE_FIRST_FPREG_OFFSET + (24 * FPREG_SIZE)) |
| 106 | #define PROBE_CPU_D25_OFFSET (PROBE_FIRST_FPREG_OFFSET + (25 * FPREG_SIZE)) |
| 107 | #define PROBE_CPU_D26_OFFSET (PROBE_FIRST_FPREG_OFFSET + (26 * FPREG_SIZE)) |
| 108 | #define PROBE_CPU_D27_OFFSET (PROBE_FIRST_FPREG_OFFSET + (27 * FPREG_SIZE)) |
| 109 | #define PROBE_CPU_D28_OFFSET (PROBE_FIRST_FPREG_OFFSET + (28 * FPREG_SIZE)) |
| 110 | #define PROBE_CPU_D29_OFFSET (PROBE_FIRST_FPREG_OFFSET + (29 * FPREG_SIZE)) |
| 111 | #define PROBE_CPU_D30_OFFSET (PROBE_FIRST_FPREG_OFFSET + (30 * FPREG_SIZE)) |
| 112 | #define PROBE_CPU_D31_OFFSET (PROBE_FIRST_FPREG_OFFSET + (31 * FPREG_SIZE)) |
| 113 | |
| 114 | #define PROBE_SIZE (PROBE_FIRST_FPREG_OFFSET + (32 * FPREG_SIZE)) |
| 115 | #else |
| 116 | #define PROBE_SIZE (PROBE_FIRST_FPREG_OFFSET + (16 * FPREG_SIZE)) |
| 117 | #endif // CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32) |
| 118 | |
| 119 | #define OUT_SIZE GPREG_SIZE |
| 120 | |
| 121 | // These ASSERTs remind you that if you change the layout of Probe::State, |
| 122 | // you need to change ctiMasmProbeTrampoline offsets above to match. |
| 123 | #define PROBE_OFFSETOF(x) offsetof(struct Probe::State, x) |
| 124 | static_assert(PROBE_OFFSETOF(probeFunction) == PROBE_PROBE_FUNCTION_OFFSET, "Probe::State::probeFunction's offset matches ctiMasmProbeTrampoline" ); |
| 125 | static_assert(PROBE_OFFSETOF(arg) == PROBE_ARG_OFFSET, "Probe::State::arg's offset matches ctiMasmProbeTrampoline" ); |
| 126 | static_assert(PROBE_OFFSETOF(initializeStackFunction) == PROBE_INIT_STACK_FUNCTION_OFFSET, "Probe::State::initializeStackFunction's offset matches ctiMasmProbeTrampoline" ); |
| 127 | static_assert(PROBE_OFFSETOF(initializeStackArg) == PROBE_INIT_STACK_ARG_OFFSET, "Probe::State::initializeStackArg's offset matches ctiMasmProbeTrampoline" ); |
| 128 | |
| 129 | static_assert(!(PROBE_CPU_R0_OFFSET & 0x3), "Probe::State::cpu.gprs[r0]'s offset should be 4 byte aligned" ); |
| 130 | |
| 131 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r0]) == PROBE_CPU_R0_OFFSET, "Probe::State::cpu.gprs[r0]'s offset matches ctiMasmProbeTrampoline" ); |
| 132 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r1]) == PROBE_CPU_R1_OFFSET, "Probe::State::cpu.gprs[r1]'s offset matches ctiMasmProbeTrampoline" ); |
| 133 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r2]) == PROBE_CPU_R2_OFFSET, "Probe::State::cpu.gprs[r2]'s offset matches ctiMasmProbeTrampoline" ); |
| 134 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r3]) == PROBE_CPU_R3_OFFSET, "Probe::State::cpu.gprs[r3]'s offset matches ctiMasmProbeTrampoline" ); |
| 135 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r4]) == PROBE_CPU_R4_OFFSET, "Probe::State::cpu.gprs[r4]'s offset matches ctiMasmProbeTrampoline" ); |
| 136 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r5]) == PROBE_CPU_R5_OFFSET, "Probe::State::cpu.gprs[r5]'s offset matches ctiMasmProbeTrampoline" ); |
| 137 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r6]) == PROBE_CPU_R6_OFFSET, "Probe::State::cpu.gprs[r6]'s offset matches ctiMasmProbeTrampoline" ); |
| 138 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r7]) == PROBE_CPU_R7_OFFSET, "Probe::State::cpu.gprs[r7]'s offset matches ctiMasmProbeTrampoline" ); |
| 139 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r8]) == PROBE_CPU_R8_OFFSET, "Probe::State::cpu.gprs[r8]'s offset matches ctiMasmProbeTrampoline" ); |
| 140 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r9]) == PROBE_CPU_R9_OFFSET, "Probe::State::cpu.gprs[r9]'s offset matches ctiMasmProbeTrampoline" ); |
| 141 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r10]) == PROBE_CPU_R10_OFFSET, "Probe::State::cpu.gprs[r10]'s offset matches ctiMasmProbeTrampoline" ); |
| 142 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r11]) == PROBE_CPU_R11_OFFSET, "Probe::State::cpu.gprs[r11]'s offset matches ctiMasmProbeTrampoline" ); |
| 143 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::ip]) == PROBE_CPU_IP_OFFSET, "Probe::State::cpu.gprs[ip]'s offset matches ctiMasmProbeTrampoline" ); |
| 144 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::sp]) == PROBE_CPU_SP_OFFSET, "Probe::State::cpu.gprs[sp]'s offset matches ctiMasmProbeTrampoline" ); |
| 145 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::lr]) == PROBE_CPU_LR_OFFSET, "Probe::State::cpu.gprs[lr]'s offset matches ctiMasmProbeTrampoline" ); |
| 146 | static_assert(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::pc]) == PROBE_CPU_PC_OFFSET, "Probe::State::cpu.gprs[pc]'s offset matches ctiMasmProbeTrampoline" ); |
| 147 | |
| 148 | static_assert(PROBE_OFFSETOF(cpu.sprs[ARMRegisters::apsr]) == PROBE_CPU_APSR_OFFSET, "Probe::State::cpu.sprs[apsr]'s offset matches ctiMasmProbeTrampoline" ); |
| 149 | static_assert(PROBE_OFFSETOF(cpu.sprs[ARMRegisters::fpscr]) == PROBE_CPU_FPSCR_OFFSET, "Probe::State::cpu.sprs[fpscr]'s offset matches ctiMasmProbeTrampoline" ); |
| 150 | |
| 151 | static_assert(!(PROBE_CPU_D0_OFFSET & 0x7), "Probe::State::cpu.fprs[d0]'s offset should be 8 byte aligned" ); |
| 152 | |
| 153 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d0]) == PROBE_CPU_D0_OFFSET, "Probe::State::cpu.fprs[d0]'s offset matches ctiMasmProbeTrampoline" ); |
| 154 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d1]) == PROBE_CPU_D1_OFFSET, "Probe::State::cpu.fprs[d1]'s offset matches ctiMasmProbeTrampoline" ); |
| 155 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d2]) == PROBE_CPU_D2_OFFSET, "Probe::State::cpu.fprs[d2]'s offset matches ctiMasmProbeTrampoline" ); |
| 156 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d3]) == PROBE_CPU_D3_OFFSET, "Probe::State::cpu.fprs[d3]'s offset matches ctiMasmProbeTrampoline" ); |
| 157 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d4]) == PROBE_CPU_D4_OFFSET, "Probe::State::cpu.fprs[d4]'s offset matches ctiMasmProbeTrampoline" ); |
| 158 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d5]) == PROBE_CPU_D5_OFFSET, "Probe::State::cpu.fprs[d5]'s offset matches ctiMasmProbeTrampoline" ); |
| 159 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d6]) == PROBE_CPU_D6_OFFSET, "Probe::State::cpu.fprs[d6]'s offset matches ctiMasmProbeTrampoline" ); |
| 160 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d7]) == PROBE_CPU_D7_OFFSET, "Probe::State::cpu.fprs[d7]'s offset matches ctiMasmProbeTrampoline" ); |
| 161 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d8]) == PROBE_CPU_D8_OFFSET, "Probe::State::cpu.fprs[d8]'s offset matches ctiMasmProbeTrampoline" ); |
| 162 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d9]) == PROBE_CPU_D9_OFFSET, "Probe::State::cpu.fprs[d9]'s offset matches ctiMasmProbeTrampoline" ); |
| 163 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d10]) == PROBE_CPU_D10_OFFSET, "Probe::State::cpu.fprs[d10]'s offset matches ctiMasmProbeTrampoline" ); |
| 164 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d11]) == PROBE_CPU_D11_OFFSET, "Probe::State::cpu.fprs[d11]'s offset matches ctiMasmProbeTrampoline" ); |
| 165 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d12]) == PROBE_CPU_D12_OFFSET, "Probe::State::cpu.fprs[d12]'s offset matches ctiMasmProbeTrampoline" ); |
| 166 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d13]) == PROBE_CPU_D13_OFFSET, "Probe::State::cpu.fprs[d13]'s offset matches ctiMasmProbeTrampoline" ); |
| 167 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d14]) == PROBE_CPU_D14_OFFSET, "Probe::State::cpu.fprs[d14]'s offset matches ctiMasmProbeTrampoline" ); |
| 168 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d15]) == PROBE_CPU_D15_OFFSET, "Probe::State::cpu.fprs[d15]'s offset matches ctiMasmProbeTrampoline" ); |
| 169 | |
| 170 | #if CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32) |
| 171 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d16]) == PROBE_CPU_D16_OFFSET, "Probe::State::cpu.fprs[d16]'s offset matches ctiMasmProbeTrampoline" ); |
| 172 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d17]) == PROBE_CPU_D17_OFFSET, "Probe::State::cpu.fprs[d17]'s offset matches ctiMasmProbeTrampoline" ); |
| 173 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d18]) == PROBE_CPU_D18_OFFSET, "Probe::State::cpu.fprs[d18]'s offset matches ctiMasmProbeTrampoline" ); |
| 174 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d19]) == PROBE_CPU_D19_OFFSET, "Probe::State::cpu.fprs[d19]'s offset matches ctiMasmProbeTrampoline" ); |
| 175 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d20]) == PROBE_CPU_D20_OFFSET, "Probe::State::cpu.fprs[d20]'s offset matches ctiMasmProbeTrampoline" ); |
| 176 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d21]) == PROBE_CPU_D21_OFFSET, "Probe::State::cpu.fprs[d21]'s offset matches ctiMasmProbeTrampoline" ); |
| 177 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d22]) == PROBE_CPU_D22_OFFSET, "Probe::State::cpu.fprs[d22]'s offset matches ctiMasmProbeTrampoline" ); |
| 178 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d23]) == PROBE_CPU_D23_OFFSET, "Probe::State::cpu.fprs[d23]'s offset matches ctiMasmProbeTrampoline" ); |
| 179 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d24]) == PROBE_CPU_D24_OFFSET, "Probe::State::cpu.fprs[d24]'s offset matches ctiMasmProbeTrampoline" ); |
| 180 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d25]) == PROBE_CPU_D25_OFFSET, "Probe::State::cpu.fprs[d25]'s offset matches ctiMasmProbeTrampoline" ); |
| 181 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d26]) == PROBE_CPU_D26_OFFSET, "Probe::State::cpu.fprs[d26]'s offset matches ctiMasmProbeTrampoline" ); |
| 182 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d27]) == PROBE_CPU_D27_OFFSET, "Probe::State::cpu.fprs[d27]'s offset matches ctiMasmProbeTrampoline" ); |
| 183 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d28]) == PROBE_CPU_D28_OFFSET, "Probe::State::cpu.fprs[d28]'s offset matches ctiMasmProbeTrampoline" ); |
| 184 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d29]) == PROBE_CPU_D29_OFFSET, "Probe::State::cpu.fprs[d29]'s offset matches ctiMasmProbeTrampoline" ); |
| 185 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d30]) == PROBE_CPU_D30_OFFSET, "Probe::State::cpu.fprs[d30]'s offset matches ctiMasmProbeTrampoline" ); |
| 186 | static_assert(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d31]) == PROBE_CPU_D31_OFFSET, "Probe::State::cpu.fprs[d31]'s offset matches ctiMasmProbeTrampoline" ); |
| 187 | #endif // CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32) |
| 188 | |
| 189 | static_assert(sizeof(Probe::State) == PROBE_SIZE, "Probe::State's size matches ctiMasmProbeTrampoline" ); |
| 190 | #undef PROBE_OFFSETOF |
| 191 | |
| 192 | struct IncomingRecord { |
| 193 | uintptr_t lr; |
| 194 | uintptr_t ip; |
| 195 | uintptr_t apsr; |
| 196 | uintptr_t r0; |
| 197 | uintptr_t r1; |
| 198 | uintptr_t r2; |
| 199 | }; |
| 200 | |
| 201 | #define IN_LR_OFFSET (0 * PTR_SIZE) |
| 202 | #define IN_IP_OFFSET (1 * PTR_SIZE) |
| 203 | #define IN_APSR_OFFSET (2 * PTR_SIZE) |
| 204 | #define IN_R0_OFFSET (3 * PTR_SIZE) |
| 205 | #define IN_R1_OFFSET (4 * PTR_SIZE) |
| 206 | #define IN_R2_OFFSET (5 * PTR_SIZE) |
| 207 | #define IN_SIZE (6 * PTR_SIZE) |
| 208 | |
| 209 | static_assert(IN_LR_OFFSET == offsetof(IncomingRecord, lr), "IN_LR_OFFSET is incorrect" ); |
| 210 | static_assert(IN_IP_OFFSET == offsetof(IncomingRecord, ip), "IN_IP_OFFSET is incorrect" ); |
| 211 | static_assert(IN_APSR_OFFSET == offsetof(IncomingRecord, apsr), "IN_APSR_OFFSET is incorrect" ); |
| 212 | static_assert(IN_R0_OFFSET == offsetof(IncomingRecord, r0), "IN_R0_OFFSET is incorrect" ); |
| 213 | static_assert(IN_R1_OFFSET == offsetof(IncomingRecord, r1), "IN_R1_OFFSET is incorrect" ); |
| 214 | static_assert(IN_R2_OFFSET == offsetof(IncomingRecord, r2), "IN_R2_OFFSET is incorrect" ); |
| 215 | static_assert(IN_SIZE == sizeof(IncomingRecord), "IN_SIZE is incorrect" ); |
| 216 | |
| 217 | asm ( |
| 218 | ".text" "\n" |
| 219 | ".align 2" "\n" |
| 220 | ".globl " SYMBOL_STRING(ctiMasmProbeTrampoline) "\n" |
| 221 | HIDE_SYMBOL(ctiMasmProbeTrampoline) "\n" |
| 222 | ".thumb" "\n" |
| 223 | ".thumb_func " THUMB_FUNC_PARAM(ctiMasmProbeTrampoline) "\n" |
| 224 | SYMBOL_STRING(ctiMasmProbeTrampoline) ":" "\n" |
| 225 | |
| 226 | // MacroAssemblerARMv7::probe() has already generated code to store some values. |
| 227 | // The top of stack now contains the IncomingRecord. |
| 228 | // |
| 229 | // Incoming register values: |
| 230 | // r0: probe function |
| 231 | // r1: probe arg |
| 232 | // r2: Probe::executeProbe |
| 233 | // ip: scratch, was ctiMasmProbeTrampoline |
| 234 | // lr: return address |
| 235 | |
| 236 | "mov ip, sp" "\n" |
| 237 | "str r2, [ip, #-" STRINGIZE_VALUE_OF(PTR_SIZE) "]" "\n" // Stash Probe::executeProbe. |
| 238 | |
| 239 | "mov r2, sp" "\n" |
| 240 | "sub r2, r2, #" STRINGIZE_VALUE_OF(PROBE_SIZE + OUT_SIZE) "\n" |
| 241 | |
| 242 | // The ARM EABI specifies that the stack needs to be 16 byte aligned. |
| 243 | "bic r2, r2, #0xf" "\n" |
| 244 | "mov sp, r2" "\n" // Set the sp to protect the Probe::State from interrupts before we initialize it. |
| 245 | "ldr r2, [ip, #-" STRINGIZE_VALUE_OF(PTR_SIZE) "]" "\n" // Reload Probe::executeProbe. |
| 246 | |
| 247 | "str r0, [sp, #" STRINGIZE_VALUE_OF(PROBE_PROBE_FUNCTION_OFFSET) "]" "\n" |
| 248 | "str r1, [sp, #" STRINGIZE_VALUE_OF(PROBE_ARG_OFFSET) "]" "\n" |
| 249 | "str lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_PC_OFFSET) "]" "\n" |
| 250 | |
| 251 | "add r0, ip, #" STRINGIZE_VALUE_OF(IN_SIZE) "\n" |
| 252 | "str r0, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n" |
| 253 | |
| 254 | "add lr, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_R3_OFFSET) "\n" |
| 255 | "stmia lr, { r3-r11 }" "\n" |
| 256 | |
| 257 | "vmrs lr, FPSCR" "\n" |
| 258 | "str lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_FPSCR_OFFSET) "]" "\n" |
| 259 | |
| 260 | "ldr r4, [ip, #" STRINGIZE_VALUE_OF(IN_LR_OFFSET) "]" "\n" |
| 261 | "ldr r5, [ip, #" STRINGIZE_VALUE_OF(IN_IP_OFFSET) "]" "\n" |
| 262 | "ldr r6, [ip, #" STRINGIZE_VALUE_OF(IN_APSR_OFFSET) "]" "\n" |
| 263 | "ldr r7, [ip, #" STRINGIZE_VALUE_OF(IN_R0_OFFSET) "]" "\n" |
| 264 | "ldr r8, [ip, #" STRINGIZE_VALUE_OF(IN_R1_OFFSET) "]" "\n" |
| 265 | "ldr r9, [ip, #" STRINGIZE_VALUE_OF(IN_R2_OFFSET) "]" "\n" |
| 266 | "str r4, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_LR_OFFSET) "]" "\n" |
| 267 | "str r5, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_IP_OFFSET) "]" "\n" |
| 268 | "str r6, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_APSR_OFFSET) "]" "\n" |
| 269 | "str r7, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_R0_OFFSET) "]" "\n" |
| 270 | "str r8, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_R1_OFFSET) "]" "\n" |
| 271 | "str r9, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_R2_OFFSET) "]" "\n" |
| 272 | |
| 273 | "add ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_D0_OFFSET) "\n" |
| 274 | "vstmia.64 ip!, { d0-d15 }" "\n" |
| 275 | #if CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32) |
| 276 | "vstmia.64 ip!, { d16-d31 }" "\n" |
| 277 | #endif |
| 278 | |
| 279 | // r5 is a callee saved register. We'll use it for preserving the Probe::State*. |
| 280 | // https://stackoverflow.com/questions/261419/arm-to-c-calling-convention-registers-to-save#261496 |
| 281 | "mov r5, sp" "\n" |
| 282 | |
| 283 | "mov r0, sp" "\n" // the Probe::State* arg. |
| 284 | "blx r2" "\n" // Call Probe::executeProbe. |
| 285 | |
| 286 | // Make sure the Probe::State is entirely below the result stack pointer so |
| 287 | // that register values are still preserved when we call the initializeStack |
| 288 | // function. |
| 289 | "ldr r1, [r5, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n" // Result sp. |
| 290 | "add r2, r5, #" STRINGIZE_VALUE_OF(PROBE_SIZE + OUT_SIZE) "\n" // End of ProveContext + buffer. |
| 291 | "cmp r1, r2" "\n" |
| 292 | "bge " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineProbeStateIsSafe) "\n" |
| 293 | |
| 294 | // Allocate a safe place on the stack below the result stack pointer to stash the Probe::State. |
| 295 | "sub r1, r1, #" STRINGIZE_VALUE_OF(PROBE_SIZE + OUT_SIZE) "\n" |
| 296 | "bic r1, r1, #0xf" "\n" // The ARM EABI specifies that the stack needs to be 16 byte aligned. |
| 297 | "mov sp, r1" "\n" // Set the new sp to protect that memory from interrupts before we copy the Probe::State. |
| 298 | |
| 299 | // Copy the Probe::State to the safe place. |
| 300 | // Note: we have to copy from low address to higher address because we're moving the |
| 301 | // Probe::State to a lower address. |
| 302 | "add r7, r5, #" STRINGIZE_VALUE_OF(PROBE_SIZE) "\n" |
| 303 | |
| 304 | LOCAL_LABEL_STRING(ctiMasmProbeTrampolineCopyLoop) ":" "\n" |
| 305 | "ldr r3, [r5], #4" "\n" |
| 306 | "ldr r4, [r5], #4" "\n" |
| 307 | "str r3, [r1], #4" "\n" |
| 308 | "str r4, [r1], #4" "\n" |
| 309 | "cmp r5, r7" "\n" |
| 310 | "blt " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineCopyLoop) "\n" |
| 311 | |
| 312 | "mov r5, sp" "\n" |
| 313 | |
| 314 | // Call initializeStackFunction if present. |
| 315 | LOCAL_LABEL_STRING(ctiMasmProbeTrampolineProbeStateIsSafe) ":" "\n" |
| 316 | "ldr r2, [r5, #" STRINGIZE_VALUE_OF(PROBE_INIT_STACK_FUNCTION_OFFSET) "]" "\n" |
| 317 | "cbz r2, " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineRestoreRegisters) "\n" |
| 318 | |
| 319 | "mov r0, r5" "\n" // Set the Probe::State* arg. |
| 320 | "blx r2" "\n" // Call the initializeStackFunction (loaded into r2 above). |
| 321 | |
| 322 | LOCAL_LABEL_STRING(ctiMasmProbeTrampolineRestoreRegisters) ":" "\n" |
| 323 | |
| 324 | "mov sp, r5" "\n" // Ensure that sp points to the Probe::State*. |
| 325 | |
| 326 | // To enable probes to modify register state, we copy all registers |
| 327 | // out of the Probe::State before returning. |
| 328 | |
| 329 | #if CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32) |
| 330 | "add ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_D31_OFFSET + FPREG_SIZE) "\n" |
| 331 | "vldmdb.64 ip!, { d16-d31 }" "\n" |
| 332 | "vldmdb.64 ip!, { d0-d15 }" "\n" |
| 333 | #else |
| 334 | "add ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_D15_OFFSET + FPREG_SIZE) "\n" |
| 335 | "vldmdb.64 ip!, { d0-d15 }" "\n" |
| 336 | #endif |
| 337 | |
| 338 | "add ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_R11_OFFSET + GPREG_SIZE) "\n" |
| 339 | "ldmdb ip, { r0-r11 }" "\n" |
| 340 | "ldr ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_FPSCR_OFFSET) "]" "\n" |
| 341 | "vmsr FPSCR, ip" "\n" |
| 342 | |
| 343 | // There are 5 more registers left to restore: ip, sp, lr, pc, and apsr. |
| 344 | |
| 345 | // Set up the restore area for sp and pc. |
| 346 | "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n" |
| 347 | |
| 348 | // Push the pc on to the restore area. |
| 349 | "ldr ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_PC_OFFSET) "]" "\n" |
| 350 | "sub lr, lr, #" STRINGIZE_VALUE_OF(OUT_SIZE) "\n" |
| 351 | "str ip, [lr]" "\n" |
| 352 | // Point sp to the restore area. |
| 353 | "str lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n" |
| 354 | |
| 355 | // All done with math i.e. won't trash the status register (apsr) and don't need |
| 356 | // scratch registers (lr and ip) anymore. Restore apsr, lr, and ip. |
| 357 | "ldr ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_APSR_OFFSET) "]" "\n" |
| 358 | "msr APSR_nzcvq, ip" "\n" |
| 359 | "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_LR_OFFSET) "]" "\n" |
| 360 | "ldr ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_IP_OFFSET) "]" "\n" |
| 361 | |
| 362 | // Restore the sp and pc. |
| 363 | "ldr sp, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n" |
| 364 | "pop { pc }" "\n" |
| 365 | ); |
| 366 | #endif // COMPILER(GCC_COMPATIBLE) |
| 367 | |
| 368 | void MacroAssembler::probe(Probe::Function function, void* arg) |
| 369 | { |
| 370 | sub32(TrustedImm32(sizeof(IncomingRecord)), sp); |
| 371 | |
| 372 | store32(lr, Address(sp, offsetof(IncomingRecord, lr))); |
| 373 | store32(ip, Address(sp, offsetof(IncomingRecord, ip))); |
| 374 | m_assembler.mrs(ip, apsr); |
| 375 | store32(ip, Address(sp, offsetof(IncomingRecord, apsr))); |
| 376 | store32(r0, Address(sp, offsetof(IncomingRecord, r0))); |
| 377 | store32(r1, Address(sp, offsetof(IncomingRecord, r1))); |
| 378 | store32(r2, Address(sp, offsetof(IncomingRecord, r2))); |
| 379 | |
| 380 | // The following may emit a T1 mov instruction, which is effectively a movs. |
| 381 | // This means we must first preserve the apsr flags above first. |
| 382 | move(TrustedImmPtr(reinterpret_cast<void*>(function)), r0); |
| 383 | move(TrustedImmPtr(arg), r1); |
| 384 | move(TrustedImmPtr(reinterpret_cast<void*>(Probe::executeProbe)), r2); |
| 385 | move(TrustedImmPtr(reinterpret_cast<void*>(ctiMasmProbeTrampoline)), ip); |
| 386 | m_assembler.blx(ip); |
| 387 | } |
| 388 | #endif // ENABLE(MASM_PROBE) |
| 389 | |
| 390 | } // namespace JSC |
| 391 | |
| 392 | #endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2) |
| 393 | |