7c682a28573801ee9c9b084222e8974f4e1bbd8b
[WebKit-https.git] / Source / JavaScriptCore / assembler / MacroAssemblerARMv7.cpp
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_OR_CLANG)
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 COMPILE_ASSERT(PROBE_OFFSETOF(probeFunction) == PROBE_PROBE_FUNCTION_OFFSET, ProbeState_probeFunction_offset_matches_ctiMasmProbeTrampoline);
125 COMPILE_ASSERT(PROBE_OFFSETOF(arg) == PROBE_ARG_OFFSET, ProbeState_arg_offset_matches_ctiMasmProbeTrampoline);
126 COMPILE_ASSERT(PROBE_OFFSETOF(initializeStackFunction) == PROBE_INIT_STACK_FUNCTION_OFFSET, ProbeState_initializeStackFunction_offset_matches_ctiMasmProbeTrampoline);
127 COMPILE_ASSERT(PROBE_OFFSETOF(initializeStackArg) == PROBE_INIT_STACK_ARG_OFFSET, ProbeState_initializeStackArg_offset_matches_ctiMasmProbeTrampoline);
128
129 COMPILE_ASSERT(!(PROBE_CPU_R0_OFFSET & 0x3), ProbeState_cpu_r0_offset_should_be_4_byte_aligned);
130
131 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r0]) == PROBE_CPU_R0_OFFSET, ProbeState_cpu_r0_offset_matches_ctiMasmProbeTrampoline);
132 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r1]) == PROBE_CPU_R1_OFFSET, ProbeState_cpu_r1_offset_matches_ctiMasmProbeTrampoline);
133 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r2]) == PROBE_CPU_R2_OFFSET, ProbeState_cpu_r2_offset_matches_ctiMasmProbeTrampoline);
134 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r3]) == PROBE_CPU_R3_OFFSET, ProbeState_cpu_r3_offset_matches_ctiMasmProbeTrampoline);
135 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r4]) == PROBE_CPU_R4_OFFSET, ProbeState_cpu_r4_offset_matches_ctiMasmProbeTrampoline);
136 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r5]) == PROBE_CPU_R5_OFFSET, ProbeState_cpu_r5_offset_matches_ctiMasmProbeTrampoline);
137 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r6]) == PROBE_CPU_R6_OFFSET, ProbeState_cpu_r6_offset_matches_ctiMasmProbeTrampoline);
138 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r7]) == PROBE_CPU_R7_OFFSET, ProbeState_cpu_r7_offset_matches_ctiMasmProbeTrampoline);
139 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r8]) == PROBE_CPU_R8_OFFSET, ProbeState_cpu_r8_offset_matches_ctiMasmProbeTrampoline);
140 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r9]) == PROBE_CPU_R9_OFFSET, ProbeState_cpu_r9_offset_matches_ctiMasmProbeTrampoline);
141 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r10]) == PROBE_CPU_R10_OFFSET, ProbeState_cpu_r10_offset_matches_ctiMasmProbeTrampoline);
142 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::r11]) == PROBE_CPU_R11_OFFSET, ProbeState_cpu_r11_offset_matches_ctiMasmProbeTrampoline);
143 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::ip]) == PROBE_CPU_IP_OFFSET, ProbeState_cpu_ip_offset_matches_ctiMasmProbeTrampoline);
144 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::sp]) == PROBE_CPU_SP_OFFSET, ProbeState_cpu_sp_offset_matches_ctiMasmProbeTrampoline);
145 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::lr]) == PROBE_CPU_LR_OFFSET, ProbeState_cpu_lr_offset_matches_ctiMasmProbeTrampoline);
146 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.gprs[ARMRegisters::pc]) == PROBE_CPU_PC_OFFSET, ProbeState_cpu_pc_offset_matches_ctiMasmProbeTrampoline);
147
148 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.sprs[ARMRegisters::apsr]) == PROBE_CPU_APSR_OFFSET, ProbeState_cpu_apsr_offset_matches_ctiMasmProbeTrampoline);
149 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.sprs[ARMRegisters::fpscr]) == PROBE_CPU_FPSCR_OFFSET, ProbeState_cpu_fpscr_offset_matches_ctiMasmProbeTrampoline);
150
151 COMPILE_ASSERT(!(PROBE_CPU_D0_OFFSET & 0x7), ProbeState_cpu_d0_offset_should_be_8_byte_aligned);
152
153 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d0]) == PROBE_CPU_D0_OFFSET, ProbeState_cpu_d0_offset_matches_ctiMasmProbeTrampoline);
154 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d1]) == PROBE_CPU_D1_OFFSET, ProbeState_cpu_d1_offset_matches_ctiMasmProbeTrampoline);
155 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d2]) == PROBE_CPU_D2_OFFSET, ProbeState_cpu_d2_offset_matches_ctiMasmProbeTrampoline);
156 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d3]) == PROBE_CPU_D3_OFFSET, ProbeState_cpu_d3_offset_matches_ctiMasmProbeTrampoline);
157 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d4]) == PROBE_CPU_D4_OFFSET, ProbeState_cpu_d4_offset_matches_ctiMasmProbeTrampoline);
158 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d5]) == PROBE_CPU_D5_OFFSET, ProbeState_cpu_d5_offset_matches_ctiMasmProbeTrampoline);
159 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d6]) == PROBE_CPU_D6_OFFSET, ProbeState_cpu_d6_offset_matches_ctiMasmProbeTrampoline);
160 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d7]) == PROBE_CPU_D7_OFFSET, ProbeState_cpu_d7_offset_matches_ctiMasmProbeTrampoline);
161 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d8]) == PROBE_CPU_D8_OFFSET, ProbeState_cpu_d8_offset_matches_ctiMasmProbeTrampoline);
162 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d9]) == PROBE_CPU_D9_OFFSET, ProbeState_cpu_d9_offset_matches_ctiMasmProbeTrampoline);
163 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d10]) == PROBE_CPU_D10_OFFSET, ProbeState_cpu_d10_offset_matches_ctiMasmProbeTrampoline);
164 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d11]) == PROBE_CPU_D11_OFFSET, ProbeState_cpu_d11_offset_matches_ctiMasmProbeTrampoline);
165 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d12]) == PROBE_CPU_D12_OFFSET, ProbeState_cpu_d12_offset_matches_ctiMasmProbeTrampoline);
166 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d13]) == PROBE_CPU_D13_OFFSET, ProbeState_cpu_d13_offset_matches_ctiMasmProbeTrampoline);
167 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d14]) == PROBE_CPU_D14_OFFSET, ProbeState_cpu_d14_offset_matches_ctiMasmProbeTrampoline);
168 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d15]) == PROBE_CPU_D15_OFFSET, ProbeState_cpu_d15_offset_matches_ctiMasmProbeTrampoline);
169
170 #if CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32)
171 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d16]) == PROBE_CPU_D16_OFFSET, ProbeState_cpu_d16_offset_matches_ctiMasmProbeTrampoline);
172 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d17]) == PROBE_CPU_D17_OFFSET, ProbeState_cpu_d17_offset_matches_ctiMasmProbeTrampoline);
173 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d18]) == PROBE_CPU_D18_OFFSET, ProbeState_cpu_d18_offset_matches_ctiMasmProbeTrampoline);
174 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d19]) == PROBE_CPU_D19_OFFSET, ProbeState_cpu_d19_offset_matches_ctiMasmProbeTrampoline);
175 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d20]) == PROBE_CPU_D20_OFFSET, ProbeState_cpu_d20_offset_matches_ctiMasmProbeTrampoline);
176 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d21]) == PROBE_CPU_D21_OFFSET, ProbeState_cpu_d21_offset_matches_ctiMasmProbeTrampoline);
177 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d22]) == PROBE_CPU_D22_OFFSET, ProbeState_cpu_d22_offset_matches_ctiMasmProbeTrampoline);
178 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d23]) == PROBE_CPU_D23_OFFSET, ProbeState_cpu_d23_offset_matches_ctiMasmProbeTrampoline);
179 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d24]) == PROBE_CPU_D24_OFFSET, ProbeState_cpu_d24_offset_matches_ctiMasmProbeTrampoline);
180 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d25]) == PROBE_CPU_D25_OFFSET, ProbeState_cpu_d25_offset_matches_ctiMasmProbeTrampoline);
181 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d26]) == PROBE_CPU_D26_OFFSET, ProbeState_cpu_d26_offset_matches_ctiMasmProbeTrampoline);
182 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d27]) == PROBE_CPU_D27_OFFSET, ProbeState_cpu_d27_offset_matches_ctiMasmProbeTrampoline);
183 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d28]) == PROBE_CPU_D28_OFFSET, ProbeState_cpu_d28_offset_matches_ctiMasmProbeTrampoline);
184 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d29]) == PROBE_CPU_D29_OFFSET, ProbeState_cpu_d29_offset_matches_ctiMasmProbeTrampoline);
185 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d30]) == PROBE_CPU_D30_OFFSET, ProbeState_cpu_d30_offset_matches_ctiMasmProbeTrampoline);
186 COMPILE_ASSERT(PROBE_OFFSETOF(cpu.fprs[ARMRegisters::d31]) == PROBE_CPU_D31_OFFSET, ProbeState_cpu_d31_offset_matches_ctiMasmProbeTrampoline);
187 #endif // CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32)
188
189 COMPILE_ASSERT(sizeof(Probe::State) == PROBE_SIZE, ProbeState_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     "it        ge" "\n"
293     "bge     " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineProbeStateIsSafe) "\n"
294
295     // Allocate a safe place on the stack below the result stack pointer to stash the Probe::State.
296     "sub       r1, r1, #" STRINGIZE_VALUE_OF(PROBE_SIZE + OUT_SIZE) "\n"
297     "bic       r1, r1, #0xf" "\n" // The ARM EABI specifies that the stack needs to be 16 byte aligned.
298     "mov       sp, r1" "\n" // Set the new sp to protect that memory from interrupts before we copy the Probe::State.
299
300     // Copy the Probe::State to the safe place.
301     // Note: we have to copy from low address to higher address because we're moving the
302     // Probe::State to a lower address.
303     "add       r7, r5, #" STRINGIZE_VALUE_OF(PROBE_SIZE) "\n"
304
305     LOCAL_LABEL_STRING(ctiMasmProbeTrampolineCopyLoop) ":" "\n"
306     "ldr       r3, [r5], #4" "\n"
307     "ldr       r4, [r5], #4" "\n"
308     "str       r3, [r1], #4" "\n"
309     "str       r4, [r1], #4" "\n"
310     "cmp       r5, r7" "\n"
311     "it        lt" "\n"
312     "blt     " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineCopyLoop) "\n"
313
314     "mov       r5, sp" "\n"
315
316     // Call initializeStackFunction if present.
317     LOCAL_LABEL_STRING(ctiMasmProbeTrampolineProbeStateIsSafe) ":" "\n"
318     "ldr       r2, [r5, #" STRINGIZE_VALUE_OF(PROBE_INIT_STACK_FUNCTION_OFFSET) "]" "\n"
319     "cbz       r2, " LOCAL_LABEL_STRING(ctiMasmProbeTrampolineRestoreRegisters) "\n"
320
321     "mov       r0, r5" "\n" // Set the Probe::State* arg.
322     "blx       r2" "\n" // Call the initializeStackFunction (loaded into r2 above).
323
324     LOCAL_LABEL_STRING(ctiMasmProbeTrampolineRestoreRegisters) ":" "\n"
325
326     "mov       sp, r5" "\n" // Ensure that sp points to the Probe::State*.
327
328     // To enable probes to modify register state, we copy all registers
329     // out of the Probe::State before returning.
330
331 #if CPU(ARM_NEON) || CPU(ARM_VFP_V3_D32)
332     "add       ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_D31_OFFSET + FPREG_SIZE) "\n"
333     "vldmdb.64 ip!, { d16-d31 }" "\n"
334     "vldmdb.64 ip!, { d0-d15 }" "\n"
335 #else
336     "add       ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_D15_OFFSET + FPREG_SIZE) "\n"
337     "vldmdb.64 ip!, { d0-d15 }" "\n"
338 #endif
339
340     "add       ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_R11_OFFSET + GPREG_SIZE) "\n"
341     "ldmdb     ip, { r0-r11 }" "\n"
342     "ldr       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_FPSCR_OFFSET) "]" "\n"
343     "vmsr      FPSCR, ip" "\n"
344
345     // There are 5 more registers left to restore: ip, sp, lr, pc, and apsr.
346
347     // Set up the restore area for sp and pc.
348     "ldr       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
349
350     // Push the pc on to the restore area.
351     "ldr       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_PC_OFFSET) "]" "\n"
352     "sub       lr, lr, #" STRINGIZE_VALUE_OF(OUT_SIZE) "\n"
353     "str       ip, [lr]" "\n"
354     // Point sp to the restore area.
355     "str       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
356
357     // All done with math i.e. won't trash the status register (apsr) and don't need
358     // scratch registers (lr and ip) anymore. Restore apsr, lr, and ip.
359     "ldr       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_APSR_OFFSET) "]" "\n"
360     "msr       APSR, ip" "\n"
361     "ldr       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_LR_OFFSET) "]" "\n"
362     "ldr       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_IP_OFFSET) "]" "\n"
363
364     // Restore the sp and pc.
365     "ldr       sp, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
366     "pop       { pc }" "\n"
367 );
368 #endif // COMPILER(GCC_OR_CLANG)
369
370 void MacroAssembler::probe(Probe::Function function, void* arg)
371 {
372     sub32(TrustedImm32(sizeof(IncomingRecord)), sp);
373
374     store32(lr, Address(sp, offsetof(IncomingRecord, lr)));
375     store32(ip, Address(sp, offsetof(IncomingRecord, ip)));
376     m_assembler.mrs(ip, apsr);
377     store32(ip, Address(sp, offsetof(IncomingRecord, apsr)));
378     store32(r0, Address(sp, offsetof(IncomingRecord, r0)));
379     store32(r1, Address(sp, offsetof(IncomingRecord, r1)));
380     store32(r2, Address(sp, offsetof(IncomingRecord, r2)));
381
382     // The following may emit a T1 mov instruction, which is effectively a movs.
383     // This means we must first preserve the apsr flags above first.
384     move(TrustedImmPtr(reinterpret_cast<void*>(function)), r0);
385     move(TrustedImmPtr(arg), r1);
386     move(TrustedImmPtr(reinterpret_cast<void*>(Probe::executeProbe)), r2);
387     move(TrustedImmPtr(reinterpret_cast<void*>(ctiMasmProbeTrampoline)), ip);
388     m_assembler.blx(ip);
389 }
390 #endif // ENABLE(MASM_PROBE)
391
392 } // namespace JSC
393
394 #endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)