blob: ffd1b138052d90356123a07c1ee49880016af4f6 [file] [log] [blame]
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001%def header():
2/*
3 * Copyright (C) 2020 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * This is a #include, not a %include, because we want the C pre-processor
20 * to expand the macros into assembler assignment statements.
21 */
22#include "asm_support.h"
23#include "arch/arm64/asm_support_arm64.S"
Nicolas Geoffray4fc75692020-01-13 21:49:22 +000024
25/**
26 * ARM64 Runtime register usage conventions.
27 *
28 * r0 : w0 is 32-bit return register and x0 is 64-bit.
29 * r0-r7 : Argument registers.
30 * r8-r15 : Caller save registers (used as temporary registers).
31 * r16-r17: Also known as ip0-ip1, respectively. Used as scratch registers by
32 * the linker, by the trampolines and other stubs (the compiler uses
33 * these as temporary registers).
34 * r18 : Reserved for platform (SCS, shadow call stack)
35 * r19 : Pointer to thread-local storage.
36 * r20-r29: Callee save registers.
37 * r30 : (lr) is reserved (the link register).
38 * rsp : (sp) is reserved (the stack pointer).
39 * rzr : (zr) is reserved (the zero register).
40 *
41 * Floating-point registers
42 * v0-v31
43 *
44 * v0 : s0 is return register for singles (32-bit) and d0 for doubles (64-bit).
45 * This is analogous to the C/C++ (hard-float) calling convention.
46 * v0-v7 : Floating-point argument registers in both Dalvik and C/C++ conventions.
47 * Also used as temporary and codegen scratch registers.
48 *
49 * v0-v7 and v16-v31 : Caller save registers (used as temporary registers).
50 * v8-v15 : bottom 64-bits preserved across C calls (d8-d15 are preserved).
51 *
52 * v16-v31: Used as codegen temp/scratch.
53 * v8-v15 : Can be used for promotion.
54 *
55 * Must maintain 16-byte stack alignment.
56 *
57 * Nterp notes:
58 *
59 * The following registers have fixed assignments:
60 *
61 * reg nick purpose
62 * x19 xSELF self (Thread) pointer
63 * x20 wMR marking register
64 * x29 xFP interpreted frame pointer, used for accessing locals and args
65 * x22 xPC interpreted program counter, used for fetching instructions
66 * x23 xINST first 16-bit code unit of current instruction
67 * x24 xIBASE interpreted instruction base pointer, used for computed goto
68 * x25 xREFS base of object references of dex registers.
69 * x16 ip scratch reg
70 * x17 ip2 scratch reg (used by macros)
71 *
72 * Macros are provided for common operations. They MUST NOT alter unspecified registers or
73 * condition codes.
74*/
75
76/* single-purpose registers, given names for clarity */
77#define xSELF x19
78#define CFI_DEX 22 // DWARF register number of the register holding dex-pc (xPC).
79#define CFI_TMP 0 // DWARF register number of the first argument register (r0).
80#define xPC x22
81#define xINST x23
82#define wINST w23
83#define xIBASE x24
84#define xREFS x25
85#define CFI_REFS 25
86#define ip x16
87#define ip2 x17
88#define wip w16
89#define wip2 w17
90
91// To avoid putting ifdefs arond the use of wMR, make sure it's defined.
92// IsNterpSupported returns false for configurations that don't have wMR (typically CMS).
93#ifndef wMR
94#define wMR w20
95#endif
96
97// Temporary registers while setting up a frame.
98#define xNEW_FP x26
99#define xNEW_REFS x27
100#define CFI_NEW_REFS 27
101
102// +8 for the ArtMethod of the caller.
103#define OFFSET_TO_FIRST_ARGUMENT_IN_STACK (CALLEE_SAVES_SIZE + 8)
104
105/*
106 * Fetch the next instruction from xPC into wINST. Does not advance xPC.
107 */
108.macro FETCH_INST
109 ldrh wINST, [xPC]
110.endm
111
112/*
113 * Fetch the next instruction from the specified offset. Advances xPC
114 * to point to the next instruction. "count" is in 16-bit code units.
115 *
116 * Because of the limited size of immediate constants on ARM, this is only
117 * suitable for small forward movements (i.e. don't try to implement "goto"
118 * with this).
119 *
120 * This must come AFTER anything that can throw an exception, or the
121 * exception catch may miss. (This also implies that it must come after
122 * EXPORT_PC.)
123 */
124.macro FETCH_ADVANCE_INST count
125 ldrh wINST, [xPC, #((\count)*2)]!
126.endm
127
128/*
129 * Similar to FETCH_ADVANCE_INST, but does not update xPC. Used to load
130 * xINST ahead of possible exception point. Be sure to manually advance xPC
131 * later.
132 */
133.macro PREFETCH_INST count
134 ldrh wINST, [xPC, #((\count)*2)]
135.endm
136
137/* Advance xPC by some number of code units. */
138.macro ADVANCE count
139 add xPC, xPC, #((\count)*2)
140.endm
141
142/*
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000143 * Fetch a half-word code unit from an offset past the current PC. The
144 * "count" value is in 16-bit code units. Does not advance xPC.
145 *
146 * The "_S" variant works the same but treats the value as signed.
147 */
148.macro FETCH reg, count
149 ldrh \reg, [xPC, #((\count)*2)]
150.endm
151
152.macro FETCH_S reg, count
153 ldrsh \reg, [xPC, #((\count)*2)]
154.endm
155
156/*
157 * Fetch one byte from an offset past the current PC. Pass in the same
158 * "count" as you would for FETCH, and an additional 0/1 indicating which
159 * byte of the halfword you want (lo/hi).
160 */
161.macro FETCH_B reg, count, byte
162 ldrb \reg, [xPC, #((\count)*2+(\byte))]
163.endm
164
165/*
166 * Put the instruction's opcode field into the specified register.
167 */
168.macro GET_INST_OPCODE reg
169 and \reg, xINST, #255
170.endm
171
172/*
173 * Begin executing the opcode in _reg. Clobbers reg
174 */
175
176.macro GOTO_OPCODE reg
177 add \reg, xIBASE, \reg, lsl #${handler_size_bits}
178 br \reg
179.endm
180
181/*
182 * Get/set the 32-bit value from a Dalvik register.
183 */
184.macro GET_VREG reg, vreg
185 ldr \reg, [xFP, \vreg, uxtw #2]
186.endm
187.macro GET_VREG_OBJECT reg, vreg
188 ldr \reg, [xREFS, \vreg, uxtw #2]
189.endm
190.macro SET_VREG reg, vreg
191 str \reg, [xFP, \vreg, uxtw #2]
192 str wzr, [xREFS, \vreg, uxtw #2]
193.endm
Nicolas Geoffrayaeb7f9f2020-11-11 13:39:18 +0000194.macro SET_VREG_OBJECT reg, vreg
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000195 str \reg, [xFP, \vreg, uxtw #2]
196 str \reg, [xREFS, \vreg, uxtw #2]
197.endm
198.macro SET_VREG_FLOAT reg, vreg
199 str \reg, [xFP, \vreg, uxtw #2]
200 str wzr, [xREFS, \vreg, uxtw #2]
201.endm
202
203/*
204 * Get/set the 64-bit value from a Dalvik register.
205 */
206.macro GET_VREG_WIDE reg, vreg
207 add ip2, xFP, \vreg, uxtw #2
208 ldr \reg, [ip2]
209.endm
210.macro SET_VREG_WIDE reg, vreg
211 add ip2, xFP, \vreg, uxtw #2
212 str \reg, [ip2]
213 add ip2, xREFS, \vreg, uxtw #2
214 str xzr, [ip2]
215.endm
216.macro GET_VREG_DOUBLE reg, vreg
217 add ip2, xFP, \vreg, uxtw #2
218 ldr \reg, [ip2]
219.endm
220.macro SET_VREG_DOUBLE reg, vreg
221 add ip2, xFP, \vreg, uxtw #2
222 str \reg, [ip2]
223 add ip2, xREFS, \vreg, uxtw #2
224 str xzr, [ip2]
225.endm
226
227/*
228 * Get the 32-bit value from a Dalvik register and sign-extend to 64-bit.
229 * Used to avoid an extra instruction in int-to-long.
230 */
231.macro GET_VREG_S reg, vreg
232 ldrsw \reg, [xFP, \vreg, uxtw #2]
233.endm
234
235// An assembly entry that has a OatQuickMethodHeader prefix.
236.macro OAT_ENTRY name, end
237 .type \name, #function
238 .hidden \name
239 .global \name
240 .balign 16
David Srbecky113d6ea2021-03-02 22:49:46 +0000241 // Padding of 3 * 8 bytes to get 16 bytes alignment of code entry.
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000242 .long 0
243 .long 0
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000244 .long 0
David Srbecky113d6ea2021-03-02 22:49:46 +0000245 // OatQuickMethodHeader. Note that the top two bits must be clear.
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000246 .long (\end - \name)
247\name:
248.endm
249
250.macro SIZE name
251 .size \name, .-\name
252.endm
253
254.macro NAME_START name
255 .type \name, #function
256 .hidden \name // Hide this as a global symbol, so we do not incur plt calls.
257 .global \name
258 /* Cache alignment for function entry */
259 .balign 16
260\name:
261.endm
262
263.macro NAME_END name
264 SIZE \name
265.endm
266
267// Macro for defining entrypoints into runtime. We don't need to save registers
268// (we're not holding references there), but there is no
269// kDontSave runtime method. So just use the kSaveRefsOnly runtime method.
270.macro NTERP_TRAMPOLINE name, helper
271ENTRY \name
272 SETUP_SAVE_REFS_ONLY_FRAME
273 bl \helper
274 RESTORE_SAVE_REFS_ONLY_FRAME
275 REFRESH_MARKING_REGISTER
276 RETURN_OR_DELIVER_PENDING_EXCEPTION
277END \name
278.endm
279
280.macro CLEAR_STATIC_VOLATILE_MARKER reg
281 and \reg, \reg, #-2
282.endm
283
284.macro CLEAR_INSTANCE_VOLATILE_MARKER reg
285 neg \reg, \reg
286.endm
287
288.macro EXPORT_PC
289 str xPC, [xREFS, #-16]
290.endm
291
292.macro BRANCH
Nicolas Geoffrayd726cb12021-09-21 17:20:14 +0100293 // Update method counter and do a suspend check if the branch is negative or zero.
294 cmp wINST, #0
295 b.le 2f
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00002961:
Vladimir Marko98fa40a2021-03-15 14:04:43 +0000297 add xPC, xPC, wINST, sxtw #1 // update xPC
298 FETCH wINST, 0 // load wINST
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000299 GET_INST_OPCODE ip // extract opcode from wINST
300 GOTO_OPCODE ip // jump to next instruction
3012:
302 ldr x0, [sp]
303 ldrh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
Nicolas Geoffray61673dc2021-11-06 13:58:31 +0000304#if (NTERP_HOTNESS_VALUE != 0)
305#error Expected 0 for hotness value
306#endif
307 // If the counter is at zero, handle this in the runtime.
Vladimir Markoce131fe2021-10-26 20:03:35 +0000308 cbz w2, NterpHandleHotnessOverflow
Nicolas Geoffray61673dc2021-11-06 13:58:31 +0000309 add x2, x2, #-1
310 strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000311 // Otherwise, do a suspend check.
312 ldr x0, [xSELF, #THREAD_FLAGS_OFFSET]
313 ands x0, x0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
314 b.eq 1b
315 EXPORT_PC
316 bl art_quick_test_suspend
317 b 1b
318.endm
319
Nicolas Geoffraye1d2dce2020-09-21 10:06:31 +0100320// Uses x12, x13, and x14 as temporaries.
321.macro FETCH_CODE_ITEM_INFO code_item, registers, outs, ins, load_ins
322 tbz \code_item, #0, 4f
323 and \code_item, \code_item, #-2 // Remove the extra bit that marks it's a compact dex file
324 ldrh w13, [\code_item, #COMPACT_CODE_ITEM_FIELDS_OFFSET]
325 ubfx \registers, w13, #COMPACT_CODE_ITEM_REGISTERS_SIZE_SHIFT, #4
326 ubfx \outs, w13, #COMPACT_CODE_ITEM_OUTS_SIZE_SHIFT, #4
327 .if \load_ins
328 ubfx \ins, w13, #COMPACT_CODE_ITEM_INS_SIZE_SHIFT, #4
329 .else
330 ubfx w14, w13, #COMPACT_CODE_ITEM_INS_SIZE_SHIFT, #4
331 add \registers, \registers, w14
332 .endif
333 ldrh w13, [\code_item, #COMPACT_CODE_ITEM_FLAGS_OFFSET]
334 tst w13, #COMPACT_CODE_ITEM_REGISTERS_INS_OUTS_FLAGS
335 b.eq 3f
336 sub x14, \code_item, #4
337 tst w13, #COMPACT_CODE_ITEM_INSNS_FLAG
338 csel x14, x14, \code_item, ne
339
340 tbz w13, #COMPACT_CODE_ITEM_REGISTERS_BIT, 1f
341 ldrh w12, [x14, #-2]!
342 add \registers, \registers, w12
3431:
344 tbz w13, #COMPACT_CODE_ITEM_INS_BIT, 2f
345 ldrh w12, [x14, #-2]!
346 .if \load_ins
347 add \ins, \ins, w12
348 .else
349 add \registers, \registers, w12
350 .endif
3512:
352 tbz w13, #COMPACT_CODE_ITEM_OUTS_BIT, 3f
353 ldrh w12, [x14, #-2]!
354 add \outs, \outs, w12
3553:
356 .if \load_ins
357 add \registers, \registers, \ins
358 .endif
359 add \code_item, \code_item, #COMPACT_CODE_ITEM_INSNS_OFFSET
360 b 5f
3614:
362 // Fetch dex register size.
363 ldrh \registers, [\code_item, #CODE_ITEM_REGISTERS_SIZE_OFFSET]
364 // Fetch outs size.
365 ldrh \outs, [\code_item, #CODE_ITEM_OUTS_SIZE_OFFSET]
366 .if \load_ins
367 ldrh \ins, [\code_item, #CODE_ITEM_INS_SIZE_OFFSET]
368 .endif
369 add \code_item, \code_item, #CODE_ITEM_INSNS_OFFSET
3705:
371.endm
372
Nicolas Geoffrayafae11f2021-11-10 16:45:13 +0000373.macro TEST_IF_MARKING label
374 cbnz wMR, \label
375.endm
376
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000377// Setup the stack to start executing the method. Expects:
378// - x0 to contain the ArtMethod
379//
380// Outputs
381// - ip contains the dex registers size
Nicolas Geoffraye5859642021-01-08 18:09:36 +0000382// - x28 contains the old stack pointer.
Nicolas Geoffraye1d2dce2020-09-21 10:06:31 +0100383// - \code_item is replaced with a pointer to the instructions
384// - if load_ins is 1, w15 contains the ins
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000385//
Nicolas Geoffraye1d2dce2020-09-21 10:06:31 +0100386// Uses ip, ip2, x12, x13, x14 as temporaries.
387.macro SETUP_STACK_FRAME code_item, refs, fp, cfi_refs, load_ins
388 FETCH_CODE_ITEM_INFO \code_item, wip, wip2, w15, \load_ins
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000389
Nicolas Geoffray6af553d2020-11-17 13:07:31 +0000390 // Compute required frame size: ((2 * ip) + ip2) * 4 + 24
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000391 // 24 is for saving the previous frame, pc, and method being executed.
392 add x14, ip, ip
393 add x14, x14, ip2
394 lsl x14, x14, #2
395 add x14, x14, #24
396
397 // Compute new stack pointer in x14
398 sub x14, sp, x14
399 // Alignment
400 and x14, x14, #-16
401
402 // Set reference and dex registers, align to pointer size for previous frame and dex pc.
403 add \refs, x14, ip2, lsl #2
404 add \refs, \refs, 28
405 and \refs, \refs, #(-__SIZEOF_POINTER__)
406 add \fp, \refs, ip, lsl #2
407
408 // Now setup the stack pointer.
Nicolas Geoffraye5859642021-01-08 18:09:36 +0000409 mov x28, sp
410 .cfi_def_cfa_register x28
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000411 mov sp, x14
Nicolas Geoffraye5859642021-01-08 18:09:36 +0000412 str x28, [\refs, #-8]
Nicolas Geoffrayfaf5f3f2020-07-03 18:36:45 +0100413 CFI_DEF_CFA_BREG_PLUS_UCONST \cfi_refs, -8, CALLEE_SAVES_SIZE
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000414
415 // Put nulls in reference frame.
416 cbz ip, 2f
417 mov ip2, \refs
4181:
419 str xzr, [ip2], #8 // May clear vreg[0].
420 cmp ip2, \fp
421 b.lo 1b
4222:
423 // Save the ArtMethod.
424 str x0, [sp]
425.endm
426
427// Increase method hotness and do suspend check before starting executing the method.
428.macro START_EXECUTING_INSTRUCTIONS
429 ldr x0, [sp]
430 ldrh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
Nicolas Geoffray61673dc2021-11-06 13:58:31 +0000431#if (NTERP_HOTNESS_VALUE != 0)
432#error Expected 0 for hotness value
433#endif
434 // If the counter is at zero, handle this in the runtime.
Vladimir Markoce131fe2021-10-26 20:03:35 +0000435 cbz w2, 2f
Nicolas Geoffray61673dc2021-11-06 13:58:31 +0000436 add x2, x2, #-1
437 strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000438 ldr x0, [xSELF, #THREAD_FLAGS_OFFSET]
439 tst x0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
440 b.ne 3f
4411:
442 FETCH_INST
443 GET_INST_OPCODE ip
444 GOTO_OPCODE ip
4452:
446 mov x1, xzr
447 mov x2, xFP
448 bl nterp_hot_method
449 b 1b
4503:
451 EXPORT_PC
452 bl art_quick_test_suspend
453 b 1b
454.endm
455
456.macro SPILL_ALL_CALLEE_SAVES
457 INCREASE_FRAME CALLEE_SAVES_SIZE
458 // Note: we technically don't need to save x19 and x20,
459 // but the runtime will expect those values to be there when unwinding
460 // (see Arm64Context::DoLongJump checking for the thread register).
461 SAVE_ALL_CALLEE_SAVES 0
462.endm
463
464.macro RESTORE_ALL_CALLEE_SAVES
465 // FP callee-saves
466 ldp d8, d9, [sp, #0]
467 ldp d10, d11, [sp, #16]
468 ldp d12, d13, [sp, #32]
469 ldp d14, d15, [sp, #48]
470
471 // GP callee-saves.
472 // No need to restore x19 (it's always the thread), and
473 // don't restore x20 (the marking register) as it may have been updated.
474 RESTORE_TWO_REGS x21, x22, 80
475 RESTORE_TWO_REGS x23, x24, 96
476 RESTORE_TWO_REGS x25, x26, 112
477 RESTORE_TWO_REGS x27, x28, 128
478 RESTORE_TWO_REGS x29, lr, 144
479
480 DECREASE_FRAME CALLEE_SAVES_SIZE
481.endm
482
483.macro SPILL_ALL_ARGUMENTS
Nicolas Geoffraye5859642021-01-08 18:09:36 +0000484 stp x0, x1, [sp, #-128]!
485 stp x2, x3, [sp, #16]
486 stp x4, x5, [sp, #32]
487 stp x6, x7, [sp, #48]
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000488 stp d0, d1, [sp, #64]
489 stp d2, d3, [sp, #80]
490 stp d4, d5, [sp, #96]
491 stp d6, d7, [sp, #112]
492.endm
493
494.macro RESTORE_ALL_ARGUMENTS
Nicolas Geoffraye5859642021-01-08 18:09:36 +0000495 ldp x2, x3, [sp, #16]
496 ldp x4, x5, [sp, #32]
497 ldp x6, x7, [sp, #48]
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000498 ldp d0, d1, [sp, #64]
499 ldp d2, d3, [sp, #80]
500 ldp d4, d5, [sp, #96]
501 ldp d6, d7, [sp, #112]
Nicolas Geoffraye5859642021-01-08 18:09:36 +0000502 ldp x0, x1, [sp], #128
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000503.endm
504
505// Helper to setup the stack after doing a nterp to nterp call. This will setup:
506// - xNEW_FP: the new pointer to dex registers
507// - xNEW_REFS: the new pointer to references
508// - xPC: the new PC pointer to execute
509// - x2: value in instruction to decode the number of arguments.
510// - x3: first dex register
511// - x4: top of dex register array
512//
513// The method expects:
514// - x0 to contain the ArtMethod
515// - x8 to contain the code item
516.macro SETUP_STACK_FOR_INVOKE
517 // We do the same stack overflow check as the compiler. See CanMethodUseNterp
518 // in how we limit the maximum nterp frame size.
519 sub x16, sp, #STACK_OVERFLOW_RESERVED_BYTES
520 ldr wzr, [x16]
521
522 // Spill all callee saves to have a consistent stack frame whether we
523 // are called by compiled code or nterp.
524 SPILL_ALL_CALLEE_SAVES
525
526 // Setup the frame.
Nicolas Geoffraye1d2dce2020-09-21 10:06:31 +0100527 SETUP_STACK_FRAME x8, xNEW_REFS, xNEW_FP, CFI_NEW_REFS, load_ins=0
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000528 // Make x4 point to the top of the dex register array.
529 add x4, xNEW_FP, ip, uxtx #2
530
531 // Fetch instruction information before replacing xPC.
532 // TODO: move this down to the method that uses it, fetching it directly from wINST.
533 FETCH_B w2, 0, 1
534 // TODO: we could avoid this as instance invokes already fetch it.
535 FETCH w3, 2
536
537 // Set the dex pc pointer.
Nicolas Geoffraye1d2dce2020-09-21 10:06:31 +0100538 mov xPC, x8
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000539 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
540.endm
541
542// Setup arguments based on a non-range nterp to nterp call, and start executing
543// the method. We expect:
544// - xNEW_FP: the new pointer to dex registers
545// - xNEW_REFS: the new pointer to references
546// - xPC: the new PC pointer to execute
547// - x2: number of arguments (bits 4-7), 5th argument if any (bits 0-3)
548// - x3: first dex register
549// - x4: top of dex register array
550// - x1: receiver if non-static.
551.macro SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
552 // /* op vA, vB, {vC...vG} */
553 asr ip2, x2, #4
554 cbz ip2, 6f
555 mov ip, #-4
556 cmp ip2, #2
557 b.lt 1f
558 b.eq 2f
559 cmp ip2, #4
560 b.lt 3f
561 b.eq 4f
562
563 // We use a decrementing ip to store references relative
564 // to xNEW_FP and dex registers relative to x4
565 //
566 // TODO: We could set up ip as the number of registers (this can be an additional output from
567 // SETUP_STACK_FOR_INVOKE) and then just decrement it by one before copying each arg.
568 // Maybe even introduce macros NEW_VREG_ADDRESS/NEW_VREG_REF_ADDRESS.
5695:
570 and x2, x2, #15
571 GET_VREG_OBJECT w5, w2
572 str w5, [xNEW_FP, ip]
573 GET_VREG w5, w2
574 str w5, [x4, ip]
575 sub ip, ip, #4
5764:
577 asr x2, x3, #12
578 GET_VREG_OBJECT w5, w2
579 str w5, [xNEW_FP, ip]
580 GET_VREG w5, w2
581 str w5, [x4, ip]
582 sub ip, ip, #4
5833:
584 ubfx x2, x3, #8, #4
585 GET_VREG_OBJECT w5, w2
586 str w5, [xNEW_FP, ip]
587 GET_VREG w5, w2
588 str w5, [x4, ip]
589 sub ip, ip, #4
5902:
591 ubfx x2, x3, #4, #4
592 GET_VREG_OBJECT w5, w2
593 str w5, [xNEW_FP, ip]
594 GET_VREG w5, w2
595 str w5, [x4, ip]
596 .if !\is_string_init
597 sub ip, ip, #4
598 .endif
5991:
600 .if \is_string_init
601 // Ignore the first argument
602 .elseif \is_static
603 and x2, x3, #0xf
604 GET_VREG_OBJECT w5, w2
605 str w5, [xNEW_FP, ip]
606 GET_VREG w5, w2
607 str w5, [x4, ip]
608 .else
609 str w1, [xNEW_FP, ip]
610 str w1, [x4, ip]
611 .endif
612
6136:
614 // Start executing the method.
615 mov xFP, xNEW_FP
616 mov xREFS, xNEW_REFS
Nicolas Geoffrayfaf5f3f2020-07-03 18:36:45 +0100617 CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000618 START_EXECUTING_INSTRUCTIONS
619.endm
620
621// Setup arguments based on a range nterp to nterp call, and start executing
622// the method.
623// - xNEW_FP: the new pointer to dex registers
624// - xNEW_REFS: the new pointer to references
625// - xPC: the new PC pointer to execute
626// - x2: number of arguments
627// - x3: first dex register
628// - x4: top of dex register array
629// - x1: receiver if non-static.
630//
631// Uses ip, ip2, x5, x6 as temporaries.
632.macro SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
633 mov ip, #-4
634 .if \is_string_init
635 // Ignore the first argument
636 sub x2, x2, #1
637 add x3, x3, #1
638 .elseif !\is_static
639 sub x2, x2, #1
640 add x3, x3, #1
641 .endif
642
643 cbz x2, 2f
644 add ip2, xREFS, x3, lsl #2 // pointer to first argument in reference array
645 add ip2, ip2, x2, lsl #2 // pointer to last argument in reference array
646 add x5, xFP, x3, lsl #2 // pointer to first argument in register array
647 add x6, x5, x2, lsl #2 // pointer to last argument in register array
6481:
649 ldr w7, [ip2, #-4]!
650 str w7, [xNEW_FP, ip]
651 sub x2, x2, 1
652 ldr w7, [x6, #-4]!
653 str w7, [x4, ip]
654 sub ip, ip, 4
655 cbnz x2, 1b
6562:
657 .if \is_string_init
658 // Ignore first argument
659 .elseif !\is_static
660 str w1, [xNEW_FP, ip]
661 str w1, [x4, ip]
662 .endif
663 mov xFP, xNEW_FP
664 mov xREFS, xNEW_REFS
Nicolas Geoffrayfaf5f3f2020-07-03 18:36:45 +0100665 CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000666 START_EXECUTING_INSTRUCTIONS
667.endm
668
669.macro GET_SHORTY dest, is_interface, is_polymorphic, is_custom
670 stp x0, x1, [sp, #-16]!
671 .if \is_polymorphic
672 ldr x0, [sp, #16]
673 mov x1, xPC
674 bl NterpGetShortyFromInvokePolymorphic
675 .elseif \is_custom
676 ldr x0, [sp, #16]
677 mov x1, xPC
678 bl NterpGetShortyFromInvokeCustom
679 .elseif \is_interface
680 ldr x0, [sp, #16]
681 FETCH w1, 1
682 bl NterpGetShortyFromMethodId
683 .else
684 bl NterpGetShorty
685 .endif
686 mov \dest, x0
687 ldp x0, x1, [sp], #16
688.endm
689
Nicolas Geoffray5c7cddf2021-03-08 20:06:58 +0000690.macro GET_SHORTY_SLOW_PATH dest, is_interface
691 // Save all registers that can hold arguments in the fast path.
692 stp x0, x1, [sp, #-32]!
693 str w2, [sp, #16]
694 str s0, [sp, #20]
695 .if \is_interface
696 ldr x0, [sp, #32]
697 FETCH w1, 1
698 bl NterpGetShortyFromMethodId
699 .else
700 bl NterpGetShorty
701 .endif
702 mov \dest, x0
703 ldr w2, [sp, #16]
704 ldr s0, [sp, #20]
705 ldp x0, x1, [sp], #32
706.endm
707
Nicolas Geoffray47171752020-08-31 15:03:20 +0100708// Input: x0 contains the ArtMethod
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000709// Output: x8 contains the code item
710.macro GET_CODE_ITEM
Nicolas Geoffray47171752020-08-31 15:03:20 +0100711 ldr x8, [x0, #ART_METHOD_DATA_OFFSET_64]
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000712.endm
713
714.macro DO_ENTRY_POINT_CHECK call_compiled_code
715 // On entry, the method is x0, the instance is x1
716 adr x2, ExecuteNterpImpl
717 ldr x3, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
718 cmp x2, x3
719 b.ne \call_compiled_code
720.endm
721
722.macro UPDATE_REGISTERS_FOR_STRING_INIT old_value, new_value
723 mov wip, wzr
7241:
725 GET_VREG_OBJECT wip2, wip
726 cmp wip2, \old_value
727 b.ne 2f
728 SET_VREG_OBJECT \new_value, wip
7292:
730 add wip, wip, #1
731 add ip2, xREFS, wip, uxtw #2
732 cmp ip2, xFP
733 b.ne 1b
734.endm
735
736// Puts the next floating point argument into the expected register,
737// fetching values based on a non-range invoke.
738// Uses ip and ip2.
739.macro LOOP_OVER_SHORTY_LOADING_FPS dreg, sreg, inst, shorty, arg_index, finished
7401: // LOOP
741 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
742 cbz wip, \finished // if (wip == '\0') goto finished
743 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE
744 b.eq 2f
745 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT
746 b.eq 3f
747 lsr \inst, \inst, #4
748 add \arg_index, \arg_index, #1
749 // Handle extra argument in arg array taken by a long.
750 cmp wip, #74 // if (wip != 'J') goto LOOP
751 b.ne 1b
752 lsr \inst, \inst, #4
753 add \arg_index, \arg_index, #1
754 b 1b // goto LOOP
7552: // FOUND_DOUBLE
756 and ip, \inst, #0xf
757 GET_VREG wip, wip
758 lsr \inst, \inst, #4
759 add \arg_index, \arg_index, #1
760 cmp \arg_index, #4
761 b.eq 5f
762 and ip2, \inst, #0xf
763 lsr \inst, \inst, #4
764 add \arg_index, \arg_index, #1
765 b 6f
7665:
767 // TODO: Extract from wINST here and below? (Requires using a different register
768 // in the COMMON_INVOKE_NON_RANGE.)
769 FETCH_B wip2, 0, 1
770 and wip2, wip2, #0xf
7716:
772 GET_VREG wip2, wip2
773 add ip, ip, ip2, lsl #32
774 fmov \dreg, ip
775 b 4f
7763: // FOUND_FLOAT
777 cmp \arg_index, #4
778 b.eq 7f
779 and ip, \inst, #0xf
780 lsr \inst, \inst, #4
781 add \arg_index, \arg_index, #1
782 b 8f
7837:
784 FETCH_B wip, 0, 1
785 and wip, wip, #0xf
7868:
787 GET_VREG \sreg, wip
7884:
789.endm
790
791// Puts the next int/long/object argument in the expected register,
792// fetching values based on a non-range invoke.
793// Uses ip and ip2.
794.macro LOOP_OVER_SHORTY_LOADING_GPRS gpr_reg64, gpr_reg32, inst, shorty, arg_index, finished
7951: // LOOP
796 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
797 cbz wip, \finished // if (wip == '\0') goto finished
798 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG
799 b.eq 2f
800 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT
801 b.eq 3f
802 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE
803 b.eq 4f
804 cmp \arg_index, #4
805 b.eq 7f
806 and ip, \inst, #0xf
807 lsr \inst, \inst, #4
808 add \arg_index, \arg_index, #1
809 b 8f
8107:
811 FETCH_B wip, 0, 1
812 and wip, wip, #0xf
8138:
814 GET_VREG \gpr_reg32, wip
815 b 5f
8162: // FOUND_LONG
817 and ip, \inst, #0xf
818 GET_VREG wip, wip
819 lsr \inst, \inst, #4
820 add \arg_index, \arg_index, #1
821 cmp \arg_index, #4
822 b.eq 9f
823 and ip2, \inst, #0xf
824 lsr \inst, \inst, #4
825 add \arg_index, \arg_index, #1
826 b 10f
8279:
828 FETCH_B wip2, 0, 1
829 and wip2, wip2, #0xf
83010:
831 GET_VREG wip2, wip2
832 add \gpr_reg64, ip, ip2, lsl #32
833 b 5f
8343: // SKIP_FLOAT
835 lsr \inst, \inst, #4
836 add \arg_index, \arg_index, #1
837 b 1b
8384: // SKIP_DOUBLE
839 lsr \inst, \inst, #4
840 add \arg_index, \arg_index, #1
841 cmp \arg_index, #4
842 b.eq 1b
843 lsr \inst, \inst, #4
844 add \arg_index, \arg_index, #1
845 b 1b
8465:
847.endm
848
Nicolas Geoffray5c7cddf2021-03-08 20:06:58 +0000849.macro SETUP_RETURN_VALUE shorty
850 ldrb wip, [\shorty]
851 cmp ip, #68 // Test if result type char == 'D'.
852 b.eq 1f
853 cmp ip, #70 // Test if result type char == 'F'.
854 b.ne 2f
855 fmov w0, s0
856 b 2f
8571:
858 fmov x0, d0
8592:
860.endm
861
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000862.macro COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
863 .if \is_polymorphic
864 // We always go to compiled code for polymorphic calls.
865 .elseif \is_custom
866 // We always go to compiled code for custom calls.
867 .else
868 DO_ENTRY_POINT_CHECK .Lcall_compiled_code_\suffix
869 GET_CODE_ITEM
870 .if \is_string_init
871 bl nterp_to_nterp_string_init_non_range
872 .elseif \is_static
873 bl nterp_to_nterp_static_non_range
874 .else
875 bl nterp_to_nterp_instance_non_range
876 .endif
877 b .Ldone_return_\suffix
878 .endif
879
880.Lcall_compiled_code_\suffix:
Nicolas Geoffray5c7cddf2021-03-08 20:06:58 +0000881 .if \is_polymorphic
882 // No fast path for polymorphic calls.
883 .elseif \is_custom
884 // No fast path for custom calls.
885 .elseif \is_string_init
886 // No fast path for string.init.
887 .else
Nicolas Geoffray43c9cd72021-03-10 15:09:19 +0000888 ldr wip, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
889 tbz wip, #ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG_BIT, .Lfast_path_with_few_args_\suffix
890 FETCH_B wip2, 0, 1
891 asr ip, ip2, #4
892 .if \is_static
893 cbz ip, .Linvoke_fast_path_\suffix
894 .else
895 cmp ip, #1
896 b.eq .Linvoke_fast_path_\suffix
897 .endif
898 FETCH w8, 2
899 cmp ip, #2
900 .if \is_static
901 b.lt .Lone_arg_fast_path_\suffix
902 .endif
903 b.eq .Ltwo_args_fast_path_\suffix
904 cmp ip, #4
905 b.lt .Lthree_args_fast_path_\suffix
906 b.eq .Lfour_args_fast_path_\suffix
907
908 and ip, ip2, #15
909 GET_VREG w5, wip
910.Lfour_args_fast_path_\suffix:
911 asr ip, x8, #12
912 GET_VREG w4, wip
913.Lthree_args_fast_path_\suffix:
914 ubfx ip, x8, #8, #4
915 GET_VREG w3, wip
916.Ltwo_args_fast_path_\suffix:
917 ubfx ip, x8, #4, #4
918 GET_VREG w2, wip
919.Lone_arg_fast_path_\suffix:
920 .if \is_static
921 and ip, x8, #0xf
922 GET_VREG w1, wip
923 .else
924 // First argument already in w1.
925 .endif
926.Linvoke_fast_path_\suffix:
927 .if \is_interface
928 // Setup hidden argument.
929 mov ip2, x26
930 .endif
931 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
932 blr lr
933 FETCH_ADVANCE_INST 3
934 GET_INST_OPCODE ip
935 GOTO_OPCODE ip
936
937.Lfast_path_with_few_args_\suffix:
Nicolas Geoffray5c7cddf2021-03-08 20:06:58 +0000938 // Fast path when we have zero or one argument (modulo 'this'). If there
939 // is one argument, we can put it in both floating point and core register.
940 FETCH_B w2, 0, 1
941 .if \is_static
942 cmp w2, #(2 << 4)
943 .else
944 cmp w2, #(3 << 4)
945 .endif
946 b.ge .Lget_shorty_\suffix
947 .if \is_static
Nicolas Geoffray43c9cd72021-03-10 15:09:19 +0000948 tbz w2, #4, .Linvoke_with_few_args_\suffix
Nicolas Geoffray5c7cddf2021-03-08 20:06:58 +0000949 .else
Nicolas Geoffray43c9cd72021-03-10 15:09:19 +0000950 tbnz w2, #4, .Linvoke_with_few_args_\suffix
Nicolas Geoffray5c7cddf2021-03-08 20:06:58 +0000951 .endif
952 FETCH w2, 2
953 .if \is_static
954 and w2, w2, #0xf // dex register of first argument
955 GET_VREG w1, w2
956 fmov s0, w1
957 .else
958 ubfx x2, x2, #4, #4 // dex register of second argument
959 GET_VREG w2, w2
960 fmov s0, w2
961 .endif
Nicolas Geoffray43c9cd72021-03-10 15:09:19 +0000962.Linvoke_with_few_args_\suffix:
Nicolas Geoffray5c7cddf2021-03-08 20:06:58 +0000963 // Check if the next instruction is move-result or move-result-wide.
964 // If it is, we fetch the shorty and jump to the regular invocation.
965 FETCH w27, 3
966 and ip, x27, #0xfe
967 cmp ip, #0x0a
968 b.eq .Lget_shorty_and_invoke_\suffix
969 .if \is_interface
970 // Setup hidden argument.
971 mov ip2, x26
972 .endif
973 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
974 blr lr
975 # TODO: Use some other register for shorty and prefetch the instruction directly to wINST.
976 mov xINST, x27
977 ADVANCE 3
978 GET_INST_OPCODE ip
979 GOTO_OPCODE ip
980.Lget_shorty_and_invoke_\suffix:
981 GET_SHORTY_SLOW_PATH xINST, \is_interface
982 b .Lgpr_setup_finished_\suffix
983 .endif
984
985.Lget_shorty_\suffix:
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000986 GET_SHORTY xINST, \is_interface, \is_polymorphic, \is_custom
987 // From this point:
988 // - xINST contains shorty (in callee-save to switch over return value after call).
989 // - x0 contains method
990 // - x1 contains 'this' pointer for instance method.
Nicolas Geoffrayd5a86952021-01-19 10:35:54 +0000991 // - for interface calls, x26 contains the interface method.
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000992 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character
993 FETCH w11, 2 // arguments
994 .if \is_string_init
995 lsr x11, x11, #4
996 mov x10, #1 // ignore first argument
997 .elseif \is_static
998 mov x10, xzr // arg_index
999 .else
1000 lsr x11, x11, #4
1001 mov x10, #1 // ignore first argument
1002 .endif
1003 LOOP_OVER_SHORTY_LOADING_FPS d0, s0, x11, x9, x10, .Lxmm_setup_finished_\suffix
1004 LOOP_OVER_SHORTY_LOADING_FPS d1, s1, x11, x9, x10, .Lxmm_setup_finished_\suffix
1005 LOOP_OVER_SHORTY_LOADING_FPS d2, s2, x11, x9, x10, .Lxmm_setup_finished_\suffix
1006 LOOP_OVER_SHORTY_LOADING_FPS d3, s3, x11, x9, x10, .Lxmm_setup_finished_\suffix
1007 LOOP_OVER_SHORTY_LOADING_FPS d4, s4, x11, x9, x10, .Lxmm_setup_finished_\suffix
1008.Lxmm_setup_finished_\suffix:
1009 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character
1010 FETCH w11, 2 // arguments
1011 .if \is_string_init
1012 lsr x11, x11, #4
1013 mov x10, #1 // ignore first argument
1014 LOOP_OVER_SHORTY_LOADING_GPRS x1, w1, x11, x9, x10, .Lgpr_setup_finished_\suffix
1015 .elseif \is_static
1016 mov x10, xzr // arg_index
1017 LOOP_OVER_SHORTY_LOADING_GPRS x1, w1, x11, x9, x10, .Lgpr_setup_finished_\suffix
1018 .else
1019 lsr x11, x11, #4
1020 mov x10, #1 // ignore first argument
1021 .endif
1022 LOOP_OVER_SHORTY_LOADING_GPRS x2, w2, x11, x9, x10, .Lgpr_setup_finished_\suffix
1023 LOOP_OVER_SHORTY_LOADING_GPRS x3, w3, x11, x9, x10, .Lgpr_setup_finished_\suffix
1024 LOOP_OVER_SHORTY_LOADING_GPRS x4, w4, x11, x9, x10, .Lgpr_setup_finished_\suffix
1025 LOOP_OVER_SHORTY_LOADING_GPRS x5, w5, x11, x9, x10, .Lgpr_setup_finished_\suffix
1026.Lgpr_setup_finished_\suffix:
1027 .if \is_polymorphic
1028 bl art_quick_invoke_polymorphic
1029 .elseif \is_custom
1030 bl art_quick_invoke_custom
1031 .else
1032 .if \is_interface
Nicolas Geoffrayd5a86952021-01-19 10:35:54 +00001033 // Setup hidden argument.
1034 mov ip2, x26
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001035 .endif
1036 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
1037 blr lr
1038 .endif
Nicolas Geoffray5c7cddf2021-03-08 20:06:58 +00001039 SETUP_RETURN_VALUE xINST
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001040.Ldone_return_\suffix:
1041 /* resume execution of caller */
1042 .if \is_string_init
1043 FETCH w11, 2 // arguments
1044 and x11, x11, #0xf
1045 GET_VREG w1, w11
1046 UPDATE_REGISTERS_FOR_STRING_INIT w1, w0
1047 .endif
1048
1049 .if \is_polymorphic
1050 FETCH_ADVANCE_INST 4
1051 .else
1052 FETCH_ADVANCE_INST 3
1053 .endif
1054 GET_INST_OPCODE ip
1055 GOTO_OPCODE ip
1056.endm
1057
1058// Puts the next floating point argument into the expected register,
1059// fetching values based on a range invoke.
1060// Uses ip as temporary.
1061.macro LOOP_RANGE_OVER_SHORTY_LOADING_FPS dreg, sreg, shorty, arg_index, stack_index, finished
10621: // LOOP
1063 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
1064 cbz wip, \finished // if (wip == '\0') goto finished
1065 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE
1066 b.eq 2f
1067 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT
1068 b.eq 3f
1069 add \arg_index, \arg_index, #1
1070 add \stack_index, \stack_index, #1
1071 // Handle extra argument in arg array taken by a long.
1072 cmp wip, #74 // if (wip != 'J') goto LOOP
1073 b.ne 1b
1074 add \arg_index, \arg_index, #1
1075 add \stack_index, \stack_index, #1
1076 b 1b // goto LOOP
10772: // FOUND_DOUBLE
1078 GET_VREG_DOUBLE \dreg, \arg_index
1079 add \arg_index, \arg_index, #2
1080 add \stack_index, \stack_index, #2
1081 b 4f
10823: // FOUND_FLOAT
1083 GET_VREG \sreg, \arg_index
1084 add \arg_index, \arg_index, #1
1085 add \stack_index, \stack_index, #1
10864:
1087.endm
1088
1089// Puts the next floating point argument into the expected stack slot,
1090// fetching values based on a range invoke.
1091// Uses ip as temporary.
1092//
1093// TODO: We could just copy all the vregs to the stack slots in a simple loop
1094// without looking at the shorty at all. (We could also drop
1095// the "stack_index" from the macros for loading registers.) We could also do
1096// that conditionally if argument word count > 6; otherwise we know that all
1097// args fit into registers.
1098.macro LOOP_RANGE_OVER_FPs shorty, arg_index, stack_index, finished
10991: // LOOP
1100 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
1101 cbz wip, \finished // if (wip == '\0') goto finished
1102 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE
1103 b.eq 2f
1104 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT
1105 b.eq 3f
1106 add \arg_index, \arg_index, #1
1107 add \stack_index, \stack_index, #1
1108 // Handle extra argument in arg array taken by a long.
1109 cmp wip, #74 // if (wip != 'J') goto LOOP
1110 b.ne 1b
1111 add \arg_index, \arg_index, #1
1112 add \stack_index, \stack_index, #1
1113 b 1b // goto LOOP
11142: // FOUND_DOUBLE
1115 GET_VREG_WIDE ip, \arg_index
1116 add ip2, sp, \stack_index, uxtw #2
1117 str ip, [ip2]
1118 add \arg_index, \arg_index, #2
1119 add \stack_index, \stack_index, #2
1120 b 1b
11213: // FOUND_FLOAT
1122 GET_VREG wip, \arg_index
1123 str wip, [sp, \stack_index, uxtw #2]
1124 add \arg_index, \arg_index, #1
1125 add \stack_index, \stack_index, #1
1126 b 1b
1127.endm
1128
1129// Puts the next int/long/object argument in the expected register,
1130// fetching values based on a range invoke.
1131// Uses ip as temporary.
1132.macro LOOP_RANGE_OVER_SHORTY_LOADING_GPRS reg64, reg32, shorty, arg_index, stack_index, finished
11331: // LOOP
1134 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
1135 cbz wip, \finished // if (wip == '\0') goto finished
1136 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG
1137 b.eq 2f
1138 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT
1139 b.eq 3f
1140 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE
1141 b.eq 4f
1142 GET_VREG \reg32, \arg_index
1143 add \arg_index, \arg_index, #1
1144 add \stack_index, \stack_index, #1
1145 b 5f
11462: // FOUND_LONG
1147 GET_VREG_WIDE \reg64, \arg_index
1148 add \arg_index, \arg_index, #2
1149 add \stack_index, \stack_index, #2
1150 b 5f
11513: // SKIP_FLOAT
1152 add \arg_index, \arg_index, #1
1153 add \stack_index, \stack_index, #1
1154 b 1b
11554: // SKIP_DOUBLE
1156 add \arg_index, \arg_index, #2
1157 add \stack_index, \stack_index, #2
1158 b 1b
11595:
1160.endm
1161
1162// Puts the next int/long/object argument in the expected stack slot,
1163// fetching values based on a range invoke.
1164// Uses ip as temporary.
1165.macro LOOP_RANGE_OVER_INTs shorty, arg_index, stack_index, finished
11661: // LOOP
1167 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
1168 cbz wip, \finished // if (wip == '\0') goto finished
1169 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG
1170 b.eq 2f
1171 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT
1172 b.eq 3f
1173 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE
1174 b.eq 4f
1175 GET_VREG wip, \arg_index
1176 str wip, [sp, \stack_index, uxtw #2]
1177 add \arg_index, \arg_index, #1
1178 add \stack_index, \stack_index, #1
1179 b 1b
11802: // FOUND_LONG
1181 GET_VREG_WIDE ip, \arg_index
1182 add ip2, sp, \stack_index, uxtw #2
1183 str ip, [ip2]
1184 add \arg_index, \arg_index, #2
1185 add \stack_index, \stack_index, #2
1186 b 1b
11873: // SKIP_FLOAT
1188 add \arg_index, \arg_index, #1
1189 add \stack_index, \stack_index, #1
1190 b 1b
11914: // SKIP_DOUBLE
1192 add \arg_index, \arg_index, #2
1193 add \stack_index, \stack_index, #2
1194 b 1b
1195.endm
1196
1197.macro COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
1198 .if \is_polymorphic
1199 // We always go to compiled code for polymorphic calls.
1200 .elseif \is_custom
1201 // We always go to compiled code for custom calls.
1202 .else
1203 DO_ENTRY_POINT_CHECK .Lcall_compiled_code_range_\suffix
1204 GET_CODE_ITEM
1205 .if \is_string_init
1206 bl nterp_to_nterp_string_init_range
1207 .elseif \is_static
1208 bl nterp_to_nterp_static_range
1209 .else
1210 bl nterp_to_nterp_instance_range
1211 .endif
1212 b .Ldone_return_range_\suffix
1213 .endif
1214
1215.Lcall_compiled_code_range_\suffix:
Nicolas Geoffray5c7cddf2021-03-08 20:06:58 +00001216 .if \is_polymorphic
1217 // No fast path for polymorphic calls.
1218 .elseif \is_custom
1219 // No fast path for custom calls.
1220 .elseif \is_string_init
1221 // No fast path for string.init.
1222 .else
Nicolas Geoffray43c9cd72021-03-10 15:09:19 +00001223 ldr wip, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
1224 tbz wip, #ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG_BIT, .Lfast_path_with_few_args_range_\suffix
1225 FETCH_B wip2, 0, 1 // Number of arguments
1226 .if \is_static
1227 cbz ip2, .Linvoke_fast_path_range_\suffix
1228 .else
1229 cmp ip2, #1
1230 b.eq .Linvoke_fast_path_range_\suffix
1231 .endif
1232 FETCH wip, 2 // dex register of first argument
1233 add x8, xFP, wip, uxtw #2 // location of first dex register value
1234 cmp ip2, #2
1235 .if \is_static
1236 b.lt .Lone_arg_fast_path_range_\suffix
1237 .endif
1238 b.eq .Ltwo_args_fast_path_range_\suffix
1239 cmp ip2, #4
1240 b.lt .Lthree_args_fast_path_range_\suffix
1241 b.eq .Lfour_args_fast_path_range_\suffix
1242 cmp ip2, #6
1243 b.lt .Lfive_args_fast_path_range_\suffix
1244 b.eq .Lsix_args_fast_path_range_\suffix
1245 cmp ip2, #7
1246 b.eq .Lseven_args_fast_path_range_\suffix
1247 // Setup x8 to point to the stack location of parameters we do not need
1248 // to put parameters in.
1249 add x9, sp, #8 // Add space for the ArtMethod
1250
1251.Lloop_over_fast_path_range_\suffix:
1252 sub ip2, ip2, #1
1253 ldr wip, [x8, ip2, lsl #2]
1254 str wip, [x9, ip2, lsl #2]
1255 cmp ip2, #7
1256 b.ne .Lloop_over_fast_path_range_\suffix
1257
1258.Lseven_args_fast_path_range_\suffix:
1259 ldr w7, [x8, #24]
1260.Lsix_args_fast_path_range_\suffix:
1261 ldr w6, [x8, #20]
1262.Lfive_args_fast_path_range_\suffix:
1263 ldr w5, [x8, #16]
1264.Lfour_args_fast_path_range_\suffix:
1265 ldr w4, [x8, #12]
1266.Lthree_args_fast_path_range_\suffix:
1267 ldr w3, [x8, #8]
1268.Ltwo_args_fast_path_range_\suffix:
1269 ldr w2, [x8, #4]
1270.Lone_arg_fast_path_range_\suffix:
1271 .if \is_static
1272 ldr w1, [x8, #0]
1273 .else
1274 // First argument already in w1.
1275 .endif
1276.Linvoke_fast_path_range_\suffix:
1277 .if \is_interface
1278 // Setup hidden argument.
1279 mov ip2, x26
1280 .endif
1281 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
1282 blr lr
1283 FETCH_ADVANCE_INST 3
1284 GET_INST_OPCODE ip
1285 GOTO_OPCODE ip
1286
1287.Lfast_path_with_few_args_range_\suffix:
Nicolas Geoffray5c7cddf2021-03-08 20:06:58 +00001288 // Fast path when we have zero or one argument (modulo 'this'). If there
1289 // is one argument, we can put it in both floating point and core register.
1290 FETCH_B w2, 0, 1 // number of arguments
1291 .if \is_static
1292 cmp w2, #1
1293 .else
1294 cmp w2, #2
1295 .endif
Nicolas Geoffray43c9cd72021-03-10 15:09:19 +00001296 b.lt .Linvoke_with_few_args_range_\suffix
Nicolas Geoffray5c7cddf2021-03-08 20:06:58 +00001297 b.ne .Lget_shorty_range_\suffix
1298 FETCH w3, 2 // dex register of first argument
1299 .if \is_static
1300 GET_VREG w1, w3
1301 fmov s0, w1
1302 .else
1303 add w3, w3, #1 // Add 1 for next argument
1304 GET_VREG w2, w3
1305 fmov s0, w2
1306 .endif
Nicolas Geoffray43c9cd72021-03-10 15:09:19 +00001307.Linvoke_with_few_args_range_\suffix:
Nicolas Geoffray5c7cddf2021-03-08 20:06:58 +00001308 // Check if the next instruction is move-result or move-result-wide.
1309 // If it is, we fetch the shorty and jump to the regular invocation.
1310 FETCH w27, 3
1311 and ip, x27, #0xfe
1312 cmp ip, #0x0a
1313 b.eq .Lget_shorty_and_invoke_range_\suffix
1314 .if \is_interface
1315 // Setup hidden argument.
1316 mov ip2, x26
1317 .endif
1318 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
1319 blr lr
1320 mov xINST, x27
1321 ADVANCE 3
1322 GET_INST_OPCODE ip
1323 GOTO_OPCODE ip
1324.Lget_shorty_and_invoke_range_\suffix:
1325 GET_SHORTY_SLOW_PATH xINST, \is_interface
1326 b .Lgpr_setup_finished_range_\suffix
1327 .endif
1328
1329.Lget_shorty_range_\suffix:
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001330 GET_SHORTY xINST, \is_interface, \is_polymorphic, \is_custom
1331 // From this point:
1332 // - xINST contains shorty (in callee-save to switch over return value after call).
1333 // - x0 contains method
1334 // - x1 contains 'this' pointer for instance method.
Nicolas Geoffrayd5a86952021-01-19 10:35:54 +00001335 // - for interface calls, x26 contains the interface method.
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001336 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character
1337 FETCH w10, 2 // arguments
1338 .if \is_string_init
1339 add x10, x10, #1 // arg start index
1340 mov x11, #1 // index in stack
1341 .elseif \is_static
1342 mov x11, xzr // index in stack
1343 .else
1344 add x10, x10, #1 // arg start index
1345 mov x11, #1 // index in stack
1346 .endif
1347 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d0, s0, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1348 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d1, s1, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1349 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d2, s2, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1350 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d3, s3, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1351 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d4, s4, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1352 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d5, s5, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1353 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d6, s6, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1354 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d7, s7, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1355 // Store in the outs array (stored above the ArtMethod in the stack)
1356 add x11, x11, #2 // Add two words for the ArtMethod stored before the outs.
1357 LOOP_RANGE_OVER_FPs x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1358.Lxmm_setup_finished_range_\suffix:
1359 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character
1360 FETCH w10, 2 // arguments
1361 .if \is_string_init
1362 add x10, x10, #1 // arg start index
1363 mov x11, #1 // index in stack
Nicolas Geoffray4483d2a2020-11-16 09:42:20 +00001364 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x1, w1, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001365 .elseif \is_static
1366 mov x11, xzr // index in stack
Nicolas Geoffray4483d2a2020-11-16 09:42:20 +00001367 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x1, w1, x9, w10, w11 .Lgpr_setup_finished_range_\suffix
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001368 .else
1369 add x10, x10, #1 // arg start index
1370 mov x11, #1 // index in stack
1371 .endif
1372 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x2, w2, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1373 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x3, w3, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1374 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x4, w4, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1375 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x5, w5, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1376 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x6, w6, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1377 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x7, w7, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1378 // Store in the outs array (stored above the ArtMethod in the stack)
1379 add x11, x11, #2 // Add two words for the ArtMethod stored before the outs.
1380 LOOP_RANGE_OVER_INTs x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1381.Lgpr_setup_finished_range_\suffix:
1382 .if \is_polymorphic
1383 bl art_quick_invoke_polymorphic
1384 .elseif \is_custom
1385 bl art_quick_invoke_custom
1386 .else
1387 .if \is_interface
Nicolas Geoffrayd5a86952021-01-19 10:35:54 +00001388 // Setup hidden argument.
1389 mov ip2, x26
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001390 .endif
1391 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
1392 blr lr
1393 .endif
Nicolas Geoffray5c7cddf2021-03-08 20:06:58 +00001394 SETUP_RETURN_VALUE xINST
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001395.Ldone_return_range_\suffix:
1396 /* resume execution of caller */
1397 .if \is_string_init
1398 FETCH w11, 2 // arguments
1399 GET_VREG w1, w11
1400 UPDATE_REGISTERS_FOR_STRING_INIT w1, w0
1401 .endif
1402
1403 .if \is_polymorphic
Nicolas Geoffray5c7cddf2021-03-08 20:06:58 +00001404 FETCH_ADVANCE_INST 4
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001405 .else
1406 FETCH_ADVANCE_INST 3
1407 .endif
1408 GET_INST_OPCODE ip
1409 GOTO_OPCODE ip
1410.endm
1411
Vladimir Marko955f40f2020-12-03 14:53:29 +00001412.macro WRITE_BARRIER_IF_OBJECT is_object, value, holder, label
1413 .if \is_object
1414 cbz \value, \label
1415 ldr ip, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1416 lsr wip2, \holder, #CARD_TABLE_CARD_SHIFT
1417 strb wip, [ip, ip2]
1418\label:
1419 .endif
1420.endm
1421
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001422// Fetch some information from the thread cache.
1423// Uses ip and ip2 as temporaries.
1424.macro FETCH_FROM_THREAD_CACHE dest_reg, slow_path
1425 add ip, xSELF, #THREAD_INTERPRETER_CACHE_OFFSET // cache address
1426 ubfx ip2, xPC, #2, #THREAD_INTERPRETER_CACHE_SIZE_LOG2 // entry index
1427 add ip, ip, ip2, lsl #4 // entry address within the cache
1428 ldp ip, \dest_reg, [ip] // entry key (pc) and value (offset)
1429 cmp ip, xPC
1430 b.ne \slow_path
1431.endm
1432
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001433// Puts the next int/long/object parameter passed in physical register
1434// in the expected dex register array entry, and in case of object in the
1435// expected reference array entry.
1436.macro LOOP_OVER_SHORTY_STORING_GPRS gpr_64, gpr_32, shorty, arg_offset, regs, refs, finished
14371: // LOOP
1438 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
1439 cbz wip, \finished // if (wip == '\0') goto finished
1440 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG
1441 b.eq 2f
1442 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT
1443 b.eq 3f
1444 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE
1445 b.eq 4f
1446 str \gpr_32, [\regs, \arg_offset]
1447 cmp wip, #76 // if (wip != 'L') goto NOT_REFERENCE
1448 b.ne 6f
1449 str \gpr_32, [\refs, \arg_offset]
14506: // NOT_REFERENCE
1451 add \arg_offset, \arg_offset, #4
1452 b 5f
14532: // FOUND_LONG
1454 str \gpr_64, [\regs, \arg_offset]
1455 add \arg_offset, \arg_offset, #8
1456 b 5f
14573: // SKIP_FLOAT
1458 add \arg_offset, \arg_offset, #4
1459 b 1b
14604: // SKIP_DOUBLE
1461 add \arg_offset, \arg_offset, #8
1462 b 1b
14635:
1464.endm
1465
1466// Puts the next floating point parameter passed in physical register
1467// in the expected dex register array entry.
1468// Uses ip as temporary.
1469.macro LOOP_OVER_SHORTY_STORING_FPS dreg, sreg, shorty, arg_offset, fp, finished
14701: // LOOP
1471 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
1472 cbz wip, \finished // if (wip == '\0') goto finished
1473 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE
1474 b.eq 2f
1475 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT
1476 b.eq 3f
1477 add \arg_offset, \arg_offset, #4
1478 // Handle extra argument in arg array taken by a long.
1479 cmp wip, #74 // if (wip != 'J') goto LOOP
1480 b.ne 1b
1481 add \arg_offset, \arg_offset, #4
1482 b 1b // goto LOOP
14832: // FOUND_DOUBLE
1484 str \dreg, [\fp, \arg_offset]
1485 add \arg_offset, \arg_offset, #8
1486 b 4f
14873: // FOUND_FLOAT
1488 str \sreg, [\fp, \arg_offset]
1489 add \arg_offset, \arg_offset, #4
14904:
1491.endm
1492
1493// Puts the next floating point parameter passed in stack
1494// in the expected dex register array entry.
1495// Uses ip as temporary.
1496//
1497// TODO: Or we could just spill regs to the reserved slots in the caller's
1498// frame and copy all regs in a simple loop. This time, however, we would
1499// need to look at the shorty anyway to look for the references.
1500// (The trade-off is different for passing arguments and receiving them.)
1501.macro LOOP_OVER_FPs shorty, arg_offset, regs, stack_ptr, finished
15021: // LOOP
1503 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
1504 cbz wip, \finished // if (wip == '\0') goto finished
1505 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE
1506 b.eq 2f
1507 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT
1508 b.eq 3f
1509 add \arg_offset, \arg_offset, #4
1510 // Handle extra argument in arg array taken by a long.
1511 cmp wip, #74 // if (wip != 'J') goto LOOP
1512 b.ne 1b
1513 add \arg_offset, \arg_offset, #4
1514 b 1b // goto LOOP
15152: // FOUND_DOUBLE
1516 add ip, \stack_ptr, \arg_offset
1517 ldr ip, [ip, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1518 str ip, [\regs, \arg_offset]
1519 add \arg_offset, \arg_offset, #8
1520 b 1b
15213: // FOUND_FLOAT
1522 add ip, \stack_ptr, \arg_offset
1523 ldr wip, [ip, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1524 str wip, [\regs, \arg_offset]
1525 add \arg_offset, \arg_offset, #4
1526 b 1b
1527.endm
1528
1529// Puts the next int/long/object parameter passed in stack
1530// in the expected dex register array entry, and in case of object in the
1531// expected reference array entry.
1532// Uses ip and ip2 as temporary.
1533.macro LOOP_OVER_INTs shorty, arg_offset, regs, refs, stack_ptr, finished
15341: // LOOP
1535 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
1536 cbz wip, \finished // if (wip == '\0') goto finished
1537 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG
1538 b.eq 2f
1539 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT
1540 b.eq 3f
1541 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE
1542 b.eq 4f
1543 add ip2, \stack_ptr, \arg_offset
1544 ldr wip2, [ip2, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1545 str wip2, [\regs, \arg_offset]
1546 cmp wip, #76 // if (wip != 'L') goto loop
1547 b.ne 3f
1548 str wip2, [\refs, \arg_offset]
1549 add \arg_offset, \arg_offset, #4
1550 b 1b
15512: // FOUND_LONG
1552 add ip, \stack_ptr, \arg_offset
1553 ldr ip, [ip, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1554 str ip, [\regs, \arg_offset]
1555 add \arg_offset, \arg_offset, #8
1556 b 1b
15573: // SKIP_FLOAT
1558 add \arg_offset, \arg_offset, #4
1559 b 1b
15604: // SKIP_DOUBLE
1561 add \arg_offset, \arg_offset, #8
1562 b 1b
1563.endm
1564
Nicolas Geoffray40cd07c2021-03-15 18:33:23 +00001565.macro SETUP_REFERENCE_PARAMETER_IN_GPR gpr32, regs, refs, ins, arg_offset, finished
1566 str \gpr32, [\regs, \arg_offset]
1567 sub \ins, \ins, #1
1568 str \gpr32, [\refs, \arg_offset]
1569 add \arg_offset, \arg_offset, #4
1570 cbz \ins, \finished
1571.endm
1572
1573// Uses ip2 as temporary.
1574.macro SETUP_REFERENCE_PARAMETERS_IN_STACK regs, refs, ins, stack_ptr, arg_offset
15751:
1576 ldr wip2, [\stack_ptr, \arg_offset]
1577 sub \ins, \ins, #1
1578 str wip2, [\regs, \arg_offset]
1579 str wip2, [\refs, \arg_offset]
1580 add \arg_offset, \arg_offset, #4
1581 cbnz \ins, 1b
1582.endm
1583
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001584%def entry():
1585/*
1586 * ArtMethod entry point.
1587 *
1588 * On entry:
1589 * x0 ArtMethod* callee
1590 * rest method parameters
1591 */
1592
1593OAT_ENTRY ExecuteNterpImpl, EndExecuteNterpImpl
1594 .cfi_startproc
1595 sub x16, sp, #STACK_OVERFLOW_RESERVED_BYTES
1596 ldr wzr, [x16]
1597 /* Spill callee save regs */
1598 SPILL_ALL_CALLEE_SAVES
1599
Nicolas Geoffrayaeb7f9f2020-11-11 13:39:18 +00001600 ldr xPC, [x0, #ART_METHOD_DATA_OFFSET_64]
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001601 // Setup the stack for executing the method.
Nicolas Geoffraye1d2dce2020-09-21 10:06:31 +01001602 SETUP_STACK_FRAME xPC, xREFS, xFP, CFI_REFS, load_ins=1
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001603
1604 // Setup the parameters
Nicolas Geoffraye1d2dce2020-09-21 10:06:31 +01001605 cbz w15, .Lxmm_setup_finished
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001606
Nicolas Geoffraye1d2dce2020-09-21 10:06:31 +01001607 sub ip2, ip, x15
Nicolas Geoffraye5859642021-01-08 18:09:36 +00001608 ldr w26, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
1609 lsl x21, ip2, #2 // x21 is now the offset for inputs into the registers array.
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001610
Nicolas Geoffray40cd07c2021-03-15 18:33:23 +00001611 tbz w26, #ART_METHOD_NTERP_ENTRY_POINT_FAST_PATH_FLAG_BIT, .Lsetup_slow_path
1612 // Setup pointer to inputs in FP and pointer to inputs in REFS
1613 add x10, xFP, x21
1614 add x11, xREFS, x21
1615 mov x12, #0
1616 SETUP_REFERENCE_PARAMETER_IN_GPR w1, x10, x11, w15, x12, .Lxmm_setup_finished
1617 SETUP_REFERENCE_PARAMETER_IN_GPR w2, x10, x11, w15, x12, .Lxmm_setup_finished
1618 SETUP_REFERENCE_PARAMETER_IN_GPR w3, x10, x11, w15, x12, .Lxmm_setup_finished
1619 SETUP_REFERENCE_PARAMETER_IN_GPR w4, x10, x11, w15, x12, .Lxmm_setup_finished
1620 SETUP_REFERENCE_PARAMETER_IN_GPR w5, x10, x11, w15, x12, .Lxmm_setup_finished
1621 SETUP_REFERENCE_PARAMETER_IN_GPR w6, x10, x11, w15, x12, .Lxmm_setup_finished
1622 SETUP_REFERENCE_PARAMETER_IN_GPR w7, x10, x11, w15, x12, .Lxmm_setup_finished
1623 add x28, x28, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK
1624 SETUP_REFERENCE_PARAMETERS_IN_STACK x10, x11, w15, x28, x12
1625 b .Lxmm_setup_finished
1626
1627.Lsetup_slow_path:
Nicolas Geoffraye5859642021-01-08 18:09:36 +00001628 // If the method is not static and there is one argument ('this'), we don't need to fetch the
1629 // shorty.
1630 tbnz w26, #ART_METHOD_IS_STATIC_FLAG_BIT, .Lsetup_with_shorty
1631 str w1, [xFP, x21]
1632 str w1, [xREFS, x21]
1633 cmp w15, #1
1634 b.eq .Lxmm_setup_finished
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001635
Nicolas Geoffraye5859642021-01-08 18:09:36 +00001636.Lsetup_with_shorty:
1637 // TODO: Get shorty in a better way and remove below
1638 SPILL_ALL_ARGUMENTS
1639 bl NterpGetShorty
1640 // Save shorty in callee-save xIBASE.
1641 mov xIBASE, x0
1642 RESTORE_ALL_ARGUMENTS
1643
1644 // Setup pointer to inputs in FP and pointer to inputs in REFS
1645 add x10, xFP, x21
1646 add x11, xREFS, x21
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001647 mov x12, #0
Nicolas Geoffraye5859642021-01-08 18:09:36 +00001648
1649 add x9, xIBASE, #1 // shorty + 1 ; ie skip return arg character
1650 tbnz w26, #ART_METHOD_IS_STATIC_FLAG_BIT, .Lhandle_static_method
1651 add x10, x10, #4
1652 add x11, x11, #4
1653 add x28, x28, #4
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001654 b .Lcontinue_setup_gprs
1655.Lhandle_static_method:
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001656 LOOP_OVER_SHORTY_STORING_GPRS x1, w1, x9, x12, x10, x11, .Lgpr_setup_finished
1657.Lcontinue_setup_gprs:
1658 LOOP_OVER_SHORTY_STORING_GPRS x2, w2, x9, x12, x10, x11, .Lgpr_setup_finished
1659 LOOP_OVER_SHORTY_STORING_GPRS x3, w3, x9, x12, x10, x11, .Lgpr_setup_finished
1660 LOOP_OVER_SHORTY_STORING_GPRS x4, w4, x9, x12, x10, x11, .Lgpr_setup_finished
1661 LOOP_OVER_SHORTY_STORING_GPRS x5, w5, x9, x12, x10, x11, .Lgpr_setup_finished
1662 LOOP_OVER_SHORTY_STORING_GPRS x6, w6, x9, x12, x10, x11, .Lgpr_setup_finished
1663 LOOP_OVER_SHORTY_STORING_GPRS x7, w7, x9, x12, x10, x11, .Lgpr_setup_finished
Nicolas Geoffraye5859642021-01-08 18:09:36 +00001664 LOOP_OVER_INTs x9, x12, x10, x11, x28, .Lgpr_setup_finished
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001665.Lgpr_setup_finished:
1666 add x9, xIBASE, #1 // shorty + 1 ; ie skip return arg character
1667 mov x12, #0 // reset counter
1668 LOOP_OVER_SHORTY_STORING_FPS d0, s0, x9, x12, x10, .Lxmm_setup_finished
1669 LOOP_OVER_SHORTY_STORING_FPS d1, s1, x9, x12, x10, .Lxmm_setup_finished
1670 LOOP_OVER_SHORTY_STORING_FPS d2, s2, x9, x12, x10, .Lxmm_setup_finished
1671 LOOP_OVER_SHORTY_STORING_FPS d3, s3, x9, x12, x10, .Lxmm_setup_finished
1672 LOOP_OVER_SHORTY_STORING_FPS d4, s4, x9, x12, x10, .Lxmm_setup_finished
1673 LOOP_OVER_SHORTY_STORING_FPS d5, s5, x9, x12, x10, .Lxmm_setup_finished
1674 LOOP_OVER_SHORTY_STORING_FPS d6, s6, x9, x12, x10, .Lxmm_setup_finished
1675 LOOP_OVER_SHORTY_STORING_FPS d7, s7, x9, x12, x10, .Lxmm_setup_finished
Nicolas Geoffraye5859642021-01-08 18:09:36 +00001676 LOOP_OVER_FPs x9, x12, x10, x28, .Lxmm_setup_finished
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001677.Lxmm_setup_finished:
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001678 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
1679
1680 // Set rIBASE
1681 adr xIBASE, artNterpAsmInstructionStart
1682 /* start executing the instruction at xPC */
1683 START_EXECUTING_INSTRUCTIONS
1684 /* NOTE: no fallthrough */
1685 // cfi info continues, and covers the whole nterp implementation.
1686 SIZE ExecuteNterpImpl
1687
1688%def opcode_pre():
1689
1690%def helpers():
1691
1692%def footer():
1693/*
1694 * ===========================================================================
1695 * Common subroutines and data
1696 * ===========================================================================
1697 */
1698
1699 .text
1700 .align 2
1701
David Srbecky14a814b2021-03-12 13:33:29 +00001702// Enclose all code below in a symbol (which gets printed in backtraces).
1703NAME_START nterp_helper
1704
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001705// Note: mterp also uses the common_* names below for helpers, but that's OK
Vladimir Marko955f40f2020-12-03 14:53:29 +00001706// as the assembler compiled each interpreter separately.
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001707common_errDivideByZero:
1708 EXPORT_PC
1709 bl art_quick_throw_div_zero
1710
Nicolas Geoffrayaeb7f9f2020-11-11 13:39:18 +00001711// Expect index in w1, length in w3.
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001712common_errArrayIndex:
1713 EXPORT_PC
1714 mov x0, x1
1715 mov x1, x3
1716 bl art_quick_throw_array_bounds
1717
1718common_errNullObject:
1719 EXPORT_PC
1720 bl art_quick_throw_null_pointer_exception
1721
1722NterpCommonInvokeStatic:
1723 COMMON_INVOKE_NON_RANGE is_static=1, suffix="invokeStatic"
1724
1725NterpCommonInvokeStaticRange:
1726 COMMON_INVOKE_RANGE is_static=1, suffix="invokeStatic"
1727
1728NterpCommonInvokeInstance:
1729 COMMON_INVOKE_NON_RANGE suffix="invokeInstance"
1730
1731NterpCommonInvokeInstanceRange:
1732 COMMON_INVOKE_RANGE suffix="invokeInstance"
1733
1734NterpCommonInvokeInterface:
1735 COMMON_INVOKE_NON_RANGE is_interface=1, suffix="invokeInterface"
1736
1737NterpCommonInvokeInterfaceRange:
1738 COMMON_INVOKE_RANGE is_interface=1, suffix="invokeInterface"
1739
1740NterpCommonInvokePolymorphic:
1741 COMMON_INVOKE_NON_RANGE is_polymorphic=1, suffix="invokePolymorphic"
1742
1743NterpCommonInvokePolymorphicRange:
1744 COMMON_INVOKE_RANGE is_polymorphic=1, suffix="invokePolymorphic"
1745
1746NterpCommonInvokeCustom:
1747 COMMON_INVOKE_NON_RANGE is_static=1, is_custom=1, suffix="invokeCustom"
1748
1749NterpCommonInvokeCustomRange:
1750 COMMON_INVOKE_RANGE is_static=1, is_custom=1, suffix="invokeCustom"
1751
1752NterpHandleStringInit:
1753 COMMON_INVOKE_NON_RANGE is_string_init=1, suffix="stringInit"
1754
1755NterpHandleStringInitRange:
1756 COMMON_INVOKE_RANGE is_string_init=1, suffix="stringInit"
1757
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001758NterpNewArray:
1759 /* new-array vA, vB, class@CCCC */
1760 EXPORT_PC
1761 // Fast-path which gets the class from thread-local cache.
1762 FETCH_FROM_THREAD_CACHE x0, 2f
Nicolas Geoffrayafae11f2021-11-10 16:45:13 +00001763 TEST_IF_MARKING 3f
Nicolas Geoffray4fc75692020-01-13 21:49:22 +000017641:
1765 lsr w1, wINST, #12 // w1<- B
1766 GET_VREG w1, w1 // w1<- vB (array length)
1767 ldr lr, [xSELF, #THREAD_ALLOC_ARRAY_ENTRYPOINT_OFFSET]
1768 blr lr
1769 ubfx w1, wINST, #8, #4 // w1<- A
1770 SET_VREG_OBJECT w0, w1
1771 FETCH_ADVANCE_INST 2
1772 GET_INST_OPCODE ip
1773 GOTO_OPCODE ip
17742:
1775 mov x0, xSELF
1776 ldr x1, [sp, 0]
1777 mov x2, xPC
1778 bl nterp_get_class_or_allocate_object
1779 b 1b
17803:
1781 bl art_quick_read_barrier_mark_reg00
1782 b 1b
1783
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001784NterpHandleHotnessOverflow:
1785 add x1, xPC, xINST, lsl #1
1786 mov x2, xFP
1787 bl nterp_hot_method
1788 cbnz x0, 1f
Vladimir Marko98fa40a2021-03-15 14:04:43 +00001789 add xPC, xPC, wINST, sxtw #1 // update xPC
1790 FETCH wINST, 0 // load wINST
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001791 GET_INST_OPCODE ip // extract opcode from wINST
1792 GOTO_OPCODE ip // jump to next instruction
17931:
1794 // Drop the current frame.
1795 ldr ip, [xREFS, #-8]
1796 mov sp, ip
1797 .cfi_def_cfa sp, CALLEE_SAVES_SIZE
1798
1799 // The transition frame of type SaveAllCalleeSaves saves x19 and x20,
1800 // but not managed ABI. So we need to restore callee-saves of the nterp frame,
1801 // and save managed ABI callee saves, which will be restored by the callee upon
1802 // return.
1803 RESTORE_ALL_CALLEE_SAVES
1804 INCREASE_FRAME ((CALLEE_SAVES_SIZE) - 16)
1805
1806 // FP callee-saves
1807 stp d8, d9, [sp, #0]
1808 stp d10, d11, [sp, #16]
1809 stp d12, d13, [sp, #32]
1810 stp d14, d15, [sp, #48]
1811
1812 // GP callee-saves.
1813 SAVE_TWO_REGS x21, x22, 64
1814 SAVE_TWO_REGS x23, x24, 80
1815 SAVE_TWO_REGS x25, x26, 96
1816 SAVE_TWO_REGS x27, x28, 112
1817 SAVE_TWO_REGS x29, lr, 128
1818
1819 // Setup the new frame
1820 ldr x1, [x0, #OSR_DATA_FRAME_SIZE]
1821 // Given stack size contains all callee saved registers, remove them.
1822 sub x1, x1, #(CALLEE_SAVES_SIZE - 16)
1823
1824 // We know x1 cannot be 0, as it at least contains the ArtMethod.
1825
1826 // Remember CFA in a callee-save register.
1827 mov xINST, sp
1828 .cfi_def_cfa_register xINST
1829
1830 sub sp, sp, x1
1831
1832 add x2, x0, #OSR_DATA_MEMORY
18332:
1834 sub x1, x1, #8
1835 ldr ip, [x2, x1]
1836 str ip, [sp, x1]
1837 cbnz x1, 2b
1838
1839 // Fetch the native PC to jump to and save it in a callee-save register.
1840 ldr xFP, [x0, #OSR_DATA_NATIVE_PC]
1841
1842 // Free the memory holding OSR Data.
1843 bl free
1844
1845 // Jump to the compiled code.
1846 br xFP
1847
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001848// This is the logical end of ExecuteNterpImpl, where the frame info applies.
1849// EndExecuteNterpImpl includes the methods below as we want the runtime to
1850// see them as part of the Nterp PCs.
1851.cfi_endproc
1852
1853nterp_to_nterp_static_non_range:
1854 .cfi_startproc
1855 SETUP_STACK_FOR_INVOKE
1856 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0
1857 .cfi_endproc
1858
1859nterp_to_nterp_string_init_non_range:
1860 .cfi_startproc
1861 SETUP_STACK_FOR_INVOKE
1862 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1
1863 .cfi_endproc
1864
1865nterp_to_nterp_instance_non_range:
1866 .cfi_startproc
1867 SETUP_STACK_FOR_INVOKE
1868 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
1869 .cfi_endproc
1870
1871nterp_to_nterp_static_range:
1872 .cfi_startproc
1873 SETUP_STACK_FOR_INVOKE
1874 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=1
1875 .cfi_endproc
1876
1877nterp_to_nterp_instance_range:
1878 .cfi_startproc
1879 SETUP_STACK_FOR_INVOKE
1880 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0
1881 .cfi_endproc
1882
1883nterp_to_nterp_string_init_range:
1884 .cfi_startproc
1885 SETUP_STACK_FOR_INVOKE
1886 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1
1887 .cfi_endproc
1888
David Srbecky14a814b2021-03-12 13:33:29 +00001889NAME_END nterp_helper
1890
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001891// This is the end of PCs contained by the OatQuickMethodHeader created for the interpreter
1892// entry point.
1893 .type EndExecuteNterpImpl, #function
1894 .hidden EndExecuteNterpImpl
1895 .global EndExecuteNterpImpl
1896EndExecuteNterpImpl:
1897
1898// Entrypoints into runtime.
1899NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField
1900NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset
1901NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray
1902NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange
1903NTERP_TRAMPOLINE nterp_get_class_or_allocate_object, NterpGetClassOrAllocateObject
1904NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod
1905NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod
1906NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject
1907
1908// gen_mterp.py will inline the following definitions
1909// within [ExecuteNterpImpl, EndExecuteNterpImpl).
1910%def instruction_end():
1911
1912 .type artNterpAsmInstructionEnd, #function
1913 .hidden artNterpAsmInstructionEnd
1914 .global artNterpAsmInstructionEnd
1915artNterpAsmInstructionEnd:
1916 // artNterpAsmInstructionEnd is used as landing pad for exception handling.
1917 FETCH_INST
1918 GET_INST_OPCODE ip
1919 GOTO_OPCODE ip
1920
1921%def instruction_start():
1922
1923 .type artNterpAsmInstructionStart, #function
1924 .hidden artNterpAsmInstructionStart
1925 .global artNterpAsmInstructionStart
1926artNterpAsmInstructionStart = .L_op_nop
1927 .text
1928
Vladimir Marko955f40f2020-12-03 14:53:29 +00001929%def default_helper_prefix():
1930% return "nterp_"
1931
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001932%def opcode_start():
1933 NAME_START nterp_${opcode}
1934%def opcode_end():
1935 NAME_END nterp_${opcode}
1936%def helper_start(name):
1937 NAME_START ${name}
1938%def helper_end(name):
1939 NAME_END ${name}