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 the next instruction from an offset specified by "reg" and advance xPC.
144 * xPC to point to the next instruction.  "reg" must specify the distance
145 * in bytes, *not* 16-bit code units, and may be a signed value.
146 *
147 */
148.macro FETCH_ADVANCE_INST_RB reg
149    add     xPC, xPC, \reg, sxtw
150    ldrh    wINST, [xPC]
151.endm
152
153/*
154 * Fetch a half-word code unit from an offset past the current PC.  The
155 * "count" value is in 16-bit code units.  Does not advance xPC.
156 *
157 * The "_S" variant works the same but treats the value as signed.
158 */
159.macro FETCH reg, count
160    ldrh    \reg, [xPC, #((\count)*2)]
161.endm
162
163.macro FETCH_S reg, count
164    ldrsh   \reg, [xPC, #((\count)*2)]
165.endm
166
167/*
168 * Fetch one byte from an offset past the current PC.  Pass in the same
169 * "count" as you would for FETCH, and an additional 0/1 indicating which
170 * byte of the halfword you want (lo/hi).
171 */
172.macro FETCH_B reg, count, byte
173    ldrb     \reg, [xPC, #((\count)*2+(\byte))]
174.endm
175
176/*
177 * Put the instruction's opcode field into the specified register.
178 */
179.macro GET_INST_OPCODE reg
180    and     \reg, xINST, #255
181.endm
182
183/*
184 * Begin executing the opcode in _reg.  Clobbers reg
185 */
186
187.macro GOTO_OPCODE reg
188    add     \reg, xIBASE, \reg, lsl #${handler_size_bits}
189    br      \reg
190.endm
191
192/*
193 * Get/set the 32-bit value from a Dalvik register.
194 */
195.macro GET_VREG reg, vreg
196    ldr     \reg, [xFP, \vreg, uxtw #2]
197.endm
198.macro GET_VREG_OBJECT reg, vreg
199    ldr     \reg, [xREFS, \vreg, uxtw #2]
200.endm
201.macro SET_VREG reg, vreg
202    str     \reg, [xFP, \vreg, uxtw #2]
203    str     wzr, [xREFS, \vreg, uxtw #2]
204.endm
205.macro SET_VREG_OBJECT reg, vreg, tmpreg
206    str     \reg, [xFP, \vreg, uxtw #2]
207    str     \reg, [xREFS, \vreg, uxtw #2]
208.endm
209.macro SET_VREG_FLOAT reg, vreg
210    str     \reg, [xFP, \vreg, uxtw #2]
211    str     wzr, [xREFS, \vreg, uxtw #2]
212.endm
213
214/*
215 * Get/set the 64-bit value from a Dalvik register.
216 */
217.macro GET_VREG_WIDE reg, vreg
218    add     ip2, xFP, \vreg, uxtw #2
219    ldr     \reg, [ip2]
220.endm
221.macro SET_VREG_WIDE reg, vreg
222    add     ip2, xFP, \vreg, uxtw #2
223    str     \reg, [ip2]
224    add     ip2, xREFS, \vreg, uxtw #2
225    str     xzr, [ip2]
226.endm
227.macro GET_VREG_DOUBLE reg, vreg
228    add     ip2, xFP, \vreg, uxtw #2
229    ldr     \reg, [ip2]
230.endm
231.macro SET_VREG_DOUBLE reg, vreg
232    add     ip2, xFP, \vreg, uxtw #2
233    str     \reg, [ip2]
234    add     ip2, xREFS, \vreg, uxtw #2
235    str     xzr, [ip2]
236.endm
237
238/*
239 * Get the 32-bit value from a Dalvik register and sign-extend to 64-bit.
240 * Used to avoid an extra instruction in int-to-long.
241 */
242.macro GET_VREG_S reg, vreg
243    ldrsw   \reg, [xFP, \vreg, uxtw #2]
244.endm
245
246// An assembly entry that has a OatQuickMethodHeader prefix.
247.macro OAT_ENTRY name, end
248    .type \name, #function
249    .hidden \name
250    .global \name
251    .balign 16
252    // Padding of 8 bytes to get 16 bytes alignment of code entry.
253    .long 0
254    .long 0
255    // OatQuickMethodHeader.
256    .long 0
257    .long (\end - \name)
258\name:
259.endm
260
261.macro SIZE name
262    .size \name, .-\name
263.endm
264
265.macro NAME_START name
266    .type \name, #function
267    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
268    .global \name
269    /* Cache alignment for function entry */
270    .balign 16
271\name:
272.endm
273
274.macro NAME_END name
275  SIZE \name
276.endm
277
278// Macro for defining entrypoints into runtime. We don't need to save registers
279// (we're not holding references there), but there is no
280// kDontSave runtime method. So just use the kSaveRefsOnly runtime method.
281.macro NTERP_TRAMPOLINE name, helper
282ENTRY \name
283  SETUP_SAVE_REFS_ONLY_FRAME
284  bl \helper
285  RESTORE_SAVE_REFS_ONLY_FRAME
286  REFRESH_MARKING_REGISTER
287  RETURN_OR_DELIVER_PENDING_EXCEPTION
288END \name
289.endm
290
291.macro CLEAR_STATIC_VOLATILE_MARKER reg
292  and \reg, \reg, #-2
293.endm
294
295.macro CLEAR_INSTANCE_VOLATILE_MARKER reg
296  neg \reg, \reg
297.endm
298
299.macro EXPORT_PC
300    str    xPC, [xREFS, #-16]
301.endm
302
303.macro BRANCH
304    // Update method counter and do a suspend check if the branch is negative.
305    tbnz wINST, #31, 2f
3061:
307    add w2, wINST, wINST                // w2<- byte offset
308    FETCH_ADVANCE_INST_RB w2            // update xPC, 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    add x2, x2, #1
315    and w2, w2, #NTERP_HOTNESS_MASK
316    strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
317    // If the counter overflows, handle this in the runtime.
318    cbz w2, NterpHandleHotnessOverflow
319    // Otherwise, do a suspend check.
320    ldr x0, [xSELF, #THREAD_FLAGS_OFFSET]
321    ands x0, x0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
322    b.eq 1b
323    EXPORT_PC
324    bl    art_quick_test_suspend
325    b 1b
326.endm
327
328// Setup the stack to start executing the method. Expects:
329// - x0 to contain the ArtMethod
330//
331// Outputs
332// - ip contains the dex registers size
333// - x13 contains the old stack pointer.
334//
335// Uses ip, ip2, x13, x14 as temporaries.
336.macro SETUP_STACK_FRAME code_item, refs, fp, cfi_refs
337    // Fetch dex register size.
338    ldrh wip, [\code_item, #CODE_ITEM_REGISTERS_SIZE_OFFSET]
339    // Fetch outs size.
340    ldrh wip2, [\code_item, #CODE_ITEM_OUTS_SIZE_OFFSET]
341
342    // Compute required frame size: ((2 * ip) + ip1) * 4 + 24
343    // 24 is for saving the previous frame, pc, and method being executed.
344    add x14, ip, ip
345    add x14, x14, ip2
346    lsl x14, x14, #2
347    add x14, x14, #24
348
349    // Compute new stack pointer in x14
350    sub x14, sp, x14
351    // Alignment
352    and x14, x14, #-16
353
354    // Set reference and dex registers, align to pointer size for previous frame and dex pc.
355    add \refs, x14, ip2, lsl #2
356    add \refs, \refs, 28
357    and \refs, \refs, #(-__SIZEOF_POINTER__)
358    add \fp, \refs, ip, lsl #2
359
360    // Now setup the stack pointer.
361    mov x13, sp
362    .cfi_def_cfa_register x13
363    mov sp, x14
364    str x13, [\refs, #-8]
365    CFI_DEF_CFA_BREG_PLUS_UCONST \cfi_refs, -8, CALLEE_SAVES_SIZE
366
367    // Put nulls in reference frame.
368    cbz ip, 2f
369    mov ip2, \refs
3701:
371    str xzr, [ip2], #8  // May clear vreg[0].
372    cmp ip2, \fp
373    b.lo 1b
3742:
375    // Save the ArtMethod.
376    str x0, [sp]
377.endm
378
379// Increase method hotness and do suspend check before starting executing the method.
380.macro START_EXECUTING_INSTRUCTIONS
381    ldr x0, [sp]
382    ldrh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
383    add x2, x2, #1
384    and w2, w2, #NTERP_HOTNESS_MASK
385    strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
386    // If the counter overflows, handle this in the runtime.
387    cbz w2, 2f
388    ldr x0, [xSELF, #THREAD_FLAGS_OFFSET]
389    tst x0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
390    b.ne 3f
3911:
392    FETCH_INST
393    GET_INST_OPCODE ip
394    GOTO_OPCODE ip
3952:
396    mov x1, xzr
397    mov x2, xFP
398    bl nterp_hot_method
399    b 1b
4003:
401    EXPORT_PC
402    bl art_quick_test_suspend
403    b 1b
404.endm
405
406.macro SPILL_ALL_CALLEE_SAVES
407    INCREASE_FRAME CALLEE_SAVES_SIZE
408    // Note: we technically don't need to save x19 and x20,
409    // but the runtime will expect those values to be there when unwinding
410    // (see Arm64Context::DoLongJump checking for the thread register).
411    SAVE_ALL_CALLEE_SAVES 0
412.endm
413
414.macro RESTORE_ALL_CALLEE_SAVES
415    // FP callee-saves
416    ldp d8, d9, [sp, #0]
417    ldp d10, d11, [sp, #16]
418    ldp d12, d13, [sp, #32]
419    ldp d14, d15, [sp, #48]
420
421    // GP callee-saves.
422    // No need to restore x19 (it's always the thread), and
423    // don't restore x20 (the marking register) as it may have been updated.
424    RESTORE_TWO_REGS x21, x22, 80
425    RESTORE_TWO_REGS x23, x24, 96
426    RESTORE_TWO_REGS x25, x26, 112
427    RESTORE_TWO_REGS x27, x28, 128
428    RESTORE_TWO_REGS x29, lr, 144
429
430    DECREASE_FRAME CALLEE_SAVES_SIZE
431.endm
432
433.macro SPILL_ALL_ARGUMENTS
434    INCREASE_FRAME 128
435    // GP arguments.
436    SAVE_TWO_REGS x0, x1, 0
437    SAVE_TWO_REGS x2, x3, 16
438    SAVE_TWO_REGS x4, x5, 32
439    SAVE_TWO_REGS x6, x7, 48
440
441    // FP arguments
442    stp d0, d1, [sp, #64]
443    stp d2, d3, [sp, #80]
444    stp d4, d5, [sp, #96]
445    stp d6, d7, [sp, #112]
446.endm
447
448.macro RESTORE_ALL_ARGUMENTS
449    // GP arguments.
450    RESTORE_TWO_REGS x0, x1, 0
451    RESTORE_TWO_REGS x2, x3, 16
452    RESTORE_TWO_REGS x4, x5, 32
453    RESTORE_TWO_REGS x6, x7, 48
454
455    // FP arguments
456    ldp d0, d1, [sp, #64]
457    ldp d2, d3, [sp, #80]
458    ldp d4, d5, [sp, #96]
459    ldp d6, d7, [sp, #112]
460    DECREASE_FRAME 128
461.endm
462
463// Helper to setup the stack after doing a nterp to nterp call. This will setup:
464// - xNEW_FP: the new pointer to dex registers
465// - xNEW_REFS: the new pointer to references
466// - xPC: the new PC pointer to execute
467// - x2: value in instruction to decode the number of arguments.
468// - x3: first dex register
469// - x4: top of dex register array
470//
471// The method expects:
472// - x0 to contain the ArtMethod
473// - x8 to contain the code item
474.macro SETUP_STACK_FOR_INVOKE
475   // We do the same stack overflow check as the compiler. See CanMethodUseNterp
476   // in how we limit the maximum nterp frame size.
477   sub x16, sp, #STACK_OVERFLOW_RESERVED_BYTES
478   ldr wzr, [x16]
479
480   // Spill all callee saves to have a consistent stack frame whether we
481   // are called by compiled code or nterp.
482   SPILL_ALL_CALLEE_SAVES
483
484   // Setup the frame.
485   SETUP_STACK_FRAME x8, xNEW_REFS, xNEW_FP, CFI_NEW_REFS
486   // Make x4 point to the top of the dex register array.
487   add x4, xNEW_FP, ip, uxtx #2
488
489   // Fetch instruction information before replacing xPC.
490   // TODO: move this down to the method that uses it, fetching it directly from wINST.
491   FETCH_B w2, 0, 1
492   // TODO: we could avoid this as instance invokes already fetch it.
493   FETCH w3, 2
494
495   // Set the dex pc pointer.
496   add xPC, x8, #CODE_ITEM_INSNS_OFFSET
497   CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
498.endm
499
500// Setup arguments based on a non-range nterp to nterp call, and start executing
501// the method. We expect:
502// - xNEW_FP: the new pointer to dex registers
503// - xNEW_REFS: the new pointer to references
504// - xPC: the new PC pointer to execute
505// - x2: number of arguments (bits 4-7), 5th argument if any (bits 0-3)
506// - x3: first dex register
507// - x4: top of dex register array
508// - x1: receiver if non-static.
509.macro SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
510   // /* op vA, vB, {vC...vG} */
511   asr ip2, x2, #4
512   cbz ip2, 6f
513   mov ip, #-4
514   cmp ip2, #2
515   b.lt 1f
516   b.eq 2f
517   cmp ip2, #4
518   b.lt 3f
519   b.eq 4f
520
521  // We use a decrementing ip to store references relative
522  // to xNEW_FP and dex registers relative to x4
523  //
524  // TODO: We could set up ip as the number of registers (this can be an additional output from
525  // SETUP_STACK_FOR_INVOKE) and then just decrement it by one before copying each arg.
526  // Maybe even introduce macros NEW_VREG_ADDRESS/NEW_VREG_REF_ADDRESS.
5275:
528   and         x2, x2, #15
529   GET_VREG_OBJECT w5, w2
530   str         w5, [xNEW_FP, ip]
531   GET_VREG    w5, w2
532   str         w5, [x4, ip]
533   sub         ip, ip, #4
5344:
535   asr         x2, x3, #12
536   GET_VREG_OBJECT w5, w2
537   str         w5, [xNEW_FP, ip]
538   GET_VREG    w5, w2
539   str         w5, [x4, ip]
540   sub         ip, ip, #4
5413:
542   ubfx        x2, x3, #8, #4
543   GET_VREG_OBJECT w5, w2
544   str         w5, [xNEW_FP, ip]
545   GET_VREG    w5, w2
546   str         w5, [x4, ip]
547   sub         ip, ip, #4
5482:
549   ubfx        x2, x3, #4, #4
550   GET_VREG_OBJECT w5, w2
551   str         w5, [xNEW_FP, ip]
552   GET_VREG    w5, w2
553   str         w5, [x4, ip]
554   .if !\is_string_init
555   sub         ip, ip, #4
556   .endif
5571:
558   .if \is_string_init
559   // Ignore the first argument
560   .elseif \is_static
561   and         x2, x3, #0xf
562   GET_VREG_OBJECT w5, w2
563   str         w5, [xNEW_FP, ip]
564   GET_VREG    w5, w2
565   str         w5, [x4, ip]
566   .else
567   str         w1, [xNEW_FP, ip]
568   str         w1, [x4, ip]
569   .endif
570
5716:
572   // Start executing the method.
573   mov xFP, xNEW_FP
574   mov xREFS, xNEW_REFS
575   CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE
576   START_EXECUTING_INSTRUCTIONS
577.endm
578
579// Setup arguments based on a range nterp to nterp call, and start executing
580// the method.
581// - xNEW_FP: the new pointer to dex registers
582// - xNEW_REFS: the new pointer to references
583// - xPC: the new PC pointer to execute
584// - x2: number of arguments
585// - x3: first dex register
586// - x4: top of dex register array
587// - x1: receiver if non-static.
588//
589// Uses ip, ip2, x5, x6 as temporaries.
590.macro SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
591   mov ip, #-4
592   .if \is_string_init
593   // Ignore the first argument
594   sub x2, x2, #1
595   add x3, x3, #1
596   .elseif !\is_static
597   sub x2, x2, #1
598   add x3, x3, #1
599   .endif
600
601   cbz x2, 2f
602   add ip2, xREFS, x3, lsl #2  // pointer to first argument in reference array
603   add ip2, ip2, x2, lsl #2    // pointer to last argument in reference array
604   add x5, xFP, x3, lsl #2     // pointer to first argument in register array
605   add x6, x5, x2, lsl #2      // pointer to last argument in register array
6061:
607   ldr  w7, [ip2, #-4]!
608   str  w7, [xNEW_FP, ip]
609   sub  x2, x2, 1
610   ldr  w7, [x6, #-4]!
611   str  w7, [x4, ip]
612   sub ip, ip, 4
613   cbnz x2, 1b
6142:
615   .if \is_string_init
616   // Ignore first argument
617   .elseif !\is_static
618   str w1, [xNEW_FP, ip]
619   str w1, [x4, ip]
620   .endif
621   mov xFP, xNEW_FP
622   mov xREFS, xNEW_REFS
623   CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE
624   START_EXECUTING_INSTRUCTIONS
625.endm
626
627.macro GET_SHORTY dest, is_interface, is_polymorphic, is_custom
628   stp x0, x1, [sp, #-16]!
629   .if \is_polymorphic
630   ldr x0, [sp, #16]
631   mov x1, xPC
632   bl NterpGetShortyFromInvokePolymorphic
633   .elseif \is_custom
634   ldr x0, [sp, #16]
635   mov x1, xPC
636   bl NterpGetShortyFromInvokeCustom
637   .elseif \is_interface
638   ldr x0, [sp, #16]
639   FETCH w1, 1
640   bl NterpGetShortyFromMethodId
641   .else
642   bl NterpGetShorty
643   .endif
644   mov \dest, x0
645   ldp x0, x1, [sp], #16
646.endm
647
648// Output: x8 contains the code item
649.macro GET_CODE_ITEM
650   // TODO: Get code item in a better way.
651   stp x0, x1, [sp, #-16]!
652   bl NterpGetCodeItem
653   mov x8, x0
654   ldp x0, x1, [sp], #16
655.endm
656
657.macro DO_ENTRY_POINT_CHECK call_compiled_code
658   // On entry, the method is x0, the instance is x1
659   adr x2, ExecuteNterpImpl
660   ldr x3, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
661   cmp x2, x3
662   b.ne  \call_compiled_code
663.endm
664
665.macro UPDATE_REGISTERS_FOR_STRING_INIT old_value, new_value
666   mov wip, wzr
6671:
668   GET_VREG_OBJECT wip2, wip
669   cmp wip2, \old_value
670   b.ne 2f
671   SET_VREG_OBJECT \new_value, wip
6722:
673   add wip, wip, #1
674   add ip2, xREFS, wip, uxtw #2
675   cmp ip2, xFP
676   b.ne 1b
677.endm
678
679// Puts the next floating point argument into the expected register,
680// fetching values based on a non-range invoke.
681// Uses ip and ip2.
682.macro LOOP_OVER_SHORTY_LOADING_FPS dreg, sreg, inst, shorty, arg_index, finished
6831: // LOOP
684    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
685    cbz wip, \finished              // if (wip == '\0') goto finished
686    cmp wip, #68                    // if (wip == 'D') goto FOUND_DOUBLE
687    b.eq 2f
688    cmp wip, #70                    // if (wip == 'F') goto FOUND_FLOAT
689    b.eq 3f
690    lsr \inst, \inst, #4
691    add \arg_index, \arg_index, #1
692    //  Handle extra argument in arg array taken by a long.
693    cmp wip, #74                   // if (wip != 'J') goto LOOP
694    b.ne 1b
695    lsr \inst, \inst, #4
696    add \arg_index, \arg_index, #1
697    b 1b                        // goto LOOP
6982:  // FOUND_DOUBLE
699    and ip, \inst, #0xf
700    GET_VREG wip, wip
701    lsr \inst, \inst, #4
702    add \arg_index, \arg_index, #1
703    cmp \arg_index, #4
704    b.eq 5f
705    and ip2, \inst, #0xf
706    lsr \inst, \inst, #4
707    add \arg_index, \arg_index, #1
708    b 6f
7095:
710    // TODO: Extract from wINST here and below? (Requires using a different register
711    // in the COMMON_INVOKE_NON_RANGE.)
712    FETCH_B wip2, 0, 1
713    and wip2, wip2, #0xf
7146:
715    GET_VREG wip2, wip2
716    add ip, ip, ip2, lsl #32
717    fmov \dreg, ip
718    b 4f
7193:  // FOUND_FLOAT
720    cmp \arg_index, #4
721    b.eq 7f
722    and ip, \inst, #0xf
723    lsr \inst, \inst, #4
724    add \arg_index, \arg_index, #1
725    b 8f
7267:
727    FETCH_B wip, 0, 1
728    and wip, wip, #0xf
7298:
730    GET_VREG \sreg, wip
7314:
732.endm
733
734// Puts the next int/long/object argument in the expected register,
735// fetching values based on a non-range invoke.
736// Uses ip and ip2.
737.macro LOOP_OVER_SHORTY_LOADING_GPRS gpr_reg64, gpr_reg32, inst, shorty, arg_index, finished
7381: // LOOP
739    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
740    cbz wip, \finished              // if (wip == '\0') goto finished
741    cmp wip, #74                    // if (wip == 'J') goto FOUND_LONG
742    b.eq 2f
743    cmp wip, #70                    // if (wip == 'F') goto SKIP_FLOAT
744    b.eq 3f
745    cmp wip, #68                    // if (wip == 'D') goto SKIP_DOUBLE
746    b.eq 4f
747    cmp \arg_index, #4
748    b.eq 7f
749    and ip, \inst, #0xf
750    lsr \inst, \inst, #4
751    add \arg_index, \arg_index, #1
752    b 8f
7537:
754    FETCH_B wip, 0, 1
755    and wip, wip, #0xf
7568:
757    GET_VREG \gpr_reg32, wip
758    b 5f
7592:  // FOUND_LONG
760    and ip, \inst, #0xf
761    GET_VREG wip, wip
762    lsr \inst, \inst, #4
763    add \arg_index, \arg_index, #1
764    cmp \arg_index, #4
765    b.eq 9f
766    and ip2, \inst, #0xf
767    lsr \inst, \inst, #4
768    add \arg_index, \arg_index, #1
769    b 10f
7709:
771    FETCH_B wip2, 0, 1
772    and wip2, wip2, #0xf
77310:
774    GET_VREG wip2, wip2
775    add \gpr_reg64, ip, ip2, lsl #32
776    b 5f
7773:  // SKIP_FLOAT
778    lsr \inst, \inst, #4
779    add \arg_index, \arg_index, #1
780    b 1b
7814:  // SKIP_DOUBLE
782    lsr \inst, \inst, #4
783    add \arg_index, \arg_index, #1
784    cmp \arg_index, #4
785    b.eq 1b
786    lsr \inst, \inst, #4
787    add \arg_index, \arg_index, #1
788    b 1b
7895:
790.endm
791
792.macro COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
793   .if \is_polymorphic
794   // We always go to compiled code for polymorphic calls.
795   .elseif \is_custom
796   // We always go to compiled code for custom calls.
797   .else
798     DO_ENTRY_POINT_CHECK .Lcall_compiled_code_\suffix
799     GET_CODE_ITEM
800     .if \is_string_init
801     bl nterp_to_nterp_string_init_non_range
802     .elseif \is_static
803     bl nterp_to_nterp_static_non_range
804     .else
805     bl nterp_to_nterp_instance_non_range
806     .endif
807     b .Ldone_return_\suffix
808   .endif
809
810.Lcall_compiled_code_\suffix:
811   GET_SHORTY xINST, \is_interface, \is_polymorphic, \is_custom
812   // From this point:
813   // - xINST contains shorty (in callee-save to switch over return value after call).
814   // - x0 contains method
815   // - x1 contains 'this' pointer for instance method.
816   add x9, xINST, #1  // shorty + 1  ; ie skip return arg character
817   FETCH w11, 2 // arguments
818   .if \is_string_init
819   lsr x11, x11, #4
820   mov x10, #1       // ignore first argument
821   .elseif \is_static
822   mov x10, xzr      // arg_index
823   .else
824   lsr x11, x11, #4
825   mov x10, #1       // ignore first argument
826   .endif
827   LOOP_OVER_SHORTY_LOADING_FPS d0, s0, x11, x9, x10, .Lxmm_setup_finished_\suffix
828   LOOP_OVER_SHORTY_LOADING_FPS d1, s1, x11, x9, x10, .Lxmm_setup_finished_\suffix
829   LOOP_OVER_SHORTY_LOADING_FPS d2, s2, x11, x9, x10, .Lxmm_setup_finished_\suffix
830   LOOP_OVER_SHORTY_LOADING_FPS d3, s3, x11, x9, x10, .Lxmm_setup_finished_\suffix
831   LOOP_OVER_SHORTY_LOADING_FPS d4, s4, x11, x9, x10, .Lxmm_setup_finished_\suffix
832.Lxmm_setup_finished_\suffix:
833   add x9, xINST, #1  // shorty + 1  ; ie skip return arg character
834   FETCH w11, 2 // arguments
835   .if \is_string_init
836   lsr x11, x11, #4
837   mov x10, #1       // ignore first argument
838   LOOP_OVER_SHORTY_LOADING_GPRS x1, w1, x11, x9, x10, .Lgpr_setup_finished_\suffix
839   .elseif \is_static
840   mov x10, xzr      // arg_index
841   LOOP_OVER_SHORTY_LOADING_GPRS x1, w1, x11, x9, x10, .Lgpr_setup_finished_\suffix
842   .else
843   lsr x11, x11, #4
844   mov x10, #1       // ignore first argument
845   .endif
846   LOOP_OVER_SHORTY_LOADING_GPRS x2, w2, x11, x9, x10, .Lgpr_setup_finished_\suffix
847   LOOP_OVER_SHORTY_LOADING_GPRS x3, w3, x11, x9, x10, .Lgpr_setup_finished_\suffix
848   LOOP_OVER_SHORTY_LOADING_GPRS x4, w4, x11, x9, x10, .Lgpr_setup_finished_\suffix
849   LOOP_OVER_SHORTY_LOADING_GPRS x5, w5, x11, x9, x10, .Lgpr_setup_finished_\suffix
850.Lgpr_setup_finished_\suffix:
851   .if \is_polymorphic
852   bl art_quick_invoke_polymorphic
853   .elseif \is_custom
854   bl art_quick_invoke_custom
855   .else
856      .if \is_interface
857      // Setup hidden argument
858      FETCH wip2, 1
859      .endif
860      ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
861      blr lr
862   .endif
863   ldrb wip, [xINST]
864   cmp ip, #68       // Test if result type char == 'D'.
865   b.eq .Lreturn_double_\suffix
866   cmp ip, #70
867   b.ne .Ldone_return_\suffix
868.Lreturn_float_\suffix:
869   fmov w0, s0
870   b .Ldone_return_\suffix
871.Lreturn_double_\suffix:
872   fmov x0, d0
873.Ldone_return_\suffix:
874   /* resume execution of caller */
875   .if \is_string_init
876   FETCH w11, 2 // arguments
877   and x11, x11, #0xf
878   GET_VREG w1, w11
879   UPDATE_REGISTERS_FOR_STRING_INIT w1, w0
880   .endif
881
882   .if \is_polymorphic
883   FETCH_ADVANCE_INST 4
884   .else
885   FETCH_ADVANCE_INST 3
886   .endif
887   GET_INST_OPCODE ip
888   GOTO_OPCODE ip
889.endm
890
891// Puts the next floating point argument into the expected register,
892// fetching values based on a range invoke.
893// Uses ip as temporary.
894.macro LOOP_RANGE_OVER_SHORTY_LOADING_FPS dreg, sreg, shorty, arg_index, stack_index, finished
8951: // LOOP
896    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
897    cbz wip, \finished              // if (wip == '\0') goto finished
898    cmp wip, #68                    // if (wip == 'D') goto FOUND_DOUBLE
899    b.eq 2f
900    cmp wip, #70                    // if (wip == 'F') goto FOUND_FLOAT
901    b.eq 3f
902    add \arg_index, \arg_index, #1
903    add \stack_index, \stack_index, #1
904    //  Handle extra argument in arg array taken by a long.
905    cmp wip, #74                    // if (wip != 'J') goto LOOP
906    b.ne 1b
907    add \arg_index, \arg_index, #1
908    add \stack_index, \stack_index, #1
909    b 1b                        // goto LOOP
9102:  // FOUND_DOUBLE
911    GET_VREG_DOUBLE \dreg, \arg_index
912    add \arg_index, \arg_index, #2
913    add \stack_index, \stack_index, #2
914    b 4f
9153:  // FOUND_FLOAT
916    GET_VREG \sreg, \arg_index
917    add \arg_index, \arg_index, #1
918    add \stack_index, \stack_index, #1
9194:
920.endm
921
922// Puts the next floating point argument into the expected stack slot,
923// fetching values based on a range invoke.
924// Uses ip as temporary.
925//
926// TODO: We could just copy all the vregs to the stack slots in a simple loop
927// without looking at the shorty at all. (We could also drop
928// the "stack_index" from the macros for loading registers.) We could also do
929// that conditionally if argument word count > 6; otherwise we know that all
930// args fit into registers.
931.macro LOOP_RANGE_OVER_FPs shorty, arg_index, stack_index, finished
9321: // LOOP
933    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
934    cbz wip, \finished              // if (wip == '\0') goto finished
935    cmp wip, #68                    // if (wip == 'D') goto FOUND_DOUBLE
936    b.eq 2f
937    cmp wip, #70                    // if (wip == 'F') goto FOUND_FLOAT
938    b.eq 3f
939    add \arg_index, \arg_index, #1
940    add \stack_index, \stack_index, #1
941    //  Handle extra argument in arg array taken by a long.
942    cmp wip, #74                    // if (wip != 'J') goto LOOP
943    b.ne 1b
944    add \arg_index, \arg_index, #1
945    add \stack_index, \stack_index, #1
946    b 1b                        // goto LOOP
9472:  // FOUND_DOUBLE
948    GET_VREG_WIDE ip, \arg_index
949    add ip2, sp, \stack_index, uxtw #2
950    str ip, [ip2]
951    add \arg_index, \arg_index, #2
952    add \stack_index, \stack_index, #2
953    b 1b
9543:  // FOUND_FLOAT
955    GET_VREG wip, \arg_index
956    str wip, [sp, \stack_index, uxtw #2]
957    add \arg_index, \arg_index, #1
958    add \stack_index, \stack_index, #1
959    b 1b
960.endm
961
962// Puts the next int/long/object argument in the expected register,
963// fetching values based on a range invoke.
964// Uses ip as temporary.
965.macro LOOP_RANGE_OVER_SHORTY_LOADING_GPRS reg64, reg32, shorty, arg_index, stack_index, finished
9661: // LOOP
967    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
968    cbz wip, \finished              // if (wip == '\0') goto finished
969    cmp wip, #74                    // if (wip == 'J') goto FOUND_LONG
970    b.eq 2f
971    cmp wip, #70                   // if (wip == 'F') goto SKIP_FLOAT
972    b.eq 3f
973    cmp wip, #68                    // if (wip == 'D') goto SKIP_DOUBLE
974    b.eq 4f
975    GET_VREG \reg32, \arg_index
976    add \arg_index, \arg_index, #1
977    add \stack_index, \stack_index, #1
978    b 5f
9792:  // FOUND_LONG
980    GET_VREG_WIDE \reg64, \arg_index
981    add \arg_index, \arg_index, #2
982    add \stack_index, \stack_index, #2
983    b 5f
9843:  // SKIP_FLOAT
985    add \arg_index, \arg_index, #1
986    add \stack_index, \stack_index, #1
987    b 1b
9884:  // SKIP_DOUBLE
989    add \arg_index, \arg_index, #2
990    add \stack_index, \stack_index, #2
991    b 1b
9925:
993.endm
994
995// Puts the next int/long/object argument in the expected stack slot,
996// fetching values based on a range invoke.
997// Uses ip as temporary.
998.macro LOOP_RANGE_OVER_INTs shorty, arg_index, stack_index, finished
9991: // LOOP
1000    ldrb wip, [\shorty], #1         // Load next character in shorty, and increment.
1001    cbz wip, \finished              // if (wip == '\0') goto finished
1002    cmp wip, #74                    // if (wip == 'J') goto FOUND_LONG
1003    b.eq 2f
1004    cmp wip, #70                    // if (wip == 'F') goto SKIP_FLOAT
1005    b.eq 3f
1006    cmp wip, #68                    // if (wip == 'D') goto SKIP_DOUBLE
1007    b.eq 4f
1008    GET_VREG wip, \arg_index
1009    str wip, [sp, \stack_index, uxtw #2]
1010    add \arg_index, \arg_index, #1
1011    add \stack_index, \stack_index, #1
1012    b 1b
10132:  // FOUND_LONG
1014    GET_VREG_WIDE ip, \arg_index
1015    add ip2, sp, \stack_index, uxtw #2
1016    str ip, [ip2]
1017    add \arg_index, \arg_index, #2
1018    add \stack_index, \stack_index, #2
1019    b 1b
10203:  // SKIP_FLOAT
1021    add \arg_index, \arg_index, #1
1022    add \stack_index, \stack_index, #1
1023    b 1b
10244:  // SKIP_DOUBLE
1025    add \arg_index, \arg_index, #2
1026    add \stack_index, \stack_index, #2
1027    b 1b
1028.endm
1029
1030.macro COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
1031   .if \is_polymorphic
1032   // We always go to compiled code for polymorphic calls.
1033   .elseif \is_custom
1034   // We always go to compiled code for custom calls.
1035   .else
1036     DO_ENTRY_POINT_CHECK .Lcall_compiled_code_range_\suffix
1037     GET_CODE_ITEM
1038     .if \is_string_init
1039     bl nterp_to_nterp_string_init_range
1040     .elseif \is_static
1041     bl nterp_to_nterp_static_range
1042     .else
1043     bl nterp_to_nterp_instance_range
1044     .endif
1045     b .Ldone_return_range_\suffix
1046   .endif
1047
1048.Lcall_compiled_code_range_\suffix:
1049   GET_SHORTY xINST, \is_interface, \is_polymorphic, \is_custom
1050   // From this point:
1051   // - xINST contains shorty (in callee-save to switch over return value after call).
1052   // - x0 contains method
1053   // - x1 contains 'this' pointer for instance method.
1054   add x9, xINST, #1  // shorty + 1  ; ie skip return arg character
1055   FETCH w10, 2 // arguments
1056   .if \is_string_init
1057   add x10, x10, #1  // arg start index
1058   mov x11, #1       // index in stack
1059   .elseif \is_static
1060   mov x11, xzr      // index in stack
1061   .else
1062   add x10, x10, #1  // arg start index
1063   mov x11, #1       // index in stack
1064   .endif
1065   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d0, s0, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1066   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d1, s1, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1067   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d2, s2, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1068   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d3, s3, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1069   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d4, s4, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1070   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d5, s5, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1071   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d6, s6, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1072   LOOP_RANGE_OVER_SHORTY_LOADING_FPS d7, s7, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1073   // Store in the outs array (stored above the ArtMethod in the stack)
1074   add x11, x11, #2 // Add two words for the ArtMethod stored before the outs.
1075   LOOP_RANGE_OVER_FPs x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1076.Lxmm_setup_finished_range_\suffix:
1077   add x9, xINST, #1  // shorty + 1  ; ie skip return arg character
1078   FETCH w10, 2 // arguments
1079   .if \is_string_init
1080   add x10, x10, #1  // arg start index
1081   mov x11, #1       // index in stack
1082   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x1, w1, x9, w10, w11, .Lgpr_setup_finished_\suffix
1083   .elseif \is_static
1084   mov x11, xzr      // index in stack
1085   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x1, w1, x9, w10, w11 .Lgpr_setup_finished_\suffix
1086   .else
1087   add x10, x10, #1  // arg start index
1088   mov x11, #1       // index in stack
1089   .endif
1090   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x2, w2, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1091   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x3, w3, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1092   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x4, w4, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1093   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x5, w5, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1094   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x6, w6, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1095   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x7, w7, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1096   // Store in the outs array (stored above the ArtMethod in the stack)
1097   add x11, x11, #2 // Add two words for the ArtMethod stored before the outs.
1098   LOOP_RANGE_OVER_INTs x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1099.Lgpr_setup_finished_range_\suffix:
1100   .if \is_polymorphic
1101   bl art_quick_invoke_polymorphic
1102   .elseif \is_custom
1103   bl art_quick_invoke_custom
1104   .else
1105      .if \is_interface
1106      // Setup hidden argument
1107      FETCH wip2, 1
1108      .endif
1109      ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
1110      blr lr
1111   .endif
1112   ldrb wip, [xINST]
1113   cmp ip, #68       // Test if result type char == 'D'.
1114   b.eq .Lreturn_double_range_\suffix
1115   cmp ip, #70
1116   b.ne .Ldone_return_\suffix
1117.Lreturn_float_range_\suffix:
1118   fmov w0, s0
1119   b .Ldone_return_range_\suffix
1120.Lreturn_double_range_\suffix:
1121   fmov x0, d0
1122.Ldone_return_range_\suffix:
1123   /* resume execution of caller */
1124   .if \is_string_init
1125   FETCH w11, 2 // arguments
1126   GET_VREG w1, w11
1127   UPDATE_REGISTERS_FOR_STRING_INIT w1, w0
1128   .endif
1129
1130   .if \is_polymorphic
1131    FETCH_ADVANCE_INST 4
1132   .else
1133   FETCH_ADVANCE_INST 3
1134   .endif
1135   GET_INST_OPCODE ip
1136   GOTO_OPCODE ip
1137.endm
1138
1139// Fetch some information from the thread cache.
1140// Uses ip and ip2 as temporaries.
1141.macro FETCH_FROM_THREAD_CACHE dest_reg, slow_path
1142   add      ip, xSELF, #THREAD_INTERPRETER_CACHE_OFFSET       // cache address
1143   ubfx     ip2, xPC, #2, #THREAD_INTERPRETER_CACHE_SIZE_LOG2  // entry index
1144   add      ip, ip, ip2, lsl #4            // entry address within the cache
1145   ldp      ip, \dest_reg, [ip]           // entry key (pc) and value (offset)
1146   cmp      ip, xPC
1147   b.ne \slow_path
1148.endm
1149
1150// Helper for static field get.
1151.macro OP_SGET load="ldr", volatile_load="ldar", maybe_extend="", wide="0"
1152   // Fast-path which gets the field from thread-local cache.
1153   FETCH_FROM_THREAD_CACHE x0, 4f
11541:
1155   ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1156   ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1157   cbnz wMR, 3f
11582:
1159   lsr w2, wINST, #8              // w2 <- A
1160   .if \wide
1161   ldr x0, [x0, x1]
1162   SET_VREG_WIDE x0, w2          // fp[A] <- value
1163   .else
1164   \load w0, [x0, x1]
1165   SET_VREG w0, w2               // fp[A] <- value
1166   .endif
1167   FETCH_ADVANCE_INST 2
1168   GET_INST_OPCODE ip
1169   GOTO_OPCODE ip
11703:
1171   bl art_quick_read_barrier_mark_reg00
1172   b 2b
11734:
1174   mov x0, xSELF
1175   ldr x1, [sp]
1176   mov x2, xPC
1177   EXPORT_PC
1178   bl nterp_get_static_field
1179   tbz x0, #0, 1b
1180   CLEAR_STATIC_VOLATILE_MARKER x0
1181   ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1182   ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1183   cbnz wMR, 7f
11845:
1185   lsr w2, wINST, #8              // w2 <- A
1186   add x0, x0, x1
1187   .if \wide
1188   ldar x0, [x0]
1189   SET_VREG_WIDE x0, w2          // fp[A] <- value
1190   .else
1191   \volatile_load w0, [x0]
1192   \maybe_extend
1193   SET_VREG w0, w2               // fp[A] <- value
1194   .endif
1195   FETCH_ADVANCE_INST 2
1196   GET_INST_OPCODE ip
1197   GOTO_OPCODE ip
11987:
1199   bl art_quick_read_barrier_mark_reg00
1200   b 5b
1201.endm
1202
1203// Helper for static field put.
1204.macro OP_SPUT store="str", volatile_store="stlr", wide="0":
1205   // Fast-path which gets the field from thread-local cache.
1206   FETCH_FROM_THREAD_CACHE x0, 4f
12071:
1208   ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1209   ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1210   cbnz wMR, 3f
12112:
1212   lsr w2, wINST, #8              // w2 <- A
1213   .if \wide
1214   GET_VREG_WIDE x2, w2           // x2 <- v[A]
1215   \store    x2, [x0, x1]
1216   .else
1217   GET_VREG w2, w2                // w2 <- v[A]
1218   \store    w2, [x0, x1]
1219   .endif
1220   FETCH_ADVANCE_INST 2
1221   GET_INST_OPCODE ip
1222   GOTO_OPCODE ip
12233:
1224   bl art_quick_read_barrier_mark_reg00
1225   b 2b
12264:
1227   mov x0, xSELF
1228   ldr x1, [sp]
1229   mov x2, xPC
1230   EXPORT_PC
1231   bl nterp_get_static_field
1232   tbz x0, #0, 1b
1233   CLEAR_STATIC_VOLATILE_MARKER x0
1234   ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1235   ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1236   cbnz wMR, 6f
12375:
1238   lsr w2, wINST, #8              // w2 <- A
1239   add x0, x0, x1
1240   .if \wide
1241   GET_VREG_WIDE x2, w2           // x2 <- v[A]
1242   \volatile_store    x2, [x0]
1243   .else
1244   GET_VREG w2, w2                // w2 <- v[A]
1245   \volatile_store    w2, [x0]
1246   .endif
1247   FETCH_ADVANCE_INST 2
1248   GET_INST_OPCODE ip
1249   GOTO_OPCODE ip
12506:
1251   bl art_quick_read_barrier_mark_reg00
1252   b 5b
1253.endm
1254
1255
1256// Helper for instance field put.
1257.macro OP_IPUT store="str", volatile_store="stlr", wide="0":
1258   // Fast-path which gets the field from thread-local cache.
1259   FETCH_FROM_THREAD_CACHE x0, 2f
12601:
1261   ubfx    w1, wINST, #8, #4           // w1<- A
1262   lsr     w2, wINST, #12              // w2<- B
1263   GET_VREG w2, w2                     // vB (object we're operating on)
1264   cbz w2, common_errNullObject
1265   .if \wide
1266   GET_VREG_WIDE x1, w1                // x1<- fp[A]/fp[A+1]
1267   \store x1, [x2, x0]
1268   .else
1269   GET_VREG w1, w1                     // w1 <- v[A]
1270   \store w1, [x2, x0]
1271   .endif
1272   FETCH_ADVANCE_INST 2
1273   GET_INST_OPCODE ip
1274   GOTO_OPCODE ip
12752:
1276   mov x0, xSELF
1277   ldr x1, [sp]
1278   mov x2, xPC
1279   EXPORT_PC
1280   bl nterp_get_instance_field_offset
1281   tbz w0, #31, 1b
1282   CLEAR_INSTANCE_VOLATILE_MARKER w0
1283   ubfx    w1, wINST, #8, #4           // w1<- A
1284   lsr     w2, wINST, #12              // w2<- B
1285   GET_VREG w2, w2                     // vB (object we're operating on)
1286   cbz w2, common_errNullObject
1287   add x2, x2, x0
1288   .if \wide
1289   GET_VREG_WIDE x1, w1                // x1<- fp[A]/fp[A+1]
1290   \volatile_store x1, [x2]
1291   .else
1292   GET_VREG w1, w1                     // w1 <- v[A]
1293   \volatile_store w1, [x2]
1294   .endif
1295   FETCH_ADVANCE_INST 2
1296   GET_INST_OPCODE ip
1297   GOTO_OPCODE ip
1298.endm
1299
1300// Helper for instance field get.
1301.macro OP_IGET load="ldr", volatile_load="ldar", maybe_extend="", wide="0"
1302   // Fast-path which gets the field from thread-local cache.
1303   FETCH_FROM_THREAD_CACHE x0, 2f
13041:
1305   lsr     w2, wINST, #12              // w2<- B
1306   GET_VREG w3, w2                     // w3<- object we're operating on
1307   ubfx    w2, wINST, #8, #4           // w2<- A
1308   cbz     w3, common_errNullObject    // object was null
1309   .if \wide
1310   \load x0, [x3, x0]
1311   SET_VREG_WIDE x0, w2                // fp[A] <- value
1312   .else
1313   \load w0, [x3, x0]
1314   SET_VREG w0, w2                     // fp[A] <- value
1315   .endif
1316   FETCH_ADVANCE_INST 2
1317   GET_INST_OPCODE ip
1318   GOTO_OPCODE ip
13192:
1320   mov x0, xSELF
1321   ldr x1, [sp]
1322   mov x2, xPC
1323   EXPORT_PC
1324   bl nterp_get_instance_field_offset
1325   tbz w0, #31, 1b
1326   CLEAR_INSTANCE_VOLATILE_MARKER w0
1327   lsr     w2, wINST, #12              // w2<- B
1328   GET_VREG w3, w2                     // w3<- object we're operating on
1329   ubfx    w2, wINST, #8, #4           // w2<- A
1330   cbz     w3, common_errNullObject    // object was null
1331   add x3, x3, x0
1332   .if \wide
1333   \volatile_load x0, [x3]
1334   SET_VREG_WIDE x0, w2                // fp[A] <- value
1335   .else
1336   \volatile_load w0, [x3]
1337   \maybe_extend
1338   SET_VREG w0, w2                     // fp[A] <- value
1339   .endif
1340   FETCH_ADVANCE_INST 2
1341   GET_INST_OPCODE ip
1342   GOTO_OPCODE ip
1343.endm
1344
1345// Puts the next int/long/object parameter passed in physical register
1346// in the expected dex register array entry, and in case of object in the
1347// expected reference array entry.
1348.macro LOOP_OVER_SHORTY_STORING_GPRS gpr_64, gpr_32, shorty, arg_offset, regs, refs, finished
13491: // LOOP
1350    ldrb wip, [\shorty], #1       // Load next character in shorty, and increment.
1351    cbz wip, \finished            // if (wip == '\0') goto finished
1352    cmp wip, #74                  // if (wip == 'J') goto FOUND_LONG
1353    b.eq 2f
1354    cmp wip, #70                  // if (wip == 'F') goto SKIP_FLOAT
1355    b.eq 3f
1356    cmp wip, #68                  // if (wip == 'D') goto SKIP_DOUBLE
1357    b.eq 4f
1358    str \gpr_32, [\regs, \arg_offset]
1359    cmp wip, #76                  // if (wip != 'L') goto NOT_REFERENCE
1360    b.ne 6f
1361    str \gpr_32, [\refs, \arg_offset]
13626:  // NOT_REFERENCE
1363    add \arg_offset, \arg_offset, #4
1364    b 5f
13652:  // FOUND_LONG
1366    str \gpr_64, [\regs, \arg_offset]
1367    add \arg_offset, \arg_offset, #8
1368    b 5f
13693:  // SKIP_FLOAT
1370    add \arg_offset, \arg_offset, #4
1371    b 1b
13724:  // SKIP_DOUBLE
1373    add \arg_offset, \arg_offset, #8
1374    b 1b
13755:
1376.endm
1377
1378// Puts the next floating point parameter passed in physical register
1379// in the expected dex register array entry.
1380// Uses ip as temporary.
1381.macro LOOP_OVER_SHORTY_STORING_FPS dreg, sreg, shorty, arg_offset, fp, finished
13821: // LOOP
1383    ldrb wip, [\shorty], #1                 // Load next character in shorty, and increment.
1384    cbz wip, \finished                      // if (wip == '\0') goto finished
1385    cmp wip, #68                            // if (wip == 'D') goto FOUND_DOUBLE
1386    b.eq 2f
1387    cmp wip, #70                            // if (wip == 'F') goto FOUND_FLOAT
1388    b.eq 3f
1389    add \arg_offset, \arg_offset, #4
1390    //  Handle extra argument in arg array taken by a long.
1391    cmp wip, #74                            // if (wip != 'J') goto LOOP
1392    b.ne 1b
1393    add \arg_offset, \arg_offset, #4
1394    b 1b                        // goto LOOP
13952:  // FOUND_DOUBLE
1396    str \dreg, [\fp, \arg_offset]
1397    add \arg_offset, \arg_offset, #8
1398    b 4f
13993:  // FOUND_FLOAT
1400    str \sreg, [\fp, \arg_offset]
1401    add \arg_offset, \arg_offset, #4
14024:
1403.endm
1404
1405// Puts the next floating point parameter passed in stack
1406// in the expected dex register array entry.
1407// Uses ip as temporary.
1408//
1409// TODO: Or we could just spill regs to the reserved slots in the caller's
1410// frame and copy all regs in a simple loop. This time, however, we would
1411// need to look at the shorty anyway to look for the references.
1412// (The trade-off is different for passing arguments and receiving them.)
1413.macro LOOP_OVER_FPs shorty, arg_offset, regs, stack_ptr, finished
14141: // LOOP
1415    ldrb wip, [\shorty], #1                 // Load next character in shorty, and increment.
1416    cbz wip, \finished                      // if (wip == '\0') goto finished
1417    cmp wip, #68                            // if (wip == 'D') goto FOUND_DOUBLE
1418    b.eq 2f
1419    cmp wip, #70                            // if (wip == 'F') goto FOUND_FLOAT
1420    b.eq 3f
1421    add \arg_offset, \arg_offset, #4
1422    //  Handle extra argument in arg array taken by a long.
1423    cmp wip, #74                            // if (wip != 'J') goto LOOP
1424    b.ne 1b
1425    add \arg_offset, \arg_offset, #4
1426    b 1b                        // goto LOOP
14272:  // FOUND_DOUBLE
1428    add ip, \stack_ptr, \arg_offset
1429    ldr ip, [ip,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1430    str ip, [\regs, \arg_offset]
1431    add \arg_offset, \arg_offset, #8
1432    b 1b
14333:  // FOUND_FLOAT
1434    add ip, \stack_ptr, \arg_offset
1435    ldr wip, [ip,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1436    str wip, [\regs, \arg_offset]
1437    add \arg_offset, \arg_offset, #4
1438    b 1b
1439.endm
1440
1441// Puts the next int/long/object parameter passed in stack
1442// in the expected dex register array entry, and in case of object in the
1443// expected reference array entry.
1444// Uses ip and ip2 as temporary.
1445.macro LOOP_OVER_INTs shorty, arg_offset, regs, refs, stack_ptr, finished
14461: // LOOP
1447    ldrb wip, [\shorty], #1       // Load next character in shorty, and increment.
1448    cbz wip, \finished            // if (wip == '\0') goto finished
1449    cmp wip, #74                  // if (wip == 'J') goto FOUND_LONG
1450    b.eq 2f
1451    cmp wip, #70                  // if (wip == 'F') goto SKIP_FLOAT
1452    b.eq 3f
1453    cmp wip, #68                  // if (wip == 'D') goto SKIP_DOUBLE
1454    b.eq 4f
1455    add ip2, \stack_ptr, \arg_offset
1456    ldr wip2, [ip2,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1457    str wip2, [\regs, \arg_offset]
1458    cmp wip, #76                  // if (wip != 'L') goto loop
1459    b.ne 3f
1460    str wip2, [\refs, \arg_offset]
1461    add \arg_offset, \arg_offset, #4
1462    b 1b
14632:  // FOUND_LONG
1464    add ip, \stack_ptr, \arg_offset
1465    ldr ip, [ip,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1466    str ip, [\regs, \arg_offset]
1467    add \arg_offset, \arg_offset, #8
1468    b 1b
14693:  // SKIP_FLOAT
1470    add \arg_offset, \arg_offset, #4
1471    b 1b
14724:  // SKIP_DOUBLE
1473    add \arg_offset, \arg_offset, #8
1474    b 1b
1475.endm
1476
1477%def entry():
1478/*
1479 * ArtMethod entry point.
1480 *
1481 * On entry:
1482 *  x0   ArtMethod* callee
1483 *  rest  method parameters
1484 */
1485
1486OAT_ENTRY ExecuteNterpImpl, EndExecuteNterpImpl
1487    .cfi_startproc
1488    sub x16, sp, #STACK_OVERFLOW_RESERVED_BYTES
1489    ldr wzr, [x16]
1490    /* Spill callee save regs */
1491    SPILL_ALL_CALLEE_SAVES
1492
1493    // TODO: Get shorty in a better way and remove below
1494    SPILL_ALL_ARGUMENTS
1495
1496    // Save method in callee-save xINST
1497    mov xINST, x0
1498    bl NterpGetShorty
1499    // Save shorty in callee-save xIBASE.
1500    mov xIBASE, x0
1501    mov x0, xINST
1502    bl NterpGetCodeItem
1503    mov xPC, x0
1504
1505    RESTORE_ALL_ARGUMENTS
1506
1507    // Setup the stack for executing the method.
1508    SETUP_STACK_FRAME xPC, xREFS, xFP, CFI_REFS
1509
1510    // Setup the parameters
1511    ldrh wip2, [xPC, #CODE_ITEM_INS_SIZE_OFFSET]
1512    cbz wip2, .Lxmm_setup_finished
1513
1514    sub ip2, ip, ip2
1515    lsl x8, ip2, #2 // x8 is now the offset for inputs into the registers array.
1516
1517    // Setup shorty, pointer to inputs in FP and pointer to inputs in REFS
1518    add x9, xIBASE, #1  // shorty + 1  ; ie skip return arg character
1519    add x10, xFP, x8
1520    add x11, xREFS, x8
1521
1522    ldr wip, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
1523    // TODO: could be TBNZ but we'd need a constant for log2(ART_METHOD_IS_STATIC_FLAG).
1524    tst wip, #ART_METHOD_IS_STATIC_FLAG
1525    b.ne .Lhandle_static_method
1526    str w1, [x10], #4
1527    str w1, [x11], #4
1528    add x13, x13, #4
1529    mov x12, #0
1530    b .Lcontinue_setup_gprs
1531.Lhandle_static_method:
1532    mov x12, #0
1533    LOOP_OVER_SHORTY_STORING_GPRS x1, w1, x9, x12, x10, x11, .Lgpr_setup_finished
1534.Lcontinue_setup_gprs:
1535    LOOP_OVER_SHORTY_STORING_GPRS x2, w2, x9, x12, x10, x11, .Lgpr_setup_finished
1536    LOOP_OVER_SHORTY_STORING_GPRS x3, w3, x9, x12, x10, x11, .Lgpr_setup_finished
1537    LOOP_OVER_SHORTY_STORING_GPRS x4, w4, x9, x12, x10, x11, .Lgpr_setup_finished
1538    LOOP_OVER_SHORTY_STORING_GPRS x5, w5, x9, x12, x10, x11, .Lgpr_setup_finished
1539    LOOP_OVER_SHORTY_STORING_GPRS x6, w6, x9, x12, x10, x11, .Lgpr_setup_finished
1540    LOOP_OVER_SHORTY_STORING_GPRS x7, w7, x9, x12, x10, x11, .Lgpr_setup_finished
1541    LOOP_OVER_INTs x9, x12, x10, x11, x13, .Lgpr_setup_finished
1542.Lgpr_setup_finished:
1543    add x9, xIBASE, #1  // shorty + 1  ; ie skip return arg character
1544    mov x12, #0  // reset counter
1545    LOOP_OVER_SHORTY_STORING_FPS d0, s0, x9, x12, x10, .Lxmm_setup_finished
1546    LOOP_OVER_SHORTY_STORING_FPS d1, s1, x9, x12, x10, .Lxmm_setup_finished
1547    LOOP_OVER_SHORTY_STORING_FPS d2, s2, x9, x12, x10, .Lxmm_setup_finished
1548    LOOP_OVER_SHORTY_STORING_FPS d3, s3, x9, x12, x10, .Lxmm_setup_finished
1549    LOOP_OVER_SHORTY_STORING_FPS d4, s4, x9, x12, x10, .Lxmm_setup_finished
1550    LOOP_OVER_SHORTY_STORING_FPS d5, s5, x9, x12, x10, .Lxmm_setup_finished
1551    LOOP_OVER_SHORTY_STORING_FPS d6, s6, x9, x12, x10, .Lxmm_setup_finished
1552    LOOP_OVER_SHORTY_STORING_FPS d7, s7, x9, x12, x10, .Lxmm_setup_finished
1553    LOOP_OVER_FPs x9, x12, x10, x13, .Lxmm_setup_finished
1554.Lxmm_setup_finished:
1555    // Set the dex pc pointer.
1556    add xPC, xPC, #CODE_ITEM_INSNS_OFFSET
1557    CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
1558
1559    // Set rIBASE
1560    adr xIBASE, artNterpAsmInstructionStart
1561    /* start executing the instruction at xPC */
1562    START_EXECUTING_INSTRUCTIONS
1563    /* NOTE: no fallthrough */
1564    // cfi info continues, and covers the whole nterp implementation.
1565    SIZE ExecuteNterpImpl
1566
1567%def opcode_pre():
1568
1569%def helpers():
1570
1571%def footer():
1572/*
1573 * ===========================================================================
1574 *  Common subroutines and data
1575 * ===========================================================================
1576 */
1577
1578    .text
1579    .align  2
1580
1581// Note: mterp also uses the common_* names below for helpers, but that's OK
1582// as the C compiler compiled each interpreter separately.
1583common_errDivideByZero:
1584    EXPORT_PC
1585    bl art_quick_throw_div_zero
1586
1587// Expect array in w0, index in w1, length in w2
1588common_errArrayIndex:
1589    EXPORT_PC
1590    mov x0, x1
1591    mov x1, x3
1592    bl art_quick_throw_array_bounds
1593
1594common_errNullObject:
1595    EXPORT_PC
1596    bl art_quick_throw_null_pointer_exception
1597
1598NterpCommonInvokeStatic:
1599    COMMON_INVOKE_NON_RANGE is_static=1, suffix="invokeStatic"
1600
1601NterpCommonInvokeStaticRange:
1602    COMMON_INVOKE_RANGE is_static=1, suffix="invokeStatic"
1603
1604NterpCommonInvokeInstance:
1605    COMMON_INVOKE_NON_RANGE suffix="invokeInstance"
1606
1607NterpCommonInvokeInstanceRange:
1608    COMMON_INVOKE_RANGE suffix="invokeInstance"
1609
1610NterpCommonInvokeInterface:
1611    COMMON_INVOKE_NON_RANGE is_interface=1, suffix="invokeInterface"
1612
1613NterpCommonInvokeInterfaceRange:
1614    COMMON_INVOKE_RANGE is_interface=1, suffix="invokeInterface"
1615
1616NterpCommonInvokePolymorphic:
1617    COMMON_INVOKE_NON_RANGE is_polymorphic=1, suffix="invokePolymorphic"
1618
1619NterpCommonInvokePolymorphicRange:
1620    COMMON_INVOKE_RANGE is_polymorphic=1, suffix="invokePolymorphic"
1621
1622NterpCommonInvokeCustom:
1623    COMMON_INVOKE_NON_RANGE is_static=1, is_custom=1, suffix="invokeCustom"
1624
1625NterpCommonInvokeCustomRange:
1626    COMMON_INVOKE_RANGE is_static=1, is_custom=1, suffix="invokeCustom"
1627
1628NterpHandleStringInit:
1629   COMMON_INVOKE_NON_RANGE is_string_init=1, suffix="stringInit"
1630
1631NterpHandleStringInitRange:
1632   COMMON_INVOKE_RANGE is_string_init=1, suffix="stringInit"
1633
1634NterpNewInstance:
1635   EXPORT_PC
1636   // Fast-path which gets the class from thread-local cache.
1637   FETCH_FROM_THREAD_CACHE x0, 2f
1638   cbnz wMR, 3f
16394:
1640   ldr lr, [xSELF, #THREAD_ALLOC_OBJECT_ENTRYPOINT_OFFSET]
1641   blr lr
16421:
1643   lsr w1, wINST, #8                    // w1 <- A
1644   SET_VREG_OBJECT w0, w1               // fp[A] <- value
1645   FETCH_ADVANCE_INST 2
1646   GET_INST_OPCODE ip
1647   GOTO_OPCODE ip
16482:
1649   mov x0, xSELF
1650   ldr x1, [sp]
1651   mov x2, xPC
1652   bl nterp_get_class_or_allocate_object
1653   b 1b
16543:
1655   bl art_quick_read_barrier_mark_reg00
1656   b 4b
1657
1658NterpNewArray:
1659   /* new-array vA, vB, class@CCCC */
1660   EXPORT_PC
1661   // Fast-path which gets the class from thread-local cache.
1662   FETCH_FROM_THREAD_CACHE x0, 2f
1663   cbnz wMR, 3f
16641:
1665   lsr     w1, wINST, #12              // w1<- B
1666   GET_VREG w1, w1                     // w1<- vB (array length)
1667   ldr lr, [xSELF, #THREAD_ALLOC_ARRAY_ENTRYPOINT_OFFSET]
1668   blr lr
1669   ubfx    w1, wINST, #8, #4           // w1<- A
1670   SET_VREG_OBJECT w0, w1
1671   FETCH_ADVANCE_INST 2
1672   GET_INST_OPCODE ip
1673   GOTO_OPCODE ip
16742:
1675   mov x0, xSELF
1676   ldr x1, [sp, 0]
1677   mov x2, xPC
1678   bl nterp_get_class_or_allocate_object
1679   b 1b
16803:
1681   bl art_quick_read_barrier_mark_reg00
1682   b 1b
1683
1684NterpPutObjectInstanceField:
1685   // Fast-path which gets the field from thread-local cache.
1686   FETCH_FROM_THREAD_CACHE x0, 3f
16871:
1688   ubfx    w1, wINST, #8, #4           // w1<- A
1689   lsr     w2, wINST, #12              // w2<- B
1690   GET_VREG w2, w2                     // vB (object we're operating on)
1691   cbz w2, common_errNullObject        // is object null?
1692   GET_VREG w1, w1                     // w1 <- v[A]
1693   str w1, [x2, x0]
1694   cbz w1, 2f
1695   ldr x1, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1696   lsr w3, w2, #CARD_TABLE_CARD_SHIFT
1697   strb w1, [x1, x3]
16982:
1699   FETCH_ADVANCE_INST 2
1700   GET_INST_OPCODE ip
1701   GOTO_OPCODE ip
17023:
1703   mov x0, xSELF
1704   ldr x1, [sp]
1705   mov x2, xPC
1706   EXPORT_PC
1707   bl nterp_get_instance_field_offset
1708   tbz w0, #31, 1b
1709   CLEAR_INSTANCE_VOLATILE_MARKER w0
1710   ubfx    w1, wINST, #8, #4           // w1<- A
1711   lsr     w2, wINST, #12              // w2<- B
1712   GET_VREG w2, w2                     // vB (object we're operating on)
1713   cbz w2, common_errNullObject        // is object null?
1714   GET_VREG w1, w1                     // w1 <- v[A]
1715   add x3, x2, x0
1716   stlr w1, [x3]
1717   cbz w1, 2b
1718   ldr x1, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1719   lsr w3, w2, #CARD_TABLE_CARD_SHIFT
1720   strb w1, [x1, x3]
1721   b 2b
1722
1723NterpGetObjectInstanceField:
1724   // Fast-path which gets the field from thread-local cache.
1725   FETCH_FROM_THREAD_CACHE x0, 4f
17261:
1727   ubfx    w1, wINST, #8, #4           // w1<- A
1728   lsr     w2, wINST, #12              // w2<- B
1729   GET_VREG w2, w2                     // vB (object we're operating on)
1730   cbz w2, common_errNullObject
1731   ldr w0, [x2, x0]
1732   cbnz wMR, 3f
17332:
1734   SET_VREG_OBJECT w0, w1              // fp[A] <- value
1735   FETCH_ADVANCE_INST 2
1736   GET_INST_OPCODE ip
1737   GOTO_OPCODE ip
17383:
1739   bl art_quick_read_barrier_mark_reg00
1740   b 2b
17414:
1742   mov x0, xSELF
1743   ldr x1, [sp]
1744   mov x2, xPC
1745   EXPORT_PC
1746   bl nterp_get_instance_field_offset
1747   tbz w0, #31, 1b
1748   CLEAR_INSTANCE_VOLATILE_MARKER w0
1749   ubfx    w1, wINST, #8, #4           // w1<- A
1750   lsr     w2, wINST, #12              // w2<- B
1751   GET_VREG w2, w2                     // vB (object we're operating on)
1752   cbz w2, common_errNullObject
1753   add x2, x2, x0
1754   ldar w0, [x2]
1755   cbnz wMR, 6f
17565:
1757   SET_VREG_OBJECT w0, w1              // fp[A] <- value
1758   FETCH_ADVANCE_INST 2
1759   GET_INST_OPCODE ip
1760   GOTO_OPCODE ip
17616:
1762   bl art_quick_read_barrier_mark_reg00
1763   b 5b
1764
1765NterpPutObjectStaticField:
1766   // Fast-path which gets the field from thread-local cache.
1767   FETCH_FROM_THREAD_CACHE x0, 5f
17681:
1769   ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1770   ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1771   cbnz wMR, 4f
17722:
1773   lsr w2, wINST, #8                    // w2 <- A
1774   GET_VREG w2, w2
1775   str w2, [x0, x1]
1776   cbz w2, 3f
1777   ldr x1, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1778   lsr w3, w0, #CARD_TABLE_CARD_SHIFT
1779   strb w1, [x1, x3]
17803:
1781   FETCH_ADVANCE_INST 2
1782   GET_INST_OPCODE ip
1783   GOTO_OPCODE ip
17844:
1785   bl art_quick_read_barrier_mark_reg00
1786   b 2b
17875:
1788   mov x0, xSELF
1789   ldr x1, [sp]
1790   mov x2, xPC
1791   EXPORT_PC
1792   bl nterp_get_static_field
1793   tbz x0, #0, 1b
1794   CLEAR_STATIC_VOLATILE_MARKER x0
1795   ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1796   ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1797   cbnz wMR, 7f
17986:
1799   lsr w2, wINST, #8                    // w1 <- A
1800   GET_VREG w2, w2
1801   add ip, x0, x1
1802   stlr w2, [ip]
1803   cbz w2, 3b
1804   ldr x1, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1805   lsr w3, w0, #CARD_TABLE_CARD_SHIFT
1806   strb w1, [x1, x3]
1807   b 3b
18087:
1809   bl art_quick_read_barrier_mark_reg00
1810   b 6b
1811
1812NterpGetObjectStaticField:
1813   // Fast-path which gets the field from thread-local cache.
1814   FETCH_FROM_THREAD_CACHE x0, 4f
18151:
1816   ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1817   ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1818   cbnz wMR, 3f
1819   ldr w0, [x0, x1]
1820   // No need to check the marking register, we know it's not set here.
18212:
1822   lsr w1, wINST, #8                    // w1 <- A
1823   SET_VREG_OBJECT w0, w1               // fp[A] <- value
1824   FETCH_ADVANCE_INST 2
1825   GET_INST_OPCODE ip
1826   GOTO_OPCODE ip
18273:
1828   bl art_quick_read_barrier_mark_reg00
1829   ldr w0, [x0, x1]
1830   // Here, we know the marking register is set.
1831   bl art_quick_read_barrier_mark_reg00
1832   b 2b
18334:
1834   mov x0, xSELF
1835   ldr x1, [sp]
1836   mov x2, xPC
1837   EXPORT_PC
1838   bl nterp_get_static_field
1839   tbz x0, #0, 1b
1840   CLEAR_STATIC_VOLATILE_MARKER x0
1841   ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1842   ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1843   cbnz wMR, 7f
18445:
1845   add x0, x0, x1
1846   ldar w0, [x0]
1847   cbnz wMR, 8f
18486:
1849   lsr w1, wINST, #8                    // w1 <- A
1850   SET_VREG_OBJECT w0, w1               // fp[A] <- value
1851   FETCH_ADVANCE_INST 2
1852   GET_INST_OPCODE ip
1853   GOTO_OPCODE ip
18547:
1855   bl art_quick_read_barrier_mark_reg00
1856   b 5b
18578:
1858   bl art_quick_read_barrier_mark_reg00
1859   b 6b
1860
1861NterpGetBooleanStaticField:
1862  OP_SGET load="ldrb", volatile_load="ldarb", maybe_extend="", wide=0
1863
1864NterpGetByteStaticField:
1865  OP_SGET load="ldrsb", volatile_load="ldarb", maybe_extend="sbfx w0, w0, #0, #8", wide=0
1866
1867NterpGetCharStaticField:
1868  OP_SGET load="ldrh", volatile_load="ldarh", maybe_extend="", wide=0
1869
1870NterpGetShortStaticField:
1871  OP_SGET load="ldrsh", volatile_load="ldarh", maybe_extend="sbfx w0, w0, #0, #16", wide=0
1872
1873NterpGetWideStaticField:
1874  OP_SGET load="ldr", volatile_load="ldar", maybe_extend="", wide=1
1875
1876NterpGetIntStaticField:
1877  OP_SGET load="ldr", volatile_load="ldar", maybe_extend="", wide=0
1878
1879NterpPutStaticField:
1880  OP_SPUT store="str", volatile_store="stlr", wide=0
1881
1882NterpPutBooleanStaticField:
1883NterpPutByteStaticField:
1884  OP_SPUT store="strb", volatile_store="stlrb", wide=0
1885
1886NterpPutCharStaticField:
1887NterpPutShortStaticField:
1888  OP_SPUT store="strh", volatile_store="stlrh", wide=0
1889
1890NterpPutWideStaticField:
1891  OP_SPUT store="str", volatile_store="stlr", wide=1
1892
1893NterpPutInstanceField:
1894  OP_IPUT store="str", volatile_store="stlr", wide=0
1895
1896NterpPutBooleanInstanceField:
1897NterpPutByteInstanceField:
1898  OP_IPUT store="strb", volatile_store="stlrb", wide=0
1899
1900NterpPutCharInstanceField:
1901NterpPutShortInstanceField:
1902  OP_IPUT store="strh", volatile_store="stlrh", wide=0
1903
1904NterpPutWideInstanceField:
1905  OP_IPUT store="str", volatile_store="stlr", wide=1
1906
1907NterpGetBooleanInstanceField:
1908  OP_IGET load="ldrb", volatile_load="ldarb", maybe_extend="", wide=0
1909
1910NterpGetByteInstanceField:
1911  OP_IGET load="ldrsb", volatile_load="ldarb", maybe_extend="sbfx w0, w0, #0, #8", wide=0
1912
1913NterpGetCharInstanceField:
1914  OP_IGET load="ldrh", volatile_load="ldarh", maybe_extend="", wide=0
1915
1916NterpGetShortInstanceField:
1917  OP_IGET load="ldrsh", volatile_load="ldarh", maybe_extend="sbfx w0, w0, #0, #16", wide=0
1918
1919NterpGetWideInstanceField:
1920  OP_IGET load="ldr", volatile_load="ldar", maybe_extend="", wide=1
1921
1922NterpGetInstanceField:
1923  OP_IGET load="ldr", volatile_load="ldar", maybe_extend="", wide=0
1924
1925NterpInstanceOf:
1926    /* instance-of vA, vB, class@CCCC */
1927   // Fast-path which gets the class from thread-local cache.
1928   EXPORT_PC
1929   FETCH_FROM_THREAD_CACHE x1, 3f
1930   cbnz wMR, 4f
19311:
1932   lsr     w2, wINST, #12              // w2<- B
1933   GET_VREG w0, w2                     // w0<- vB (object)
1934   cbz w0, 2f
1935   bl artInstanceOfFromCode
19362:
1937   ubfx    w1, wINST, #8, #4           // w1<- A
1938   SET_VREG w0, w1
1939   FETCH_ADVANCE_INST 2
1940   GET_INST_OPCODE ip
1941   GOTO_OPCODE ip
19423:
1943   mov x0, xSELF
1944   ldr x1, [sp]
1945   mov x2, xPC
1946   bl nterp_get_class_or_allocate_object
1947   mov x1, x0
1948   b 1b
19494:
1950   bl art_quick_read_barrier_mark_reg01
1951   b 1b
1952
1953NterpCheckCast:
1954   // Fast-path which gets the class from thread-local cache.
1955   EXPORT_PC
1956   FETCH_FROM_THREAD_CACHE x1, 3f
1957   cbnz wMR, 4f
19581:
1959   lsr     w2, wINST, #8               // w2<- A
1960   GET_VREG w0, w2                     // w2<- vA (object)
1961   cbz w0, 2f
1962   bl art_quick_check_instance_of
19632:
1964   FETCH_ADVANCE_INST 2
1965   GET_INST_OPCODE ip
1966   GOTO_OPCODE ip
19673:
1968   mov x0, xSELF
1969   ldr x1, [sp]
1970   mov x2, xPC
1971   bl nterp_get_class_or_allocate_object
1972   mov x1, x0
1973   b 1b
19744:
1975   bl art_quick_read_barrier_mark_reg01
1976   b 1b
1977
1978NterpHandleHotnessOverflow:
1979    add x1, xPC, xINST, lsl #1
1980    mov x2, xFP
1981    bl nterp_hot_method
1982    cbnz x0, 1f
1983    add w2, wINST, wINST                // w2<- byte offset
1984    FETCH_ADVANCE_INST_RB w2            // update xPC, load wINST
1985    GET_INST_OPCODE ip                  // extract opcode from wINST
1986    GOTO_OPCODE ip                      // jump to next instruction
19871:
1988    // Drop the current frame.
1989    ldr ip, [xREFS, #-8]
1990    mov sp, ip
1991    .cfi_def_cfa sp, CALLEE_SAVES_SIZE
1992
1993    // The transition frame of type SaveAllCalleeSaves saves x19 and x20,
1994    // but not managed ABI. So we need to restore callee-saves of the nterp frame,
1995    // and save managed ABI callee saves, which will be restored by the callee upon
1996    // return.
1997    RESTORE_ALL_CALLEE_SAVES
1998    INCREASE_FRAME ((CALLEE_SAVES_SIZE) - 16)
1999
2000    // FP callee-saves
2001    stp d8, d9, [sp, #0]
2002    stp d10, d11, [sp, #16]
2003    stp d12, d13, [sp, #32]
2004    stp d14, d15, [sp, #48]
2005
2006    // GP callee-saves.
2007    SAVE_TWO_REGS x21, x22, 64
2008    SAVE_TWO_REGS x23, x24, 80
2009    SAVE_TWO_REGS x25, x26, 96
2010    SAVE_TWO_REGS x27, x28, 112
2011    SAVE_TWO_REGS x29, lr, 128
2012
2013    // Setup the new frame
2014    ldr x1, [x0, #OSR_DATA_FRAME_SIZE]
2015    // Given stack size contains all callee saved registers, remove them.
2016    sub x1, x1, #(CALLEE_SAVES_SIZE - 16)
2017
2018    // We know x1 cannot be 0, as it at least contains the ArtMethod.
2019
2020    // Remember CFA in a callee-save register.
2021    mov xINST, sp
2022    .cfi_def_cfa_register xINST
2023
2024    sub sp, sp, x1
2025
2026    add x2, x0, #OSR_DATA_MEMORY
20272:
2028    sub x1, x1, #8
2029    ldr ip, [x2, x1]
2030    str ip, [sp, x1]
2031    cbnz x1, 2b
2032
2033    // Fetch the native PC to jump to and save it in a callee-save register.
2034    ldr xFP, [x0, #OSR_DATA_NATIVE_PC]
2035
2036    // Free the memory holding OSR Data.
2037    bl free
2038
2039    // Jump to the compiled code.
2040    br xFP
2041
2042NterpHandleInvokeInterfaceOnObjectMethodRange:
2043   // First argument is the 'this' pointer.
2044   FETCH w1, 2
2045   GET_VREG w1, w1
2046   // Note: x1 is null, this will be handled by our SIGSEGV handler.
2047   ldr w2, [x1, #MIRROR_OBJECT_CLASS_OFFSET]
2048   add w2, w2, #MIRROR_CLASS_VTABLE_OFFSET_64
2049   ldr x0, [x2, w0, sxtw #3]
2050   b NterpCommonInvokeInstanceRange
2051
2052NterpHandleInvokeInterfaceOnObjectMethod:
2053   // First argument is the 'this' pointer.
2054   FETCH w1, 2
2055   and w1, w1, #0xf
2056   GET_VREG w1, w1
2057   // Note: x1 is null, this will be handled by our SIGSEGV handler.
2058   ldr w2, [x1, #MIRROR_OBJECT_CLASS_OFFSET]
2059   add w2, w2, #MIRROR_CLASS_VTABLE_OFFSET_64
2060   ldr x0, [x2, w0, sxtw #3]
2061   b NterpCommonInvokeInstance
2062
2063// This is the logical end of ExecuteNterpImpl, where the frame info applies.
2064// EndExecuteNterpImpl includes the methods below as we want the runtime to
2065// see them as part of the Nterp PCs.
2066.cfi_endproc
2067
2068nterp_to_nterp_static_non_range:
2069    .cfi_startproc
2070    SETUP_STACK_FOR_INVOKE
2071    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0
2072    .cfi_endproc
2073
2074nterp_to_nterp_string_init_non_range:
2075    .cfi_startproc
2076    SETUP_STACK_FOR_INVOKE
2077    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1
2078    .cfi_endproc
2079
2080nterp_to_nterp_instance_non_range:
2081    .cfi_startproc
2082    SETUP_STACK_FOR_INVOKE
2083    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
2084    .cfi_endproc
2085
2086nterp_to_nterp_static_range:
2087    .cfi_startproc
2088    SETUP_STACK_FOR_INVOKE
2089    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=1
2090    .cfi_endproc
2091
2092nterp_to_nterp_instance_range:
2093    .cfi_startproc
2094    SETUP_STACK_FOR_INVOKE
2095    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0
2096    .cfi_endproc
2097
2098nterp_to_nterp_string_init_range:
2099    .cfi_startproc
2100    SETUP_STACK_FOR_INVOKE
2101    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1
2102    .cfi_endproc
2103
2104// This is the end of PCs contained by the OatQuickMethodHeader created for the interpreter
2105// entry point.
2106    .type EndExecuteNterpImpl, #function
2107    .hidden EndExecuteNterpImpl
2108    .global EndExecuteNterpImpl
2109EndExecuteNterpImpl:
2110
2111// Entrypoints into runtime.
2112NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField
2113NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset
2114NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray
2115NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange
2116NTERP_TRAMPOLINE nterp_get_class_or_allocate_object, NterpGetClassOrAllocateObject
2117NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod
2118NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod
2119NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject
2120
2121// gen_mterp.py will inline the following definitions
2122// within [ExecuteNterpImpl, EndExecuteNterpImpl).
2123%def instruction_end():
2124
2125    .type artNterpAsmInstructionEnd, #function
2126    .hidden artNterpAsmInstructionEnd
2127    .global artNterpAsmInstructionEnd
2128artNterpAsmInstructionEnd:
2129    // artNterpAsmInstructionEnd is used as landing pad for exception handling.
2130    FETCH_INST
2131    GET_INST_OPCODE ip
2132    GOTO_OPCODE ip
2133
2134%def instruction_start():
2135
2136    .type artNterpAsmInstructionStart, #function
2137    .hidden artNterpAsmInstructionStart
2138    .global artNterpAsmInstructionStart
2139artNterpAsmInstructionStart = .L_op_nop
2140    .text
2141
2142%def opcode_start():
2143    NAME_START nterp_${opcode}
2144%def opcode_end():
2145    NAME_END nterp_${opcode}
2146%def helper_start(name):
2147    NAME_START ${name}
2148%def helper_end(name):
2149    NAME_END ${name}
2150