blob: 2201b558497d9951f3c750acf647263d0c7bb003 [file] [log] [blame]
Stuart Monteithb95a5342014-03-12 13:32:32 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "asm_support_arm64.S"
18
19#include "arch/quick_alloc_entrypoints.S"
20
21
22 /*
23 * Macro that sets up the callee save frame to conform with
24 * Runtime::CreateCalleeSaveMethod(kSaveAll)
25 */
26.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
27 adrp x9, :got:_ZN3art7Runtime9instance_E
28 ldr x9, [x9, #:got_lo12:_ZN3art7Runtime9instance_E]
29
30 // Our registers aren't intermixed - just spill in order.
31 ldr x9,[x9] // x9 = & (art::Runtime * art::Runtime.instance_) .
32
33 // x9 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs] .
Hiroshi Yamauchiab088112014-07-14 13:00:14 -070034 THIS_LOAD_REQUIRES_READ_BARRIER
Stuart Monteithb95a5342014-03-12 13:32:32 +000035 ldr x9, [x9, RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET ]
36
37 sub sp, sp, #368
38 .cfi_adjust_cfa_offset 368
39
Andreas Gampe5c1e4352014-04-21 19:28:24 -070040 // Ugly compile-time check, but we only have the preprocessor.
41#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 368)
42#error "SAVE_ALL_CALLEE_SAVE_FRAME(ARM64) size not as expected."
43#endif
44
Stuart Monteithb95a5342014-03-12 13:32:32 +000045 // FP args
Andreas Gampe6cf80102014-05-19 11:32:41 -070046 stp d0, d1, [sp, #8]
Stuart Monteithb95a5342014-03-12 13:32:32 +000047 stp d2, d3, [sp, #24]
48 stp d4, d5, [sp, #40]
49 stp d6, d7, [sp, #56]
50
51 // FP callee-saves
52 stp d8, d9, [sp, #72]
53 stp d10, d11, [sp, #88]
54 stp d12, d13, [sp, #104]
55 stp d14, d15, [sp, #120]
56
57 stp d16, d17, [sp, #136]
58 stp d18, d19, [sp, #152]
59 stp d20, d21, [sp, #168]
60 stp d22, d23, [sp, #184]
61 stp d24, d25, [sp, #200]
62 stp d26, d27, [sp, #216]
63 stp d28, d29, [sp, #232]
64 stp d30, d31, [sp, #248]
65
66
67 // Callee saved.
68 stp xSELF, x19, [sp, #264]
Andreas Gampe03906cf2014-04-07 12:08:28 -070069 .cfi_rel_offset x18, 264
70 .cfi_rel_offset x19, 272
Stuart Monteithb95a5342014-03-12 13:32:32 +000071
Andreas Gampe03906cf2014-04-07 12:08:28 -070072 stp x20, x21, [sp, #280]
73 .cfi_rel_offset x20, 280
74 .cfi_rel_offset x21, 288
75
76 stp x22, x23, [sp, #296]
77 .cfi_rel_offset x22, 296
78 .cfi_rel_offset x23, 304
79
80 stp x24, x25, [sp, #312]
81 .cfi_rel_offset x24, 312
82 .cfi_rel_offset x25, 320
83
84 stp x26, x27, [sp, #328]
85 .cfi_rel_offset x26, 328
86 .cfi_rel_offset x27, 336
87
88 stp x28, xFP, [sp, #344] // Save FP.
89 .cfi_rel_offset x28, 344
90 .cfi_rel_offset x29, 352
91
92 str xLR, [sp, #360]
93 .cfi_rel_offset x30, 360
Stuart Monteithb95a5342014-03-12 13:32:32 +000094
95 // Loads appropriate callee-save-method
96 str x9, [sp] // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs]
97
98.endm
99
100 /*
101 * Macro that sets up the callee save frame to conform with
102 * Runtime::CreateCalleeSaveMethod(kRefsOnly).
103 */
Andreas Gampe5c1e4352014-04-21 19:28:24 -0700104// WIP.
Stuart Monteithb95a5342014-03-12 13:32:32 +0000105.macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME
Andreas Gampe5c1e4352014-04-21 19:28:24 -0700106 adrp x9, :got:_ZN3art7Runtime9instance_E
107 ldr x9, [x9, #:got_lo12:_ZN3art7Runtime9instance_E]
108
109 // Our registers aren't intermixed - just spill in order.
110 ldr x9,[x9] // x9 = & (art::Runtime * art::Runtime.instance_) .
111
112 // x9 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs] .
Hiroshi Yamauchiab088112014-07-14 13:00:14 -0700113 THIS_LOAD_REQUIRES_READ_BARRIER
Andreas Gampe5c1e4352014-04-21 19:28:24 -0700114 ldr x9, [x9, RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET ]
115
116 sub sp, sp, #176
117 .cfi_adjust_cfa_offset 176
118
119 // Ugly compile-time check, but we only have the preprocessor.
120#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 176)
121#error "REFS_ONLY_CALLEE_SAVE_FRAME(ARM64) size not as expected."
122#endif
123
124 // FP callee-saves
125 stp d8, d9, [sp, #8]
126 stp d10, d11, [sp, #24]
127 stp d12, d13, [sp, #40]
128 stp d14, d15, [sp, #56]
129
130 // Callee saved.
131 stp xSELF, x19, [sp, #72]
132 .cfi_rel_offset x18, 72
133 .cfi_rel_offset x19, 80
134
135 stp x20, x21, [sp, #88]
136 .cfi_rel_offset x20, 88
137 .cfi_rel_offset x21, 96
138
139 stp x22, x23, [sp, #104]
140 .cfi_rel_offset x22, 104
141 .cfi_rel_offset x23, 112
142
143 stp x24, x25, [sp, #120]
144 .cfi_rel_offset x24, 120
145 .cfi_rel_offset x25, 128
146
147 stp x26, x27, [sp, #136]
148 .cfi_rel_offset x26, 136
149 .cfi_rel_offset x27, 144
150
151 stp x28, xFP, [sp, #152] // Save FP.
152 .cfi_rel_offset x28, 152
153 .cfi_rel_offset x29, 160
154
155 str xLR, [sp, #168]
156 .cfi_rel_offset x30, 168
157
158 // Loads appropriate callee-save-method
159 str x9, [sp] // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs]
Stuart Monteithb95a5342014-03-12 13:32:32 +0000160.endm
161
162.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
Andreas Gampe00c1e6d2014-04-25 15:47:13 -0700163 // FP callee saves
164 ldp d8, d9, [sp, #8]
165 ldp d10, d11, [sp, #24]
166 ldp d12, d13, [sp, #40]
167 ldp d14, d15, [sp, #56]
168
169 // Callee saved.
170 ldp xSELF, x19, [sp, #72]
171 .cfi_restore x18
172 .cfi_restore x19
173
174 ldp x20, x21, [sp, #88]
175 .cfi_restore x20
176 .cfi_restore x21
177
178 ldp x22, x23, [sp, #104]
179 .cfi_restore x22
180 .cfi_restore x23
181
182 ldp x24, x25, [sp, #120]
183 .cfi_restore x24
184 .cfi_restore x25
185
186 ldp x26, x27, [sp, #136]
187 .cfi_restore x26
188 .cfi_restore x27
189
190 ldp x28, xFP, [sp, #152] // Save FP.
191 .cfi_restore x28
192 .cfi_restore x29
193
194 ldr xLR, [sp, #168]
195 .cfi_restore x30
196
197 add sp, sp, #176
198 .cfi_adjust_cfa_offset -176
Stuart Monteithb95a5342014-03-12 13:32:32 +0000199.endm
200
Andreas Gamped58342c2014-06-05 14:18:08 -0700201.macro POP_REF_ONLY_CALLEE_SAVE_FRAME
202 add sp, sp, #176
203 .cfi_adjust_cfa_offset -176
204.endm
205
Stuart Monteithb95a5342014-03-12 13:32:32 +0000206.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
Zheng Xu48241e72014-05-23 11:52:42 +0800207 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
208 ret
Stuart Monteithb95a5342014-03-12 13:32:32 +0000209.endm
210
211
212.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
213 sub sp, sp, #304
214 .cfi_adjust_cfa_offset 304
215
Andreas Gampe5c1e4352014-04-21 19:28:24 -0700216 // Ugly compile-time check, but we only have the preprocessor.
217#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 304)
218#error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(ARM64) size not as expected."
219#endif
220
Stuart Monteithb95a5342014-03-12 13:32:32 +0000221 stp d0, d1, [sp, #16]
222 stp d2, d3, [sp, #32]
223 stp d4, d5, [sp, #48]
224 stp d6, d7, [sp, #64]
225 stp d8, d9, [sp, #80]
226 stp d10, d11, [sp, #96]
227 stp d12, d13, [sp, #112]
228 stp d14, d15, [sp, #128]
229
230 stp x1, x2, [sp, #144]
Andreas Gampe03906cf2014-04-07 12:08:28 -0700231 .cfi_rel_offset x1, 144
232 .cfi_rel_offset x2, 152
Stuart Monteithb95a5342014-03-12 13:32:32 +0000233
Andreas Gampe03906cf2014-04-07 12:08:28 -0700234 stp x3, x4, [sp, #160]
235 .cfi_rel_offset x3, 160
236 .cfi_rel_offset x4, 168
237
238 stp x5, x6, [sp, #176]
239 .cfi_rel_offset x5, 176
240 .cfi_rel_offset x6, 184
241
242 stp x7, xSELF, [sp, #192]
243 .cfi_rel_offset x7, 192
244 .cfi_rel_offset x18, 200
245
246 stp x19, x20, [sp, #208]
247 .cfi_rel_offset x19, 208
248 .cfi_rel_offset x20, 216
249
250 stp x21, x22, [sp, #224]
251 .cfi_rel_offset x21, 224
252 .cfi_rel_offset x22, 232
253
254 stp x23, x24, [sp, #240]
255 .cfi_rel_offset x23, 240
256 .cfi_rel_offset x24, 248
257
258 stp x25, x26, [sp, #256]
259 .cfi_rel_offset x25, 256
260 .cfi_rel_offset x26, 264
261
262 stp x27, x28, [sp, #272]
263 .cfi_rel_offset x27, 272
264 .cfi_rel_offset x28, 280
265
266 stp xFP, xLR, [sp, #288]
267 .cfi_rel_offset x29, 288
268 .cfi_rel_offset x30, 296
Stuart Monteithb95a5342014-03-12 13:32:32 +0000269.endm
270
271 /*
272 * Macro that sets up the callee save frame to conform with
273 * Runtime::CreateCalleeSaveMethod(kRefsAndArgs).
274 *
275 * TODO This is probably too conservative - saving FP & LR.
276 */
277.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
278 adrp x9, :got:_ZN3art7Runtime9instance_E
279 ldr x9, [x9, #:got_lo12:_ZN3art7Runtime9instance_E]
280
281 // Our registers aren't intermixed - just spill in order.
282 ldr x9,[x9] // x9 = & (art::Runtime * art::Runtime.instance_) .
283
284 // x9 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs] .
Hiroshi Yamauchiab088112014-07-14 13:00:14 -0700285 THIS_LOAD_REQUIRES_READ_BARRIER
Stuart Monteithb95a5342014-03-12 13:32:32 +0000286 ldr x9, [x9, RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET ]
287
288 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
289
290 str x9, [sp] // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs]
291.endm
292
293.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
294
295 ldp d0, d1, [sp, #16]
296 ldp d2, d3, [sp, #32]
297 ldp d4, d5, [sp, #48]
298 ldp d6, d7, [sp, #64]
299 ldp d8, d9, [sp, #80]
300 ldp d10, d11, [sp, #96]
301 ldp d12, d13, [sp, #112]
302 ldp d14, d15, [sp, #128]
303
304 // args.
305 ldp x1, x2, [sp, #144]
Andreas Gampe03906cf2014-04-07 12:08:28 -0700306 .cfi_restore x1
307 .cfi_restore x2
308
Stuart Monteithb95a5342014-03-12 13:32:32 +0000309 ldp x3, x4, [sp, #160]
Andreas Gampe03906cf2014-04-07 12:08:28 -0700310 .cfi_restore x3
311 .cfi_restore x4
312
Stuart Monteithb95a5342014-03-12 13:32:32 +0000313 ldp x5, x6, [sp, #176]
Andreas Gampe03906cf2014-04-07 12:08:28 -0700314 .cfi_restore x5
315 .cfi_restore x6
316
Stuart Monteithb95a5342014-03-12 13:32:32 +0000317 ldp x7, xSELF, [sp, #192]
Andreas Gampe03906cf2014-04-07 12:08:28 -0700318 .cfi_restore x7
319 .cfi_restore x18
320
Stuart Monteithb95a5342014-03-12 13:32:32 +0000321 ldp x19, x20, [sp, #208]
Andreas Gampe03906cf2014-04-07 12:08:28 -0700322 .cfi_restore x19
323 .cfi_restore x20
324
Stuart Monteithb95a5342014-03-12 13:32:32 +0000325 ldp x21, x22, [sp, #224]
Andreas Gampe03906cf2014-04-07 12:08:28 -0700326 .cfi_restore x21
327 .cfi_restore x22
328
Stuart Monteithb95a5342014-03-12 13:32:32 +0000329 ldp x23, x24, [sp, #240]
Andreas Gampe03906cf2014-04-07 12:08:28 -0700330 .cfi_restore x23
331 .cfi_restore x24
332
Stuart Monteithb95a5342014-03-12 13:32:32 +0000333 ldp x25, x26, [sp, #256]
Andreas Gampe03906cf2014-04-07 12:08:28 -0700334 .cfi_restore x25
335 .cfi_restore x26
336
Stuart Monteithb95a5342014-03-12 13:32:32 +0000337 ldp x27, x28, [sp, #272]
Andreas Gampe03906cf2014-04-07 12:08:28 -0700338 .cfi_restore x27
339 .cfi_restore x28
340
Stuart Monteithb95a5342014-03-12 13:32:32 +0000341 ldp xFP, xLR, [sp, #288]
Andreas Gampe03906cf2014-04-07 12:08:28 -0700342 .cfi_restore x29
343 .cfi_restore x30
Stuart Monteithb95a5342014-03-12 13:32:32 +0000344
345 add sp, sp, #304
346 .cfi_adjust_cfa_offset -304
347.endm
348
349.macro RETURN_IF_RESULT_IS_ZERO
Andreas Gampe00c1e6d2014-04-25 15:47:13 -0700350 cbnz x0, 1f // result non-zero branch over
351 ret // return
3521:
Stuart Monteithb95a5342014-03-12 13:32:32 +0000353.endm
354
355.macro RETURN_IF_RESULT_IS_NON_ZERO
Andreas Gampe00c1e6d2014-04-25 15:47:13 -0700356 cbz x0, 1f // result zero branch over
357 ret // return
3581:
Stuart Monteithb95a5342014-03-12 13:32:32 +0000359.endm
360
361 /*
362 * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending
363 * exception is Thread::Current()->exception_
364 */
365.macro DELIVER_PENDING_EXCEPTION
366 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
367 mov x0, xSELF
368 mov x1, sp
369
370 // Point of no return.
371 b artDeliverPendingExceptionFromCode // artDeliverPendingExceptionFromCode(Thread*, SP)
372 brk 0 // Unreached
373.endm
374
Andreas Gampe6e4e59c2014-05-05 20:11:02 -0700375.macro RETURN_OR_DELIVER_PENDING_EXCEPTION_REG reg
376 ldr \reg, [xSELF, # THREAD_EXCEPTION_OFFSET] // Get exception field.
377 cbnz \reg, 1f
Stuart Monteithb95a5342014-03-12 13:32:32 +0000378 ret
3791:
380 DELIVER_PENDING_EXCEPTION
381.endm
382
Andreas Gampe6e4e59c2014-05-05 20:11:02 -0700383.macro RETURN_OR_DELIVER_PENDING_EXCEPTION
384 RETURN_OR_DELIVER_PENDING_EXCEPTION_REG x9
385.endm
386
387// Same as above with x1. This is helpful in stubs that want to avoid clobbering another register.
388.macro RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
389 RETURN_OR_DELIVER_PENDING_EXCEPTION_REG x1
390.endm
391
392.macro RETURN_IF_W0_IS_ZERO_OR_DELIVER
393 cbnz w0, 1f // result non-zero branch over
394 ret // return
3951:
396 DELIVER_PENDING_EXCEPTION
397.endm
398
Stuart Monteithb95a5342014-03-12 13:32:32 +0000399.macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
400 .extern \cxx_name
401ENTRY \c_name
Andreas Gampe5c1e4352014-04-21 19:28:24 -0700402 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
Serban Constantinescu63206f32014-05-07 18:40:49 +0100403 mov x0, xSELF // pass Thread::Current
Andreas Gampe5c1e4352014-04-21 19:28:24 -0700404 mov x1, sp // pass SP
405 b \cxx_name // \cxx_name(Thread*, SP)
Stuart Monteithb95a5342014-03-12 13:32:32 +0000406END \c_name
407.endm
408
409.macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name
410 .extern \cxx_name
411ENTRY \c_name
Serban Constantinescu75b91132014-04-09 18:39:10 +0100412 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context.
Serban Constantinescu63206f32014-05-07 18:40:49 +0100413 mov x1, xSELF // pass Thread::Current.
Serban Constantinescu75b91132014-04-09 18:39:10 +0100414 mov x2, sp // pass SP.
Andreas Gampe5c1e4352014-04-21 19:28:24 -0700415 b \cxx_name // \cxx_name(arg, Thread*, SP).
Stuart Monteithb95a5342014-03-12 13:32:32 +0000416 brk 0
417END \c_name
418.endm
419
420.macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
421 .extern \cxx_name
422ENTRY \c_name
423 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
Serban Constantinescu63206f32014-05-07 18:40:49 +0100424 mov x2, xSELF // pass Thread::Current
Andreas Gampe5c1e4352014-04-21 19:28:24 -0700425 mov x3, sp // pass SP
426 b \cxx_name // \cxx_name(arg1, arg2, Thread*, SP)
Stuart Monteithb95a5342014-03-12 13:32:32 +0000427 brk 0
428END \c_name
429.endm
430
431 /*
432 * Called by managed code, saves callee saves and then calls artThrowException
433 * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception.
434 */
435ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode
436
437 /*
438 * Called by managed code to create and deliver a NullPointerException.
439 */
440NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
441
442 /*
443 * Called by managed code to create and deliver an ArithmeticException.
444 */
445NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode
446
447 /*
448 * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
449 * index, arg2 holds limit.
450 */
451TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
452
453 /*
454 * Called by managed code to create and deliver a StackOverflowError.
455 */
456NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode
457
458 /*
459 * Called by managed code to create and deliver a NoSuchMethodError.
460 */
461ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode
462
463 /*
Stuart Monteithb95a5342014-03-12 13:32:32 +0000464 * All generated callsites for interface invokes and invocation slow paths will load arguments
Andreas Gampe51f76352014-05-21 08:28:48 -0700465 * as usual - except instead of loading arg0/x0 with the target Method*, arg0/x0 will contain
466 * the method_idx. This wrapper will save arg1-arg3, load the caller's Method*, align the
Stuart Monteithb95a5342014-03-12 13:32:32 +0000467 * stack and call the appropriate C helper.
Andreas Gampe51f76352014-05-21 08:28:48 -0700468 * NOTE: "this" is first visible argument of the target, and so can be found in arg1/x1.
Stuart Monteithb95a5342014-03-12 13:32:32 +0000469 *
Andreas Gampe51f76352014-05-21 08:28:48 -0700470 * The helper will attempt to locate the target and return a 128-bit result in x0/x1 consisting
Stuart Monteithb95a5342014-03-12 13:32:32 +0000471 * of the target Method* in x0 and method->code_ in x1.
472 *
Andreas Gampe51f76352014-05-21 08:28:48 -0700473 * If unsuccessful, the helper will return NULL/????. There will be a pending exception in the
Stuart Monteithb95a5342014-03-12 13:32:32 +0000474 * thread and we branch to another stub to deliver it.
475 *
476 * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
477 * pointing back to the original caller.
Andreas Gampe51f76352014-05-21 08:28:48 -0700478 *
479 * Adapted from ARM32 code.
480 *
481 * Clobbers x12.
Stuart Monteithb95a5342014-03-12 13:32:32 +0000482 */
483.macro INVOKE_TRAMPOLINE c_name, cxx_name
484 .extern \cxx_name
485ENTRY \c_name
Andreas Gampe51f76352014-05-21 08:28:48 -0700486 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME // save callee saves in case allocation triggers GC
487 // Helper signature is always
488 // (method_idx, *this_object, *caller_method, *self, sp)
489
Alexei Zavjalov41c507a2014-05-15 16:02:46 +0700490 ldr w2, [sp, #FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE] // pass caller Method*
Andreas Gampe51f76352014-05-21 08:28:48 -0700491 mov x3, xSELF // pass Thread::Current
492 mov x4, sp
493 bl \cxx_name // (method_idx, this, caller, Thread*, SP)
494 mov x12, x1 // save Method*->code_
495 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
496 cbz x0, 1f // did we find the target? if not go to exception delivery
497 br x12 // tail call to target
4981:
499 DELIVER_PENDING_EXCEPTION
Stuart Monteithb95a5342014-03-12 13:32:32 +0000500END \c_name
501.endm
502
503INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
504INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
505
506INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
507INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
508INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
509INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
510
Andreas Gampe03906cf2014-04-07 12:08:28 -0700511
512.macro INVOKE_STUB_CREATE_FRAME
513
Andreas Gampecf4035a2014-05-28 22:43:01 -0700514SAVE_SIZE=6*8 // x4, x5, x19(wSUSPEND), SP, LR & FP saved.
515SAVE_SIZE_AND_METHOD=SAVE_SIZE+STACK_REFERENCE_SIZE
516
Andreas Gampe03906cf2014-04-07 12:08:28 -0700517
Zheng Xu48241e72014-05-23 11:52:42 +0800518 mov x9, sp // Save stack pointer.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700519 .cfi_register sp,x9
520
Zheng Xu48241e72014-05-23 11:52:42 +0800521 add x10, x2, # SAVE_SIZE_AND_METHOD // calculate size of frame.
522 sub x10, sp, x10 // Calculate SP position - saves + ArtMethod* + args
523 and x10, x10, # ~0xf // Enforce 16 byte stack alignment.
524 mov sp, x10 // Set new SP.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700525
Zheng Xu48241e72014-05-23 11:52:42 +0800526 sub x10, x9, #SAVE_SIZE // Calculate new FP (later). Done here as we must move SP
527 .cfi_def_cfa_register x10 // before this.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700528 .cfi_adjust_cfa_offset SAVE_SIZE
529
Andreas Gampecf4035a2014-05-28 22:43:01 -0700530 stp x9, x19, [x10, #32] // Save old stack pointer and x19(wSUSPEND)
Andreas Gampe03906cf2014-04-07 12:08:28 -0700531 .cfi_rel_offset sp, 32
Andreas Gampecf4035a2014-05-28 22:43:01 -0700532 .cfi_rel_offset x19, 40
Andreas Gampe03906cf2014-04-07 12:08:28 -0700533
Zheng Xu48241e72014-05-23 11:52:42 +0800534 stp x4, x5, [x10, #16] // Save result and shorty addresses.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700535 .cfi_rel_offset x4, 16
536 .cfi_rel_offset x5, 24
537
Zheng Xu48241e72014-05-23 11:52:42 +0800538 stp xFP, xLR, [x10] // Store LR & FP.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700539 .cfi_rel_offset x29, 0
540 .cfi_rel_offset x30, 8
541
Zheng Xu48241e72014-05-23 11:52:42 +0800542 mov xFP, x10 // Use xFP now, as it's callee-saved.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700543 .cfi_def_cfa_register x29
Zheng Xu48241e72014-05-23 11:52:42 +0800544 mov xSELF, x3 // Move thread pointer into SELF register.
545 mov wSUSPEND, #SUSPEND_CHECK_INTERVAL // reset wSUSPEND to suspend check interval
Andreas Gampe03906cf2014-04-07 12:08:28 -0700546
547 // Copy arguments into stack frame.
548 // Use simple copy routine for now.
549 // 4 bytes per slot.
550 // X1 - source address
551 // W2 - args length
552 // X9 - destination address.
553 // W10 - temporary
Andreas Gampecf4035a2014-05-28 22:43:01 -0700554 add x9, sp, #4 // Destination address is bottom of stack + NULL.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700555
556 // Use \@ to differentiate between macro invocations.
557.LcopyParams\@:
558 cmp w2, #0
559 beq .LendCopyParams\@
560 sub w2, w2, #4 // Need 65536 bytes of range.
561 ldr w10, [x1, x2]
562 str w10, [x9, x2]
563
564 b .LcopyParams\@
565
566.LendCopyParams\@:
567
Andreas Gampecf4035a2014-05-28 22:43:01 -0700568 // Store NULL into StackReference<Method>* at bottom of frame.
569 str wzr, [sp]
Andreas Gampe03906cf2014-04-07 12:08:28 -0700570
Andreas Gampecf4035a2014-05-28 22:43:01 -0700571#if (STACK_REFERENCE_SIZE != 4)
572#error "STACK_REFERENCE_SIZE(ARM64) size not as expected."
573#endif
Andreas Gampe03906cf2014-04-07 12:08:28 -0700574.endm
575
576.macro INVOKE_STUB_CALL_AND_RETURN
577
578 // load method-> METHOD_QUICK_CODE_OFFSET
579 ldr x9, [x0 , #METHOD_QUICK_CODE_OFFSET]
580 // Branch to method.
581 blr x9
582
583 // Restore return value address and shorty address.
584 ldp x4,x5, [xFP, #16]
585 .cfi_restore x4
586 .cfi_restore x5
587
588 // Store result (w0/x0/s0/d0) appropriately, depending on resultType.
589 ldrb w10, [x5]
590
591 // Don't set anything for a void type.
592 cmp w10, #'V'
593 beq .Lexit_art_quick_invoke_stub\@
594
595 cmp w10, #'D'
596 bne .Lreturn_is_float\@
597 str d0, [x4]
598 b .Lexit_art_quick_invoke_stub\@
599
600.Lreturn_is_float\@:
601 cmp w10, #'F'
602 bne .Lreturn_is_int\@
603 str s0, [x4]
604 b .Lexit_art_quick_invoke_stub\@
605
606 // Just store x0. Doesn't matter if it is 64 or 32 bits.
607.Lreturn_is_int\@:
608 str x0, [x4]
609
610.Lexit_art_quick_invoke_stub\@:
Andreas Gamped58342c2014-06-05 14:18:08 -0700611 ldp x2, x19, [xFP, #32] // Restore stack pointer and x19.
Andreas Gampecf4035a2014-05-28 22:43:01 -0700612 .cfi_restore x19
Andreas Gampe03906cf2014-04-07 12:08:28 -0700613 mov sp, x2
614 .cfi_restore sp
615
Andreas Gamped58342c2014-06-05 14:18:08 -0700616 ldp xFP, xLR, [xFP] // Restore old frame pointer and link register.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700617 .cfi_restore x29
618 .cfi_restore x30
619
620 ret
621
622.endm
623
624
Stuart Monteithb95a5342014-03-12 13:32:32 +0000625/*
626 * extern"C" void art_quick_invoke_stub(ArtMethod *method, x0
627 * uint32_t *args, x1
628 * uint32_t argsize, w2
629 * Thread *self, x3
630 * JValue *result, x4
631 * char *shorty); x5
632 * +----------------------+
633 * | |
634 * | C/C++ frame |
635 * | LR'' |
636 * | FP'' | <- SP'
637 * +----------------------+
638 * +----------------------+
639 * | SP' |
640 * | X5 |
641 * | X4 | Saved registers
642 * | LR' |
643 * | FP' | <- FP
644 * +----------------------+
645 * | uint32_t out[n-1] |
646 * | : : | Outs
647 * | uint32_t out[0] |
Andreas Gampecf4035a2014-05-28 22:43:01 -0700648 * | StackRef<ArtMethod> | <- SP value=null
Stuart Monteithb95a5342014-03-12 13:32:32 +0000649 * +----------------------+
650 *
651 * Outgoing registers:
652 * x0 - Method*
653 * x1-x7 - integer parameters.
654 * d0-d7 - Floating point parameters.
655 * xSELF = self
Zheng Xu48241e72014-05-23 11:52:42 +0800656 * wSUSPEND = suspend count
Stuart Monteithb95a5342014-03-12 13:32:32 +0000657 * SP = & of ArtMethod*
658 * x1 = "this" pointer.
659 *
660 */
661ENTRY art_quick_invoke_stub
662 // Spill registers as per AACPS64 calling convention.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700663 INVOKE_STUB_CREATE_FRAME
Stuart Monteithb95a5342014-03-12 13:32:32 +0000664
665 // Fill registers x/w1 to x/w7 and s/d0 to s/d7 with parameters.
666 // Parse the passed shorty to determine which register to load.
667 // Load addresses for routines that load WXSD registers.
668 adr x11, .LstoreW2
669 adr x12, .LstoreX2
670 adr x13, .LstoreS0
671 adr x14, .LstoreD0
672
673 // Initialize routine offsets to 0 for integers and floats.
674 // x8 for integers, x15 for floating point.
675 mov x8, #0
676 mov x15, #0
677
678 add x10, x5, #1 // Load shorty address, plus one to skip return value.
679 ldr w1, [x9],#4 // Load "this" parameter, and increment arg pointer.
680
681 // Loop to fill registers.
682.LfillRegisters:
683 ldrb w17, [x10], #1 // Load next character in signature, and increment.
684 cbz w17, .LcallFunction // Exit at end of signature. Shorty 0 terminated.
685
686 cmp w17, #'F' // is this a float?
687 bne .LisDouble
688
689 cmp x15, # 8*12 // Skip this load if all registers full.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700690 beq .Ladvance4
Stuart Monteithb95a5342014-03-12 13:32:32 +0000691
692 add x17, x13, x15 // Calculate subroutine to jump to.
693 br x17
694
695.LisDouble:
696 cmp w17, #'D' // is this a double?
697 bne .LisLong
698
699 cmp x15, # 8*12 // Skip this load if all registers full.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700700 beq .Ladvance8
Stuart Monteithb95a5342014-03-12 13:32:32 +0000701
702 add x17, x14, x15 // Calculate subroutine to jump to.
703 br x17
704
705.LisLong:
706 cmp w17, #'J' // is this a long?
707 bne .LisOther
708
Andreas Gampe9de65ff2014-03-21 17:25:57 -0700709 cmp x8, # 6*12 // Skip this load if all registers full.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700710 beq .Ladvance8
Stuart Monteithb95a5342014-03-12 13:32:32 +0000711
712 add x17, x12, x8 // Calculate subroutine to jump to.
713 br x17
714
Stuart Monteithb95a5342014-03-12 13:32:32 +0000715.LisOther: // Everything else takes one vReg.
Andreas Gampe9de65ff2014-03-21 17:25:57 -0700716 cmp x8, # 6*12 // Skip this load if all registers full.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700717 beq .Ladvance4
718
Stuart Monteithb95a5342014-03-12 13:32:32 +0000719 add x17, x11, x8 // Calculate subroutine to jump to.
720 br x17
721
Andreas Gampe03906cf2014-04-07 12:08:28 -0700722.Ladvance4:
723 add x9, x9, #4
724 b .LfillRegisters
725
726.Ladvance8:
727 add x9, x9, #8
728 b .LfillRegisters
729
Stuart Monteithb95a5342014-03-12 13:32:32 +0000730// Macro for loading a parameter into a register.
731// counter - the register with offset into these tables
732// size - the size of the register - 4 or 8 bytes.
733// register - the name of the register to be loaded.
734.macro LOADREG counter size register return
735 ldr \register , [x9], #\size
736 add \counter, \counter, 12
737 b \return
738.endm
739
740// Store ints.
741.LstoreW2:
742 LOADREG x8 4 w2 .LfillRegisters
743 LOADREG x8 4 w3 .LfillRegisters
744 LOADREG x8 4 w4 .LfillRegisters
745 LOADREG x8 4 w5 .LfillRegisters
746 LOADREG x8 4 w6 .LfillRegisters
747 LOADREG x8 4 w7 .LfillRegisters
748
749// Store longs.
750.LstoreX2:
751 LOADREG x8 8 x2 .LfillRegisters
752 LOADREG x8 8 x3 .LfillRegisters
753 LOADREG x8 8 x4 .LfillRegisters
754 LOADREG x8 8 x5 .LfillRegisters
755 LOADREG x8 8 x6 .LfillRegisters
756 LOADREG x8 8 x7 .LfillRegisters
757
758// Store singles.
759.LstoreS0:
760 LOADREG x15 4 s0 .LfillRegisters
761 LOADREG x15 4 s1 .LfillRegisters
762 LOADREG x15 4 s2 .LfillRegisters
763 LOADREG x15 4 s3 .LfillRegisters
764 LOADREG x15 4 s4 .LfillRegisters
765 LOADREG x15 4 s5 .LfillRegisters
766 LOADREG x15 4 s6 .LfillRegisters
767 LOADREG x15 4 s7 .LfillRegisters
768
769// Store doubles.
770.LstoreD0:
771 LOADREG x15 8 d0 .LfillRegisters
772 LOADREG x15 8 d1 .LfillRegisters
773 LOADREG x15 8 d2 .LfillRegisters
774 LOADREG x15 8 d3 .LfillRegisters
775 LOADREG x15 8 d4 .LfillRegisters
776 LOADREG x15 8 d5 .LfillRegisters
777 LOADREG x15 8 d6 .LfillRegisters
778 LOADREG x15 8 d7 .LfillRegisters
779
780
781.LcallFunction:
782
Andreas Gampe03906cf2014-04-07 12:08:28 -0700783 INVOKE_STUB_CALL_AND_RETURN
Stuart Monteithb95a5342014-03-12 13:32:32 +0000784
Stuart Monteithb95a5342014-03-12 13:32:32 +0000785END art_quick_invoke_stub
786
787/* extern"C"
788 * void art_quick_invoke_static_stub(ArtMethod *method, x0
789 * uint32_t *args, x1
790 * uint32_t argsize, w2
791 * Thread *self, x3
792 * JValue *result, x4
793 * char *shorty); x5
794 */
795ENTRY art_quick_invoke_static_stub
796 // Spill registers as per AACPS64 calling convention.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700797 INVOKE_STUB_CREATE_FRAME
Stuart Monteithb95a5342014-03-12 13:32:32 +0000798
799 // Fill registers x/w1 to x/w7 and s/d0 to s/d7 with parameters.
800 // Parse the passed shorty to determine which register to load.
801 // Load addresses for routines that load WXSD registers.
802 adr x11, .LstoreW1_2
803 adr x12, .LstoreX1_2
804 adr x13, .LstoreS0_2
805 adr x14, .LstoreD0_2
806
807 // Initialize routine offsets to 0 for integers and floats.
808 // x8 for integers, x15 for floating point.
809 mov x8, #0
810 mov x15, #0
811
812 add x10, x5, #1 // Load shorty address, plus one to skip return value.
813
814 // Loop to fill registers.
815.LfillRegisters2:
816 ldrb w17, [x10], #1 // Load next character in signature, and increment.
817 cbz w17, .LcallFunction2 // Exit at end of signature. Shorty 0 terminated.
818
819 cmp w17, #'F' // is this a float?
820 bne .LisDouble2
821
822 cmp x15, # 8*12 // Skip this load if all registers full.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700823 beq .Ladvance4_2
Stuart Monteithb95a5342014-03-12 13:32:32 +0000824
825 add x17, x13, x15 // Calculate subroutine to jump to.
826 br x17
827
828.LisDouble2:
829 cmp w17, #'D' // is this a double?
830 bne .LisLong2
831
832 cmp x15, # 8*12 // Skip this load if all registers full.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700833 beq .Ladvance8_2
Stuart Monteithb95a5342014-03-12 13:32:32 +0000834
835 add x17, x14, x15 // Calculate subroutine to jump to.
836 br x17
837
838.LisLong2:
839 cmp w17, #'J' // is this a long?
840 bne .LisOther2
841
842 cmp x8, # 7*12 // Skip this load if all registers full.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700843 beq .Ladvance8_2
Stuart Monteithb95a5342014-03-12 13:32:32 +0000844
845 add x17, x12, x8 // Calculate subroutine to jump to.
846 br x17
847
Stuart Monteithb95a5342014-03-12 13:32:32 +0000848.LisOther2: // Everything else takes one vReg.
849 cmp x8, # 7*12 // Skip this load if all registers full.
Andreas Gampe03906cf2014-04-07 12:08:28 -0700850 beq .Ladvance4_2
851
Stuart Monteithb95a5342014-03-12 13:32:32 +0000852 add x17, x11, x8 // Calculate subroutine to jump to.
853 br x17
854
Andreas Gampe03906cf2014-04-07 12:08:28 -0700855.Ladvance4_2:
856 add x9, x9, #4
857 b .LfillRegisters2
858
859.Ladvance8_2:
860 add x9, x9, #8
861 b .LfillRegisters2
862
Stuart Monteithb95a5342014-03-12 13:32:32 +0000863// Store ints.
864.LstoreW1_2:
865 LOADREG x8 4 w1 .LfillRegisters2
866 LOADREG x8 4 w2 .LfillRegisters2
867 LOADREG x8 4 w3 .LfillRegisters2
868 LOADREG x8 4 w4 .LfillRegisters2
869 LOADREG x8 4 w5 .LfillRegisters2
870 LOADREG x8 4 w6 .LfillRegisters2
871 LOADREG x8 4 w7 .LfillRegisters2
872
873// Store longs.
874.LstoreX1_2:
875 LOADREG x8 8 x1 .LfillRegisters2
876 LOADREG x8 8 x2 .LfillRegisters2
877 LOADREG x8 8 x3 .LfillRegisters2
878 LOADREG x8 8 x4 .LfillRegisters2
879 LOADREG x8 8 x5 .LfillRegisters2
880 LOADREG x8 8 x6 .LfillRegisters2
881 LOADREG x8 8 x7 .LfillRegisters2
882
883// Store singles.
884.LstoreS0_2:
885 LOADREG x15 4 s0 .LfillRegisters2
886 LOADREG x15 4 s1 .LfillRegisters2
887 LOADREG x15 4 s2 .LfillRegisters2
888 LOADREG x15 4 s3 .LfillRegisters2
889 LOADREG x15 4 s4 .LfillRegisters2
890 LOADREG x15 4 s5 .LfillRegisters2
891 LOADREG x15 4 s6 .LfillRegisters2
892 LOADREG x15 4 s7 .LfillRegisters2
893
894// Store doubles.
895.LstoreD0_2:
896 LOADREG x15 8 d0 .LfillRegisters2
897 LOADREG x15 8 d1 .LfillRegisters2
898 LOADREG x15 8 d2 .LfillRegisters2
899 LOADREG x15 8 d3 .LfillRegisters2
900 LOADREG x15 8 d4 .LfillRegisters2
901 LOADREG x15 8 d5 .LfillRegisters2
902 LOADREG x15 8 d6 .LfillRegisters2
903 LOADREG x15 8 d7 .LfillRegisters2
904
905
906.LcallFunction2:
907
Andreas Gampe03906cf2014-04-07 12:08:28 -0700908 INVOKE_STUB_CALL_AND_RETURN
Stuart Monteithb95a5342014-03-12 13:32:32 +0000909
Stuart Monteithb95a5342014-03-12 13:32:32 +0000910END art_quick_invoke_static_stub
911
Andreas Gampe03906cf2014-04-07 12:08:28 -0700912
Stuart Monteithb95a5342014-03-12 13:32:32 +0000913
914 /*
915 * On entry x0 is uintptr_t* gprs_ and x1 is uint64_t* fprs_
916 */
917
918ENTRY art_quick_do_long_jump
919 // Load FPRs
920 ldp d0, d1, [x1], #16
921 ldp d2, d3, [x1], #16
922 ldp d4, d5, [x1], #16
923 ldp d6, d7, [x1], #16
924 ldp d8, d9, [x1], #16
925 ldp d10, d11, [x1], #16
926 ldp d12, d13, [x1], #16
927 ldp d14, d15, [x1], #16
928 ldp d16, d17, [x1], #16
929 ldp d18, d19, [x1], #16
930 ldp d20, d21, [x1], #16
931 ldp d22, d23, [x1], #16
932 ldp d24, d25, [x1], #16
933 ldp d26, d27, [x1], #16
934 ldp d28, d29, [x1], #16
935 ldp d30, d31, [x1]
936
937 // Load GPRs
938 // TODO: lots of those are smashed, could optimize.
939 add x0, x0, #30*8
940 ldp x30, x1, [x0], #-16
941 ldp x28, x29, [x0], #-16
942 ldp x26, x27, [x0], #-16
943 ldp x24, x25, [x0], #-16
944 ldp x22, x23, [x0], #-16
945 ldp x20, x21, [x0], #-16
946 ldp x18, x19, [x0], #-16
947 ldp x16, x17, [x0], #-16
948 ldp x14, x15, [x0], #-16
949 ldp x12, x13, [x0], #-16
950 ldp x10, x11, [x0], #-16
951 ldp x8, x9, [x0], #-16
952 ldp x6, x7, [x0], #-16
953 ldp x4, x5, [x0], #-16
954 ldp x2, x3, [x0], #-16
955 mov sp, x1
956
957 // TODO: Is it really OK to use LR for the target PC?
958 mov x0, #0
959 mov x1, #0
960 br xLR
961END art_quick_do_long_jump
962
Andreas Gampef4e910b2014-04-29 16:55:52 -0700963 /*
964 * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
965 * failure.
966 */
967 .extern artHandleFillArrayDataFromCode
Andreas Gampef4e910b2014-04-29 16:55:52 -0700968ENTRY art_quick_handle_fill_data
969 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // Save callee saves in case exception allocation triggers GC.
970 mov x2, xSELF // Pass Thread::Current.
971 mov x3, sp // Pass SP.
972 bl artHandleFillArrayDataFromCode // (Array*, const DexFile::Payload*, Thread*, SP)
973 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
974 RETURN_IF_RESULT_IS_ZERO
975 DELIVER_PENDING_EXCEPTION
976END art_quick_handle_fill_data
Stuart Monteithb95a5342014-03-12 13:32:32 +0000977
Andreas Gampe4fc046e2014-05-06 16:56:39 -0700978 /*
979 * Entry from managed code that calls artLockObjectFromCode, may block for GC. x0 holds the
980 * possibly null object to lock.
981 *
982 * Derived from arm32 code.
983 */
984 .extern artLockObjectFromCode
985ENTRY art_quick_lock_object
986 cbz w0, .Lslow_lock
987 add x4, x0, #LOCK_WORD_OFFSET // exclusive load/store had no immediate anymore
988.Lretry_lock:
989 ldr w2, [xSELF, #THREAD_ID_OFFSET] // TODO: Can the thread ID really change during the loop?
990 ldxr w1, [x4]
991 cbnz w1, .Lnot_unlocked // already thin locked
992 stxr w3, w2, [x4]
993 cbnz w3, .Lstrex_fail // store failed, retry
Andreas Gampe675967d2014-05-14 16:28:34 -0700994 dmb ishld // full (LoadLoad|LoadStore) memory barrier
Andreas Gampe4fc046e2014-05-06 16:56:39 -0700995 ret
996.Lstrex_fail:
997 b .Lretry_lock // unlikely forward branch, need to reload and recheck r1/r2
998.Lnot_unlocked:
999 lsr w3, w1, 30
1000 cbnz w3, .Lslow_lock // if either of the top two bits are set, go slow path
1001 eor w2, w1, w2 // lock_word.ThreadId() ^ self->ThreadId()
1002 uxth w2, w2 // zero top 16 bits
1003 cbnz w2, .Lslow_lock // lock word and self thread id's match -> recursive lock
1004 // else contention, go to slow path
1005 add w2, w1, #65536 // increment count in lock word placing in w2 for storing
1006 lsr w1, w2, 30 // if either of the top two bits are set, we overflowed.
1007 cbnz w1, .Lslow_lock // if we overflow the count go slow path
1008 str w2, [x0, #LOCK_WORD_OFFSET]// no need for stxr as we hold the lock
1009 ret
1010.Lslow_lock:
1011 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case we block
1012 mov x1, xSELF // pass Thread::Current
1013 mov x2, sp // pass SP
1014 bl artLockObjectFromCode // (Object* obj, Thread*, SP)
1015 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
1016 RETURN_IF_W0_IS_ZERO_OR_DELIVER
1017END art_quick_lock_object
1018
1019 /*
1020 * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
1021 * x0 holds the possibly null object to lock.
1022 *
1023 * Derived from arm32 code.
1024 */
1025 .extern artUnlockObjectFromCode
1026ENTRY art_quick_unlock_object
1027 cbz x0, .Lslow_unlock
1028 ldr w1, [x0, #LOCK_WORD_OFFSET]
1029 lsr w2, w1, 30
1030 cbnz w2, .Lslow_unlock // if either of the top two bits are set, go slow path
1031 ldr w2, [xSELF, #THREAD_ID_OFFSET]
1032 eor w3, w1, w2 // lock_word.ThreadId() ^ self->ThreadId()
1033 uxth w3, w3 // zero top 16 bits
1034 cbnz w3, .Lslow_unlock // do lock word and self thread id's match?
1035 cmp w1, #65536
1036 bpl .Lrecursive_thin_unlock
1037 // transition to unlocked, w3 holds 0
Andreas Gampe675967d2014-05-14 16:28:34 -07001038 dmb ish // full (LoadStore|StoreStore) memory barrier
Andreas Gampe4fc046e2014-05-06 16:56:39 -07001039 str w3, [x0, #LOCK_WORD_OFFSET]
1040 ret
1041.Lrecursive_thin_unlock:
1042 sub w1, w1, #65536
1043 str w1, [x0, #LOCK_WORD_OFFSET]
1044 ret
1045.Lslow_unlock:
1046 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case exception allocation triggers GC
1047 mov x1, xSELF // pass Thread::Current
1048 mov x2, sp // pass SP
1049 bl artUnlockObjectFromCode // (Object* obj, Thread*, SP)
1050 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
1051 RETURN_IF_W0_IS_ZERO_OR_DELIVER
1052END art_quick_unlock_object
Andreas Gampe525cde22014-04-22 15:44:50 -07001053
1054 /*
1055 * Entry from managed code that calls artIsAssignableFromCode and on failure calls
1056 * artThrowClassCastException.
1057 */
1058 .extern artThrowClassCastException
1059ENTRY art_quick_check_cast
1060 // Store arguments and link register
1061 sub sp, sp, #32 // Stack needs to be 16b aligned on calls
1062 .cfi_adjust_cfa_offset 32
1063 stp x0, x1, [sp]
1064 .cfi_rel_offset x0, 0
1065 .cfi_rel_offset x1, 8
1066 stp xSELF, xLR, [sp, #16]
1067 .cfi_rel_offset x18, 16
1068 .cfi_rel_offset x30, 24
1069
1070 // Call runtime code
1071 bl artIsAssignableFromCode
1072
1073 // Check for exception
1074 cbz x0, .Lthrow_class_cast_exception
1075
1076 // Restore and return
1077 ldp x0, x1, [sp]
1078 .cfi_restore x0
1079 .cfi_restore x1
1080 ldp xSELF, xLR, [sp, #16]
1081 .cfi_restore x18
1082 .cfi_restore x30
1083 add sp, sp, #32
1084 .cfi_adjust_cfa_offset -32
1085 ret
1086
1087.Lthrow_class_cast_exception:
1088 // Restore
1089 ldp x0, x1, [sp]
1090 .cfi_restore x0
1091 .cfi_restore x1
1092 ldp xSELF, xLR, [sp, #16]
1093 .cfi_restore x18
1094 .cfi_restore x30
1095 add sp, sp, #32
1096 .cfi_adjust_cfa_offset -32
1097
1098 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
1099 mov x2, xSELF // pass Thread::Current
1100 mov x3, sp // pass SP
1101 b artThrowClassCastException // (Class*, Class*, Thread*, SP)
1102 brk 0 // We should not return here...
1103END art_quick_check_cast
1104
Andreas Gampef4e910b2014-04-29 16:55:52 -07001105 /*
1106 * Entry from managed code for array put operations of objects where the value being stored
1107 * needs to be checked for compatibility.
1108 * x0 = array, x1 = index, x2 = value
1109 *
1110 * Currently all values should fit into w0/w1/w2, and w1 always will as indices are 32b. We
1111 * assume, though, that the upper 32b are zeroed out. At least for x1/w1 we can do better by
1112 * using index-zero-extension in load/stores.
1113 *
1114 * Temporaries: x3, x4
1115 * TODO: x4 OK? ip seems wrong here.
1116 */
1117ENTRY art_quick_aput_obj_with_null_and_bound_check
1118 tst x0, x0
1119 bne art_quick_aput_obj_with_bound_check
1120 b art_quick_throw_null_pointer_exception
1121END art_quick_aput_obj_with_null_and_bound_check
1122
1123ENTRY art_quick_aput_obj_with_bound_check
1124 ldr w3, [x0, #ARRAY_LENGTH_OFFSET]
1125 cmp w3, w1
1126 bhi art_quick_aput_obj
1127 mov x0, x1
1128 mov x1, x3
1129 b art_quick_throw_array_bounds
1130END art_quick_aput_obj_with_bound_check
1131
1132ENTRY art_quick_aput_obj
1133 cbz x2, .Ldo_aput_null
1134 ldr w3, [x0, #CLASS_OFFSET] // Heap reference = 32b
1135 // This also zero-extends to x3
1136 ldr w4, [x2, #CLASS_OFFSET] // Heap reference = 32b
1137 // This also zero-extends to x4
1138 ldr w3, [x3, #CLASS_COMPONENT_TYPE_OFFSET] // Heap reference = 32b
1139 // This also zero-extends to x3
1140 cmp w3, w4 // value's type == array's component type - trivial assignability
1141 bne .Lcheck_assignability
1142.Ldo_aput:
1143 add x3, x0, #OBJECT_ARRAY_DATA_OFFSET
1144 // "Compress" = do nothing
1145 str w2, [x3, x1, lsl #2] // Heap reference = 32b
1146 ldr x3, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1147 lsr x0, x0, #7
1148 strb w3, [x3, x0]
1149 ret
1150.Ldo_aput_null:
1151 add x3, x0, #OBJECT_ARRAY_DATA_OFFSET
1152 // "Compress" = do nothing
1153 str w2, [x3, x1, lsl #2] // Heap reference = 32b
1154 ret
1155.Lcheck_assignability:
1156 // Store arguments and link register
1157 sub sp, sp, #48 // Stack needs to be 16b aligned on calls
1158 .cfi_adjust_cfa_offset 48
1159 stp x0, x1, [sp]
1160 .cfi_rel_offset x0, 0
1161 .cfi_rel_offset x1, 8
1162 stp x2, xSELF, [sp, #16]
1163 .cfi_rel_offset x2, 16
1164 .cfi_rel_offset x18, 24
1165 str xLR, [sp, #32]
1166 .cfi_rel_offset x30, 32
1167
1168 // Call runtime code
1169 mov x0, x3 // Heap reference, 32b, "uncompress" = do nothing, already zero-extended
1170 mov x1, x4 // Heap reference, 32b, "uncompress" = do nothing, already zero-extended
1171 bl artIsAssignableFromCode
1172
1173 // Check for exception
1174 cbz x0, .Lthrow_array_store_exception
1175
1176 // Restore
1177 ldp x0, x1, [sp]
1178 .cfi_restore x0
1179 .cfi_restore x1
1180 ldp x2, xSELF, [sp, #16]
1181 .cfi_restore x2
1182 .cfi_restore x18
1183 ldr xLR, [sp, #32]
1184 .cfi_restore x30
1185 add sp, sp, #48
1186 .cfi_adjust_cfa_offset -48
1187
1188 add x3, x0, #OBJECT_ARRAY_DATA_OFFSET
1189 // "Compress" = do nothing
1190 str w2, [x3, x1, lsl #2] // Heap reference = 32b
1191 ldr x3, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1192 lsr x0, x0, #7
1193 strb w3, [x3, x0]
1194 ret
1195.Lthrow_array_store_exception:
1196 ldp x0, x1, [sp]
1197 .cfi_restore x0
1198 .cfi_restore x1
1199 ldp x2, xSELF, [sp, #16]
1200 .cfi_restore x2
1201 .cfi_restore x18
1202 ldr xLR, [sp, #32]
1203 .cfi_restore x30
1204 add sp, sp, #48
1205 .cfi_adjust_cfa_offset -48
1206
1207 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
1208 mov x1, x2 // Pass value.
1209 mov x2, xSELF // Pass Thread::Current.
1210 mov x3, sp // Pass SP.
1211 b artThrowArrayStoreException // (Object*, Object*, Thread*, SP).
1212 brk 0 // Unreached.
1213END art_quick_aput_obj
1214
Stuart Monteithb95a5342014-03-12 13:32:32 +00001215// Macro to facilitate adding new allocation entrypoints.
1216.macro TWO_ARG_DOWNCALL name, entrypoint, return
1217 .extern \entrypoint
1218ENTRY \name
Andreas Gampe00c1e6d2014-04-25 15:47:13 -07001219 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC
1220 mov x2, xSELF // pass Thread::Current
1221 mov x3, sp // pass SP
1222 bl \entrypoint // (uint32_t type_idx, Method* method, Thread*, SP)
1223 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
1224 \return
1225 DELIVER_PENDING_EXCEPTION
Stuart Monteithb95a5342014-03-12 13:32:32 +00001226END \name
1227.endm
1228
1229// Macro to facilitate adding new array allocation entrypoints.
1230.macro THREE_ARG_DOWNCALL name, entrypoint, return
1231 .extern \entrypoint
1232ENTRY \name
Andreas Gampe00c1e6d2014-04-25 15:47:13 -07001233 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC
1234 mov x3, xSELF // pass Thread::Current
1235 mov x4, sp // pass SP
1236 bl \entrypoint
1237 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
1238 \return
1239 DELIVER_PENDING_EXCEPTION
Stuart Monteithb95a5342014-03-12 13:32:32 +00001240END \name
1241.endm
1242
Andreas Gampe6e4e59c2014-05-05 20:11:02 -07001243// Macros taking opportunity of code similarities for downcalls with referrer.
1244
1245// TODO: xSELF -> x19. Temporarily rely on xSELF being saved in REF_ONLY
1246.macro ONE_ARG_REF_DOWNCALL name, entrypoint, return
1247 .extern \entrypoint
1248ENTRY \name
1249 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC
Andreas Gampecf4035a2014-05-28 22:43:01 -07001250 ldr w1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer
Andreas Gampe6e4e59c2014-05-05 20:11:02 -07001251 mov x2, xSELF // pass Thread::Current
1252 mov x3, sp // pass SP
1253 bl \entrypoint // (uint32_t type_idx, Method* method, Thread*, SP)
1254 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
1255 \return
1256END \name
1257.endm
1258
1259// TODO: xSELF -> x19. Temporarily rely on xSELF being saved in REF_ONLY
1260.macro TWO_ARG_REF_DOWNCALL name, entrypoint, return
1261 .extern \entrypoint
1262ENTRY \name
1263 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC
Andreas Gampecf4035a2014-05-28 22:43:01 -07001264 ldr w2, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer
Andreas Gampe6e4e59c2014-05-05 20:11:02 -07001265 mov x3, xSELF // pass Thread::Current
1266 mov x4, sp // pass SP
1267 bl \entrypoint
1268 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
1269 \return
1270END \name
1271.endm
1272
1273// TODO: xSELF -> x19. Temporarily rely on xSELF being saved in REF_ONLY
1274.macro THREE_ARG_REF_DOWNCALL name, entrypoint, return
1275 .extern \entrypoint
1276ENTRY \name
1277 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC
Andreas Gampecf4035a2014-05-28 22:43:01 -07001278 ldr w3, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer
Andreas Gampe6e4e59c2014-05-05 20:11:02 -07001279 mov x4, xSELF // pass Thread::Current
1280 mov x5, sp // pass SP
1281 bl \entrypoint
1282 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
1283 \return
1284END \name
1285.endm
1286
Matteo Franchindfd891a2014-04-30 12:17:17 +01001287 /*
1288 * Entry from managed code when uninitialized static storage, this stub will run the class
1289 * initializer and deliver the exception on error. On success the static storage base is
1290 * returned.
1291 */
1292TWO_ARG_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode, RETURN_IF_RESULT_IS_NON_ZERO
1293
Andreas Gampe6aac3552014-06-09 14:55:53 -07001294TWO_ARG_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode, RETURN_IF_RESULT_IS_NON_ZERO
1295TWO_ARG_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_RESULT_IS_NON_ZERO
Matteo Franchindfd891a2014-04-30 12:17:17 +01001296
Andreas Gampe6e4e59c2014-05-05 20:11:02 -07001297ONE_ARG_REF_DOWNCALL art_quick_get32_static, artGet32StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1298ONE_ARG_REF_DOWNCALL art_quick_get64_static, artGet64StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1299ONE_ARG_REF_DOWNCALL art_quick_get_obj_static, artGetObjStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1300
1301TWO_ARG_REF_DOWNCALL art_quick_get32_instance, artGet32InstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1302TWO_ARG_REF_DOWNCALL art_quick_get64_instance, artGet64InstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1303TWO_ARG_REF_DOWNCALL art_quick_get_obj_instance, artGetObjInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1304
1305TWO_ARG_REF_DOWNCALL art_quick_set32_static, artSet32StaticFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1306TWO_ARG_REF_DOWNCALL art_quick_set_obj_static, artSetObjStaticFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1307
1308THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1309THREE_ARG_DOWNCALL art_quick_set64_instance, artSet64InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1310THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1311
1312// This is separated out as the argument order is different.
1313 .extern artSet64StaticFromCode
1314ENTRY art_quick_set64_static
1315 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC
1316 mov x3, x1 // Store value
Andreas Gampecf4035a2014-05-28 22:43:01 -07001317 ldr w1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer
Andreas Gampe6e4e59c2014-05-05 20:11:02 -07001318 mov x2, x3 // Put value param
1319 mov x3, xSELF // pass Thread::Current
1320 mov x4, sp // pass SP
1321 bl artSet64StaticFromCode
1322 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
1323 RETURN_IF_W0_IS_ZERO_OR_DELIVER
1324END art_quick_set64_static
1325
Matteo Franchindfd891a2014-04-30 12:17:17 +01001326 /*
1327 * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
1328 * exception on error. On success the String is returned. x0 holds the referring method,
1329 * w1 holds the string index. The fast path check for hit in strings cache has already been
1330 * performed.
1331 */
1332TWO_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO
Andreas Gampe6e4e59c2014-05-05 20:11:02 -07001333
Stuart Monteithb95a5342014-03-12 13:32:32 +00001334// Generate the allocation entrypoints for each allocator.
1335GENERATE_ALL_ALLOC_ENTRYPOINTS
1336
Zheng Xu48241e72014-05-23 11:52:42 +08001337 /*
1338 * Called by managed code when the value in wSUSPEND has been decremented to 0.
1339 */
1340 .extern artTestSuspendFromCode
1341ENTRY art_quick_test_suspend
1342 ldrh w0, [xSELF, #THREAD_FLAGS_OFFSET] // get xSELF->state_and_flags.as_struct.flags
1343 mov wSUSPEND, #SUSPEND_CHECK_INTERVAL // reset wSUSPEND to SUSPEND_CHECK_INTERVAL
1344 cbnz w0, .Lneed_suspend // check flags == 0
1345 ret // return if flags == 0
1346.Lneed_suspend:
1347 mov x0, xSELF
1348 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves for stack crawl
1349 mov x1, sp
1350 bl artTestSuspendFromCode // (Thread*, SP)
1351 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
1352END art_quick_test_suspend
Stuart Monteithb95a5342014-03-12 13:32:32 +00001353
Andreas Gampee62a07e2014-03-26 14:53:21 -07001354 /*
1355 * Called by managed code that is attempting to call a method on a proxy class. On entry
1356 * x0 holds the proxy method and x1 holds the receiver; The frame size of the invoked proxy
1357 * method agrees with a ref and args callee save frame.
1358 */
1359 .extern artQuickProxyInvokeHandler
1360ENTRY art_quick_proxy_invoke_handler
1361 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
1362 str x0, [sp, #0] // place proxy method at bottom of frame
1363 mov x2, xSELF // pass Thread::Current
1364 mov x3, sp // pass SP
1365 bl artQuickProxyInvokeHandler // (Method* proxy method, receiver, Thread*, SP)
Serban Constantinescu63206f32014-05-07 18:40:49 +01001366 ldr xSELF, [sp, #200] // Restore self pointer.
Andreas Gampee62a07e2014-03-26 14:53:21 -07001367 ldr x2, [xSELF, THREAD_EXCEPTION_OFFSET]
1368 cbnz x2, .Lexception_in_proxy // success if no exception is pending
Andreas Gamped1e91672014-06-02 22:50:05 -07001369 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME // Restore frame
1370 fmov d0, x0 // Store result in d0 in case it was float or double
Andreas Gampee62a07e2014-03-26 14:53:21 -07001371 ret // return on success
1372.Lexception_in_proxy:
1373 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
1374 DELIVER_PENDING_EXCEPTION
1375END art_quick_proxy_invoke_handler
Stuart Monteithb95a5342014-03-12 13:32:32 +00001376
Andreas Gampe51f76352014-05-21 08:28:48 -07001377 /*
1378 * Called to resolve an imt conflict. x12 is a hidden argument that holds the target method's
1379 * dex method index.
1380 */
1381ENTRY art_quick_imt_conflict_trampoline
Andreas Gampecf4035a2014-05-28 22:43:01 -07001382 ldr w0, [sp, #0] // load caller Method*
Andreas Gampe51f76352014-05-21 08:28:48 -07001383 ldr w0, [x0, #METHOD_DEX_CACHE_METHODS_OFFSET] // load dex_cache_resolved_methods
1384 add x0, x0, #OBJECT_ARRAY_DATA_OFFSET // get starting address of data
1385 ldr w0, [x0, x12, lsl 2] // load the target method
1386 b art_quick_invoke_interface_trampoline
1387END art_quick_imt_conflict_trampoline
Stuart Monteithb95a5342014-03-12 13:32:32 +00001388
1389ENTRY art_quick_resolution_trampoline
1390 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
1391 mov x2, xSELF
1392 mov x3, sp
1393 bl artQuickResolutionTrampoline // (called, receiver, Thread*, SP)
Matteo Franchindfd891a2014-04-30 12:17:17 +01001394 cbz x0, 1f
1395 mov x9, x0 // Remember returned code pointer in x9.
Andreas Gampecf4035a2014-05-28 22:43:01 -07001396 ldr w0, [sp, #0] // artQuickResolutionTrampoline puts called method in *SP.
Stuart Monteithb95a5342014-03-12 13:32:32 +00001397 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
Andreas Gampec6ee54e2014-03-24 16:45:44 -07001398 br x9
Stuart Monteithb95a5342014-03-12 13:32:32 +000013991:
1400 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
1401 DELIVER_PENDING_EXCEPTION
1402END art_quick_resolution_trampoline
1403
1404/*
1405 * Generic JNI frame layout:
1406 *
1407 * #-------------------#
1408 * | |
1409 * | caller method... |
1410 * #-------------------# <--- SP on entry
1411 * | Return X30/LR |
1412 * | X29/FP | callee save
1413 * | X28 | callee save
1414 * | X27 | callee save
1415 * | X26 | callee save
1416 * | X25 | callee save
1417 * | X24 | callee save
1418 * | X23 | callee save
1419 * | X22 | callee save
1420 * | X21 | callee save
1421 * | X20 | callee save
1422 * | X19 | callee save
1423 * | X7 | arg7
1424 * | X6 | arg6
1425 * | X5 | arg5
1426 * | X4 | arg4
1427 * | X3 | arg3
1428 * | X2 | arg2
1429 * | X1 | arg1
1430 * | D15 | float arg 8
1431 * | D14 | float arg 8
1432 * | D13 | float arg 8
1433 * | D12 | callee save
1434 * | D11 | callee save
1435 * | D10 | callee save
1436 * | D9 | callee save
1437 * | D8 | callee save
1438 * | D7 | float arg 8
1439 * | D6 | float arg 7
1440 * | D5 | float arg 6
1441 * | D4 | float arg 5
1442 * | D3 | float arg 4
1443 * | D2 | float arg 3
1444 * | D1 | float arg 2
1445 * | D0 | float arg 1
Andreas Gampecf4035a2014-05-28 22:43:01 -07001446 * | Method* | <- X0
Stuart Monteithb95a5342014-03-12 13:32:32 +00001447 * #-------------------#
1448 * | local ref cookie | // 4B
Mathieu Chartier421c5372014-05-14 14:11:40 -07001449 * | handle scope size | // 4B
Stuart Monteithb95a5342014-03-12 13:32:32 +00001450 * #-------------------#
1451 * | JNI Call Stack |
1452 * #-------------------# <--- SP on native call
1453 * | |
1454 * | Stack for Regs | The trampoline assembly will pop these values
1455 * | | into registers for native call
1456 * #-------------------#
1457 * | Native code ptr |
1458 * #-------------------#
1459 * | Free scratch |
1460 * #-------------------#
1461 * | Ptr to (1) | <--- SP
1462 * #-------------------#
1463 */
1464 /*
1465 * Called to do a generic JNI down-call
1466 */
1467ENTRY art_quick_generic_jni_trampoline
1468 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
1469 str x0, [sp, #0] // Store native ArtMethod* to bottom of stack.
1470
1471 // Save SP , so we can have static CFI info.
1472 mov x28, sp
1473 .cfi_def_cfa_register x28
1474
1475 // This looks the same, but is different: this will be updated to point to the bottom
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07001476 // of the frame when the handle scope is inserted.
Stuart Monteithb95a5342014-03-12 13:32:32 +00001477 mov xFP, sp
1478
1479 mov x8, #5120
1480 sub sp, sp, x8
1481
1482 // prepare for artQuickGenericJniTrampoline call
1483 // (Thread*, SP)
1484 // x0 x1 <= C calling convention
1485 // xSELF xFP <= where they are
1486
1487 mov x0, xSELF // Thread*
1488 mov x1, xFP
1489 bl artQuickGenericJniTrampoline // (Thread*, sp)
1490
Andreas Gampec200a4a2014-06-16 18:39:09 -07001491 // The C call will have registered the complete save-frame on success.
1492 // The result of the call is:
1493 // x0: pointer to native code, 0 on error.
1494 // x1: pointer to the bottom of the used area of the alloca, can restore stack till there.
Stuart Monteithb95a5342014-03-12 13:32:32 +00001495
Andreas Gampec200a4a2014-06-16 18:39:09 -07001496 // Check for error = 0.
1497 cbz x0, .Lentry_error
Stuart Monteithb95a5342014-03-12 13:32:32 +00001498
Andreas Gampec200a4a2014-06-16 18:39:09 -07001499 // Release part of the alloca.
1500 mov sp, x1
Stuart Monteithb95a5342014-03-12 13:32:32 +00001501
Andreas Gampec200a4a2014-06-16 18:39:09 -07001502 // Save the code pointer
1503 mov xIP0, x0
Stuart Monteithb95a5342014-03-12 13:32:32 +00001504
1505 // Load parameters from frame into registers.
1506 // TODO Check with artQuickGenericJniTrampoline.
1507 // Also, check again APPCS64 - the stack arguments are interleaved.
Andreas Gampec200a4a2014-06-16 18:39:09 -07001508 ldp x0, x1, [sp]
1509 ldp x2, x3, [sp, #16]
1510 ldp x4, x5, [sp, #32]
1511 ldp x6, x7, [sp, #48]
Stuart Monteithb95a5342014-03-12 13:32:32 +00001512
Andreas Gampec200a4a2014-06-16 18:39:09 -07001513 ldp d0, d1, [sp, #64]
1514 ldp d2, d3, [sp, #80]
1515 ldp d4, d5, [sp, #96]
1516 ldp d6, d7, [sp, #112]
Stuart Monteithb95a5342014-03-12 13:32:32 +00001517
Andreas Gampec200a4a2014-06-16 18:39:09 -07001518 add sp, sp, #128
Stuart Monteithb95a5342014-03-12 13:32:32 +00001519
1520 blr xIP0 // native call.
1521
1522 // Restore self pointer.
1523 ldr xSELF, [x28, #200]
1524
1525 // result sign extension is handled in C code
1526 // prepare for artQuickGenericJniEndTrampoline call
Andreas Gampec200a4a2014-06-16 18:39:09 -07001527 // (Thread*, result, result_f)
1528 // x0 x1 x2 <= C calling convention
1529 mov x1, x0 // Result (from saved)
Stuart Monteithb95a5342014-03-12 13:32:32 +00001530 mov x0, xSELF // Thread register
Andreas Gampec200a4a2014-06-16 18:39:09 -07001531 fmov x2, d0 // d0 will contain floating point result, but needs to go into x2
Stuart Monteithb95a5342014-03-12 13:32:32 +00001532
1533 bl artQuickGenericJniEndTrampoline
1534
1535 // Tear down the alloca.
1536 mov sp, x28
1537 .cfi_def_cfa_register sp
1538
1539 // Restore self pointer.
1540 ldr xSELF, [x28, #200]
1541
1542 // Pending exceptions possible.
1543 ldr x1, [xSELF, THREAD_EXCEPTION_OFFSET]
1544 cbnz x1, .Lexception_in_native
1545
1546 // Tear down the callee-save frame.
1547 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
1548
1549 // store into fpr, for when it's a fpr return...
1550 fmov d0, x0
1551 ret
1552
1553.Lentry_error:
1554 mov sp, x28
1555 .cfi_def_cfa_register sp
1556 ldr xSELF, [x28, #200]
1557.Lexception_in_native:
1558 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
1559 DELIVER_PENDING_EXCEPTION
1560
1561END art_quick_generic_jni_trampoline
1562
1563/*
1564 * Called to bridge from the quick to interpreter ABI. On entry the arguments match those
1565 * of a quick call:
1566 * x0 = method being called/to bridge to.
1567 * x1..x7, d0..d7 = arguments to that method.
1568 */
1569ENTRY art_quick_to_interpreter_bridge
1570 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME // Set up frame and save arguments.
1571
1572 // x0 will contain mirror::ArtMethod* method.
1573 mov x1, xSELF // How to get Thread::Current() ???
1574 mov x2, sp
1575
1576 // uint64_t artQuickToInterpreterBridge(mirror::ArtMethod* method, Thread* self,
1577 // mirror::ArtMethod** sp)
1578 bl artQuickToInterpreterBridge
1579
1580 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME // TODO: no need to restore arguments in this case.
1581
1582 fmov d0, x0
1583
1584 RETURN_OR_DELIVER_PENDING_EXCEPTION
1585END art_quick_to_interpreter_bridge
1586
Andreas Gamped58342c2014-06-05 14:18:08 -07001587
1588//
1589// Instrumentation-related stubs
1590//
1591 .extern artInstrumentationMethodEntryFromCode
1592ENTRY art_quick_instrumentation_entry
1593 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
1594
1595 mov x19, x0 // Preserve method reference in a callee-save.
1596
1597 mov x2, xSELF
1598 mov x3, sp
1599 mov x4, xLR
1600 bl artInstrumentationMethodEntryFromCode // (Method*, Object*, Thread*, SP, LR)
1601
1602 mov x9, x0 // x0 = result of call.
1603 mov x0, x19 // Reload method reference.
1604
1605 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME // Note: will restore xSELF
1606 adr xLR, art_quick_instrumentation_exit
1607 br x9 // Tail-call method with lr set to art_quick_instrumentation_exit.
1608END art_quick_instrumentation_entry
1609
1610 .extern artInstrumentationMethodExitFromCode
1611ENTRY art_quick_instrumentation_exit
1612 mov xLR, #0 // Clobber LR for later checks.
1613
1614 SETUP_REF_ONLY_CALLEE_SAVE_FRAME
1615
1616 // We need to save x0 and d0. We could use a callee-save from SETUP_REF_ONLY, but then
1617 // we would need to fully restore it. As there are a lot of callee-save registers, it seems
1618 // easier to have an extra small stack area.
1619
Sebastien Hertz70f8d4b2014-06-19 11:51:41 +02001620 str x0, [sp, #-16]! // Save integer result.
Andreas Gamped58342c2014-06-05 14:18:08 -07001621 .cfi_adjust_cfa_offset 16
1622 str d0, [sp, #8] // Save floating-point result.
1623
Andreas Gamped58342c2014-06-05 14:18:08 -07001624 add x1, sp, #16 // Pass SP.
1625 mov x2, x0 // Pass integer result.
1626 fmov x3, d0 // Pass floating-point result.
Sebastien Hertz70f8d4b2014-06-19 11:51:41 +02001627 mov x0, xSELF // Pass Thread.
Andreas Gamped58342c2014-06-05 14:18:08 -07001628 bl artInstrumentationMethodExitFromCode // (Thread*, SP, gpr_res, fpr_res)
1629
1630 mov x9, x0 // Return address from instrumentation call.
1631 mov xLR, x1 // r1 is holding link register if we're to bounce to deoptimize
1632
1633 ldr d0, [sp, #8] // Restore floating-point result.
1634 ldr x0, [sp], 16 // Restore integer result, and drop stack area.
1635 .cfi_adjust_cfa_offset 16
1636
Serban Constantinescu86797a72014-06-19 16:17:56 +01001637 // Need to restore x18.
1638 ldr xSELF, [sp, #72]
Andreas Gamped58342c2014-06-05 14:18:08 -07001639 POP_REF_ONLY_CALLEE_SAVE_FRAME
1640
1641 br x9 // Tail-call out.
1642END art_quick_instrumentation_exit
1643
1644 /*
1645 * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization
1646 * will long jump to the upcall with a special exception of -1.
1647 */
1648 .extern artDeoptimize
1649ENTRY art_quick_deoptimize
1650 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
1651 mov x0, xSELF // Pass thread.
1652 mov x1, sp // Pass SP.
1653 bl artDeoptimize // artDeoptimize(Thread*, SP)
Serban Constantinescu86797a72014-06-19 16:17:56 +01001654 brk 0
Andreas Gamped58342c2014-06-05 14:18:08 -07001655END art_quick_deoptimize
1656
1657
Serban Constantinescu169489b2014-06-11 16:43:35 +01001658 /*
1659 * String's indexOf.
1660 *
1661 * TODO: Not very optimized.
1662 * On entry:
1663 * x0: string object (known non-null)
1664 * w1: char to match (known <= 0xFFFF)
1665 * w2: Starting offset in string data
1666 */
1667ENTRY art_quick_indexof
1668 ldr w3, [x0, #STRING_COUNT_OFFSET]
1669 ldr w4, [x0, #STRING_OFFSET_OFFSET]
1670 ldr w0, [x0, #STRING_VALUE_OFFSET] // x0 ?
1671
1672 /* Clamp start to [0..count] */
1673 cmp w2, #0
1674 csel w2, wzr, w2, lt
1675 cmp w2, w3
1676 csel w2, w3, w2, gt
1677
1678 /* Build a pointer to the start of the string data */
1679 add x0, x0, #STRING_DATA_OFFSET
1680 add x0, x0, x4, lsl #1
1681
1682 /* Save a copy to compute result */
1683 mov x5, x0
1684
1685 /* Build pointer to start of data to compare and pre-bias */
1686 add x0, x0, x2, lsl #1
1687 sub x0, x0, #2
1688
1689 /* Compute iteration count */
1690 sub w2, w3, w2
1691
1692 /*
1693 * At this point we have:
1694 * x0: start of the data to test
1695 * w1: char to compare
1696 * w2: iteration count
1697 * x5: original start of string data
1698 */
1699
1700 subs w2, w2, #4
1701 b.lt .Lindexof_remainder
1702
1703.Lindexof_loop4:
1704 ldrh w6, [x0, #2]!
1705 ldrh w7, [x0, #2]!
1706 ldrh w8, [x0, #2]!
1707 ldrh w9, [x0, #2]!
1708 cmp w6, w1
1709 b.eq .Lmatch_0
1710 cmp w7, w1
1711 b.eq .Lmatch_1
1712 cmp w8, w1
1713 b.eq .Lmatch_2
1714 cmp w9, w1
1715 b.eq .Lmatch_3
1716 subs w2, w2, #4
1717 b.ge .Lindexof_loop4
1718
1719.Lindexof_remainder:
1720 adds w2, w2, #4
1721 b.eq .Lindexof_nomatch
1722
1723.Lindexof_loop1:
1724 ldrh w6, [x0, #2]!
1725 cmp w6, w1
1726 b.eq .Lmatch_3
1727 subs w2, w2, #1
1728 b.ne .Lindexof_loop1
1729
1730.Lindexof_nomatch:
1731 mov x0, #-1
1732 ret
1733
1734.Lmatch_0:
1735 sub x0, x0, #6
1736 sub x0, x0, x5
1737 asr x0, x0, #1
1738 ret
1739.Lmatch_1:
1740 sub x0, x0, #4
1741 sub x0, x0, x5
1742 asr x0, x0, #1
1743 ret
1744.Lmatch_2:
1745 sub x0, x0, #2
1746 sub x0, x0, x5
1747 asr x0, x0, #1
1748 ret
1749.Lmatch_3:
1750 sub x0, x0, x5
1751 asr x0, x0, #1
1752 ret
1753END art_quick_indexof
Andreas Gampe266340d2014-05-02 07:55:24 -07001754
1755 /*
1756 * String's compareTo.
1757 *
1758 * TODO: Not very optimized.
1759 *
1760 * On entry:
1761 * x0: this object pointer
1762 * x1: comp object pointer
1763 *
1764 */
Serban Constantinescu86797a72014-06-19 16:17:56 +01001765 .extern __memcmp16
Andreas Gampe266340d2014-05-02 07:55:24 -07001766ENTRY art_quick_string_compareto
1767 mov x2, x0 // x0 is return, use x2 for first input.
1768 sub x0, x2, x1 // Same string object?
1769 cbnz x0,1f
1770 ret
17711: // Different string objects.
1772
1773 ldr w6, [x2, #STRING_OFFSET_OFFSET]
1774 ldr w5, [x1, #STRING_OFFSET_OFFSET]
1775 ldr w4, [x2, #STRING_COUNT_OFFSET]
1776 ldr w3, [x1, #STRING_COUNT_OFFSET]
1777 ldr w2, [x2, #STRING_VALUE_OFFSET]
1778 ldr w1, [x1, #STRING_VALUE_OFFSET]
1779
1780 /*
1781 * Now: CharArray* Offset Count
1782 * first arg x2 w6 w4
1783 * second arg x1 w5 w3
1784 */
1785
1786 // x0 := str1.length(w4) - str2.length(w3). ldr zero-extended w3/w4 into x3/x4.
1787 subs x0, x4, x3
1788 // Min(count1, count2) into w3.
1789 csel x3, x3, x4, ge
1790
1791 // Build pointer into string data.
1792
1793 // Add offset in array (substr etc.) (sign extend and << 1).
1794 add x2, x2, w6, sxtw #1
1795 add x1, x1, w5, sxtw #1
1796
1797 // Add offset in CharArray to array.
1798 add x2, x2, #STRING_DATA_OFFSET
1799 add x1, x1, #STRING_DATA_OFFSET
1800
Serban Constantinescu169489b2014-06-11 16:43:35 +01001801 // TODO: Tune this value.
Andreas Gampe266340d2014-05-02 07:55:24 -07001802 // Check for long string, do memcmp16 for them.
1803 cmp w3, #28 // Constant from arm32.
1804 bgt .Ldo_memcmp16
1805
1806 /*
1807 * Now:
1808 * x2: *first string data
1809 * x1: *second string data
1810 * w3: iteration count
1811 * x0: return value if comparison equal
1812 * x4, x5, x6, x7: free
1813 */
1814
1815 // Do a simple unrolled loop.
1816.Lloop:
1817 // At least two more elements?
1818 subs w3, w3, #2
1819 b.lt .Lremainder_or_done
1820
1821 ldrh w4, [x2], #2
1822 ldrh w5, [x1], #2
1823
1824 ldrh w6, [x2], #2
1825 ldrh w7, [x1], #2
1826
1827 subs w4, w4, w5
1828 b.ne .Lw4_result
1829
1830 subs w6, w6, w7
1831 b.ne .Lw6_result
1832
1833 b .Lloop
1834
1835.Lremainder_or_done:
1836 adds w3, w3, #1
1837 b.eq .Lremainder
1838 ret
1839
1840.Lremainder:
1841 ldrh w4, [x2], #2
1842 ldrh w5, [x1], #2
1843 subs w4, w4, w5
1844 b.ne .Lw4_result
1845 ret
1846
1847// Result is in w4
1848.Lw4_result:
1849 sxtw x0, w4
1850 ret
1851
1852// Result is in w6
1853.Lw6_result:
1854 sxtw x0, w6
1855 ret
1856
1857.Ldo_memcmp16:
Serban Constantinescu86797a72014-06-19 16:17:56 +01001858 mov x14, x0 // Save x0 and LR. __memcmp16 does not use these temps.
1859 mov x15, xLR // TODO: Codify and check that?
Andreas Gampe266340d2014-05-02 07:55:24 -07001860
1861 mov x0, x2
1862 uxtw x2, w3
Serban Constantinescu86797a72014-06-19 16:17:56 +01001863 bl __memcmp16
Andreas Gampe266340d2014-05-02 07:55:24 -07001864
Serban Constantinescu86797a72014-06-19 16:17:56 +01001865 mov xLR, x15 // Restore LR.
Andreas Gampe266340d2014-05-02 07:55:24 -07001866
Serban Constantinescu86797a72014-06-19 16:17:56 +01001867 cmp x0, #0 // Check the memcmp difference.
1868 csel x0, x0, x14, ne // x0 := x0 != 0 ? x14(prev x0=length diff) : x1.
Andreas Gampe266340d2014-05-02 07:55:24 -07001869 ret
1870END art_quick_string_compareto
Zheng Xu0210d112014-06-17 12:25:48 +08001871
1872// Macro to facilitate adding new entrypoints which call to native function directly.
1873// Currently, xSELF is the only thing we need to take care of between managed code and AAPCS.
1874// But we might introduce more differences.
1875.macro NATIVE_DOWNCALL name, entrypoint
1876 .extern \entrypoint
1877ENTRY \name
Serban Constantinescu86797a72014-06-19 16:17:56 +01001878 stp xSELF, xLR, [sp, #-16]!
Zheng Xu0210d112014-06-17 12:25:48 +08001879 bl \entrypoint
Serban Constantinescu86797a72014-06-19 16:17:56 +01001880 ldp xSELF, xLR, [sp], #16
Zheng Xu0210d112014-06-17 12:25:48 +08001881 ret
1882END \name
1883.endm
1884
1885NATIVE_DOWNCALL art_quick_fmod fmod
1886NATIVE_DOWNCALL art_quick_fmodf fmodf
1887NATIVE_DOWNCALL art_quick_memcpy memcpy
Serban Constantinescu86797a72014-06-19 16:17:56 +01001888NATIVE_DOWNCALL art_quick_assignable_from_code artIsAssignableFromCode