2992c5f439591249b113a8cb6cb698e3edc26102
[WebKit-https.git] / Source / JavaScriptCore / assembler / MacroAssemblerARM.cpp
1 /*
2  * Copyright (C) 2013-2017 Apple Inc.
3  * Copyright (C) 2009 University of Szeged
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
14  *
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.
26  */
27
28 #include "config.h"
29
30 #if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
31 #include "MacroAssembler.h"
32
33 #include "ProbeContext.h"
34 #include <wtf/InlineASM.h>
35
36 #if OS(LINUX)
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <elf.h>
42 #include <asm/hwcap.h>
43 #endif
44
45 namespace JSC {
46
47 static bool isVFPPresent()
48 {
49 #if OS(LINUX)
50     int fd = open("/proc/self/auxv", O_RDONLY);
51     if (fd != -1) {
52         Elf32_auxv_t aux;
53         while (read(fd, &aux, sizeof(Elf32_auxv_t))) {
54             if (aux.a_type == AT_HWCAP) {
55                 close(fd);
56                 return aux.a_un.a_val & HWCAP_VFP;
57             }
58         }
59         close(fd);
60     }
61 #endif // OS(LINUX)
62
63 #if (COMPILER(GCC_OR_CLANG) && defined(__VFP_FP__))
64     return true;
65 #else
66     return false;
67 #endif
68 }
69
70 const bool MacroAssemblerARM::s_isVFPPresent = isVFPPresent();
71
72 #if CPU(ARMV5_OR_LOWER)
73 /* On ARMv5 and below, natural alignment is required. */
74 void MacroAssemblerARM::load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
75 {
76     ARMWord op2;
77
78     ASSERT(address.scale >= 0 && address.scale <= 3);
79     op2 = m_assembler.lsl(address.index, static_cast<int>(address.scale));
80
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));
89     } else {
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);
95     }
96     m_assembler.orr(dest, dest, m_assembler.lsl(ARMRegisters::S0, 16));
97 }
98 #endif // CPU(ARMV5_OR_LOWER)
99
100 #if ENABLE(MASM_PROBE)
101
102 extern "C" void ctiMasmProbeTrampoline();
103
104 using namespace ARMRegisters;
105
106 #if COMPILER(GCC_OR_CLANG)
107
108 // The following are offsets for Probe::State fields accessed
109 // by the ctiMasmProbeTrampoline stub.
110
111 #define PTR_SIZE 4
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)
116
117 #define PROBE_FIRST_GPREG_OFFSET (4 * PTR_SIZE)
118
119 #define GPREG_SIZE 4
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))
136
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))
139
140 #define PROBE_FIRST_FPREG_OFFSET (PROBE_FIRST_GPREG_OFFSET + (18 * GPREG_SIZE))
141
142 #define FPREG_SIZE 8
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))
159
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))
177
178 #define PROBE_SIZE (PROBE_FIRST_FPREG_OFFSET + (32 * FPREG_SIZE))
179 #else
180 #define PROBE_SIZE (PROBE_FIRST_FPREG_OFFSET + (16 * FPREG_SIZE))
181 #endif // CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32)
182
183 #define OUT_SIZE GPREG_SIZE
184
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);
192
193 COMPILE_ASSERT(!(PROBE_CPU_R0_OFFSET & 0x3), ProbeState_cpu_r0_offset_should_be_4_byte_aligned);
194
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);
211
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);
214
215 COMPILE_ASSERT(!(PROBE_CPU_D0_OFFSET & 0x7), ProbeState_cpu_d0_offset_should_be_8_byte_aligned);
216
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);
233
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)
252
253 COMPILE_ASSERT(sizeof(Probe::State) == PROBE_SIZE, ProbeState_size_matches_ctiMasmProbeTrampoline);
254 #undef PROBE_OFFSETOF
255
256 struct IncomingRecord {
257     uintptr_t lr;
258     uintptr_t ip;
259     uintptr_t r6;
260     uintptr_t r0;
261     uintptr_t r1;
262     uintptr_t r2;
263 };
264
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)
272
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");
280
281 asm (
282     ".text" "\n"
283     ".globl " SYMBOL_STRING(ctiMasmProbeTrampoline) "\n"
284     HIDE_SYMBOL(ctiMasmProbeTrampoline) "\n"
285     INLINE_ARM_FUNCTION(ctiMasmProbeTrampoline) "\n"
286     SYMBOL_STRING(ctiMasmProbeTrampoline) ":" "\n"
287
288     // MacroAssemblerARMv7::probe() has already generated code to store some values.
289     // The top of stack now contains the IncomingRecord.
290     //
291     // Incoming register values:
292     //     r0: probe function
293     //     r1: probe arg
294     //     r2: Probe::executeProbe
295     //     r6: scratch
296     //     ip: scratch, was ctiMasmProbeTrampoline
297     //     lr: return address
298
299     "mov       ip, sp" "\n"
300     "mov       r6, sp" "\n"
301     "sub       r6, r6, #" STRINGIZE_VALUE_OF(PROBE_SIZE + OUT_SIZE) "\n"
302
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.
306
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"
310
311     "add       r0, ip, #" STRINGIZE_VALUE_OF(IN_SIZE) "\n"
312     "str       r0, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
313
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"
318     "mrs       lr, APSR" "\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"
322
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"
335
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"
340 #endif
341
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
344     "mov       r5, sp" "\n"
345
346     "mov       r0, sp" "\n" // the Probe::State* arg.
347     "blx       r2" "\n" // Call Probe::executeProbe.
348
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
351     // function.
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.
354     "cmp       r1, r2" "\n"
355     "bge     " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineProbeStateIsSafe) "\n"
356
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.
361
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"
366
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"
372     "cmp       r5, r7" "\n"
373     "blt     " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineCopyLoop) "\n"
374
375     "mov       r5, sp" "\n"
376
377     // Call initializeStackFunction if present.
378     LOCAL_LABEL_STRING(ctiMasmProbeTrampolineProbeStateIsSafe) ":" "\n"
379     "ldr       r2, [r5, #" STRINGIZE_VALUE_OF(PROBE_INIT_STACK_FUNCTION_OFFSET) "]" "\n"
380     "cmp       r2, #0" "\n"
381     "beq     " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineRestoreRegisters) "\n"
382
383     "mov       r0, r5" "\n" // Set the Probe::State* arg.
384     "blx       r2" "\n" // Call the initializeStackFunction (loaded into r2 above).
385
386     LOCAL_LABEL_STRING(ctiMasmProbeTrampolineRestoreRegisters) ":" "\n"
387
388     "mov       sp, r5" "\n" // Ensure that sp points to the Probe::State*.
389
390     // To enable probes to modify register state, we copy all registers
391     // out of the Probe::State before returning.
392
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"
397 #else
398     "add       ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_D15_OFFSET + FPREG_SIZE) "\n"
399     "vldmdb.64 ip!, { d0-d15 }" "\n"
400 #endif
401
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"
406
407     // There are 5 more registers left to restore: ip, sp, lr, pc, and apsr.
408
409     // Set up the restore area for sp and pc.
410     "ldr       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
411
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"
415     "str       ip, [lr]" "\n"
416     // Point sp to the restore area.
417     "str       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
418
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"
422     "msr       APSR, ip" "\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"
425
426     // Restore the sp and pc.
427     "ldr       sp, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
428     "pop       { pc }" "\n"
429 );
430 #endif // COMPILER(GCC_OR_CLANG)
431
432 void MacroAssembler::probe(Probe::Function function, void* arg)
433 {
434     sub32(TrustedImm32(sizeof(IncomingRecord)), sp);
435
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);
447     m_assembler.blx(ip);
448 }
449 #endif // ENABLE(MASM_PROBE)
450
451 } // namespace JSC
452
453 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)