xref: /aosp_15_r20/art/runtime/interpreter/mterp/arm64ng/main.S (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1%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"
24
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 *   x21  xSUSPEND  suspend check register
65 *   x29  xFP       interpreted frame pointer, used for accessing locals and args
66 *   x22  xPC       interpreted program counter, used for fetching instructions
67 *   x23  xINST     first 16-bit code unit of current instruction
68 *   x24  xIBASE    interpreted instruction base pointer, used for computed goto
69 *   x25  xREFS     base of object references of dex registers.
70 *   x16  ip        scratch reg
71 *   x17  ip2       scratch reg (used by macros)
72 *
73 * Macros are provided for common operations.  They MUST NOT alter unspecified registers or
74 * condition codes.
75*/
76
77/* single-purpose registers, given names for clarity */
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/*
143 * 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
194.macro SET_VREG_OBJECT reg, vreg
195    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 LOAD_SCALED_VREG_MASK scaled_mask_reg, unscaled_mask
207    mov     \scaled_mask_reg, \unscaled_mask << 2
208.endm
209.macro EXTRACT_SCALED_VREG scaled_vreg, scaled_mask_reg, src_reg, lsb
210    .if \lsb < 2
211    and     \scaled_vreg, \scaled_mask_reg, \src_reg, lsl #(2 - \lsb)
212    .else
213    and     \scaled_vreg, \scaled_mask_reg, \src_reg, lsr #(\lsb - 2)
214    .endif
215.endm
216.macro GET_VREG_WIDE_PRESCALED reg, scaled_vreg
217    ldr     \reg, [xFP, \scaled_vreg, uxtw]
218.endm
219.macro GET_VREG_WIDE reg, vreg
220    lsl     wip2, \vreg, #2
221    GET_VREG_WIDE_PRESCALED \reg, wip2
222.endm
223.macro SET_VREG_WIDE_PRESCALED reg, scaled_vreg
224    str     \reg, [xFP, \scaled_vreg, uxtw]
225    str     xzr, [xREFS, \scaled_vreg, uxtw]
226.endm
227.macro SET_VREG_WIDE reg, vreg
228    lsl     wip2, \vreg, #2
229    SET_VREG_WIDE_PRESCALED \reg, wip2
230.endm
231.macro GET_VREG_DOUBLE_PRESCALED reg, scaled_vreg
232    GET_VREG_WIDE_PRESCALED \reg, \scaled_vreg
233.endm
234.macro GET_VREG_DOUBLE reg, vreg
235    GET_VREG_WIDE \reg, \vreg
236.endm
237.macro SET_VREG_DOUBLE reg, vreg
238    SET_VREG_WIDE \reg, \vreg
239.endm
240
241/*
242 * Get the 32-bit value from a Dalvik register and sign-extend to 64-bit.
243 * Used to avoid an extra instruction in int-to-long.
244 */
245.macro GET_VREG_S reg, vreg
246    ldrsw   \reg, [xFP, \vreg, uxtw #2]
247.endm
248
249// An assembly entry for nterp.
250.macro OAT_ENTRY name
251    .type \name, #function
252    .hidden \name
253    .global \name
254    .balign 16
255\name:
256.endm
257
258.macro SIZE name
259    .size \name, .-\name
260.endm
261
262.macro NAME_START name
263    .type \name, #function
264    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
265    .global \name
266    /* Cache alignment for function entry */
267    .balign 16
268\name:
269.endm
270
271.macro NAME_END name
272  SIZE \name
273.endm
274
275// Macro for defining entrypoints into runtime. We don't need to save registers
276// (we're not holding references there), but there is no
277// kDontSave runtime method. So just use the kSaveRefsOnly runtime method.
278.macro NTERP_TRAMPOLINE name, helper
279ENTRY \name
280  SETUP_SAVE_REFS_ONLY_FRAME
281  bl \helper
282  RESTORE_SAVE_REFS_ONLY_FRAME
283  REFRESH_MARKING_REGISTER
284  ldr xIP0, [xSELF, # THREAD_EXCEPTION_OFFSET]   // Get exception field.
285  cbnz xIP0, nterp_deliver_pending_exception
286  ret
287END \name
288.endm
289
290.macro CLEAR_STATIC_VOLATILE_MARKER reg
291  and \reg, \reg, #-2
292.endm
293
294.macro CLEAR_INSTANCE_VOLATILE_MARKER reg
295  neg \reg, \reg
296.endm
297
298.macro EXPORT_PC
299    str    xPC, [xREFS, #-16]
300.endm
301
302.macro BRANCH
303    add     xPC, xPC, wINST, sxtw #1    // update xPC
304    // Update method counter and do a suspend check if the branch is negative or zero.
305    cmp wINST, #0
306    b.le 2f
3071:
308    FETCH wINST, 0                      // load wINST
309    GET_INST_OPCODE ip                  // extract opcode from wINST
310    GOTO_OPCODE ip                      // jump to next instruction
3112:
312    ldr x0, [sp]
313    ldrh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
314#if (NTERP_HOTNESS_VALUE != 0)
315#error Expected 0 for hotness value
316#endif
317    // If the counter is at zero, handle this in the runtime.
318    cbz w2, NterpHandleHotnessOverflow
319    add x2, x2, #-1
320    strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
321    DO_SUSPEND_CHECK continue_label=1b
322    b 1b
323.endm
324
325// Uses x12, x13, and x14 as temporaries.
326.macro FETCH_CODE_ITEM_INFO code_item, registers, outs, ins, load_ins
327    // Fetch dex register size.
328    ldrh \registers, [\code_item, #CODE_ITEM_REGISTERS_SIZE_OFFSET]
329    // Fetch outs size.
330    ldrh \outs, [\code_item, #CODE_ITEM_OUTS_SIZE_OFFSET]
331    .if \load_ins
332    ldrh \ins, [\code_item, #CODE_ITEM_INS_SIZE_OFFSET]
333    .endif
334    add \code_item, \code_item, #CODE_ITEM_INSNS_OFFSET
335.endm
336
337.macro TEST_IF_MARKING label
338    cbnz wMR, \label
339.endm
340
341// Setup the stack to start executing the method. Expects:
342// - x0 to contain the ArtMethod
343//
344// Outputs
345// - ip contains the dex registers size
346// - x28 contains the old stack pointer.
347// - \code_item is replaced with a pointer to the instructions
348// - if load_ins is 1, w15 contains the ins
349//
350// Uses ip, ip2, x12, x13, x14 as temporaries.
351.macro SETUP_STACK_FRAME code_item, refs, fp, cfi_refs, load_ins
352    FETCH_CODE_ITEM_INFO \code_item, wip, wip2, w15, \load_ins
353
354    // Compute required frame size: ((2 * ip) + ip2) * 4 + 24
355    // 24 is for saving the previous frame, pc, and method being executed.
356    add x14, ip, ip
357    add x14, x14, ip2
358    lsl x14, x14, #2
359    add x14, x14, #24
360
361    // Compute new stack pointer in x14
362    sub x14, sp, x14
363    // Alignment
364    and x14, x14, #-16
365
366    // Set reference and dex registers, align to pointer size for previous frame and dex pc.
367    add \refs, x14, ip2, lsl #2
368    add \refs, \refs, 28
369    and \refs, \refs, #(-__SIZEOF_POINTER__)
370    add \fp, \refs, ip, lsl #2
371
372    // Now setup the stack pointer.
373    mov x28, sp
374    .cfi_def_cfa_register x28
375    mov sp, x14
376    str x28, [\refs, #-8]
377    CFI_DEF_CFA_BREG_PLUS_UCONST \cfi_refs, -8, CALLEE_SAVES_SIZE
378
379    // Put nulls in reference frame.
380    cbz ip, 2f
381    mov ip2, \refs
3821:
383    str xzr, [ip2], #8  // May clear vreg[0].
384    cmp ip2, \fp
385    b.lo 1b
3862:
387    // Save the ArtMethod.
388    str x0, [sp]
389.endm
390
391// Increase method hotness and do suspend check before starting executing the method.
392.macro START_EXECUTING_INSTRUCTIONS
393    ldr x0, [sp]
394    ldrh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
395#if (NTERP_HOTNESS_VALUE != 0)
396#error Expected 0 for hotness value
397#endif
398    // If the counter is at zero, handle this in the runtime.
399    cbz w2, 3f
400    add x2, x2, #-1
401    strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
4021:
403    DO_SUSPEND_CHECK continue_label=2f
4042:
405    FETCH_INST
406    GET_INST_OPCODE ip
407    GOTO_OPCODE ip
4083:
409    CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot=4f, if_not_hot=1b
4104:
411    mov x1, xzr
412    mov x2, xFP
413    bl nterp_hot_method
414    b 2b
415.endm
416
417.macro SPILL_ALL_CALLEE_SAVES
418    INCREASE_FRAME CALLEE_SAVES_SIZE
419    // Note: we technically don't need to save x19 and x20,
420    // but the runtime will expect those values to be there when unwinding
421    // (see Arm64Context::DoLongJump checking for the thread register).
422    SAVE_ALL_CALLEE_SAVES 0
423.endm
424
425.macro RESTORE_ALL_CALLEE_SAVES
426    // FP callee-saves
427    ldp d8, d9, [sp, #0]
428    ldp d10, d11, [sp, #16]
429    ldp d12, d13, [sp, #32]
430    ldp d14, d15, [sp, #48]
431
432    // GP callee-saves.
433    // No need to restore x19 (it's always the thread), and
434    // don't restore x20 (the marking register) as it may have been updated,
435    // don't restore x21 (the suspend check register) as it may have been updated.
436    RESTORE_REG      x22, 88
437    RESTORE_TWO_REGS x23, x24, 96
438    RESTORE_TWO_REGS x25, x26, 112
439    RESTORE_TWO_REGS x27, x28, 128
440    RESTORE_TWO_REGS x29, lr, 144
441
442    DECREASE_FRAME CALLEE_SAVES_SIZE
443.endm
444
445.macro SPILL_ALL_ARGUMENTS
446    stp x0, x1, [sp, #-128]!
447    stp x2, x3, [sp, #16]
448    stp x4, x5, [sp, #32]
449    stp x6, x7, [sp, #48]
450    stp d0, d1, [sp, #64]
451    stp d2, d3, [sp, #80]
452    stp d4, d5, [sp, #96]
453    stp d6, d7, [sp, #112]
454.endm
455
456.macro RESTORE_ALL_ARGUMENTS
457    ldp x2, x3, [sp, #16]
458    ldp x4, x5, [sp, #32]
459    ldp x6, x7, [sp, #48]
460    ldp d0, d1, [sp, #64]
461    ldp d2, d3, [sp, #80]
462    ldp d4, d5, [sp, #96]
463    ldp d6, d7, [sp, #112]
464    ldp x0, x1, [sp], #128
465.endm
466
467// Helper to setup the stack after doing a nterp to nterp call. This will setup:
468// - xNEW_FP: the new pointer to dex registers
469// - xNEW_REFS: the new pointer to references
470// - xPC: the new PC pointer to execute
471// - x2: value in instruction to decode the number of arguments.
472// - x3: first dex register
473// - x4: top of dex register array
474//
475// The method expects:
476// - x0 to contain the ArtMethod
477// - x8 to contain the code item
478.macro SETUP_STACK_FOR_INVOKE
479   // We do the same stack overflow check as the compiler. See CanMethodUseNterp
480   // in how we limit the maximum nterp frame size.
481   sub x16, sp, #STACK_OVERFLOW_RESERVED_BYTES
482   ldr wzr, [x16]
483
484   // Spill all callee saves to have a consistent stack frame whether we
485   // are called by compiled code or nterp.
486   SPILL_ALL_CALLEE_SAVES
487
488   // Setup the frame.
489   SETUP_STACK_FRAME x8, xNEW_REFS, xNEW_FP, CFI_NEW_REFS, load_ins=0
490   // Make x4 point to the top of the dex register array.
491   add x4, xNEW_FP, ip, uxtx #2
492
493   // Fetch instruction information before replacing xPC.
494   // TODO: move this down to the method that uses it, fetching it directly from wINST.
495   FETCH_B w2, 0, 1
496   // TODO: we could avoid this as instance invokes already fetch it.
497   FETCH w3, 2
498
499   // Set the dex pc pointer.
500   mov xPC, x8
501   CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
502.endm
503
504// Setup arguments based on a non-range nterp to nterp call, and start executing
505// the method. We expect:
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: number of arguments (bits 4-7), 5th argument if any (bits 0-3)
510// - x3: first dex register
511// - x4: top of dex register array
512// - x1: receiver if non-static.
513.macro SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
514   // /* op vA, vB, {vC...vG} */
515   asr ip2, x2, #4
516   cbz ip2, 6f
517   mov ip, #-4
518   cmp ip2, #2
519   b.lt 1f
520   b.eq 2f
521   cmp ip2, #4
522   b.lt 3f
523   b.eq 4f
524
525  // We use a decrementing ip to store references relative
526  // to xNEW_FP and dex registers relative to x4
527  //
528  // TODO: We could set up ip as the number of registers (this can be an additional output from
529  // SETUP_STACK_FOR_INVOKE) and then just decrement it by one before copying each arg.
530  // Maybe even introduce macros NEW_VREG_ADDRESS/NEW_VREG_REF_ADDRESS.
5315:
532   and         x2, x2, #15
533   GET_VREG_OBJECT w5, w2
534   str         w5, [xNEW_FP, ip]
535   GET_VREG    w5, w2
536   str         w5, [x4, ip]
537   sub         ip, ip, #4
5384:
539   asr         x2, x3, #12
540   GET_VREG_OBJECT w5, w2
541   str         w5, [xNEW_FP, ip]
542   GET_VREG    w5, w2
543   str         w5, [x4, ip]
544   sub         ip, ip, #4
5453:
546   ubfx        x2, x3, #8, #4
547   GET_VREG_OBJECT w5, w2
548   str         w5, [xNEW_FP, ip]
549   GET_VREG    w5, w2
550   str         w5, [x4, ip]
551   sub         ip, ip, #4
5522:
553   ubfx        x2, x3, #4, #4
554   GET_VREG_OBJECT w5, w2
555   str         w5, [xNEW_FP, ip]
556   GET_VREG    w5, w2
557   str         w5, [x4, ip]
558   .if !\is_string_init
559   sub         ip, ip, #4
560   .endif
5611:
562   .if \is_string_init
563   // Ignore the first argument
564   .elseif \is_static
565   and         x2, x3, #0xf
566   GET_VREG_OBJECT w5, w2
567   str         w5, [xNEW_FP, ip]
568   GET_VREG    w5, w2
569   str         w5, [x4, ip]
570   .else
571   str         w1, [xNEW_FP, ip]
572   str         w1, [x4, ip]
573   .endif
574
5756:
576   // Start executing the method.
577   mov xFP, xNEW_FP
578   mov xREFS, xNEW_REFS
579   CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE
580   START_EXECUTING_INSTRUCTIONS
581.endm
582
583// Setup arguments based on a range nterp to nterp call, and start executing
584// the method.
585// - xNEW_FP: the new pointer to dex registers
586// - xNEW_REFS: the new pointer to references
587// - xPC: the new PC pointer to execute
588// - x2: number of arguments
589// - x3: first dex register
590// - x4: top of dex register array
591// - x1: receiver if non-static.
592//
593// Uses ip, ip2, x5, x6 as temporaries.
594.macro SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
595   mov ip, #-4
596   .if \is_string_init
597   // Ignore the first argument
598   sub x2, x2, #1
599   add x3, x3, #1
600   .elseif !\is_static
601   sub x2, x2, #1
602   add x3, x3, #1
603   .endif
604
605   cbz x2, 2f
606   add ip2, xREFS, x3, lsl #2  // pointer to first argument in reference array
607   add ip2, ip2, x2, lsl #2    // pointer to last argument in reference array
608   add x5, xFP, x3, lsl #2     // pointer to first argument in register array
609   add x6, x5, x2, lsl #2      // pointer to last argument in register array
6101:
611   ldr  w7, [ip2, #-4]!
612   str  w7, [xNEW_FP, ip]
613   sub  x2, x2, 1
614   ldr  w7, [x6, #-4]!
615   str  w7, [x4, ip]
616   sub ip, ip, 4
617   cbnz x2, 1b
6182:
619   .if \is_string_init
620   // Ignore first argument
621   .elseif !\is_static
622   str w1, [xNEW_FP, ip]
623   str w1, [x4, ip]
624   .endif
625   mov xFP, xNEW_FP
626   mov xREFS, xNEW_REFS
627   CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE
628   START_EXECUTING_INSTRUCTIONS
629.endm
630
631.macro GET_SHORTY dest, is_interface, is_polymorphic, is_custom
632   stp x0, x1, [sp, #-16]!
633   .if \is_polymorphic
634   ldr x0, [sp, #16]
635   mov x1, xPC
636   bl NterpGetShortyFromInvokePolymorphic
637   .elseif \is_custom
638   ldr x0, [sp, #16]
639   mov x1, xPC
640   bl NterpGetShortyFromInvokeCustom
641   .elseif \is_interface
642   ldr x0, [sp, #16]
643   FETCH w1, 1
644   bl NterpGetShortyFromMethodId
645   .else
646   bl NterpGetShorty
647   .endif
648   mov \dest, x0
649   ldp x0, x1, [sp], #16
650.endm
651
652.macro GET_SHORTY_SLOW_PATH dest, is_interface
653   // Save all registers that can hold arguments in the fast path.
654   stp x0, x1, [sp, #-32]!
655   str w2, [sp, #16]
656   str s0, [sp, #20]
657   .if \is_interface
658   ldr x0, [sp, #32]
659   FETCH w1, 1
660   bl NterpGetShortyFromMethodId
661   .else
662   bl NterpGetShorty
663   .endif
664   mov \dest, x0
665   ldr w2, [sp, #16]
666   ldr s0, [sp, #20]
667   ldp x0, x1, [sp], #32
668.endm
669
670// Input:  x0 contains the ArtMethod
671// Output: x8 contains the code item
672.macro GET_CODE_ITEM
673   ldr x8, [x0, #ART_METHOD_DATA_OFFSET_64]
674.endm
675
676.macro DO_ENTRY_POINT_CHECK call_compiled_code
677   // On entry, the method is x0, the instance is x1
678   adr x2, ExecuteNterpImpl
679   ldr x3, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
680   cmp x2, x3
681   b.ne  \call_compiled_code
682.endm
683
684.macro UPDATE_REGISTERS_FOR_STRING_INIT old_value, new_value
685   mov wip, wzr
6861:
687   GET_VREG_OBJECT wip2, wip
688   cmp wip2, \old_value
689   b.ne 2f
690   SET_VREG_OBJECT \new_value, wip
6912:
692   add wip, wip, #1
693   add ip2, xREFS, wip, uxtw #2
694   cmp ip2, xFP
695   b.ne 1b
696.endm
697
698// Puts the next floating point argument into the expected register,
699// fetching values based on a non-range invoke.
700// Uses ip and ip2.
701.macro LOOP_OVER_SHORTY_LOADING_FPS dreg, sreg, inst, shorty, arg_index, finished
7021: // LOOP
703    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
704    cbz wip, \finished              // if (wip == '\0') goto finished
705    cmp wip, #68                    // if (wip == 'D') goto FOUND_DOUBLE
706    b.eq 2f
707    cmp wip, #70                    // if (wip == 'F') goto FOUND_FLOAT
708    b.eq 3f
709    lsr \inst, \inst, #4
710    add \arg_index, \arg_index, #1
711    //  Handle extra argument in arg array taken by a long.
712    cmp wip, #74                   // if (wip != 'J') goto LOOP
713    b.ne 1b
714    lsr \inst, \inst, #4
715    add \arg_index, \arg_index, #1
716    b 1b                        // goto LOOP
7172:  // FOUND_DOUBLE
718    and ip, \inst, #0xf
719    GET_VREG wip, wip
720    lsr \inst, \inst, #4
721    add \arg_index, \arg_index, #1
722    cmp \arg_index, #4
723    b.eq 5f
724    and ip2, \inst, #0xf
725    lsr \inst, \inst, #4
726    add \arg_index, \arg_index, #1
727    b 6f
7285:
729    // TODO: Extract from wINST here and below? (Requires using a different register
730    // in the COMMON_INVOKE_NON_RANGE.)
731    FETCH_B wip2, 0, 1
732    and wip2, wip2, #0xf
7336:
734    GET_VREG wip2, wip2
735    add ip, ip, ip2, lsl #32
736    fmov \dreg, ip
737    b 4f
7383:  // FOUND_FLOAT
739    cmp \arg_index, #4
740    b.eq 7f
741    and ip, \inst, #0xf
742    lsr \inst, \inst, #4
743    add \arg_index, \arg_index, #1
744    b 8f
7457:
746    FETCH_B wip, 0, 1
747    and wip, wip, #0xf
7488:
749    GET_VREG \sreg, wip
7504:
751.endm
752
753// Puts the next int/long/object argument in the expected register,
754// fetching values based on a non-range invoke.
755// Uses ip and ip2.
756.macro LOOP_OVER_SHORTY_LOADING_GPRS gpr_reg64, gpr_reg32, inst, shorty, arg_index, finished
7571: // LOOP
758    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
759    cbz wip, \finished              // if (wip == '\0') goto finished
760    cmp wip, #74                    // if (wip == 'J') goto FOUND_LONG
761    b.eq 2f
762    cmp wip, #70                    // if (wip == 'F') goto SKIP_FLOAT
763    b.eq 3f
764    cmp wip, #68                    // if (wip == 'D') goto SKIP_DOUBLE
765    b.eq 4f
766    cmp \arg_index, #4
767    b.eq 7f
768    and ip, \inst, #0xf
769    lsr \inst, \inst, #4
770    add \arg_index, \arg_index, #1
771    b 8f
7727:
773    FETCH_B wip, 0, 1
774    and wip, wip, #0xf
7758:
776    GET_VREG \gpr_reg32, wip
777    b 5f
7782:  // FOUND_LONG
779    and ip, \inst, #0xf
780    GET_VREG wip, wip
781    lsr \inst, \inst, #4
782    add \arg_index, \arg_index, #1
783    cmp \arg_index, #4
784    b.eq 9f
785    and ip2, \inst, #0xf
786    lsr \inst, \inst, #4
787    add \arg_index, \arg_index, #1
788    b 10f
7899:
790    FETCH_B wip2, 0, 1
791    and wip2, wip2, #0xf
79210:
793    GET_VREG wip2, wip2
794    add \gpr_reg64, ip, ip2, lsl #32
795    b 5f
7963:  // SKIP_FLOAT
797    lsr \inst, \inst, #4
798    add \arg_index, \arg_index, #1
799    b 1b
8004:  // SKIP_DOUBLE
801    lsr \inst, \inst, #4
802    add \arg_index, \arg_index, #1
803    cmp \arg_index, #4
804    b.eq 1b
805    lsr \inst, \inst, #4
806    add \arg_index, \arg_index, #1
807    b 1b
8085:
809.endm
810
811.macro SETUP_RETURN_VALUE shorty
812   ldrb wip, [\shorty]
813   cmp ip, #68       // Test if result type char == 'D'.
814   b.eq 1f
815   cmp ip, #70       // Test if result type char == 'F'.
816   b.ne 2f
817   fmov w0, s0
818   b 2f
8191:
820   fmov x0, d0
8212:
822.endm
823
824.macro COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
825   .if \is_polymorphic
826   // We always go to compiled code for polymorphic calls.
827   .elseif \is_custom
828   // We always go to compiled code for custom calls.
829   .else
830     DO_ENTRY_POINT_CHECK .Lcall_compiled_code_\suffix
831     GET_CODE_ITEM
832     .if \is_string_init
833     bl nterp_to_nterp_string_init_non_range
834     .elseif \is_static
835     bl nterp_to_nterp_static_non_range
836     .else
837     bl nterp_to_nterp_instance_non_range
838     .endif
839     b .Ldone_return_\suffix
840   .endif
841
842.Lcall_compiled_code_\suffix:
843   .if \is_polymorphic
844   // No fast path for polymorphic calls.
845   .elseif \is_custom
846   // No fast path for custom calls.
847   .elseif \is_string_init
848   // No fast path for string.init.
849   .else
850     ldr wip, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
851     tbz wip, #ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG_BIT, .Lfast_path_with_few_args_\suffix
852     FETCH_B wip2, 0, 1
853     asr ip, ip2, #4
854     .if \is_static
855     cbz ip, .Linvoke_fast_path_\suffix
856     .else
857     cmp ip, #1
858     b.eq .Linvoke_fast_path_\suffix
859     .endif
860     FETCH w8, 2
861     cmp ip, #2
862     .if \is_static
863     b.lt .Lone_arg_fast_path_\suffix
864     .endif
865     b.eq .Ltwo_args_fast_path_\suffix
866     cmp ip, #4
867     b.lt .Lthree_args_fast_path_\suffix
868     b.eq .Lfour_args_fast_path_\suffix
869
870     and         ip, ip2, #15
871     GET_VREG    w5, wip
872.Lfour_args_fast_path_\suffix:
873     asr         ip, x8, #12
874     GET_VREG    w4, wip
875.Lthree_args_fast_path_\suffix:
876     ubfx        ip, x8, #8, #4
877     GET_VREG    w3, wip
878.Ltwo_args_fast_path_\suffix:
879     ubfx        ip, x8, #4, #4
880     GET_VREG    w2, wip
881.Lone_arg_fast_path_\suffix:
882     .if \is_static
883     and         ip, x8, #0xf
884     GET_VREG    w1, wip
885     .else
886     // First argument already in w1.
887     .endif
888.Linvoke_fast_path_\suffix:
889     .if \is_interface
890     // Setup hidden argument.
891     mov ip2, x26
892     .endif
893     ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
894     blr lr
895     FETCH_ADVANCE_INST 3
896     GET_INST_OPCODE ip
897     GOTO_OPCODE ip
898
899.Lfast_path_with_few_args_\suffix:
900     // Fast path when we have zero or one argument (modulo 'this'). If there
901     // is one argument, we can put it in both floating point and core register.
902     FETCH_B w2, 0, 1
903     .if \is_static
904     cmp w2, #(2 << 4)
905     .else
906     cmp w2, #(3 << 4)
907     .endif
908     b.ge .Lget_shorty_\suffix
909     .if \is_static
910     tbz w2, #4, .Linvoke_with_few_args_\suffix
911     .else
912     tbnz w2, #4, .Linvoke_with_few_args_\suffix
913     .endif
914     FETCH w2, 2
915     .if \is_static
916     and w2, w2, #0xf  // dex register of first argument
917     GET_VREG w1, w2
918     fmov s0, w1
919     .else
920     ubfx x2, x2, #4, #4  // dex register of second argument
921     GET_VREG w2, w2
922     fmov s0, w2
923     .endif
924.Linvoke_with_few_args_\suffix:
925     // Check if the next instruction is move-result or move-result-wide.
926     // If it is, we fetch the shorty and jump to the regular invocation.
927     FETCH w27, 3
928     and ip, x27, #0xfe
929     cmp ip, #0x0a
930     b.eq .Lget_shorty_and_invoke_\suffix
931     .if \is_interface
932     // Setup hidden argument.
933     mov ip2, x26
934     .endif
935     ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
936     blr lr
937     # TODO: Use some other register for shorty and prefetch the instruction directly to wINST.
938     mov xINST, x27
939     ADVANCE 3
940     GET_INST_OPCODE ip
941     GOTO_OPCODE ip
942.Lget_shorty_and_invoke_\suffix:
943     GET_SHORTY_SLOW_PATH xINST, \is_interface
944     b .Lgpr_setup_finished_\suffix
945   .endif
946
947.Lget_shorty_\suffix:
948   GET_SHORTY xINST, \is_interface, \is_polymorphic, \is_custom
949   // From this point:
950   // - xINST contains shorty (in callee-save to switch over return value after call).
951   // - x0 contains method
952   // - x1 contains 'this' pointer for instance method.
953   // - for interface calls, x26 contains the interface method.
954   add x9, xINST, #1  // shorty + 1  ; ie skip return arg character
955   FETCH w11, 2 // arguments
956   .if \is_string_init
957   lsr x11, x11, #4
958   mov x10, #1       // ignore first argument
959   .elseif \is_static
960   mov x10, xzr      // arg_index
961   .else
962   lsr x11, x11, #4
963   mov x10, #1       // ignore first argument
964   .endif
965   LOOP_OVER_SHORTY_LOADING_FPS d0, s0, x11, x9, x10, .Lxmm_setup_finished_\suffix
966   LOOP_OVER_SHORTY_LOADING_FPS d1, s1, x11, x9, x10, .Lxmm_setup_finished_\suffix
967   LOOP_OVER_SHORTY_LOADING_FPS d2, s2, x11, x9, x10, .Lxmm_setup_finished_\suffix
968   LOOP_OVER_SHORTY_LOADING_FPS d3, s3, x11, x9, x10, .Lxmm_setup_finished_\suffix
969   LOOP_OVER_SHORTY_LOADING_FPS d4, s4, x11, x9, x10, .Lxmm_setup_finished_\suffix
970.Lxmm_setup_finished_\suffix:
971   add x9, xINST, #1  // shorty + 1  ; ie skip return arg character
972   FETCH w11, 2 // arguments
973   .if \is_string_init
974   lsr x11, x11, #4
975   mov x10, #1       // ignore first argument
976   LOOP_OVER_SHORTY_LOADING_GPRS x1, w1, x11, x9, x10, .Lgpr_setup_finished_\suffix
977   .elseif \is_static
978   mov x10, xzr      // arg_index
979   LOOP_OVER_SHORTY_LOADING_GPRS x1, w1, x11, x9, x10, .Lgpr_setup_finished_\suffix
980   .else
981   lsr x11, x11, #4
982   mov x10, #1       // ignore first argument
983   .endif
984   LOOP_OVER_SHORTY_LOADING_GPRS x2, w2, x11, x9, x10, .Lgpr_setup_finished_\suffix
985   LOOP_OVER_SHORTY_LOADING_GPRS x3, w3, x11, x9, x10, .Lgpr_setup_finished_\suffix
986   LOOP_OVER_SHORTY_LOADING_GPRS x4, w4, x11, x9, x10, .Lgpr_setup_finished_\suffix
987   LOOP_OVER_SHORTY_LOADING_GPRS x5, w5, x11, x9, x10, .Lgpr_setup_finished_\suffix
988.Lgpr_setup_finished_\suffix:
989   .if \is_polymorphic
990   bl art_quick_invoke_polymorphic
991   .elseif \is_custom
992   bl art_quick_invoke_custom
993   .else
994      .if \is_interface
995      // Setup hidden argument.
996      mov ip2, x26
997      .endif
998      ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
999      blr lr
1000   .endif
1001   SETUP_RETURN_VALUE xINST
1002.Ldone_return_\suffix:
1003   /* resume execution of caller */
1004   .if \is_string_init
1005   FETCH w11, 2 // arguments
1006   and x11, x11, #0xf
1007   GET_VREG w1, w11
1008   UPDATE_REGISTERS_FOR_STRING_INIT w1, w0
1009   .endif
1010
1011   .if \is_polymorphic
1012   FETCH_ADVANCE_INST 4
1013   .else
1014   FETCH_ADVANCE_INST 3
1015   .endif
1016   GET_INST_OPCODE ip
1017   GOTO_OPCODE ip
1018.endm
1019
1020// Puts the next floating point argument into the expected register,
1021// fetching values based on a range invoke.
1022// Uses ip as temporary.
1023.macro LOOP_RANGE_OVER_SHORTY_LOADING_FPS dreg, sreg, shorty, arg_index, stack_index, finished
10241: // LOOP
1025    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
1026    cbz wip, \finished              // if (wip == '\0') goto finished
1027    cmp wip, #68                    // if (wip == 'D') goto FOUND_DOUBLE
1028    b.eq 2f
1029    cmp wip, #70                    // if (wip == 'F') goto FOUND_FLOAT
1030    b.eq 3f
1031    add \arg_index, \arg_index, #1
1032    add \stack_index, \stack_index, #1
1033    //  Handle extra argument in arg array taken by a long.
1034    cmp wip, #74                    // if (wip != 'J') goto LOOP
1035    b.ne 1b
1036    add \arg_index, \arg_index, #1
1037    add \stack_index, \stack_index, #1
1038    b 1b                        // goto LOOP
10392:  // FOUND_DOUBLE
1040    GET_VREG_DOUBLE \dreg, \arg_index
1041    add \arg_index, \arg_index, #2
1042    add \stack_index, \stack_index, #2
1043    b 4f
10443:  // FOUND_FLOAT
1045    GET_VREG \sreg, \arg_index
1046    add \arg_index, \arg_index, #1
1047    add \stack_index, \stack_index, #1
10484:
1049.endm
1050
1051// Puts the next floating point argument into the expected stack slot,
1052// fetching values based on a range invoke.
1053// Uses ip as temporary.
1054//
1055// TODO: We could just copy all the vregs to the stack slots in a simple loop
1056// without looking at the shorty at all. (We could also drop
1057// the "stack_index" from the macros for loading registers.) We could also do
1058// that conditionally if argument word count > 6; otherwise we know that all
1059// args fit into registers.
1060.macro LOOP_RANGE_OVER_FPs shorty, arg_index, stack_index, finished
10611: // LOOP
1062    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
1063    cbz wip, \finished              // if (wip == '\0') goto finished
1064    cmp wip, #68                    // if (wip == 'D') goto FOUND_DOUBLE
1065    b.eq 2f
1066    cmp wip, #70                    // if (wip == 'F') goto FOUND_FLOAT
1067    b.eq 3f
1068    add \arg_index, \arg_index, #1
1069    add \stack_index, \stack_index, #1
1070    //  Handle extra argument in arg array taken by a long.
1071    cmp wip, #74                    // if (wip != 'J') goto LOOP
1072    b.ne 1b
1073    add \arg_index, \arg_index, #1
1074    add \stack_index, \stack_index, #1
1075    b 1b                        // goto LOOP
10762:  // FOUND_DOUBLE
1077    GET_VREG_WIDE ip, \arg_index
1078    add ip2, sp, \stack_index, uxtw #2
1079    str ip, [ip2]
1080    add \arg_index, \arg_index, #2
1081    add \stack_index, \stack_index, #2
1082    b 1b
10833:  // FOUND_FLOAT
1084    GET_VREG wip, \arg_index
1085    str wip, [sp, \stack_index, uxtw #2]
1086    add \arg_index, \arg_index, #1
1087    add \stack_index, \stack_index, #1
1088    b 1b
1089.endm
1090
1091// Puts the next int/long/object argument in the expected register,
1092// fetching values based on a range invoke.
1093// Uses ip as temporary.
1094.macro LOOP_RANGE_OVER_SHORTY_LOADING_GPRS reg64, reg32, shorty, arg_index, stack_index, finished
10951: // LOOP
1096    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
1097    cbz wip, \finished              // if (wip == '\0') goto finished
1098    cmp wip, #74                    // if (wip == 'J') goto FOUND_LONG
1099    b.eq 2f
1100    cmp wip, #70                   // if (wip == 'F') goto SKIP_FLOAT
1101    b.eq 3f
1102    cmp wip, #68                    // if (wip == 'D') goto SKIP_DOUBLE
1103    b.eq 4f
1104    GET_VREG \reg32, \arg_index
1105    add \arg_index, \arg_index, #1
1106    add \stack_index, \stack_index, #1
1107    b 5f
11082:  // FOUND_LONG
1109    GET_VREG_WIDE \reg64, \arg_index
1110    add \arg_index, \arg_index, #2
1111    add \stack_index, \stack_index, #2
1112    b 5f
11133:  // SKIP_FLOAT
1114    add \arg_index, \arg_index, #1
1115    add \stack_index, \stack_index, #1
1116    b 1b
11174:  // SKIP_DOUBLE
1118    add \arg_index, \arg_index, #2
1119    add \stack_index, \stack_index, #2
1120    b 1b
11215:
1122.endm
1123
1124// Puts the next int/long/object argument in the expected stack slot,
1125// fetching values based on a range invoke.
1126// Uses ip as temporary.
1127.macro LOOP_RANGE_OVER_INTs shorty, arg_index, stack_index, finished
11281: // LOOP
1129    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
1130    cbz wip, \finished              // if (wip == '\0') goto finished
1131    cmp wip, #74                    // if (wip == 'J') goto FOUND_LONG
1132    b.eq 2f
1133    cmp wip, #70                    // if (wip == 'F') goto SKIP_FLOAT
1134    b.eq 3f
1135    cmp wip, #68                    // if (wip == 'D') goto SKIP_DOUBLE
1136    b.eq 4f
1137    GET_VREG wip, \arg_index
1138    str wip, [sp, \stack_index, uxtw #2]
1139    add \arg_index, \arg_index, #1
1140    add \stack_index, \stack_index, #1
1141    b 1b
11422:  // FOUND_LONG
1143    GET_VREG_WIDE ip, \arg_index
1144    add ip2, sp, \stack_index, uxtw #2
1145    str ip, [ip2]
1146    add \arg_index, \arg_index, #2
1147    add \stack_index, \stack_index, #2
1148    b 1b
11493:  // SKIP_FLOAT
1150    add \arg_index, \arg_index, #1
1151    add \stack_index, \stack_index, #1
1152    b 1b
11534:  // SKIP_DOUBLE
1154    add \arg_index, \arg_index, #2
1155    add \stack_index, \stack_index, #2
1156    b 1b
1157.endm
1158
1159.macro COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
1160   .if \is_polymorphic
1161   // We always go to compiled code for polymorphic calls.
1162   .elseif \is_custom
1163   // We always go to compiled code for custom calls.
1164   .else
1165     DO_ENTRY_POINT_CHECK .Lcall_compiled_code_range_\suffix
1166     GET_CODE_ITEM
1167     .if \is_string_init
1168     bl nterp_to_nterp_string_init_range
1169     .elseif \is_static
1170     bl nterp_to_nterp_static_range
1171     .else
1172     bl nterp_to_nterp_instance_range
1173     .endif
1174     b .Ldone_return_range_\suffix
1175   .endif
1176
1177.Lcall_compiled_code_range_\suffix:
1178   .if \is_polymorphic
1179   // No fast path for polymorphic calls.
1180   .elseif \is_custom
1181   // No fast path for custom calls.
1182   .elseif \is_string_init
1183   // No fast path for string.init.
1184   .else
1185     ldr wip, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
1186     tbz wip, #ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG_BIT, .Lfast_path_with_few_args_range_\suffix
1187     FETCH_B wip2, 0, 1  // Number of arguments
1188     .if \is_static
1189     cbz ip2, .Linvoke_fast_path_range_\suffix
1190     .else
1191     cmp ip2, #1
1192     b.eq .Linvoke_fast_path_range_\suffix
1193     .endif
1194     FETCH wip, 2  // dex register of first argument
1195     add x8, xFP, wip, uxtw #2  // location of first dex register value
1196     cmp ip2, #2
1197     .if \is_static
1198     b.lt .Lone_arg_fast_path_range_\suffix
1199     .endif
1200     b.eq .Ltwo_args_fast_path_range_\suffix
1201     cmp ip2, #4
1202     b.lt .Lthree_args_fast_path_range_\suffix
1203     b.eq .Lfour_args_fast_path_range_\suffix
1204     cmp ip2, #6
1205     b.lt .Lfive_args_fast_path_range_\suffix
1206     b.eq .Lsix_args_fast_path_range_\suffix
1207     cmp ip2, #7
1208     b.eq .Lseven_args_fast_path_range_\suffix
1209     // Setup x8 to point to the stack location of parameters we do not need
1210     // to put parameters in.
1211     add x9, sp, #8  // Add space for the ArtMethod
1212
1213.Lloop_over_fast_path_range_\suffix:
1214     sub ip2, ip2, #1
1215     ldr wip, [x8, ip2, lsl #2]
1216     str wip, [x9, ip2, lsl #2]
1217     cmp ip2, #7
1218     b.ne .Lloop_over_fast_path_range_\suffix
1219
1220.Lseven_args_fast_path_range_\suffix:
1221     ldr w7, [x8, #24]
1222.Lsix_args_fast_path_range_\suffix:
1223     ldr w6, [x8, #20]
1224.Lfive_args_fast_path_range_\suffix:
1225     ldr w5, [x8, #16]
1226.Lfour_args_fast_path_range_\suffix:
1227     ldr w4, [x8, #12]
1228.Lthree_args_fast_path_range_\suffix:
1229     ldr w3, [x8, #8]
1230.Ltwo_args_fast_path_range_\suffix:
1231     ldr w2, [x8, #4]
1232.Lone_arg_fast_path_range_\suffix:
1233     .if \is_static
1234     ldr w1, [x8, #0]
1235     .else
1236     // First argument already in w1.
1237     .endif
1238.Linvoke_fast_path_range_\suffix:
1239     .if \is_interface
1240     // Setup hidden argument.
1241     mov ip2, x26
1242     .endif
1243     ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
1244     blr lr
1245     FETCH_ADVANCE_INST 3
1246     GET_INST_OPCODE ip
1247     GOTO_OPCODE ip
1248
1249.Lfast_path_with_few_args_range_\suffix:
1250     // Fast path when we have zero or one argument (modulo 'this'). If there
1251     // is one argument, we can put it in both floating point and core register.
1252     FETCH_B w2, 0, 1 // number of arguments
1253     .if \is_static
1254     cmp w2, #1
1255     .else
1256     cmp w2, #2
1257     .endif
1258     b.lt .Linvoke_with_few_args_range_\suffix
1259     b.ne .Lget_shorty_range_\suffix
1260     FETCH w3, 2  // dex register of first argument
1261     .if \is_static
1262     GET_VREG w1, w3
1263     fmov s0, w1
1264     .else
1265     add w3, w3, #1  // Add 1 for next argument
1266     GET_VREG w2, w3
1267     fmov s0, w2
1268     .endif
1269.Linvoke_with_few_args_range_\suffix:
1270     // Check if the next instruction is move-result or move-result-wide.
1271     // If it is, we fetch the shorty and jump to the regular invocation.
1272     FETCH w27, 3
1273     and ip, x27, #0xfe
1274     cmp ip, #0x0a
1275     b.eq .Lget_shorty_and_invoke_range_\suffix
1276     .if \is_interface
1277     // Setup hidden argument.
1278     mov ip2, x26
1279     .endif
1280     ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
1281     blr lr
1282     mov xINST, x27
1283     ADVANCE 3
1284     GET_INST_OPCODE ip
1285     GOTO_OPCODE ip
1286.Lget_shorty_and_invoke_range_\suffix:
1287     GET_SHORTY_SLOW_PATH xINST, \is_interface
1288     b .Lgpr_setup_finished_range_\suffix
1289   .endif
1290
1291.Lget_shorty_range_\suffix:
1292   GET_SHORTY xINST, \is_interface, \is_polymorphic, \is_custom
1293   // From this point:
1294   // - xINST contains shorty (in callee-save to switch over return value after call).
1295   // - x0 contains method
1296   // - x1 contains 'this' pointer for instance method.
1297   // - for interface calls, x26 contains the interface method.
1298   add x9, xINST, #1  // shorty + 1  ; ie skip return arg character
1299   FETCH w10, 2 // arguments
1300   .if \is_string_init
1301   add x10, x10, #1  // arg start index
1302   mov x11, #1       // index in stack
1303   .elseif \is_static
1304   mov x11, xzr      // index in stack
1305   .else
1306   add x10, x10, #1  // arg start index
1307   mov x11, #1       // index in stack
1308   .endif
1309   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d0, s0, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1310   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d1, s1, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1311   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d2, s2, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1312   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d3, s3, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1313   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d4, s4, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1314   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d5, s5, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1315   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d6, s6, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1316   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d7, s7, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1317   // Store in the outs array (stored above the ArtMethod in the stack)
1318   add x11, x11, #2 // Add two words for the ArtMethod stored before the outs.
1319   LOOP_RANGE_OVER_FPs x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1320.Lxmm_setup_finished_range_\suffix:
1321   add x9, xINST, #1  // shorty + 1  ; ie skip return arg character
1322   FETCH w10, 2 // arguments
1323   .if \is_string_init
1324   add x10, x10, #1  // arg start index
1325   mov x11, #1       // index in stack
1326   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x1, w1, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1327   .elseif \is_static
1328   mov x11, xzr      // index in stack
1329   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x1, w1, x9, w10, w11 .Lgpr_setup_finished_range_\suffix
1330   .else
1331   add x10, x10, #1  // arg start index
1332   mov x11, #1       // index in stack
1333   .endif
1334   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x2, w2, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1335   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x3, w3, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1336   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x4, w4, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1337   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x5, w5, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1338   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x6, w6, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1339   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x7, w7, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1340   // Store in the outs array (stored above the ArtMethod in the stack)
1341   add x11, x11, #2 // Add two words for the ArtMethod stored before the outs.
1342   LOOP_RANGE_OVER_INTs x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1343.Lgpr_setup_finished_range_\suffix:
1344   .if \is_polymorphic
1345   bl art_quick_invoke_polymorphic
1346   .elseif \is_custom
1347   bl art_quick_invoke_custom
1348   .else
1349      .if \is_interface
1350      // Setup hidden argument.
1351      mov ip2, x26
1352      .endif
1353      ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
1354      blr lr
1355   .endif
1356   SETUP_RETURN_VALUE xINST
1357.Ldone_return_range_\suffix:
1358   /* resume execution of caller */
1359   .if \is_string_init
1360   FETCH w11, 2 // arguments
1361   GET_VREG w1, w11
1362   UPDATE_REGISTERS_FOR_STRING_INIT w1, w0
1363   .endif
1364
1365   .if \is_polymorphic
1366   FETCH_ADVANCE_INST 4
1367   .else
1368   FETCH_ADVANCE_INST 3
1369   .endif
1370   GET_INST_OPCODE ip
1371   GOTO_OPCODE ip
1372.endm
1373
1374.macro POISON_HEAP_REF_IF_OBJECT is_object, rRef
1375   .if \is_object
1376   POISON_HEAP_REF \rRef
1377   .endif
1378.endm
1379
1380.macro WRITE_BARRIER_IF_OBJECT is_object, value, holder, label
1381   .if \is_object
1382   cbz     \value, \label
1383   ldr     ip, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1384   lsr     wip2, \holder, #CARD_TABLE_CARD_SHIFT
1385   strb    wip, [ip, ip2]
1386\label:
1387   .endif
1388.endm
1389
1390// Puts the next int/long/object parameter passed in physical register
1391// in the expected dex register array entry, and in case of object in the
1392// expected reference array entry.
1393.macro LOOP_OVER_SHORTY_STORING_GPRS gpr_64, gpr_32, shorty, arg_offset, regs, refs, finished
13941: // LOOP
1395    ldrb wip, [\shorty], #1       // Load next character in shorty, and increment.
1396    cbz wip, \finished            // if (wip == '\0') goto finished
1397    cmp wip, #74                  // if (wip == 'J') goto FOUND_LONG
1398    b.eq 2f
1399    cmp wip, #70                  // if (wip == 'F') goto SKIP_FLOAT
1400    b.eq 3f
1401    cmp wip, #68                  // if (wip == 'D') goto SKIP_DOUBLE
1402    b.eq 4f
1403    str \gpr_32, [\regs, \arg_offset]
1404    cmp wip, #76                  // if (wip != 'L') goto NOT_REFERENCE
1405    b.ne 6f
1406    str \gpr_32, [\refs, \arg_offset]
14076:  // NOT_REFERENCE
1408    add \arg_offset, \arg_offset, #4
1409    b 5f
14102:  // FOUND_LONG
1411    str \gpr_64, [\regs, \arg_offset]
1412    add \arg_offset, \arg_offset, #8
1413    b 5f
14143:  // SKIP_FLOAT
1415    add \arg_offset, \arg_offset, #4
1416    b 1b
14174:  // SKIP_DOUBLE
1418    add \arg_offset, \arg_offset, #8
1419    b 1b
14205:
1421.endm
1422
1423// Puts the next floating point parameter passed in physical register
1424// in the expected dex register array entry.
1425// Uses ip as temporary.
1426.macro LOOP_OVER_SHORTY_STORING_FPS dreg, sreg, shorty, arg_offset, fp, finished
14271: // LOOP
1428    ldrb wip, [\shorty], #1                 // Load next character in shorty, and increment.
1429    cbz wip, \finished                      // if (wip == '\0') goto finished
1430    cmp wip, #68                            // if (wip == 'D') goto FOUND_DOUBLE
1431    b.eq 2f
1432    cmp wip, #70                            // if (wip == 'F') goto FOUND_FLOAT
1433    b.eq 3f
1434    add \arg_offset, \arg_offset, #4
1435    //  Handle extra argument in arg array taken by a long.
1436    cmp wip, #74                            // if (wip != 'J') goto LOOP
1437    b.ne 1b
1438    add \arg_offset, \arg_offset, #4
1439    b 1b                        // goto LOOP
14402:  // FOUND_DOUBLE
1441    str \dreg, [\fp, \arg_offset]
1442    add \arg_offset, \arg_offset, #8
1443    b 4f
14443:  // FOUND_FLOAT
1445    str \sreg, [\fp, \arg_offset]
1446    add \arg_offset, \arg_offset, #4
14474:
1448.endm
1449
1450// Puts the next floating point parameter passed in stack
1451// in the expected dex register array entry.
1452// Uses ip as temporary.
1453//
1454// TODO: Or we could just spill regs to the reserved slots in the caller's
1455// frame and copy all regs in a simple loop. This time, however, we would
1456// need to look at the shorty anyway to look for the references.
1457// (The trade-off is different for passing arguments and receiving them.)
1458.macro LOOP_OVER_FPs shorty, arg_offset, regs, stack_ptr, finished
14591: // LOOP
1460    ldrb wip, [\shorty], #1                 // Load next character in shorty, and increment.
1461    cbz wip, \finished                      // if (wip == '\0') goto finished
1462    cmp wip, #68                            // if (wip == 'D') goto FOUND_DOUBLE
1463    b.eq 2f
1464    cmp wip, #70                            // if (wip == 'F') goto FOUND_FLOAT
1465    b.eq 3f
1466    add \arg_offset, \arg_offset, #4
1467    //  Handle extra argument in arg array taken by a long.
1468    cmp wip, #74                            // if (wip != 'J') goto LOOP
1469    b.ne 1b
1470    add \arg_offset, \arg_offset, #4
1471    b 1b                        // goto LOOP
14722:  // FOUND_DOUBLE
1473    add ip, \stack_ptr, \arg_offset
1474    ldr ip, [ip,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1475    str ip, [\regs, \arg_offset]
1476    add \arg_offset, \arg_offset, #8
1477    b 1b
14783:  // FOUND_FLOAT
1479    add ip, \stack_ptr, \arg_offset
1480    ldr wip, [ip,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1481    str wip, [\regs, \arg_offset]
1482    add \arg_offset, \arg_offset, #4
1483    b 1b
1484.endm
1485
1486// Puts the next int/long/object parameter passed in stack
1487// in the expected dex register array entry, and in case of object in the
1488// expected reference array entry.
1489// Uses ip and ip2 as temporary.
1490.macro LOOP_OVER_INTs shorty, arg_offset, regs, refs, stack_ptr, finished
14911: // LOOP
1492    ldrb wip, [\shorty], #1       // Load next character in shorty, and increment.
1493    cbz wip, \finished            // if (wip == '\0') goto finished
1494    cmp wip, #74                  // if (wip == 'J') goto FOUND_LONG
1495    b.eq 2f
1496    cmp wip, #70                  // if (wip == 'F') goto SKIP_FLOAT
1497    b.eq 3f
1498    cmp wip, #68                  // if (wip == 'D') goto SKIP_DOUBLE
1499    b.eq 4f
1500    add ip2, \stack_ptr, \arg_offset
1501    ldr wip2, [ip2,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1502    str wip2, [\regs, \arg_offset]
1503    cmp wip, #76                  // if (wip != 'L') goto loop
1504    b.ne 3f
1505    str wip2, [\refs, \arg_offset]
1506    add \arg_offset, \arg_offset, #4
1507    b 1b
15082:  // FOUND_LONG
1509    add ip, \stack_ptr, \arg_offset
1510    ldr ip, [ip,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1511    str ip, [\regs, \arg_offset]
1512    add \arg_offset, \arg_offset, #8
1513    b 1b
15143:  // SKIP_FLOAT
1515    add \arg_offset, \arg_offset, #4
1516    b 1b
15174:  // SKIP_DOUBLE
1518    add \arg_offset, \arg_offset, #8
1519    b 1b
1520.endm
1521
1522.macro SETUP_REFERENCE_PARAMETER_IN_GPR gpr32, regs, refs, ins, arg_offset, finished
1523    str \gpr32, [\regs, \arg_offset]
1524    sub \ins, \ins, #1
1525    str \gpr32, [\refs, \arg_offset]
1526    add \arg_offset, \arg_offset, #4
1527    cbz \ins, \finished
1528.endm
1529
1530// Uses ip2 as temporary.
1531.macro SETUP_REFERENCE_PARAMETERS_IN_STACK regs, refs, ins, stack_ptr, arg_offset
15321:
1533    ldr wip2, [\stack_ptr, \arg_offset]
1534    sub \ins, \ins, #1
1535    str wip2, [\regs, \arg_offset]
1536    str wip2, [\refs, \arg_offset]
1537    add \arg_offset, \arg_offset, #4
1538    cbnz \ins, 1b
1539.endm
1540
1541.macro CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot, if_not_hot
1542    ldr wip, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
1543    tbz wip, #ART_METHOD_IS_MEMORY_SHARED_FLAG_BIT, \if_hot
1544    // Intrinsics are always in the boot image and considered hot.
1545    tbnz wip, #ART_METHOD_IS_INTRINSIC_FLAG_BIT, \if_hot
1546    ldr wip, [xSELF, #THREAD_SHARED_METHOD_HOTNESS_OFFSET]
1547    cbz wip, \if_hot
1548    add wip, wip, #-1
1549    str wip, [xSELF, #THREAD_SHARED_METHOD_HOTNESS_OFFSET]
1550    b \if_not_hot
1551.endm
1552
1553.macro DO_SUSPEND_CHECK continue_label
1554    ldr wip, [xSELF, #THREAD_FLAGS_OFFSET]
1555    tst wip, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
1556    b.eq \continue_label
1557    EXPORT_PC
1558    bl    art_quick_test_suspend
1559.endm
1560
1561%def entry():
1562/*
1563 * ArtMethod entry point.
1564 *
1565 * On entry:
1566 *  x0   ArtMethod* callee
1567 *  rest  method parameters
1568 */
1569
1570OAT_ENTRY ExecuteNterpWithClinitImpl
1571    .cfi_startproc
1572    // For simplicity, we don't do a read barrier here, but instead rely
1573    // on art_quick_resolution_trampoline to always have a suspend point before
1574    // calling back here.
1575    ldr wip, [x0, #ART_METHOD_DECLARING_CLASS_OFFSET]
1576    ldr wip2, [ip, #MIRROR_CLASS_STATUS_OFFSET]
1577    lsr wip2, wip2, #MIRROR_CLASS_STATUS_SHIFT
1578    cmp wip2, #MIRROR_CLASS_STATUS_VISIBLY_INITIALIZED
1579    b.hs ExecuteNterpImpl
1580    cmp wip2, #MIRROR_CLASS_STATUS_INITIALIZED
1581    b.lo .Linitializing_check
1582    dmb ish
1583    b ExecuteNterpImpl
1584.Linitializing_check:
1585    cmp wip2, #MIRROR_CLASS_STATUS_INITIALIZING
1586    b.lo .Lresolution_trampoline
1587    ldr wip2, [ip, #MIRROR_CLASS_CLINIT_THREAD_ID_OFFSET]
1588    ldr wip, [xSELF, #THREAD_TID_OFFSET]
1589    cmp wip, wip2
1590    b.eq ExecuteNterpImpl
1591.Lresolution_trampoline:
1592    b art_quick_resolution_trampoline
1593    .cfi_endproc
1594    .type EndExecuteNterpWithClinitImpl, #function
1595    .hidden EndExecuteNterpWithClinitImpl
1596    .global EndExecuteNterpWithClinitImpl
1597EndExecuteNterpWithClinitImpl:
1598
1599OAT_ENTRY ExecuteNterpImpl
1600    .cfi_startproc
1601    sub x16, sp, #STACK_OVERFLOW_RESERVED_BYTES
1602    ldr wzr, [x16]
1603    /* Spill callee save regs */
1604    SPILL_ALL_CALLEE_SAVES
1605
1606    ldr xPC, [x0, #ART_METHOD_DATA_OFFSET_64]
1607    // Setup the stack for executing the method.
1608    SETUP_STACK_FRAME xPC, xREFS, xFP, CFI_REFS, load_ins=1
1609
1610    // Setup the parameters
1611    cbz w15, .Lxmm_setup_finished
1612
1613    sub ip2, ip, x15
1614    ldr w26, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
1615    lsl x27, ip2, #2 // x27 is now the offset for inputs into the registers array.
1616
1617    tbz w26, #ART_METHOD_NTERP_ENTRY_POINT_FAST_PATH_FLAG_BIT, .Lsetup_slow_path
1618    // Setup pointer to inputs in FP and pointer to inputs in REFS
1619    add x10, xFP, x27
1620    add x11, xREFS, x27
1621    mov x12, #0
1622    SETUP_REFERENCE_PARAMETER_IN_GPR w1, x10, x11, w15, x12, .Lxmm_setup_finished
1623    SETUP_REFERENCE_PARAMETER_IN_GPR w2, x10, x11, w15, x12, .Lxmm_setup_finished
1624    SETUP_REFERENCE_PARAMETER_IN_GPR w3, x10, x11, w15, x12, .Lxmm_setup_finished
1625    SETUP_REFERENCE_PARAMETER_IN_GPR w4, x10, x11, w15, x12, .Lxmm_setup_finished
1626    SETUP_REFERENCE_PARAMETER_IN_GPR w5, x10, x11, w15, x12, .Lxmm_setup_finished
1627    SETUP_REFERENCE_PARAMETER_IN_GPR w6, x10, x11, w15, x12, .Lxmm_setup_finished
1628    SETUP_REFERENCE_PARAMETER_IN_GPR w7, x10, x11, w15, x12, .Lxmm_setup_finished
1629    add x28, x28, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK
1630    SETUP_REFERENCE_PARAMETERS_IN_STACK x10, x11, w15, x28, x12
1631    b .Lxmm_setup_finished
1632
1633.Lsetup_slow_path:
1634    // If the method is not static and there is one argument ('this'), we don't need to fetch the
1635    // shorty.
1636    tbnz w26, #ART_METHOD_IS_STATIC_FLAG_BIT, .Lsetup_with_shorty
1637    str w1, [xFP, x27]
1638    str w1, [xREFS, x27]
1639    cmp w15, #1
1640    b.eq .Lxmm_setup_finished
1641
1642.Lsetup_with_shorty:
1643    // TODO: Get shorty in a better way and remove below
1644    SPILL_ALL_ARGUMENTS
1645    bl NterpGetShorty
1646    // Save shorty in callee-save xIBASE.
1647    mov xIBASE, x0
1648    RESTORE_ALL_ARGUMENTS
1649
1650    // Setup pointer to inputs in FP and pointer to inputs in REFS
1651    add x10, xFP, x27
1652    add x11, xREFS, x27
1653    mov x12, #0
1654
1655    add x9, xIBASE, #1  // shorty + 1  ; ie skip return arg character
1656    tbnz w26, #ART_METHOD_IS_STATIC_FLAG_BIT, .Lhandle_static_method
1657    add x10, x10, #4
1658    add x11, x11, #4
1659    add x28, x28, #4
1660    b .Lcontinue_setup_gprs
1661.Lhandle_static_method:
1662    LOOP_OVER_SHORTY_STORING_GPRS x1, w1, x9, x12, x10, x11, .Lgpr_setup_finished
1663.Lcontinue_setup_gprs:
1664    LOOP_OVER_SHORTY_STORING_GPRS x2, w2, x9, x12, x10, x11, .Lgpr_setup_finished
1665    LOOP_OVER_SHORTY_STORING_GPRS x3, w3, x9, x12, x10, x11, .Lgpr_setup_finished
1666    LOOP_OVER_SHORTY_STORING_GPRS x4, w4, x9, x12, x10, x11, .Lgpr_setup_finished
1667    LOOP_OVER_SHORTY_STORING_GPRS x5, w5, x9, x12, x10, x11, .Lgpr_setup_finished
1668    LOOP_OVER_SHORTY_STORING_GPRS x6, w6, x9, x12, x10, x11, .Lgpr_setup_finished
1669    LOOP_OVER_SHORTY_STORING_GPRS x7, w7, x9, x12, x10, x11, .Lgpr_setup_finished
1670    LOOP_OVER_INTs x9, x12, x10, x11, x28, .Lgpr_setup_finished
1671.Lgpr_setup_finished:
1672    add x9, xIBASE, #1  // shorty + 1  ; ie skip return arg character
1673    mov x12, #0  // reset counter
1674    LOOP_OVER_SHORTY_STORING_FPS d0, s0, x9, x12, x10, .Lxmm_setup_finished
1675    LOOP_OVER_SHORTY_STORING_FPS d1, s1, x9, x12, x10, .Lxmm_setup_finished
1676    LOOP_OVER_SHORTY_STORING_FPS d2, s2, x9, x12, x10, .Lxmm_setup_finished
1677    LOOP_OVER_SHORTY_STORING_FPS d3, s3, x9, x12, x10, .Lxmm_setup_finished
1678    LOOP_OVER_SHORTY_STORING_FPS d4, s4, x9, x12, x10, .Lxmm_setup_finished
1679    LOOP_OVER_SHORTY_STORING_FPS d5, s5, x9, x12, x10, .Lxmm_setup_finished
1680    LOOP_OVER_SHORTY_STORING_FPS d6, s6, x9, x12, x10, .Lxmm_setup_finished
1681    LOOP_OVER_SHORTY_STORING_FPS d7, s7, x9, x12, x10, .Lxmm_setup_finished
1682    LOOP_OVER_FPs x9, x12, x10, x28, .Lxmm_setup_finished
1683.Lxmm_setup_finished:
1684    CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
1685
1686    // Set rIBASE
1687    adr xIBASE, artNterpAsmInstructionStart
1688    /* start executing the instruction at xPC */
1689    START_EXECUTING_INSTRUCTIONS
1690    /* NOTE: no fallthrough */
1691    // cfi info continues, and covers the whole nterp implementation.
1692    SIZE ExecuteNterpImpl
1693
1694%def opcode_pre():
1695
1696%def fetch_from_thread_cache(dest_reg, miss_label):
1697   // Fetch some information from the thread cache.
1698   // Uses ip and ip2 as temporaries.
1699   add      ip, xSELF, #THREAD_INTERPRETER_CACHE_OFFSET       // cache address
1700   ubfx     ip2, xPC, #2, #THREAD_INTERPRETER_CACHE_SIZE_LOG2  // entry index
1701   add      ip, ip, ip2, lsl #4            // entry address within the cache
1702   ldp      ip, ${dest_reg}, [ip]          // entry key (pc) and value (offset)
1703   cmp      ip, xPC
1704   b.ne     ${miss_label}
1705
1706%def footer():
1707/*
1708 * ===========================================================================
1709 *  Common subroutines and data
1710 * ===========================================================================
1711 */
1712
1713    .text
1714    .align  2
1715
1716// Enclose all code below in a symbol (which gets printed in backtraces).
1717NAME_START nterp_helper
1718
1719// Note: mterp also uses the common_* names below for helpers, but that's OK
1720// as the assembler compiled each interpreter separately.
1721common_errDivideByZero:
1722    EXPORT_PC
1723    bl art_quick_throw_div_zero
1724
1725// Expect index in w1, length in w3.
1726common_errArrayIndex:
1727    EXPORT_PC
1728    mov x0, x1
1729    mov x1, x3
1730    bl art_quick_throw_array_bounds
1731
1732common_errNullObject:
1733    EXPORT_PC
1734    bl art_quick_throw_null_pointer_exception
1735
1736NterpCommonInvokeStatic:
1737    COMMON_INVOKE_NON_RANGE is_static=1, suffix="invokeStatic"
1738
1739NterpCommonInvokeStaticRange:
1740    COMMON_INVOKE_RANGE is_static=1, suffix="invokeStatic"
1741
1742NterpCommonInvokeInstance:
1743    COMMON_INVOKE_NON_RANGE suffix="invokeInstance"
1744
1745NterpCommonInvokeInstanceRange:
1746    COMMON_INVOKE_RANGE suffix="invokeInstance"
1747
1748NterpCommonInvokeInterface:
1749    COMMON_INVOKE_NON_RANGE is_interface=1, suffix="invokeInterface"
1750
1751NterpCommonInvokeInterfaceRange:
1752    COMMON_INVOKE_RANGE is_interface=1, suffix="invokeInterface"
1753
1754NterpCommonInvokePolymorphic:
1755    COMMON_INVOKE_NON_RANGE is_polymorphic=1, suffix="invokePolymorphic"
1756
1757NterpCommonInvokePolymorphicRange:
1758    COMMON_INVOKE_RANGE is_polymorphic=1, suffix="invokePolymorphic"
1759
1760NterpCommonInvokeCustom:
1761    COMMON_INVOKE_NON_RANGE is_static=1, is_custom=1, suffix="invokeCustom"
1762
1763NterpCommonInvokeCustomRange:
1764    COMMON_INVOKE_RANGE is_static=1, is_custom=1, suffix="invokeCustom"
1765
1766NterpHandleStringInit:
1767   COMMON_INVOKE_NON_RANGE is_string_init=1, suffix="stringInit"
1768
1769NterpHandleStringInitRange:
1770   COMMON_INVOKE_RANGE is_string_init=1, suffix="stringInit"
1771
1772NterpHandleHotnessOverflow:
1773    CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot=1f, if_not_hot=5f
17741:
1775    mov x1, xPC
1776    mov x2, xFP
1777    bl nterp_hot_method
1778    cbnz x0, 3f
17792:
1780    FETCH wINST, 0                      // load wINST
1781    GET_INST_OPCODE ip                  // extract opcode from wINST
1782    GOTO_OPCODE ip                      // jump to next instruction
17833:
1784    // Drop the current frame.
1785    ldr ip, [xREFS, #-8]
1786    mov sp, ip
1787    .cfi_def_cfa sp, CALLEE_SAVES_SIZE
1788
1789    // The transition frame of type SaveAllCalleeSaves saves x19 and x20,
1790    // but not managed ABI. So we need to restore callee-saves of the nterp frame,
1791    // and save managed ABI callee saves, which will be restored by the callee upon
1792    // return.
1793    RESTORE_ALL_CALLEE_SAVES
1794    INCREASE_FRAME ((CALLEE_SAVES_SIZE) - 16)
1795
1796    // FP callee-saves
1797    stp d8, d9, [sp, #0]
1798    stp d10, d11, [sp, #16]
1799    stp d12, d13, [sp, #32]
1800    stp d14, d15, [sp, #48]
1801
1802    // GP callee-saves.
1803    SAVE_TWO_REGS x21, x22, 64
1804    SAVE_TWO_REGS x23, x24, 80
1805    SAVE_TWO_REGS x25, x26, 96
1806    SAVE_TWO_REGS x27, x28, 112
1807    SAVE_TWO_REGS x29, lr, 128
1808
1809    // Setup the new frame
1810    ldr x1, [x0, #OSR_DATA_FRAME_SIZE]
1811    // Given stack size contains all callee saved registers, remove them.
1812    sub x1, x1, #(CALLEE_SAVES_SIZE - 16)
1813
1814    // We know x1 cannot be 0, as it at least contains the ArtMethod.
1815
1816    // Remember CFA in a callee-save register.
1817    mov xINST, sp
1818    .cfi_def_cfa_register xINST
1819
1820    sub sp, sp, x1
1821
1822    add x2, x0, #OSR_DATA_MEMORY
18234:
1824    sub x1, x1, #8
1825    ldr ip, [x2, x1]
1826    str ip, [sp, x1]
1827    cbnz x1, 4b
1828
1829    // Fetch the native PC to jump to and save it in a callee-save register.
1830    ldr xFP, [x0, #OSR_DATA_NATIVE_PC]
1831
1832    // Free the memory holding OSR Data.
1833    bl free
1834
1835    // Jump to the compiled code.
1836    br xFP
18375:
1838    DO_SUSPEND_CHECK continue_label=2b
1839    b 2b
1840
1841// This is the logical end of ExecuteNterpImpl, where the frame info applies.
1842// EndExecuteNterpImpl includes the methods below as we want the runtime to
1843// see them as part of the Nterp PCs.
1844.cfi_endproc
1845
1846nterp_to_nterp_static_non_range:
1847    .cfi_startproc
1848    SETUP_STACK_FOR_INVOKE
1849    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0
1850    .cfi_endproc
1851
1852nterp_to_nterp_string_init_non_range:
1853    .cfi_startproc
1854    SETUP_STACK_FOR_INVOKE
1855    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1
1856    .cfi_endproc
1857
1858nterp_to_nterp_instance_non_range:
1859    .cfi_startproc
1860    SETUP_STACK_FOR_INVOKE
1861    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
1862    .cfi_endproc
1863
1864nterp_to_nterp_static_range:
1865    .cfi_startproc
1866    SETUP_STACK_FOR_INVOKE
1867    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=1
1868    .cfi_endproc
1869
1870nterp_to_nterp_instance_range:
1871    .cfi_startproc
1872    SETUP_STACK_FOR_INVOKE
1873    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0
1874    .cfi_endproc
1875
1876nterp_to_nterp_string_init_range:
1877    .cfi_startproc
1878    SETUP_STACK_FOR_INVOKE
1879    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1
1880    .cfi_endproc
1881
1882NAME_END nterp_helper
1883
1884// This is the end of PCs contained by the OatQuickMethodHeader created for the interpreter
1885// entry point.
1886    .type EndExecuteNterpImpl, #function
1887    .hidden EndExecuteNterpImpl
1888    .global EndExecuteNterpImpl
1889EndExecuteNterpImpl:
1890
1891// Entrypoints into runtime.
1892NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField
1893NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset
1894NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray
1895NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange
1896NTERP_TRAMPOLINE nterp_get_class, NterpGetClass
1897NTERP_TRAMPOLINE nterp_allocate_object, NterpAllocateObject
1898NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod
1899NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod
1900NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject
1901
1902ENTRY nterp_deliver_pending_exception
1903    DELIVER_PENDING_EXCEPTION
1904END nterp_deliver_pending_exception
1905
1906// gen_mterp.py will inline the following definitions
1907// within [ExecuteNterpImpl, EndExecuteNterpImpl).
1908%def instruction_end():
1909
1910    .type artNterpAsmInstructionEnd, #function
1911    .hidden artNterpAsmInstructionEnd
1912    .global artNterpAsmInstructionEnd
1913artNterpAsmInstructionEnd:
1914    // artNterpAsmInstructionEnd is used as landing pad for exception handling.
1915    FETCH_INST
1916    GET_INST_OPCODE ip
1917    GOTO_OPCODE ip
1918
1919%def instruction_start():
1920
1921    .type artNterpAsmInstructionStart, #function
1922    .hidden artNterpAsmInstructionStart
1923    .global artNterpAsmInstructionStart
1924artNterpAsmInstructionStart = .L_op_nop
1925    .text
1926
1927%def opcode_name_prefix():
1928%   return "nterp_"
1929%def opcode_start():
1930    NAME_START nterp_${opcode}
1931    # Explicitly restore CFA, just in case the previous opcode clobbered it (by .cfi_def_*).
1932    CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE
1933%def opcode_end():
1934    NAME_END nterp_${opcode}
1935    // Advance to the end of this handler. Causes error if we are past that point.
1936    .org nterp_${opcode} + NTERP_HANDLER_SIZE  // ${opcode} handler is too big!
1937%def opcode_slow_path_start(name):
1938    NAME_START ${name}
1939%def opcode_slow_path_end(name):
1940    NAME_END ${name}
1941