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 *   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/*
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 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
241    // Padding of 3 * 8 bytes to get 16 bytes alignment of code entry.
242    .long 0
243    .long 0
244    .long 0
245    // OatQuickMethodHeader. Note that the top two bits must be clear.
246    .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
293    // Update method counter and do a suspend check if the branch is negative.
294    tbnz wINST, #31, 2f
2951:
296    add     xPC, xPC, wINST, sxtw #1    // update xPC
297    FETCH wINST, 0                      // load wINST
298    GET_INST_OPCODE ip                  // extract opcode from wINST
299    GOTO_OPCODE ip                      // jump to next instruction
3002:
301    ldr x0, [sp]
302    ldrh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
303    add x2, x2, #1
304    and w2, w2, #NTERP_HOTNESS_MASK
305    strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
306    // If the counter overflows, handle this in the runtime.
307    cbz w2, NterpHandleHotnessOverflow
308    // Otherwise, do a suspend check.
309    ldr x0, [xSELF, #THREAD_FLAGS_OFFSET]
310    ands x0, x0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
311    b.eq 1b
312    EXPORT_PC
313    bl    art_quick_test_suspend
314    b 1b
315.endm
316
317// Uses x12, x13, and x14 as temporaries.
318.macro FETCH_CODE_ITEM_INFO code_item, registers, outs, ins, load_ins
319    tbz \code_item, #0, 4f
320    and \code_item, \code_item, #-2 // Remove the extra bit that marks it's a compact dex file
321    ldrh w13, [\code_item, #COMPACT_CODE_ITEM_FIELDS_OFFSET]
322    ubfx \registers, w13, #COMPACT_CODE_ITEM_REGISTERS_SIZE_SHIFT, #4
323    ubfx \outs, w13, #COMPACT_CODE_ITEM_OUTS_SIZE_SHIFT, #4
324    .if \load_ins
325    ubfx \ins, w13, #COMPACT_CODE_ITEM_INS_SIZE_SHIFT, #4
326    .else
327    ubfx w14, w13, #COMPACT_CODE_ITEM_INS_SIZE_SHIFT, #4
328    add \registers, \registers, w14
329    .endif
330    ldrh w13, [\code_item, #COMPACT_CODE_ITEM_FLAGS_OFFSET]
331    tst w13, #COMPACT_CODE_ITEM_REGISTERS_INS_OUTS_FLAGS
332    b.eq 3f
333    sub x14, \code_item, #4
334    tst w13, #COMPACT_CODE_ITEM_INSNS_FLAG
335    csel x14, x14, \code_item, ne
336
337    tbz w13, #COMPACT_CODE_ITEM_REGISTERS_BIT, 1f
338    ldrh w12, [x14, #-2]!
339    add \registers, \registers, w12
3401:
341    tbz w13, #COMPACT_CODE_ITEM_INS_BIT, 2f
342    ldrh w12, [x14, #-2]!
343    .if \load_ins
344    add \ins, \ins, w12
345    .else
346    add \registers, \registers, w12
347    .endif
3482:
349    tbz w13, #COMPACT_CODE_ITEM_OUTS_BIT, 3f
350    ldrh w12, [x14, #-2]!
351    add \outs, \outs, w12
3523:
353    .if \load_ins
354    add \registers, \registers, \ins
355    .endif
356    add \code_item, \code_item, #COMPACT_CODE_ITEM_INSNS_OFFSET
357    b 5f
3584:
359    // Fetch dex register size.
360    ldrh \registers, [\code_item, #CODE_ITEM_REGISTERS_SIZE_OFFSET]
361    // Fetch outs size.
362    ldrh \outs, [\code_item, #CODE_ITEM_OUTS_SIZE_OFFSET]
363    .if \load_ins
364    ldrh \ins, [\code_item, #CODE_ITEM_INS_SIZE_OFFSET]
365    .endif
366    add \code_item, \code_item, #CODE_ITEM_INSNS_OFFSET
3675:
368.endm
369
370// Setup the stack to start executing the method. Expects:
371// - x0 to contain the ArtMethod
372//
373// Outputs
374// - ip contains the dex registers size
375// - x28 contains the old stack pointer.
376// - \code_item is replaced with a pointer to the instructions
377// - if load_ins is 1, w15 contains the ins
378//
379// Uses ip, ip2, x12, x13, x14 as temporaries.
380.macro SETUP_STACK_FRAME code_item, refs, fp, cfi_refs, load_ins
381    FETCH_CODE_ITEM_INFO \code_item, wip, wip2, w15, \load_ins
382
383    // Compute required frame size: ((2 * ip) + ip2) * 4 + 24
384    // 24 is for saving the previous frame, pc, and method being executed.
385    add x14, ip, ip
386    add x14, x14, ip2
387    lsl x14, x14, #2
388    add x14, x14, #24
389
390    // Compute new stack pointer in x14
391    sub x14, sp, x14
392    // Alignment
393    and x14, x14, #-16
394
395    // Set reference and dex registers, align to pointer size for previous frame and dex pc.
396    add \refs, x14, ip2, lsl #2
397    add \refs, \refs, 28
398    and \refs, \refs, #(-__SIZEOF_POINTER__)
399    add \fp, \refs, ip, lsl #2
400
401    // Now setup the stack pointer.
402    mov x28, sp
403    .cfi_def_cfa_register x28
404    mov sp, x14
405    str x28, [\refs, #-8]
406    CFI_DEF_CFA_BREG_PLUS_UCONST \cfi_refs, -8, CALLEE_SAVES_SIZE
407
408    // Put nulls in reference frame.
409    cbz ip, 2f
410    mov ip2, \refs
4111:
412    str xzr, [ip2], #8  // May clear vreg[0].
413    cmp ip2, \fp
414    b.lo 1b
4152:
416    // Save the ArtMethod.
417    str x0, [sp]
418.endm
419
420// Increase method hotness and do suspend check before starting executing the method.
421.macro START_EXECUTING_INSTRUCTIONS
422    ldr x0, [sp]
423    ldrh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
424    add x2, x2, #1
425    and w2, w2, #NTERP_HOTNESS_MASK
426    strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
427    // If the counter overflows, handle this in the runtime.
428    cbz w2, 2f
429    ldr x0, [xSELF, #THREAD_FLAGS_OFFSET]
430    tst x0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
431    b.ne 3f
4321:
433    FETCH_INST
434    GET_INST_OPCODE ip
435    GOTO_OPCODE ip
4362:
437    mov x1, xzr
438    mov x2, xFP
439    bl nterp_hot_method
440    b 1b
4413:
442    EXPORT_PC
443    bl art_quick_test_suspend
444    b 1b
445.endm
446
447.macro SPILL_ALL_CALLEE_SAVES
448    INCREASE_FRAME CALLEE_SAVES_SIZE
449    // Note: we technically don't need to save x19 and x20,
450    // but the runtime will expect those values to be there when unwinding
451    // (see Arm64Context::DoLongJump checking for the thread register).
452    SAVE_ALL_CALLEE_SAVES 0
453.endm
454
455.macro RESTORE_ALL_CALLEE_SAVES
456    // FP callee-saves
457    ldp d8, d9, [sp, #0]
458    ldp d10, d11, [sp, #16]
459    ldp d12, d13, [sp, #32]
460    ldp d14, d15, [sp, #48]
461
462    // GP callee-saves.
463    // No need to restore x19 (it's always the thread), and
464    // don't restore x20 (the marking register) as it may have been updated.
465    RESTORE_TWO_REGS x21, x22, 80
466    RESTORE_TWO_REGS x23, x24, 96
467    RESTORE_TWO_REGS x25, x26, 112
468    RESTORE_TWO_REGS x27, x28, 128
469    RESTORE_TWO_REGS x29, lr, 144
470
471    DECREASE_FRAME CALLEE_SAVES_SIZE
472.endm
473
474.macro SPILL_ALL_ARGUMENTS
475    stp x0, x1, [sp, #-128]!
476    stp x2, x3, [sp, #16]
477    stp x4, x5, [sp, #32]
478    stp x6, x7, [sp, #48]
479    stp d0, d1, [sp, #64]
480    stp d2, d3, [sp, #80]
481    stp d4, d5, [sp, #96]
482    stp d6, d7, [sp, #112]
483.endm
484
485.macro RESTORE_ALL_ARGUMENTS
486    ldp x2, x3, [sp, #16]
487    ldp x4, x5, [sp, #32]
488    ldp x6, x7, [sp, #48]
489    ldp d0, d1, [sp, #64]
490    ldp d2, d3, [sp, #80]
491    ldp d4, d5, [sp, #96]
492    ldp d6, d7, [sp, #112]
493    ldp x0, x1, [sp], #128
494.endm
495
496// Helper to setup the stack after doing a nterp to nterp call. This will setup:
497// - xNEW_FP: the new pointer to dex registers
498// - xNEW_REFS: the new pointer to references
499// - xPC: the new PC pointer to execute
500// - x2: value in instruction to decode the number of arguments.
501// - x3: first dex register
502// - x4: top of dex register array
503//
504// The method expects:
505// - x0 to contain the ArtMethod
506// - x8 to contain the code item
507.macro SETUP_STACK_FOR_INVOKE
508   // We do the same stack overflow check as the compiler. See CanMethodUseNterp
509   // in how we limit the maximum nterp frame size.
510   sub x16, sp, #STACK_OVERFLOW_RESERVED_BYTES
511   ldr wzr, [x16]
512
513   // Spill all callee saves to have a consistent stack frame whether we
514   // are called by compiled code or nterp.
515   SPILL_ALL_CALLEE_SAVES
516
517   // Setup the frame.
518   SETUP_STACK_FRAME x8, xNEW_REFS, xNEW_FP, CFI_NEW_REFS, load_ins=0
519   // Make x4 point to the top of the dex register array.
520   add x4, xNEW_FP, ip, uxtx #2
521
522   // Fetch instruction information before replacing xPC.
523   // TODO: move this down to the method that uses it, fetching it directly from wINST.
524   FETCH_B w2, 0, 1
525   // TODO: we could avoid this as instance invokes already fetch it.
526   FETCH w3, 2
527
528   // Set the dex pc pointer.
529   mov xPC, x8
530   CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
531.endm
532
533// Setup arguments based on a non-range nterp to nterp call, and start executing
534// the method. We expect:
535// - xNEW_FP: the new pointer to dex registers
536// - xNEW_REFS: the new pointer to references
537// - xPC: the new PC pointer to execute
538// - x2: number of arguments (bits 4-7), 5th argument if any (bits 0-3)
539// - x3: first dex register
540// - x4: top of dex register array
541// - x1: receiver if non-static.
542.macro SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
543   // /* op vA, vB, {vC...vG} */
544   asr ip2, x2, #4
545   cbz ip2, 6f
546   mov ip, #-4
547   cmp ip2, #2
548   b.lt 1f
549   b.eq 2f
550   cmp ip2, #4
551   b.lt 3f
552   b.eq 4f
553
554  // We use a decrementing ip to store references relative
555  // to xNEW_FP and dex registers relative to x4
556  //
557  // TODO: We could set up ip as the number of registers (this can be an additional output from
558  // SETUP_STACK_FOR_INVOKE) and then just decrement it by one before copying each arg.
559  // Maybe even introduce macros NEW_VREG_ADDRESS/NEW_VREG_REF_ADDRESS.
5605:
561   and         x2, x2, #15
562   GET_VREG_OBJECT w5, w2
563   str         w5, [xNEW_FP, ip]
564   GET_VREG    w5, w2
565   str         w5, [x4, ip]
566   sub         ip, ip, #4
5674:
568   asr         x2, x3, #12
569   GET_VREG_OBJECT w5, w2
570   str         w5, [xNEW_FP, ip]
571   GET_VREG    w5, w2
572   str         w5, [x4, ip]
573   sub         ip, ip, #4
5743:
575   ubfx        x2, x3, #8, #4
576   GET_VREG_OBJECT w5, w2
577   str         w5, [xNEW_FP, ip]
578   GET_VREG    w5, w2
579   str         w5, [x4, ip]
580   sub         ip, ip, #4
5812:
582   ubfx        x2, x3, #4, #4
583   GET_VREG_OBJECT w5, w2
584   str         w5, [xNEW_FP, ip]
585   GET_VREG    w5, w2
586   str         w5, [x4, ip]
587   .if !\is_string_init
588   sub         ip, ip, #4
589   .endif
5901:
591   .if \is_string_init
592   // Ignore the first argument
593   .elseif \is_static
594   and         x2, x3, #0xf
595   GET_VREG_OBJECT w5, w2
596   str         w5, [xNEW_FP, ip]
597   GET_VREG    w5, w2
598   str         w5, [x4, ip]
599   .else
600   str         w1, [xNEW_FP, ip]
601   str         w1, [x4, ip]
602   .endif
603
6046:
605   // Start executing the method.
606   mov xFP, xNEW_FP
607   mov xREFS, xNEW_REFS
608   CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE
609   START_EXECUTING_INSTRUCTIONS
610.endm
611
612// Setup arguments based on a range nterp to nterp call, and start executing
613// the method.
614// - xNEW_FP: the new pointer to dex registers
615// - xNEW_REFS: the new pointer to references
616// - xPC: the new PC pointer to execute
617// - x2: number of arguments
618// - x3: first dex register
619// - x4: top of dex register array
620// - x1: receiver if non-static.
621//
622// Uses ip, ip2, x5, x6 as temporaries.
623.macro SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
624   mov ip, #-4
625   .if \is_string_init
626   // Ignore the first argument
627   sub x2, x2, #1
628   add x3, x3, #1
629   .elseif !\is_static
630   sub x2, x2, #1
631   add x3, x3, #1
632   .endif
633
634   cbz x2, 2f
635   add ip2, xREFS, x3, lsl #2  // pointer to first argument in reference array
636   add ip2, ip2, x2, lsl #2    // pointer to last argument in reference array
637   add x5, xFP, x3, lsl #2     // pointer to first argument in register array
638   add x6, x5, x2, lsl #2      // pointer to last argument in register array
6391:
640   ldr  w7, [ip2, #-4]!
641   str  w7, [xNEW_FP, ip]
642   sub  x2, x2, 1
643   ldr  w7, [x6, #-4]!
644   str  w7, [x4, ip]
645   sub ip, ip, 4
646   cbnz x2, 1b
6472:
648   .if \is_string_init
649   // Ignore first argument
650   .elseif !\is_static
651   str w1, [xNEW_FP, ip]
652   str w1, [x4, ip]
653   .endif
654   mov xFP, xNEW_FP
655   mov xREFS, xNEW_REFS
656   CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE
657   START_EXECUTING_INSTRUCTIONS
658.endm
659
660.macro GET_SHORTY dest, is_interface, is_polymorphic, is_custom
661   stp x0, x1, [sp, #-16]!
662   .if \is_polymorphic
663   ldr x0, [sp, #16]
664   mov x1, xPC
665   bl NterpGetShortyFromInvokePolymorphic
666   .elseif \is_custom
667   ldr x0, [sp, #16]
668   mov x1, xPC
669   bl NterpGetShortyFromInvokeCustom
670   .elseif \is_interface
671   ldr x0, [sp, #16]
672   FETCH w1, 1
673   bl NterpGetShortyFromMethodId
674   .else
675   bl NterpGetShorty
676   .endif
677   mov \dest, x0
678   ldp x0, x1, [sp], #16
679.endm
680
681.macro GET_SHORTY_SLOW_PATH dest, is_interface
682   // Save all registers that can hold arguments in the fast path.
683   stp x0, x1, [sp, #-32]!
684   str w2, [sp, #16]
685   str s0, [sp, #20]
686   .if \is_interface
687   ldr x0, [sp, #32]
688   FETCH w1, 1
689   bl NterpGetShortyFromMethodId
690   .else
691   bl NterpGetShorty
692   .endif
693   mov \dest, x0
694   ldr w2, [sp, #16]
695   ldr s0, [sp, #20]
696   ldp x0, x1, [sp], #32
697.endm
698
699// Input:  x0 contains the ArtMethod
700// Output: x8 contains the code item
701.macro GET_CODE_ITEM
702   ldr x8, [x0, #ART_METHOD_DATA_OFFSET_64]
703.endm
704
705.macro DO_ENTRY_POINT_CHECK call_compiled_code
706   // On entry, the method is x0, the instance is x1
707   adr x2, ExecuteNterpImpl
708   ldr x3, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
709   cmp x2, x3
710   b.ne  \call_compiled_code
711.endm
712
713.macro UPDATE_REGISTERS_FOR_STRING_INIT old_value, new_value
714   mov wip, wzr
7151:
716   GET_VREG_OBJECT wip2, wip
717   cmp wip2, \old_value
718   b.ne 2f
719   SET_VREG_OBJECT \new_value, wip
7202:
721   add wip, wip, #1
722   add ip2, xREFS, wip, uxtw #2
723   cmp ip2, xFP
724   b.ne 1b
725.endm
726
727// Puts the next floating point argument into the expected register,
728// fetching values based on a non-range invoke.
729// Uses ip and ip2.
730.macro LOOP_OVER_SHORTY_LOADING_FPS dreg, sreg, inst, shorty, arg_index, finished
7311: // LOOP
732    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
733    cbz wip, \finished              // if (wip == '\0') goto finished
734    cmp wip, #68                    // if (wip == 'D') goto FOUND_DOUBLE
735    b.eq 2f
736    cmp wip, #70                    // if (wip == 'F') goto FOUND_FLOAT
737    b.eq 3f
738    lsr \inst, \inst, #4
739    add \arg_index, \arg_index, #1
740    //  Handle extra argument in arg array taken by a long.
741    cmp wip, #74                   // if (wip != 'J') goto LOOP
742    b.ne 1b
743    lsr \inst, \inst, #4
744    add \arg_index, \arg_index, #1
745    b 1b                        // goto LOOP
7462:  // FOUND_DOUBLE
747    and ip, \inst, #0xf
748    GET_VREG wip, wip
749    lsr \inst, \inst, #4
750    add \arg_index, \arg_index, #1
751    cmp \arg_index, #4
752    b.eq 5f
753    and ip2, \inst, #0xf
754    lsr \inst, \inst, #4
755    add \arg_index, \arg_index, #1
756    b 6f
7575:
758    // TODO: Extract from wINST here and below? (Requires using a different register
759    // in the COMMON_INVOKE_NON_RANGE.)
760    FETCH_B wip2, 0, 1
761    and wip2, wip2, #0xf
7626:
763    GET_VREG wip2, wip2
764    add ip, ip, ip2, lsl #32
765    fmov \dreg, ip
766    b 4f
7673:  // FOUND_FLOAT
768    cmp \arg_index, #4
769    b.eq 7f
770    and ip, \inst, #0xf
771    lsr \inst, \inst, #4
772    add \arg_index, \arg_index, #1
773    b 8f
7747:
775    FETCH_B wip, 0, 1
776    and wip, wip, #0xf
7778:
778    GET_VREG \sreg, wip
7794:
780.endm
781
782// Puts the next int/long/object argument in the expected register,
783// fetching values based on a non-range invoke.
784// Uses ip and ip2.
785.macro LOOP_OVER_SHORTY_LOADING_GPRS gpr_reg64, gpr_reg32, inst, shorty, arg_index, finished
7861: // LOOP
787    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
788    cbz wip, \finished              // if (wip == '\0') goto finished
789    cmp wip, #74                    // if (wip == 'J') goto FOUND_LONG
790    b.eq 2f
791    cmp wip, #70                    // if (wip == 'F') goto SKIP_FLOAT
792    b.eq 3f
793    cmp wip, #68                    // if (wip == 'D') goto SKIP_DOUBLE
794    b.eq 4f
795    cmp \arg_index, #4
796    b.eq 7f
797    and ip, \inst, #0xf
798    lsr \inst, \inst, #4
799    add \arg_index, \arg_index, #1
800    b 8f
8017:
802    FETCH_B wip, 0, 1
803    and wip, wip, #0xf
8048:
805    GET_VREG \gpr_reg32, wip
806    b 5f
8072:  // FOUND_LONG
808    and ip, \inst, #0xf
809    GET_VREG wip, wip
810    lsr \inst, \inst, #4
811    add \arg_index, \arg_index, #1
812    cmp \arg_index, #4
813    b.eq 9f
814    and ip2, \inst, #0xf
815    lsr \inst, \inst, #4
816    add \arg_index, \arg_index, #1
817    b 10f
8189:
819    FETCH_B wip2, 0, 1
820    and wip2, wip2, #0xf
82110:
822    GET_VREG wip2, wip2
823    add \gpr_reg64, ip, ip2, lsl #32
824    b 5f
8253:  // SKIP_FLOAT
826    lsr \inst, \inst, #4
827    add \arg_index, \arg_index, #1
828    b 1b
8294:  // SKIP_DOUBLE
830    lsr \inst, \inst, #4
831    add \arg_index, \arg_index, #1
832    cmp \arg_index, #4
833    b.eq 1b
834    lsr \inst, \inst, #4
835    add \arg_index, \arg_index, #1
836    b 1b
8375:
838.endm
839
840.macro SETUP_RETURN_VALUE shorty
841   ldrb wip, [\shorty]
842   cmp ip, #68       // Test if result type char == 'D'.
843   b.eq 1f
844   cmp ip, #70       // Test if result type char == 'F'.
845   b.ne 2f
846   fmov w0, s0
847   b 2f
8481:
849   fmov x0, d0
8502:
851.endm
852
853.macro COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
854   .if \is_polymorphic
855   // We always go to compiled code for polymorphic calls.
856   .elseif \is_custom
857   // We always go to compiled code for custom calls.
858   .else
859     DO_ENTRY_POINT_CHECK .Lcall_compiled_code_\suffix
860     GET_CODE_ITEM
861     .if \is_string_init
862     bl nterp_to_nterp_string_init_non_range
863     .elseif \is_static
864     bl nterp_to_nterp_static_non_range
865     .else
866     bl nterp_to_nterp_instance_non_range
867     .endif
868     b .Ldone_return_\suffix
869   .endif
870
871.Lcall_compiled_code_\suffix:
872   .if \is_polymorphic
873   // No fast path for polymorphic calls.
874   .elseif \is_custom
875   // No fast path for custom calls.
876   .elseif \is_string_init
877   // No fast path for string.init.
878   .else
879     ldr wip, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
880     tbz wip, #ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG_BIT, .Lfast_path_with_few_args_\suffix
881     FETCH_B wip2, 0, 1
882     asr ip, ip2, #4
883     .if \is_static
884     cbz ip, .Linvoke_fast_path_\suffix
885     .else
886     cmp ip, #1
887     b.eq .Linvoke_fast_path_\suffix
888     .endif
889     FETCH w8, 2
890     cmp ip, #2
891     .if \is_static
892     b.lt .Lone_arg_fast_path_\suffix
893     .endif
894     b.eq .Ltwo_args_fast_path_\suffix
895     cmp ip, #4
896     b.lt .Lthree_args_fast_path_\suffix
897     b.eq .Lfour_args_fast_path_\suffix
898
899     and         ip, ip2, #15
900     GET_VREG    w5, wip
901.Lfour_args_fast_path_\suffix:
902     asr         ip, x8, #12
903     GET_VREG    w4, wip
904.Lthree_args_fast_path_\suffix:
905     ubfx        ip, x8, #8, #4
906     GET_VREG    w3, wip
907.Ltwo_args_fast_path_\suffix:
908     ubfx        ip, x8, #4, #4
909     GET_VREG    w2, wip
910.Lone_arg_fast_path_\suffix:
911     .if \is_static
912     and         ip, x8, #0xf
913     GET_VREG    w1, wip
914     .else
915     // First argument already in w1.
916     .endif
917.Linvoke_fast_path_\suffix:
918     .if \is_interface
919     // Setup hidden argument.
920     mov ip2, x26
921     .endif
922     ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
923     blr lr
924     FETCH_ADVANCE_INST 3
925     GET_INST_OPCODE ip
926     GOTO_OPCODE ip
927
928.Lfast_path_with_few_args_\suffix:
929     // Fast path when we have zero or one argument (modulo 'this'). If there
930     // is one argument, we can put it in both floating point and core register.
931     FETCH_B w2, 0, 1
932     .if \is_static
933     cmp w2, #(2 << 4)
934     .else
935     cmp w2, #(3 << 4)
936     .endif
937     b.ge .Lget_shorty_\suffix
938     .if \is_static
939     tbz w2, #4, .Linvoke_with_few_args_\suffix
940     .else
941     tbnz w2, #4, .Linvoke_with_few_args_\suffix
942     .endif
943     FETCH w2, 2
944     .if \is_static
945     and w2, w2, #0xf  // dex register of first argument
946     GET_VREG w1, w2
947     fmov s0, w1
948     .else
949     ubfx x2, x2, #4, #4  // dex register of second argument
950     GET_VREG w2, w2
951     fmov s0, w2
952     .endif
953.Linvoke_with_few_args_\suffix:
954     // Check if the next instruction is move-result or move-result-wide.
955     // If it is, we fetch the shorty and jump to the regular invocation.
956     FETCH w27, 3
957     and ip, x27, #0xfe
958     cmp ip, #0x0a
959     b.eq .Lget_shorty_and_invoke_\suffix
960     .if \is_interface
961     // Setup hidden argument.
962     mov ip2, x26
963     .endif
964     ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
965     blr lr
966     # TODO: Use some other register for shorty and prefetch the instruction directly to wINST.
967     mov xINST, x27
968     ADVANCE 3
969     GET_INST_OPCODE ip
970     GOTO_OPCODE ip
971.Lget_shorty_and_invoke_\suffix:
972     GET_SHORTY_SLOW_PATH xINST, \is_interface
973     b .Lgpr_setup_finished_\suffix
974   .endif
975
976.Lget_shorty_\suffix:
977   GET_SHORTY xINST, \is_interface, \is_polymorphic, \is_custom
978   // From this point:
979   // - xINST contains shorty (in callee-save to switch over return value after call).
980   // - x0 contains method
981   // - x1 contains 'this' pointer for instance method.
982   // - for interface calls, x26 contains the interface method.
983   add x9, xINST, #1  // shorty + 1  ; ie skip return arg character
984   FETCH w11, 2 // arguments
985   .if \is_string_init
986   lsr x11, x11, #4
987   mov x10, #1       // ignore first argument
988   .elseif \is_static
989   mov x10, xzr      // arg_index
990   .else
991   lsr x11, x11, #4
992   mov x10, #1       // ignore first argument
993   .endif
994   LOOP_OVER_SHORTY_LOADING_FPS d0, s0, x11, x9, x10, .Lxmm_setup_finished_\suffix
995   LOOP_OVER_SHORTY_LOADING_FPS d1, s1, x11, x9, x10, .Lxmm_setup_finished_\suffix
996   LOOP_OVER_SHORTY_LOADING_FPS d2, s2, x11, x9, x10, .Lxmm_setup_finished_\suffix
997   LOOP_OVER_SHORTY_LOADING_FPS d3, s3, x11, x9, x10, .Lxmm_setup_finished_\suffix
998   LOOP_OVER_SHORTY_LOADING_FPS d4, s4, x11, x9, x10, .Lxmm_setup_finished_\suffix
999.Lxmm_setup_finished_\suffix:
1000   add x9, xINST, #1  // shorty + 1  ; ie skip return arg character
1001   FETCH w11, 2 // arguments
1002   .if \is_string_init
1003   lsr x11, x11, #4
1004   mov x10, #1       // ignore first argument
1005   LOOP_OVER_SHORTY_LOADING_GPRS x1, w1, x11, x9, x10, .Lgpr_setup_finished_\suffix
1006   .elseif \is_static
1007   mov x10, xzr      // arg_index
1008   LOOP_OVER_SHORTY_LOADING_GPRS x1, w1, x11, x9, x10, .Lgpr_setup_finished_\suffix
1009   .else
1010   lsr x11, x11, #4
1011   mov x10, #1       // ignore first argument
1012   .endif
1013   LOOP_OVER_SHORTY_LOADING_GPRS x2, w2, x11, x9, x10, .Lgpr_setup_finished_\suffix
1014   LOOP_OVER_SHORTY_LOADING_GPRS x3, w3, x11, x9, x10, .Lgpr_setup_finished_\suffix
1015   LOOP_OVER_SHORTY_LOADING_GPRS x4, w4, x11, x9, x10, .Lgpr_setup_finished_\suffix
1016   LOOP_OVER_SHORTY_LOADING_GPRS x5, w5, x11, x9, x10, .Lgpr_setup_finished_\suffix
1017.Lgpr_setup_finished_\suffix:
1018   .if \is_polymorphic
1019   bl art_quick_invoke_polymorphic
1020   .elseif \is_custom
1021   bl art_quick_invoke_custom
1022   .else
1023      .if \is_interface
1024      // Setup hidden argument.
1025      mov ip2, x26
1026      .endif
1027      ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
1028      blr lr
1029   .endif
1030   SETUP_RETURN_VALUE xINST
1031.Ldone_return_\suffix:
1032   /* resume execution of caller */
1033   .if \is_string_init
1034   FETCH w11, 2 // arguments
1035   and x11, x11, #0xf
1036   GET_VREG w1, w11
1037   UPDATE_REGISTERS_FOR_STRING_INIT w1, w0
1038   .endif
1039
1040   .if \is_polymorphic
1041   FETCH_ADVANCE_INST 4
1042   .else
1043   FETCH_ADVANCE_INST 3
1044   .endif
1045   GET_INST_OPCODE ip
1046   GOTO_OPCODE ip
1047.endm
1048
1049// Puts the next floating point argument into the expected register,
1050// fetching values based on a range invoke.
1051// Uses ip as temporary.
1052.macro LOOP_RANGE_OVER_SHORTY_LOADING_FPS dreg, sreg, shorty, arg_index, stack_index, finished
10531: // LOOP
1054    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
1055    cbz wip, \finished              // if (wip == '\0') goto finished
1056    cmp wip, #68                    // if (wip == 'D') goto FOUND_DOUBLE
1057    b.eq 2f
1058    cmp wip, #70                    // if (wip == 'F') goto FOUND_FLOAT
1059    b.eq 3f
1060    add \arg_index, \arg_index, #1
1061    add \stack_index, \stack_index, #1
1062    //  Handle extra argument in arg array taken by a long.
1063    cmp wip, #74                    // if (wip != 'J') goto LOOP
1064    b.ne 1b
1065    add \arg_index, \arg_index, #1
1066    add \stack_index, \stack_index, #1
1067    b 1b                        // goto LOOP
10682:  // FOUND_DOUBLE
1069    GET_VREG_DOUBLE \dreg, \arg_index
1070    add \arg_index, \arg_index, #2
1071    add \stack_index, \stack_index, #2
1072    b 4f
10733:  // FOUND_FLOAT
1074    GET_VREG \sreg, \arg_index
1075    add \arg_index, \arg_index, #1
1076    add \stack_index, \stack_index, #1
10774:
1078.endm
1079
1080// Puts the next floating point argument into the expected stack slot,
1081// fetching values based on a range invoke.
1082// Uses ip as temporary.
1083//
1084// TODO: We could just copy all the vregs to the stack slots in a simple loop
1085// without looking at the shorty at all. (We could also drop
1086// the "stack_index" from the macros for loading registers.) We could also do
1087// that conditionally if argument word count > 6; otherwise we know that all
1088// args fit into registers.
1089.macro LOOP_RANGE_OVER_FPs shorty, arg_index, stack_index, finished
10901: // LOOP
1091    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
1092    cbz wip, \finished              // if (wip == '\0') goto finished
1093    cmp wip, #68                    // if (wip == 'D') goto FOUND_DOUBLE
1094    b.eq 2f
1095    cmp wip, #70                    // if (wip == 'F') goto FOUND_FLOAT
1096    b.eq 3f
1097    add \arg_index, \arg_index, #1
1098    add \stack_index, \stack_index, #1
1099    //  Handle extra argument in arg array taken by a long.
1100    cmp wip, #74                    // if (wip != 'J') goto LOOP
1101    b.ne 1b
1102    add \arg_index, \arg_index, #1
1103    add \stack_index, \stack_index, #1
1104    b 1b                        // goto LOOP
11052:  // FOUND_DOUBLE
1106    GET_VREG_WIDE ip, \arg_index
1107    add ip2, sp, \stack_index, uxtw #2
1108    str ip, [ip2]
1109    add \arg_index, \arg_index, #2
1110    add \stack_index, \stack_index, #2
1111    b 1b
11123:  // FOUND_FLOAT
1113    GET_VREG wip, \arg_index
1114    str wip, [sp, \stack_index, uxtw #2]
1115    add \arg_index, \arg_index, #1
1116    add \stack_index, \stack_index, #1
1117    b 1b
1118.endm
1119
1120// Puts the next int/long/object argument in the expected register,
1121// fetching values based on a range invoke.
1122// Uses ip as temporary.
1123.macro LOOP_RANGE_OVER_SHORTY_LOADING_GPRS reg64, reg32, shorty, arg_index, stack_index, finished
11241: // LOOP
1125    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
1126    cbz wip, \finished              // if (wip == '\0') goto finished
1127    cmp wip, #74                    // if (wip == 'J') goto FOUND_LONG
1128    b.eq 2f
1129    cmp wip, #70                   // if (wip == 'F') goto SKIP_FLOAT
1130    b.eq 3f
1131    cmp wip, #68                    // if (wip == 'D') goto SKIP_DOUBLE
1132    b.eq 4f
1133    GET_VREG \reg32, \arg_index
1134    add \arg_index, \arg_index, #1
1135    add \stack_index, \stack_index, #1
1136    b 5f
11372:  // FOUND_LONG
1138    GET_VREG_WIDE \reg64, \arg_index
1139    add \arg_index, \arg_index, #2
1140    add \stack_index, \stack_index, #2
1141    b 5f
11423:  // SKIP_FLOAT
1143    add \arg_index, \arg_index, #1
1144    add \stack_index, \stack_index, #1
1145    b 1b
11464:  // SKIP_DOUBLE
1147    add \arg_index, \arg_index, #2
1148    add \stack_index, \stack_index, #2
1149    b 1b
11505:
1151.endm
1152
1153// Puts the next int/long/object argument in the expected stack slot,
1154// fetching values based on a range invoke.
1155// Uses ip as temporary.
1156.macro LOOP_RANGE_OVER_INTs shorty, arg_index, stack_index, finished
11571: // LOOP
1158    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
1159    cbz wip, \finished              // if (wip == '\0') goto finished
1160    cmp wip, #74                    // if (wip == 'J') goto FOUND_LONG
1161    b.eq 2f
1162    cmp wip, #70                    // if (wip == 'F') goto SKIP_FLOAT
1163    b.eq 3f
1164    cmp wip, #68                    // if (wip == 'D') goto SKIP_DOUBLE
1165    b.eq 4f
1166    GET_VREG wip, \arg_index
1167    str wip, [sp, \stack_index, uxtw #2]
1168    add \arg_index, \arg_index, #1
1169    add \stack_index, \stack_index, #1
1170    b 1b
11712:  // FOUND_LONG
1172    GET_VREG_WIDE ip, \arg_index
1173    add ip2, sp, \stack_index, uxtw #2
1174    str ip, [ip2]
1175    add \arg_index, \arg_index, #2
1176    add \stack_index, \stack_index, #2
1177    b 1b
11783:  // SKIP_FLOAT
1179    add \arg_index, \arg_index, #1
1180    add \stack_index, \stack_index, #1
1181    b 1b
11824:  // SKIP_DOUBLE
1183    add \arg_index, \arg_index, #2
1184    add \stack_index, \stack_index, #2
1185    b 1b
1186.endm
1187
1188.macro COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
1189   .if \is_polymorphic
1190   // We always go to compiled code for polymorphic calls.
1191   .elseif \is_custom
1192   // We always go to compiled code for custom calls.
1193   .else
1194     DO_ENTRY_POINT_CHECK .Lcall_compiled_code_range_\suffix
1195     GET_CODE_ITEM
1196     .if \is_string_init
1197     bl nterp_to_nterp_string_init_range
1198     .elseif \is_static
1199     bl nterp_to_nterp_static_range
1200     .else
1201     bl nterp_to_nterp_instance_range
1202     .endif
1203     b .Ldone_return_range_\suffix
1204   .endif
1205
1206.Lcall_compiled_code_range_\suffix:
1207   .if \is_polymorphic
1208   // No fast path for polymorphic calls.
1209   .elseif \is_custom
1210   // No fast path for custom calls.
1211   .elseif \is_string_init
1212   // No fast path for string.init.
1213   .else
1214     ldr wip, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
1215     tbz wip, #ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG_BIT, .Lfast_path_with_few_args_range_\suffix
1216     FETCH_B wip2, 0, 1  // Number of arguments
1217     .if \is_static
1218     cbz ip2, .Linvoke_fast_path_range_\suffix
1219     .else
1220     cmp ip2, #1
1221     b.eq .Linvoke_fast_path_range_\suffix
1222     .endif
1223     FETCH wip, 2  // dex register of first argument
1224     add x8, xFP, wip, uxtw #2  // location of first dex register value
1225     cmp ip2, #2
1226     .if \is_static
1227     b.lt .Lone_arg_fast_path_range_\suffix
1228     .endif
1229     b.eq .Ltwo_args_fast_path_range_\suffix
1230     cmp ip2, #4
1231     b.lt .Lthree_args_fast_path_range_\suffix
1232     b.eq .Lfour_args_fast_path_range_\suffix
1233     cmp ip2, #6
1234     b.lt .Lfive_args_fast_path_range_\suffix
1235     b.eq .Lsix_args_fast_path_range_\suffix
1236     cmp ip2, #7
1237     b.eq .Lseven_args_fast_path_range_\suffix
1238     // Setup x8 to point to the stack location of parameters we do not need
1239     // to put parameters in.
1240     add x9, sp, #8  // Add space for the ArtMethod
1241
1242.Lloop_over_fast_path_range_\suffix:
1243     sub ip2, ip2, #1
1244     ldr wip, [x8, ip2, lsl #2]
1245     str wip, [x9, ip2, lsl #2]
1246     cmp ip2, #7
1247     b.ne .Lloop_over_fast_path_range_\suffix
1248
1249.Lseven_args_fast_path_range_\suffix:
1250     ldr w7, [x8, #24]
1251.Lsix_args_fast_path_range_\suffix:
1252     ldr w6, [x8, #20]
1253.Lfive_args_fast_path_range_\suffix:
1254     ldr w5, [x8, #16]
1255.Lfour_args_fast_path_range_\suffix:
1256     ldr w4, [x8, #12]
1257.Lthree_args_fast_path_range_\suffix:
1258     ldr w3, [x8, #8]
1259.Ltwo_args_fast_path_range_\suffix:
1260     ldr w2, [x8, #4]
1261.Lone_arg_fast_path_range_\suffix:
1262     .if \is_static
1263     ldr w1, [x8, #0]
1264     .else
1265     // First argument already in w1.
1266     .endif
1267.Linvoke_fast_path_range_\suffix:
1268     .if \is_interface
1269     // Setup hidden argument.
1270     mov ip2, x26
1271     .endif
1272     ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
1273     blr lr
1274     FETCH_ADVANCE_INST 3
1275     GET_INST_OPCODE ip
1276     GOTO_OPCODE ip
1277
1278.Lfast_path_with_few_args_range_\suffix:
1279     // Fast path when we have zero or one argument (modulo 'this'). If there
1280     // is one argument, we can put it in both floating point and core register.
1281     FETCH_B w2, 0, 1 // number of arguments
1282     .if \is_static
1283     cmp w2, #1
1284     .else
1285     cmp w2, #2
1286     .endif
1287     b.lt .Linvoke_with_few_args_range_\suffix
1288     b.ne .Lget_shorty_range_\suffix
1289     FETCH w3, 2  // dex register of first argument
1290     .if \is_static
1291     GET_VREG w1, w3
1292     fmov s0, w1
1293     .else
1294     add w3, w3, #1  // Add 1 for next argument
1295     GET_VREG w2, w3
1296     fmov s0, w2
1297     .endif
1298.Linvoke_with_few_args_range_\suffix:
1299     // Check if the next instruction is move-result or move-result-wide.
1300     // If it is, we fetch the shorty and jump to the regular invocation.
1301     FETCH w27, 3
1302     and ip, x27, #0xfe
1303     cmp ip, #0x0a
1304     b.eq .Lget_shorty_and_invoke_range_\suffix
1305     .if \is_interface
1306     // Setup hidden argument.
1307     mov ip2, x26
1308     .endif
1309     ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
1310     blr lr
1311     mov xINST, x27
1312     ADVANCE 3
1313     GET_INST_OPCODE ip
1314     GOTO_OPCODE ip
1315.Lget_shorty_and_invoke_range_\suffix:
1316     GET_SHORTY_SLOW_PATH xINST, \is_interface
1317     b .Lgpr_setup_finished_range_\suffix
1318   .endif
1319
1320.Lget_shorty_range_\suffix:
1321   GET_SHORTY xINST, \is_interface, \is_polymorphic, \is_custom
1322   // From this point:
1323   // - xINST contains shorty (in callee-save to switch over return value after call).
1324   // - x0 contains method
1325   // - x1 contains 'this' pointer for instance method.
1326   // - for interface calls, x26 contains the interface method.
1327   add x9, xINST, #1  // shorty + 1  ; ie skip return arg character
1328   FETCH w10, 2 // arguments
1329   .if \is_string_init
1330   add x10, x10, #1  // arg start index
1331   mov x11, #1       // index in stack
1332   .elseif \is_static
1333   mov x11, xzr      // index in stack
1334   .else
1335   add x10, x10, #1  // arg start index
1336   mov x11, #1       // index in stack
1337   .endif
1338   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d0, s0, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1339   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d1, s1, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1340   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d2, s2, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1341   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d3, s3, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1342   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d4, s4, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1343   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d5, s5, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1344   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d6, s6, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1345   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d7, s7, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1346   // Store in the outs array (stored above the ArtMethod in the stack)
1347   add x11, x11, #2 // Add two words for the ArtMethod stored before the outs.
1348   LOOP_RANGE_OVER_FPs x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1349.Lxmm_setup_finished_range_\suffix:
1350   add x9, xINST, #1  // shorty + 1  ; ie skip return arg character
1351   FETCH w10, 2 // arguments
1352   .if \is_string_init
1353   add x10, x10, #1  // arg start index
1354   mov x11, #1       // index in stack
1355   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x1, w1, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1356   .elseif \is_static
1357   mov x11, xzr      // index in stack
1358   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x1, w1, x9, w10, w11 .Lgpr_setup_finished_range_\suffix
1359   .else
1360   add x10, x10, #1  // arg start index
1361   mov x11, #1       // index in stack
1362   .endif
1363   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x2, w2, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1364   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x3, w3, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1365   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x4, w4, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1366   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x5, w5, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1367   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x6, w6, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1368   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x7, w7, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1369   // Store in the outs array (stored above the ArtMethod in the stack)
1370   add x11, x11, #2 // Add two words for the ArtMethod stored before the outs.
1371   LOOP_RANGE_OVER_INTs x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1372.Lgpr_setup_finished_range_\suffix:
1373   .if \is_polymorphic
1374   bl art_quick_invoke_polymorphic
1375   .elseif \is_custom
1376   bl art_quick_invoke_custom
1377   .else
1378      .if \is_interface
1379      // Setup hidden argument.
1380      mov ip2, x26
1381      .endif
1382      ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
1383      blr lr
1384   .endif
1385   SETUP_RETURN_VALUE xINST
1386.Ldone_return_range_\suffix:
1387   /* resume execution of caller */
1388   .if \is_string_init
1389   FETCH w11, 2 // arguments
1390   GET_VREG w1, w11
1391   UPDATE_REGISTERS_FOR_STRING_INIT w1, w0
1392   .endif
1393
1394   .if \is_polymorphic
1395   FETCH_ADVANCE_INST 4
1396   .else
1397   FETCH_ADVANCE_INST 3
1398   .endif
1399   GET_INST_OPCODE ip
1400   GOTO_OPCODE ip
1401.endm
1402
1403.macro WRITE_BARRIER_IF_OBJECT is_object, value, holder, label
1404   .if \is_object
1405   cbz     \value, \label
1406   ldr     ip, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1407   lsr     wip2, \holder, #CARD_TABLE_CARD_SHIFT
1408   strb    wip, [ip, ip2]
1409\label:
1410   .endif
1411.endm
1412
1413// Fetch some information from the thread cache.
1414// Uses ip and ip2 as temporaries.
1415.macro FETCH_FROM_THREAD_CACHE dest_reg, slow_path
1416   add      ip, xSELF, #THREAD_INTERPRETER_CACHE_OFFSET       // cache address
1417   ubfx     ip2, xPC, #2, #THREAD_INTERPRETER_CACHE_SIZE_LOG2  // entry index
1418   add      ip, ip, ip2, lsl #4            // entry address within the cache
1419   ldp      ip, \dest_reg, [ip]           // entry key (pc) and value (offset)
1420   cmp      ip, xPC
1421   b.ne \slow_path
1422.endm
1423
1424// Puts the next int/long/object parameter passed in physical register
1425// in the expected dex register array entry, and in case of object in the
1426// expected reference array entry.
1427.macro LOOP_OVER_SHORTY_STORING_GPRS gpr_64, gpr_32, shorty, arg_offset, regs, refs, finished
14281: // LOOP
1429    ldrb wip, [\shorty], #1       // Load next character in shorty, and increment.
1430    cbz wip, \finished            // if (wip == '\0') goto finished
1431    cmp wip, #74                  // if (wip == 'J') goto FOUND_LONG
1432    b.eq 2f
1433    cmp wip, #70                  // if (wip == 'F') goto SKIP_FLOAT
1434    b.eq 3f
1435    cmp wip, #68                  // if (wip == 'D') goto SKIP_DOUBLE
1436    b.eq 4f
1437    str \gpr_32, [\regs, \arg_offset]
1438    cmp wip, #76                  // if (wip != 'L') goto NOT_REFERENCE
1439    b.ne 6f
1440    str \gpr_32, [\refs, \arg_offset]
14416:  // NOT_REFERENCE
1442    add \arg_offset, \arg_offset, #4
1443    b 5f
14442:  // FOUND_LONG
1445    str \gpr_64, [\regs, \arg_offset]
1446    add \arg_offset, \arg_offset, #8
1447    b 5f
14483:  // SKIP_FLOAT
1449    add \arg_offset, \arg_offset, #4
1450    b 1b
14514:  // SKIP_DOUBLE
1452    add \arg_offset, \arg_offset, #8
1453    b 1b
14545:
1455.endm
1456
1457// Puts the next floating point parameter passed in physical register
1458// in the expected dex register array entry.
1459// Uses ip as temporary.
1460.macro LOOP_OVER_SHORTY_STORING_FPS dreg, sreg, shorty, arg_offset, fp, finished
14611: // LOOP
1462    ldrb wip, [\shorty], #1                 // Load next character in shorty, and increment.
1463    cbz wip, \finished                      // if (wip == '\0') goto finished
1464    cmp wip, #68                            // if (wip == 'D') goto FOUND_DOUBLE
1465    b.eq 2f
1466    cmp wip, #70                            // if (wip == 'F') goto FOUND_FLOAT
1467    b.eq 3f
1468    add \arg_offset, \arg_offset, #4
1469    //  Handle extra argument in arg array taken by a long.
1470    cmp wip, #74                            // if (wip != 'J') goto LOOP
1471    b.ne 1b
1472    add \arg_offset, \arg_offset, #4
1473    b 1b                        // goto LOOP
14742:  // FOUND_DOUBLE
1475    str \dreg, [\fp, \arg_offset]
1476    add \arg_offset, \arg_offset, #8
1477    b 4f
14783:  // FOUND_FLOAT
1479    str \sreg, [\fp, \arg_offset]
1480    add \arg_offset, \arg_offset, #4
14814:
1482.endm
1483
1484// Puts the next floating point parameter passed in stack
1485// in the expected dex register array entry.
1486// Uses ip as temporary.
1487//
1488// TODO: Or we could just spill regs to the reserved slots in the caller's
1489// frame and copy all regs in a simple loop. This time, however, we would
1490// need to look at the shorty anyway to look for the references.
1491// (The trade-off is different for passing arguments and receiving them.)
1492.macro LOOP_OVER_FPs shorty, arg_offset, regs, stack_ptr, finished
14931: // LOOP
1494    ldrb wip, [\shorty], #1                 // Load next character in shorty, and increment.
1495    cbz wip, \finished                      // if (wip == '\0') goto finished
1496    cmp wip, #68                            // if (wip == 'D') goto FOUND_DOUBLE
1497    b.eq 2f
1498    cmp wip, #70                            // if (wip == 'F') goto FOUND_FLOAT
1499    b.eq 3f
1500    add \arg_offset, \arg_offset, #4
1501    //  Handle extra argument in arg array taken by a long.
1502    cmp wip, #74                            // if (wip != 'J') goto LOOP
1503    b.ne 1b
1504    add \arg_offset, \arg_offset, #4
1505    b 1b                        // goto LOOP
15062:  // FOUND_DOUBLE
1507    add ip, \stack_ptr, \arg_offset
1508    ldr ip, [ip,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1509    str ip, [\regs, \arg_offset]
1510    add \arg_offset, \arg_offset, #8
1511    b 1b
15123:  // FOUND_FLOAT
1513    add ip, \stack_ptr, \arg_offset
1514    ldr wip, [ip,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1515    str wip, [\regs, \arg_offset]
1516    add \arg_offset, \arg_offset, #4
1517    b 1b
1518.endm
1519
1520// Puts the next int/long/object parameter passed in stack
1521// in the expected dex register array entry, and in case of object in the
1522// expected reference array entry.
1523// Uses ip and ip2 as temporary.
1524.macro LOOP_OVER_INTs shorty, arg_offset, regs, refs, stack_ptr, finished
15251: // LOOP
1526    ldrb wip, [\shorty], #1       // Load next character in shorty, and increment.
1527    cbz wip, \finished            // if (wip == '\0') goto finished
1528    cmp wip, #74                  // if (wip == 'J') goto FOUND_LONG
1529    b.eq 2f
1530    cmp wip, #70                  // if (wip == 'F') goto SKIP_FLOAT
1531    b.eq 3f
1532    cmp wip, #68                  // if (wip == 'D') goto SKIP_DOUBLE
1533    b.eq 4f
1534    add ip2, \stack_ptr, \arg_offset
1535    ldr wip2, [ip2,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1536    str wip2, [\regs, \arg_offset]
1537    cmp wip, #76                  // if (wip != 'L') goto loop
1538    b.ne 3f
1539    str wip2, [\refs, \arg_offset]
1540    add \arg_offset, \arg_offset, #4
1541    b 1b
15422:  // FOUND_LONG
1543    add ip, \stack_ptr, \arg_offset
1544    ldr ip, [ip,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1545    str ip, [\regs, \arg_offset]
1546    add \arg_offset, \arg_offset, #8
1547    b 1b
15483:  // SKIP_FLOAT
1549    add \arg_offset, \arg_offset, #4
1550    b 1b
15514:  // SKIP_DOUBLE
1552    add \arg_offset, \arg_offset, #8
1553    b 1b
1554.endm
1555
1556.macro SETUP_REFERENCE_PARAMETER_IN_GPR gpr32, regs, refs, ins, arg_offset, finished
1557    str \gpr32, [\regs, \arg_offset]
1558    sub \ins, \ins, #1
1559    str \gpr32, [\refs, \arg_offset]
1560    add \arg_offset, \arg_offset, #4
1561    cbz \ins, \finished
1562.endm
1563
1564// Uses ip2 as temporary.
1565.macro SETUP_REFERENCE_PARAMETERS_IN_STACK regs, refs, ins, stack_ptr, arg_offset
15661:
1567    ldr wip2, [\stack_ptr, \arg_offset]
1568    sub \ins, \ins, #1
1569    str wip2, [\regs, \arg_offset]
1570    str wip2, [\refs, \arg_offset]
1571    add \arg_offset, \arg_offset, #4
1572    cbnz \ins, 1b
1573.endm
1574
1575%def entry():
1576/*
1577 * ArtMethod entry point.
1578 *
1579 * On entry:
1580 *  x0   ArtMethod* callee
1581 *  rest  method parameters
1582 */
1583
1584OAT_ENTRY ExecuteNterpImpl, EndExecuteNterpImpl
1585    .cfi_startproc
1586    sub x16, sp, #STACK_OVERFLOW_RESERVED_BYTES
1587    ldr wzr, [x16]
1588    /* Spill callee save regs */
1589    SPILL_ALL_CALLEE_SAVES
1590
1591    ldr xPC, [x0, #ART_METHOD_DATA_OFFSET_64]
1592    // Setup the stack for executing the method.
1593    SETUP_STACK_FRAME xPC, xREFS, xFP, CFI_REFS, load_ins=1
1594
1595    // Setup the parameters
1596    cbz w15, .Lxmm_setup_finished
1597
1598    sub ip2, ip, x15
1599    ldr w26, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
1600    lsl x21, ip2, #2 // x21 is now the offset for inputs into the registers array.
1601
1602    tbz w26, #ART_METHOD_NTERP_ENTRY_POINT_FAST_PATH_FLAG_BIT, .Lsetup_slow_path
1603    // Setup pointer to inputs in FP and pointer to inputs in REFS
1604    add x10, xFP, x21
1605    add x11, xREFS, x21
1606    mov x12, #0
1607    SETUP_REFERENCE_PARAMETER_IN_GPR w1, x10, x11, w15, x12, .Lxmm_setup_finished
1608    SETUP_REFERENCE_PARAMETER_IN_GPR w2, x10, x11, w15, x12, .Lxmm_setup_finished
1609    SETUP_REFERENCE_PARAMETER_IN_GPR w3, x10, x11, w15, x12, .Lxmm_setup_finished
1610    SETUP_REFERENCE_PARAMETER_IN_GPR w4, x10, x11, w15, x12, .Lxmm_setup_finished
1611    SETUP_REFERENCE_PARAMETER_IN_GPR w5, x10, x11, w15, x12, .Lxmm_setup_finished
1612    SETUP_REFERENCE_PARAMETER_IN_GPR w6, x10, x11, w15, x12, .Lxmm_setup_finished
1613    SETUP_REFERENCE_PARAMETER_IN_GPR w7, x10, x11, w15, x12, .Lxmm_setup_finished
1614    add x28, x28, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK
1615    SETUP_REFERENCE_PARAMETERS_IN_STACK x10, x11, w15, x28, x12
1616    b .Lxmm_setup_finished
1617
1618.Lsetup_slow_path:
1619    // If the method is not static and there is one argument ('this'), we don't need to fetch the
1620    // shorty.
1621    tbnz w26, #ART_METHOD_IS_STATIC_FLAG_BIT, .Lsetup_with_shorty
1622    str w1, [xFP, x21]
1623    str w1, [xREFS, x21]
1624    cmp w15, #1
1625    b.eq .Lxmm_setup_finished
1626
1627.Lsetup_with_shorty:
1628    // TODO: Get shorty in a better way and remove below
1629    SPILL_ALL_ARGUMENTS
1630    bl NterpGetShorty
1631    // Save shorty in callee-save xIBASE.
1632    mov xIBASE, x0
1633    RESTORE_ALL_ARGUMENTS
1634
1635    // Setup pointer to inputs in FP and pointer to inputs in REFS
1636    add x10, xFP, x21
1637    add x11, xREFS, x21
1638    mov x12, #0
1639
1640    add x9, xIBASE, #1  // shorty + 1  ; ie skip return arg character
1641    tbnz w26, #ART_METHOD_IS_STATIC_FLAG_BIT, .Lhandle_static_method
1642    add x10, x10, #4
1643    add x11, x11, #4
1644    add x28, x28, #4
1645    b .Lcontinue_setup_gprs
1646.Lhandle_static_method:
1647    LOOP_OVER_SHORTY_STORING_GPRS x1, w1, x9, x12, x10, x11, .Lgpr_setup_finished
1648.Lcontinue_setup_gprs:
1649    LOOP_OVER_SHORTY_STORING_GPRS x2, w2, x9, x12, x10, x11, .Lgpr_setup_finished
1650    LOOP_OVER_SHORTY_STORING_GPRS x3, w3, x9, x12, x10, x11, .Lgpr_setup_finished
1651    LOOP_OVER_SHORTY_STORING_GPRS x4, w4, x9, x12, x10, x11, .Lgpr_setup_finished
1652    LOOP_OVER_SHORTY_STORING_GPRS x5, w5, x9, x12, x10, x11, .Lgpr_setup_finished
1653    LOOP_OVER_SHORTY_STORING_GPRS x6, w6, x9, x12, x10, x11, .Lgpr_setup_finished
1654    LOOP_OVER_SHORTY_STORING_GPRS x7, w7, x9, x12, x10, x11, .Lgpr_setup_finished
1655    LOOP_OVER_INTs x9, x12, x10, x11, x28, .Lgpr_setup_finished
1656.Lgpr_setup_finished:
1657    add x9, xIBASE, #1  // shorty + 1  ; ie skip return arg character
1658    mov x12, #0  // reset counter
1659    LOOP_OVER_SHORTY_STORING_FPS d0, s0, x9, x12, x10, .Lxmm_setup_finished
1660    LOOP_OVER_SHORTY_STORING_FPS d1, s1, x9, x12, x10, .Lxmm_setup_finished
1661    LOOP_OVER_SHORTY_STORING_FPS d2, s2, x9, x12, x10, .Lxmm_setup_finished
1662    LOOP_OVER_SHORTY_STORING_FPS d3, s3, x9, x12, x10, .Lxmm_setup_finished
1663    LOOP_OVER_SHORTY_STORING_FPS d4, s4, x9, x12, x10, .Lxmm_setup_finished
1664    LOOP_OVER_SHORTY_STORING_FPS d5, s5, x9, x12, x10, .Lxmm_setup_finished
1665    LOOP_OVER_SHORTY_STORING_FPS d6, s6, x9, x12, x10, .Lxmm_setup_finished
1666    LOOP_OVER_SHORTY_STORING_FPS d7, s7, x9, x12, x10, .Lxmm_setup_finished
1667    LOOP_OVER_FPs x9, x12, x10, x28, .Lxmm_setup_finished
1668.Lxmm_setup_finished:
1669    CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
1670
1671    // Set rIBASE
1672    adr xIBASE, artNterpAsmInstructionStart
1673    /* start executing the instruction at xPC */
1674    START_EXECUTING_INSTRUCTIONS
1675    /* NOTE: no fallthrough */
1676    // cfi info continues, and covers the whole nterp implementation.
1677    SIZE ExecuteNterpImpl
1678
1679%def opcode_pre():
1680
1681%def helpers():
1682
1683%def footer():
1684/*
1685 * ===========================================================================
1686 *  Common subroutines and data
1687 * ===========================================================================
1688 */
1689
1690    .text
1691    .align  2
1692
1693// Enclose all code below in a symbol (which gets printed in backtraces).
1694NAME_START nterp_helper
1695
1696// Note: mterp also uses the common_* names below for helpers, but that's OK
1697// as the assembler compiled each interpreter separately.
1698common_errDivideByZero:
1699    EXPORT_PC
1700    bl art_quick_throw_div_zero
1701
1702// Expect index in w1, length in w3.
1703common_errArrayIndex:
1704    EXPORT_PC
1705    mov x0, x1
1706    mov x1, x3
1707    bl art_quick_throw_array_bounds
1708
1709common_errNullObject:
1710    EXPORT_PC
1711    bl art_quick_throw_null_pointer_exception
1712
1713NterpCommonInvokeStatic:
1714    COMMON_INVOKE_NON_RANGE is_static=1, suffix="invokeStatic"
1715
1716NterpCommonInvokeStaticRange:
1717    COMMON_INVOKE_RANGE is_static=1, suffix="invokeStatic"
1718
1719NterpCommonInvokeInstance:
1720    COMMON_INVOKE_NON_RANGE suffix="invokeInstance"
1721
1722NterpCommonInvokeInstanceRange:
1723    COMMON_INVOKE_RANGE suffix="invokeInstance"
1724
1725NterpCommonInvokeInterface:
1726    COMMON_INVOKE_NON_RANGE is_interface=1, suffix="invokeInterface"
1727
1728NterpCommonInvokeInterfaceRange:
1729    COMMON_INVOKE_RANGE is_interface=1, suffix="invokeInterface"
1730
1731NterpCommonInvokePolymorphic:
1732    COMMON_INVOKE_NON_RANGE is_polymorphic=1, suffix="invokePolymorphic"
1733
1734NterpCommonInvokePolymorphicRange:
1735    COMMON_INVOKE_RANGE is_polymorphic=1, suffix="invokePolymorphic"
1736
1737NterpCommonInvokeCustom:
1738    COMMON_INVOKE_NON_RANGE is_static=1, is_custom=1, suffix="invokeCustom"
1739
1740NterpCommonInvokeCustomRange:
1741    COMMON_INVOKE_RANGE is_static=1, is_custom=1, suffix="invokeCustom"
1742
1743NterpHandleStringInit:
1744   COMMON_INVOKE_NON_RANGE is_string_init=1, suffix="stringInit"
1745
1746NterpHandleStringInitRange:
1747   COMMON_INVOKE_RANGE is_string_init=1, suffix="stringInit"
1748
1749NterpNewArray:
1750   /* new-array vA, vB, class@CCCC */
1751   EXPORT_PC
1752   // Fast-path which gets the class from thread-local cache.
1753   FETCH_FROM_THREAD_CACHE x0, 2f
1754   cbnz wMR, 3f
17551:
1756   lsr     w1, wINST, #12              // w1<- B
1757   GET_VREG w1, w1                     // w1<- vB (array length)
1758   ldr lr, [xSELF, #THREAD_ALLOC_ARRAY_ENTRYPOINT_OFFSET]
1759   blr lr
1760   ubfx    w1, wINST, #8, #4           // w1<- A
1761   SET_VREG_OBJECT w0, w1
1762   FETCH_ADVANCE_INST 2
1763   GET_INST_OPCODE ip
1764   GOTO_OPCODE ip
17652:
1766   mov x0, xSELF
1767   ldr x1, [sp, 0]
1768   mov x2, xPC
1769   bl nterp_get_class_or_allocate_object
1770   b 1b
17713:
1772   bl art_quick_read_barrier_mark_reg00
1773   b 1b
1774
1775NterpHandleHotnessOverflow:
1776    add x1, xPC, xINST, lsl #1
1777    mov x2, xFP
1778    bl nterp_hot_method
1779    cbnz x0, 1f
1780    add     xPC, xPC, wINST, sxtw #1    // update xPC
1781    FETCH wINST, 0                      // load wINST
1782    GET_INST_OPCODE ip                  // extract opcode from wINST
1783    GOTO_OPCODE ip                      // jump to next instruction
17841:
1785    // Drop the current frame.
1786    ldr ip, [xREFS, #-8]
1787    mov sp, ip
1788    .cfi_def_cfa sp, CALLEE_SAVES_SIZE
1789
1790    // The transition frame of type SaveAllCalleeSaves saves x19 and x20,
1791    // but not managed ABI. So we need to restore callee-saves of the nterp frame,
1792    // and save managed ABI callee saves, which will be restored by the callee upon
1793    // return.
1794    RESTORE_ALL_CALLEE_SAVES
1795    INCREASE_FRAME ((CALLEE_SAVES_SIZE) - 16)
1796
1797    // FP callee-saves
1798    stp d8, d9, [sp, #0]
1799    stp d10, d11, [sp, #16]
1800    stp d12, d13, [sp, #32]
1801    stp d14, d15, [sp, #48]
1802
1803    // GP callee-saves.
1804    SAVE_TWO_REGS x21, x22, 64
1805    SAVE_TWO_REGS x23, x24, 80
1806    SAVE_TWO_REGS x25, x26, 96
1807    SAVE_TWO_REGS x27, x28, 112
1808    SAVE_TWO_REGS x29, lr, 128
1809
1810    // Setup the new frame
1811    ldr x1, [x0, #OSR_DATA_FRAME_SIZE]
1812    // Given stack size contains all callee saved registers, remove them.
1813    sub x1, x1, #(CALLEE_SAVES_SIZE - 16)
1814
1815    // We know x1 cannot be 0, as it at least contains the ArtMethod.
1816
1817    // Remember CFA in a callee-save register.
1818    mov xINST, sp
1819    .cfi_def_cfa_register xINST
1820
1821    sub sp, sp, x1
1822
1823    add x2, x0, #OSR_DATA_MEMORY
18242:
1825    sub x1, x1, #8
1826    ldr ip, [x2, x1]
1827    str ip, [sp, x1]
1828    cbnz x1, 2b
1829
1830    // Fetch the native PC to jump to and save it in a callee-save register.
1831    ldr xFP, [x0, #OSR_DATA_NATIVE_PC]
1832
1833    // Free the memory holding OSR Data.
1834    bl free
1835
1836    // Jump to the compiled code.
1837    br xFP
1838
1839// This is the logical end of ExecuteNterpImpl, where the frame info applies.
1840// EndExecuteNterpImpl includes the methods below as we want the runtime to
1841// see them as part of the Nterp PCs.
1842.cfi_endproc
1843
1844nterp_to_nterp_static_non_range:
1845    .cfi_startproc
1846    SETUP_STACK_FOR_INVOKE
1847    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0
1848    .cfi_endproc
1849
1850nterp_to_nterp_string_init_non_range:
1851    .cfi_startproc
1852    SETUP_STACK_FOR_INVOKE
1853    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1
1854    .cfi_endproc
1855
1856nterp_to_nterp_instance_non_range:
1857    .cfi_startproc
1858    SETUP_STACK_FOR_INVOKE
1859    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
1860    .cfi_endproc
1861
1862nterp_to_nterp_static_range:
1863    .cfi_startproc
1864    SETUP_STACK_FOR_INVOKE
1865    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=1
1866    .cfi_endproc
1867
1868nterp_to_nterp_instance_range:
1869    .cfi_startproc
1870    SETUP_STACK_FOR_INVOKE
1871    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0
1872    .cfi_endproc
1873
1874nterp_to_nterp_string_init_range:
1875    .cfi_startproc
1876    SETUP_STACK_FOR_INVOKE
1877    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1
1878    .cfi_endproc
1879
1880NAME_END nterp_helper
1881
1882// This is the end of PCs contained by the OatQuickMethodHeader created for the interpreter
1883// entry point.
1884    .type EndExecuteNterpImpl, #function
1885    .hidden EndExecuteNterpImpl
1886    .global EndExecuteNterpImpl
1887EndExecuteNterpImpl:
1888
1889// Entrypoints into runtime.
1890NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField
1891NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset
1892NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray
1893NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange
1894NTERP_TRAMPOLINE nterp_get_class_or_allocate_object, NterpGetClassOrAllocateObject
1895NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod
1896NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod
1897NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject
1898
1899// gen_mterp.py will inline the following definitions
1900// within [ExecuteNterpImpl, EndExecuteNterpImpl).
1901%def instruction_end():
1902
1903    .type artNterpAsmInstructionEnd, #function
1904    .hidden artNterpAsmInstructionEnd
1905    .global artNterpAsmInstructionEnd
1906artNterpAsmInstructionEnd:
1907    // artNterpAsmInstructionEnd is used as landing pad for exception handling.
1908    FETCH_INST
1909    GET_INST_OPCODE ip
1910    GOTO_OPCODE ip
1911
1912%def instruction_start():
1913
1914    .type artNterpAsmInstructionStart, #function
1915    .hidden artNterpAsmInstructionStart
1916    .global artNterpAsmInstructionStart
1917artNterpAsmInstructionStart = .L_op_nop
1918    .text
1919
1920%def default_helper_prefix():
1921%  return "nterp_"
1922
1923%def opcode_start():
1924    NAME_START nterp_${opcode}
1925%def opcode_end():
1926    NAME_END nterp_${opcode}
1927%def helper_start(name):
1928    NAME_START ${name}
1929%def helper_end(name):
1930    NAME_END ${name}
1931