2 * Copyright (C) 2013-2017 Apple Inc.
3 * Copyright (C) 2009 University of Szeged
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
31 #include "MacroAssembler.h"
33 #include "ProbeContext.h"
34 #include <wtf/InlineASM.h>
37 #include <sys/types.h>
42 #include <asm/hwcap.h>
47 static bool isVFPPresent()
50 int fd = open("/proc/self/auxv", O_RDONLY);
53 while (read(fd, &aux, sizeof(Elf32_auxv_t))) {
54 if (aux.a_type == AT_HWCAP) {
56 return aux.a_un.a_val & HWCAP_VFP;
63 #if (COMPILER(GCC_OR_CLANG) && defined(__VFP_FP__))
70 const bool MacroAssemblerARM::s_isVFPPresent = isVFPPresent();
72 #if CPU(ARMV5_OR_LOWER)
73 /* On ARMv5 and below, natural alignment is required. */
74 void MacroAssemblerARM::load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
78 ASSERT(address.scale >= 0 && address.scale <= 3);
79 op2 = m_assembler.lsl(address.index, static_cast<int>(address.scale));
81 if (address.offset >= 0 && address.offset + 0x2 <= 0xff) {
82 m_assembler.add(ARMRegisters::S0, address.base, op2);
83 m_assembler.halfDtrUp(ARMAssembler::LoadUint16, dest, ARMRegisters::S0, ARMAssembler::getOp2Half(address.offset));
84 m_assembler.halfDtrUp(ARMAssembler::LoadUint16, ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Half(address.offset + 0x2));
85 } else if (address.offset < 0 && address.offset >= -0xff) {
86 m_assembler.add(ARMRegisters::S0, address.base, op2);
87 m_assembler.halfDtrDown(ARMAssembler::LoadUint16, dest, ARMRegisters::S0, ARMAssembler::getOp2Half(-address.offset));
88 m_assembler.halfDtrDown(ARMAssembler::LoadUint16, ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Half(-address.offset - 0x2));
90 m_assembler.moveImm(address.offset, ARMRegisters::S0);
91 m_assembler.add(ARMRegisters::S0, ARMRegisters::S0, op2);
92 m_assembler.halfDtrUpRegister(ARMAssembler::LoadUint16, dest, address.base, ARMRegisters::S0);
93 m_assembler.add(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::Op2Immediate | 0x2);
94 m_assembler.halfDtrUpRegister(ARMAssembler::LoadUint16, ARMRegisters::S0, address.base, ARMRegisters::S0);
96 m_assembler.orr(dest, dest, m_assembler.lsl(ARMRegisters::S0, 16));
98 #endif // CPU(ARMV5_OR_LOWER)
100 #if ENABLE(MASM_PROBE)
102 extern "C" void ctiMasmProbeTrampoline();
104 using namespace ARMRegisters;
106 #if COMPILER(GCC_OR_CLANG)
108 // The following are offsets for Probe::State fields accessed
109 // by the ctiMasmProbeTrampoline stub.
112 #define PROBE_PROBE_FUNCTION_OFFSET (0 * PTR_SIZE)
113 #define PROBE_ARG_OFFSET (1 * PTR_SIZE)
114 #define PROBE_INIT_STACK_FUNCTION_OFFSET (2 * PTR_SIZE)
115 #define PROBE_INIT_STACK_ARG_OFFSET (3 * PTR_SIZE)
117 #define PROBE_FIRST_GPREG_OFFSET (4 * PTR_SIZE)
120 #define PROBE_CPU_R0_OFFSET (PROBE_FIRST_GPREG_OFFSET + (0 * GPREG_SIZE))
121 #define PROBE_CPU_R1_OFFSET (PROBE_FIRST_GPREG_OFFSET + (1 * GPREG_SIZE))
122 #define PROBE_CPU_R2_OFFSET (PROBE_FIRST_GPREG_OFFSET + (2 * GPREG_SIZE))
123 #define PROBE_CPU_R3_OFFSET (PROBE_FIRST_GPREG_OFFSET + (3 * GPREG_SIZE))
124 #define PROBE_CPU_R4_OFFSET (PROBE_FIRST_GPREG_OFFSET + (4 * GPREG_SIZE))
125 #define PROBE_CPU_R5_OFFSET (PROBE_FIRST_GPREG_OFFSET + (5 * GPREG_SIZE))
126 #define PROBE_CPU_R6_OFFSET (PROBE_FIRST_GPREG_OFFSET + (6 * GPREG_SIZE))
127 #define PROBE_CPU_R7_OFFSET (PROBE_FIRST_GPREG_OFFSET + (7 * GPREG_SIZE))
128 #define PROBE_CPU_R8_OFFSET (PROBE_FIRST_GPREG_OFFSET + (8 * GPREG_SIZE))
129 #define PROBE_CPU_R9_OFFSET (PROBE_FIRST_GPREG_OFFSET + (9 * GPREG_SIZE))
130 #define PROBE_CPU_R10_OFFSET (PROBE_FIRST_GPREG_OFFSET + (10 * GPREG_SIZE))
131 #define PROBE_CPU_R11_OFFSET (PROBE_FIRST_GPREG_OFFSET + (11 * GPREG_SIZE))
132 #define PROBE_CPU_IP_OFFSET (PROBE_FIRST_GPREG_OFFSET + (12 * GPREG_SIZE))
133 #define PROBE_CPU_SP_OFFSET (PROBE_FIRST_GPREG_OFFSET + (13 * GPREG_SIZE))
134 #define PROBE_CPU_LR_OFFSET (PROBE_FIRST_GPREG_OFFSET + (14 * GPREG_SIZE))
135 #define PROBE_CPU_PC_OFFSET (PROBE_FIRST_GPREG_OFFSET + (15 * GPREG_SIZE))
137 #define PROBE_CPU_APSR_OFFSET (PROBE_FIRST_GPREG_OFFSET + (16 * GPREG_SIZE))
138 #define PROBE_CPU_FPSCR_OFFSET (PROBE_FIRST_GPREG_OFFSET + (17 * GPREG_SIZE))
140 #define PROBE_FIRST_FPREG_OFFSET (PROBE_FIRST_GPREG_OFFSET + (18 * GPREG_SIZE))
143 #define PROBE_CPU_D0_OFFSET (PROBE_FIRST_FPREG_OFFSET + (0 * FPREG_SIZE))
144 #define PROBE_CPU_D1_OFFSET (PROBE_FIRST_FPREG_OFFSET + (1 * FPREG_SIZE))
145 #define PROBE_CPU_D2_OFFSET (PROBE_FIRST_FPREG_OFFSET + (2 * FPREG_SIZE))
146 #define PROBE_CPU_D3_OFFSET (PROBE_FIRST_FPREG_OFFSET + (3 * FPREG_SIZE))
147 #define PROBE_CPU_D4_OFFSET (PROBE_FIRST_FPREG_OFFSET + (4 * FPREG_SIZE))
148 #define PROBE_CPU_D5_OFFSET (PROBE_FIRST_FPREG_OFFSET + (5 * FPREG_SIZE))
149 #define PROBE_CPU_D6_OFFSET (PROBE_FIRST_FPREG_OFFSET + (6 * FPREG_SIZE))
150 #define PROBE_CPU_D7_OFFSET (PROBE_FIRST_FPREG_OFFSET + (7 * FPREG_SIZE))
151 #define PROBE_CPU_D8_OFFSET (PROBE_FIRST_FPREG_OFFSET + (8 * FPREG_SIZE))
152 #define PROBE_CPU_D9_OFFSET (PROBE_FIRST_FPREG_OFFSET + (9 * FPREG_SIZE))
153 #define PROBE_CPU_D10_OFFSET (PROBE_FIRST_FPREG_OFFSET + (10 * FPREG_SIZE))
154 #define PROBE_CPU_D11_OFFSET (PROBE_FIRST_FPREG_OFFSET + (11 * FPREG_SIZE))
155 #define PROBE_CPU_D12_OFFSET (PROBE_FIRST_FPREG_OFFSET + (12 * FPREG_SIZE))
156 #define PROBE_CPU_D13_OFFSET (PROBE_FIRST_FPREG_OFFSET + (13 * FPREG_SIZE))
157 #define PROBE_CPU_D14_OFFSET (PROBE_FIRST_FPREG_OFFSET + (14 * FPREG_SIZE))
158 #define PROBE_CPU_D15_OFFSET (PROBE_FIRST_FPREG_OFFSET + (15 * FPREG_SIZE))
160 #if CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32)
161 #define PROBE_CPU_D16_OFFSET (PROBE_FIRST_FPREG_OFFSET + (16 * FPREG_SIZE))
162 #define PROBE_CPU_D17_OFFSET (PROBE_FIRST_FPREG_OFFSET + (17 * FPREG_SIZE))
163 #define PROBE_CPU_D18_OFFSET (PROBE_FIRST_FPREG_OFFSET + (18 * FPREG_SIZE))
164 #define PROBE_CPU_D19_OFFSET (PROBE_FIRST_FPREG_OFFSET + (19 * FPREG_SIZE))
165 #define PROBE_CPU_D20_OFFSET (PROBE_FIRST_FPREG_OFFSET + (20 * FPREG_SIZE))
166 #define PROBE_CPU_D21_OFFSET (PROBE_FIRST_FPREG_OFFSET + (21 * FPREG_SIZE))
167 #define PROBE_CPU_D22_OFFSET (PROBE_FIRST_FPREG_OFFSET + (22 * FPREG_SIZE))
168 #define PROBE_CPU_D23_OFFSET (PROBE_FIRST_FPREG_OFFSET + (23 * FPREG_SIZE))
169 #define PROBE_CPU_D24_OFFSET (PROBE_FIRST_FPREG_OFFSET + (24 * FPREG_SIZE))
170 #define PROBE_CPU_D25_OFFSET (PROBE_FIRST_FPREG_OFFSET + (25 * FPREG_SIZE))
171 #define PROBE_CPU_D26_OFFSET (PROBE_FIRST_FPREG_OFFSET + (26 * FPREG_SIZE))
172 #define PROBE_CPU_D27_OFFSET (PROBE_FIRST_FPREG_OFFSET + (27 * FPREG_SIZE))
173 #define PROBE_CPU_D28_OFFSET (PROBE_FIRST_FPREG_OFFSET + (28 * FPREG_SIZE))
174 #define PROBE_CPU_D29_OFFSET (PROBE_FIRST_FPREG_OFFSET + (29 * FPREG_SIZE))
175 #define PROBE_CPU_D30_OFFSET (PROBE_FIRST_FPREG_OFFSET + (30 * FPREG_SIZE))
176 #define PROBE_CPU_D31_OFFSET (PROBE_FIRST_FPREG_OFFSET + (31 * FPREG_SIZE))
178 #define PROBE_SIZE (PROBE_FIRST_FPREG_OFFSET + (32 * FPREG_SIZE))
180 #define PROBE_SIZE (PROBE_FIRST_FPREG_OFFSET + (16 * FPREG_SIZE))
181 #endif // CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32)
183 #define OUT_SIZE GPREG_SIZE
185 // These ASSERTs remind you that if you change the layout of Probe::State,
186 // you need to change ctiMasmProbeTrampoline offsets above to match.
187 #define PROBE_OFFSETOF(x) offsetof(struct Probe::State, x)
188 COMPILE_ASSERT(PROBE_OFFSETOF(probeFunction) == PROBE_PROBE_FUNCTION_OFFSET, ProbeState_probeFunction_offset_matches_ctiMasmProbeTrampoline);
189 COMPILE_ASSERT(PROBE_OFFSETOF(arg) == PROBE_ARG_OFFSET, ProbeState_arg_offset_matches_ctiMasmProbeTrampoline);
190 COMPILE_ASSERT(PROBE_OFFSETOF(initializeStackFunction) == PROBE_INIT_STACK_FUNCTION_OFFSET, ProbeState_initializeStackFunction_offset_matches_ctiMasmProbeTrampoline);
191 COMPILE_ASSERT(PROBE_OFFSETOF(initializeStackArg) == PROBE_INIT_STACK_ARG_OFFSET, ProbeState_initializeStackArg_offset_matches_ctiMasmProbeTrampoline);
193 COMPILE_ASSERT(!(PROBE_CPU_R0_OFFSET & 0x3), ProbeState_cpu_r0_offset_should_be_4_byte_aligned);
195 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r0]) == PROBE_CPU_R0_OFFSET, ProbeState_cpu_r0_offset_matches_ctiMasmProbeTrampoline);
196 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r1]) == PROBE_CPU_R1_OFFSET, ProbeState_cpu_r1_offset_matches_ctiMasmProbeTrampoline);
197 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r2]) == PROBE_CPU_R2_OFFSET, ProbeState_cpu_r2_offset_matches_ctiMasmProbeTrampoline);
198 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r3]) == PROBE_CPU_R3_OFFSET, ProbeState_cpu_r3_offset_matches_ctiMasmProbeTrampoline);
199 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r4]) == PROBE_CPU_R4_OFFSET, ProbeState_cpu_r4_offset_matches_ctiMasmProbeTrampoline);
200 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r5]) == PROBE_CPU_R5_OFFSET, ProbeState_cpu_r5_offset_matches_ctiMasmProbeTrampoline);
201 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r6]) == PROBE_CPU_R6_OFFSET, ProbeState_cpu_r6_offset_matches_ctiMasmProbeTrampoline);
202 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r7]) == PROBE_CPU_R7_OFFSET, ProbeState_cpu_r7_offset_matches_ctiMasmProbeTrampoline);
203 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r8]) == PROBE_CPU_R8_OFFSET, ProbeState_cpu_r8_offset_matches_ctiMasmProbeTrampoline);
204 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r9]) == PROBE_CPU_R9_OFFSET, ProbeState_cpu_r9_offset_matches_ctiMasmProbeTrampoline);
205 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r10]) == PROBE_CPU_R10_OFFSET, ProbeState_cpu_r10_offset_matches_ctiMasmProbeTrampoline);
206 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r11]) == PROBE_CPU_R11_OFFSET, ProbeState_cpu_r11_offset_matches_ctiMasmProbeTrampoline);
207 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::ip]) == PROBE_CPU_IP_OFFSET, ProbeState_cpu_ip_offset_matches_ctiMasmProbeTrampoline);
208 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::sp]) == PROBE_CPU_SP_OFFSET, ProbeState_cpu_sp_offset_matches_ctiMasmProbeTrampoline);
209 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::lr]) == PROBE_CPU_LR_OFFSET, ProbeState_cpu_lr_offset_matches_ctiMasmProbeTrampoline);
210 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::pc]) == PROBE_CPU_PC_OFFSET, ProbeState_cpu_pc_offset_matches_ctiMasmProbeTrampoline);
212 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.sprs[ARMRegisters::apsr]) == PROBE_CPU_APSR_OFFSET, ProbeState_cpu_apsr_offset_matches_ctiMasmProbeTrampoline);
213 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.sprs[ARMRegisters::fpscr]) == PROBE_CPU_FPSCR_OFFSET, ProbeState_cpu_fpscr_offset_matches_ctiMasmProbeTrampoline);
215 COMPILE_ASSERT(!(PROBE_CPU_D0_OFFSET & 0x7), ProbeState_cpu_d0_offset_should_be_8_byte_aligned);
217 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d0]) == PROBE_CPU_D0_OFFSET, ProbeState_cpu_d0_offset_matches_ctiMasmProbeTrampoline);
218 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d1]) == PROBE_CPU_D1_OFFSET, ProbeState_cpu_d1_offset_matches_ctiMasmProbeTrampoline);
219 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d2]) == PROBE_CPU_D2_OFFSET, ProbeState_cpu_d2_offset_matches_ctiMasmProbeTrampoline);
220 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d3]) == PROBE_CPU_D3_OFFSET, ProbeState_cpu_d3_offset_matches_ctiMasmProbeTrampoline);
221 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d4]) == PROBE_CPU_D4_OFFSET, ProbeState_cpu_d4_offset_matches_ctiMasmProbeTrampoline);
222 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d5]) == PROBE_CPU_D5_OFFSET, ProbeState_cpu_d5_offset_matches_ctiMasmProbeTrampoline);
223 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d6]) == PROBE_CPU_D6_OFFSET, ProbeState_cpu_d6_offset_matches_ctiMasmProbeTrampoline);
224 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d7]) == PROBE_CPU_D7_OFFSET, ProbeState_cpu_d7_offset_matches_ctiMasmProbeTrampoline);
225 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d8]) == PROBE_CPU_D8_OFFSET, ProbeState_cpu_d8_offset_matches_ctiMasmProbeTrampoline);
226 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d9]) == PROBE_CPU_D9_OFFSET, ProbeState_cpu_d9_offset_matches_ctiMasmProbeTrampoline);
227 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d10]) == PROBE_CPU_D10_OFFSET, ProbeState_cpu_d10_offset_matches_ctiMasmProbeTrampoline);
228 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d11]) == PROBE_CPU_D11_OFFSET, ProbeState_cpu_d11_offset_matches_ctiMasmProbeTrampoline);
229 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d12]) == PROBE_CPU_D12_OFFSET, ProbeState_cpu_d12_offset_matches_ctiMasmProbeTrampoline);
230 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d13]) == PROBE_CPU_D13_OFFSET, ProbeState_cpu_d13_offset_matches_ctiMasmProbeTrampoline);
231 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d14]) == PROBE_CPU_D14_OFFSET, ProbeState_cpu_d14_offset_matches_ctiMasmProbeTrampoline);
232 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d15]) == PROBE_CPU_D15_OFFSET, ProbeState_cpu_d15_offset_matches_ctiMasmProbeTrampoline);
234 #if CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32)
235 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d16]) == PROBE_CPU_D16_OFFSET, ProbeState_cpu_d16_offset_matches_ctiMasmProbeTrampoline);
236 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d17]) == PROBE_CPU_D17_OFFSET, ProbeState_cpu_d17_offset_matches_ctiMasmProbeTrampoline);
237 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d18]) == PROBE_CPU_D18_OFFSET, ProbeState_cpu_d18_offset_matches_ctiMasmProbeTrampoline);
238 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d19]) == PROBE_CPU_D19_OFFSET, ProbeState_cpu_d19_offset_matches_ctiMasmProbeTrampoline);
239 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d20]) == PROBE_CPU_D20_OFFSET, ProbeState_cpu_d20_offset_matches_ctiMasmProbeTrampoline);
240 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d21]) == PROBE_CPU_D21_OFFSET, ProbeState_cpu_d21_offset_matches_ctiMasmProbeTrampoline);
241 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d22]) == PROBE_CPU_D22_OFFSET, ProbeState_cpu_d22_offset_matches_ctiMasmProbeTrampoline);
242 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d23]) == PROBE_CPU_D23_OFFSET, ProbeState_cpu_d23_offset_matches_ctiMasmProbeTrampoline);
243 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d24]) == PROBE_CPU_D24_OFFSET, ProbeState_cpu_d24_offset_matches_ctiMasmProbeTrampoline);
244 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d25]) == PROBE_CPU_D25_OFFSET, ProbeState_cpu_d25_offset_matches_ctiMasmProbeTrampoline);
245 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d26]) == PROBE_CPU_D26_OFFSET, ProbeState_cpu_d26_offset_matches_ctiMasmProbeTrampoline);
246 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d27]) == PROBE_CPU_D27_OFFSET, ProbeState_cpu_d27_offset_matches_ctiMasmProbeTrampoline);
247 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d28]) == PROBE_CPU_D28_OFFSET, ProbeState_cpu_d28_offset_matches_ctiMasmProbeTrampoline);
248 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d29]) == PROBE_CPU_D29_OFFSET, ProbeState_cpu_d29_offset_matches_ctiMasmProbeTrampoline);
249 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d30]) == PROBE_CPU_D30_OFFSET, ProbeState_cpu_d30_offset_matches_ctiMasmProbeTrampoline);
250 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d31]) == PROBE_CPU_D31_OFFSET, ProbeState_cpu_d31_offset_matches_ctiMasmProbeTrampoline);
251 #endif // CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32)
253 COMPILE_ASSERT(sizeof(Probe::State) == PROBE_SIZE, ProbeState_size_matches_ctiMasmProbeTrampoline);
254 #undef PROBE_OFFSETOF
256 struct IncomingRecord {
265 #define IN_LR_OFFSET (0 * PTR_SIZE)
266 #define IN_IP_OFFSET (1 * PTR_SIZE)
267 #define IN_R6_OFFSET (2 * PTR_SIZE)
268 #define IN_R0_OFFSET (3 * PTR_SIZE)
269 #define IN_R1_OFFSET (4 * PTR_SIZE)
270 #define IN_R2_OFFSET (5 * PTR_SIZE)
271 #define IN_SIZE (6 * PTR_SIZE)
273 static_assert(IN_LR_OFFSET == offsetof(IncomingRecord, lr), "IN_LR_OFFSET is incorrect");
274 static_assert(IN_IP_OFFSET == offsetof(IncomingRecord, ip), "IN_IP_OFFSET is incorrect");
275 static_assert(IN_R6_OFFSET == offsetof(IncomingRecord, r6), "IN_R6_OFFSET is incorrect");
276 static_assert(IN_R0_OFFSET == offsetof(IncomingRecord, r0), "IN_R0_OFFSET is incorrect");
277 static_assert(IN_R1_OFFSET == offsetof(IncomingRecord, r1), "IN_R1_OFFSET is incorrect");
278 static_assert(IN_R2_OFFSET == offsetof(IncomingRecord, r2), "IN_R2_OFFSET is incorrect");
279 static_assert(IN_SIZE == sizeof(IncomingRecord), "IN_SIZE is incorrect");
283 ".globl " SYMBOL_STRING(ctiMasmProbeTrampoline) "\n"
284 HIDE_SYMBOL(ctiMasmProbeTrampoline) "\n"
285 INLINE_ARM_FUNCTION(ctiMasmProbeTrampoline) "\n"
286 SYMBOL_STRING(ctiMasmProbeTrampoline) ":" "\n"
288 // MacroAssemblerARMv7::probe() has already generated code to store some values.
289 // The top of stack now contains the IncomingRecord.
291 // Incoming register values:
292 // r0: probe function
294 // r2: Probe::executeProbe
296 // ip: scratch, was ctiMasmProbeTrampoline
297 // lr: return address
301 "sub r6, r6, #" STRINGIZE_VALUE_OF(PROBE_SIZE + OUT_SIZE) "\n"
303 // The ARM EABI specifies that the stack needs to be 16 byte aligned.
304 "bic r6, r6, #0xf" "\n"
305 "mov sp, r6" "\n" // Set the sp to protect the Probe::State from interrupts before we initialize it.
307 "str r0, [sp, #" STRINGIZE_VALUE_OF(PROBE_PROBE_FUNCTION_OFFSET) "]" "\n"
308 "str r1, [sp, #" STRINGIZE_VALUE_OF(PROBE_ARG_OFFSET) "]" "\n"
309 "str lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_PC_OFFSET) "]" "\n"
311 "add r0, ip, #" STRINGIZE_VALUE_OF(IN_SIZE) "\n"
312 "str r0, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
314 "add lr, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_R3_OFFSET) "\n"
315 "stmia lr, { r3-r5 }" "\n"
316 "add lr, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_R7_OFFSET) "\n"
317 "stmia lr, { r7-r11 }" "\n"
319 "str lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_APSR_OFFSET) "]" "\n"
320 "vmrs lr, FPSCR" "\n"
321 "str lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_FPSCR_OFFSET) "]" "\n"
323 "ldr r4, [ip, #" STRINGIZE_VALUE_OF(IN_LR_OFFSET) "]" "\n"
324 "ldr r5, [ip, #" STRINGIZE_VALUE_OF(IN_IP_OFFSET) "]" "\n"
325 "ldr r6, [ip, #" STRINGIZE_VALUE_OF(IN_R6_OFFSET) "]" "\n"
326 "ldr r7, [ip, #" STRINGIZE_VALUE_OF(IN_R0_OFFSET) "]" "\n"
327 "ldr r8, [ip, #" STRINGIZE_VALUE_OF(IN_R1_OFFSET) "]" "\n"
328 "ldr r9, [ip, #" STRINGIZE_VALUE_OF(IN_R2_OFFSET) "]" "\n"
329 "str r4, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_LR_OFFSET) "]" "\n"
330 "str r5, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_IP_OFFSET) "]" "\n"
331 "str r6, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_R6_OFFSET) "]" "\n"
332 "str r7, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_R0_OFFSET) "]" "\n"
333 "str r8, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_R1_OFFSET) "]" "\n"
334 "str r9, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_R2_OFFSET) "]" "\n"
336 "add ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_D0_OFFSET) "\n"
337 "vstmia.64 ip!, { d0-d15 }" "\n"
338 #if CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32)
339 "vstmia.64 ip!, { d16-d31 }" "\n"
342 // r5 is a callee saved register. We'll use it for preserving the Probe::State*.
343 // https://stackoverflow.com/questions/261419/arm-to-c-calling-convention-registers-to-save#261496
346 "mov r0, sp" "\n" // the Probe::State* arg.
347 "blx r2" "\n" // Call Probe::executeProbe.
349 // Make sure the Probe::State is entirely below the result stack pointer so
350 // that register values are still preserved when we call the initializeStack
352 "ldr r1, [r5, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n" // Result sp.
353 "add r2, r5, #" STRINGIZE_VALUE_OF(PROBE_SIZE + OUT_SIZE) "\n" // End of ProveContext + buffer.
355 "bge " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineProbeStateIsSafe) "\n"
357 // Allocate a safe place on the stack below the result stack pointer to stash the Probe::State.
358 "sub r1, r1, #" STRINGIZE_VALUE_OF(PROBE_SIZE + OUT_SIZE) "\n"
359 "bic r1, r1, #0xf" "\n" // The ARM EABI specifies that the stack needs to be 16 byte aligned.
360 "mov sp, r1" "\n" // Set the new sp to protect that memory from interrupts before we copy the Probe::State.
362 // Copy the Probe::State to the safe place.
363 // Note: we have to copy from low address to higher address because we're moving the
364 // Probe::State to a lower address.
365 "add r7, r5, #" STRINGIZE_VALUE_OF(PROBE_SIZE) "\n"
367 LOCAL_LABEL_STRING(ctiMasmProbeTrampolineCopyLoop) ":" "\n"
368 "ldr r3, [r5], #4" "\n"
369 "ldr r4, [r5], #4" "\n"
370 "str r3, [r1], #4" "\n"
371 "str r4, [r1], #4" "\n"
373 "blt " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineCopyLoop) "\n"
377 // Call initializeStackFunction if present.
378 LOCAL_LABEL_STRING(ctiMasmProbeTrampolineProbeStateIsSafe) ":" "\n"
379 "ldr r2, [r5, #" STRINGIZE_VALUE_OF(PROBE_INIT_STACK_FUNCTION_OFFSET) "]" "\n"
381 "beq " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineRestoreRegisters) "\n"
383 "mov r0, r5" "\n" // Set the Probe::State* arg.
384 "blx r2" "\n" // Call the initializeStackFunction (loaded into r2 above).
386 LOCAL_LABEL_STRING(ctiMasmProbeTrampolineRestoreRegisters) ":" "\n"
388 "mov sp, r5" "\n" // Ensure that sp points to the Probe::State*.
390 // To enable probes to modify register state, we copy all registers
391 // out of the Probe::State before returning.
393 #if CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32)
394 "add ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_D31_OFFSET + FPREG_SIZE) "\n"
395 "vldmdb.64 ip!, { d16-d31 }" "\n"
396 "vldmdb.64 ip!, { d0-d15 }" "\n"
398 "add ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_D15_OFFSET + FPREG_SIZE) "\n"
399 "vldmdb.64 ip!, { d0-d15 }" "\n"
402 "add ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_R11_OFFSET + GPREG_SIZE) "\n"
403 "ldmdb ip, { r0-r11 }" "\n"
404 "ldr ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_FPSCR_OFFSET) "]" "\n"
405 "vmsr FPSCR, ip" "\n"
407 // There are 5 more registers left to restore: ip, sp, lr, pc, and apsr.
409 // Set up the restore area for sp and pc.
410 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
412 // Push the pc on to the restore area.
413 "ldr ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_PC_OFFSET) "]" "\n"
414 "sub lr, lr, #" STRINGIZE_VALUE_OF(OUT_SIZE) "\n"
416 // Point sp to the restore area.
417 "str lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
419 // All done with math i.e. won't trash the status register (apsr) and don't need
420 // scratch registers (lr and ip) anymore. Restore apsr, lr, and ip.
421 "ldr ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_APSR_OFFSET) "]" "\n"
423 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_LR_OFFSET) "]" "\n"
424 "ldr ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_IP_OFFSET) "]" "\n"
426 // Restore the sp and pc.
427 "ldr sp, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
430 #endif // COMPILER(GCC_OR_CLANG)
432 void MacroAssembler::probe(Probe::Function function, void* arg)
434 sub32(TrustedImm32(sizeof(IncomingRecord)), sp);
436 store32(lr, Address(sp, offsetof(IncomingRecord, lr)));
437 store32(ip, Address(sp, offsetof(IncomingRecord, ip)));
438 store32(r6, Address(sp, offsetof(IncomingRecord, r6))); // S0 == r6.
439 store32(r0, Address(sp, offsetof(IncomingRecord, r0)));
440 store32(r1, Address(sp, offsetof(IncomingRecord, r1)));
441 store32(r2, Address(sp, offsetof(IncomingRecord, r2)));
442 // The following uses RegisterID::S0. So, they must come after we preserve S0 above.
443 move(TrustedImmPtr(reinterpret_cast<void*>(function)), r0);
444 move(TrustedImmPtr(arg), r1);
445 move(TrustedImmPtr(reinterpret_cast<void*>(Probe::executeProbe)), r2);
446 move(TrustedImmPtr(reinterpret_cast<void*>(ctiMasmProbeTrampoline)), ip);
449 #endif // ENABLE(MASM_PROBE)
453 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)