• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/arm/asm_support_arm.S"
24
25/**
26 * ARM EABI general notes:
27 *
28 * r0-r3 hold first 4 args to a method; they are not preserved across method calls
29 * r4-r8 are available for general use
30 * r9 is given special treatment in some situations, but not for us
31 * r10 (sl) seems to be generally available
32 * r11 (fp) is used by gcc (unless -fomit-frame-pointer is set)
33 * r12 (ip) is scratch -- not preserved across method calls
34 * r13 (sp) should be managed carefully in case a signal arrives
35 * r14 (lr) must be preserved
36 * r15 (pc) can be tinkered with directly
37 *
38 * r0 holds returns of <= 4 bytes
39 * r0-r1 hold returns of 8 bytes, low word in r0
40 *
41 * Callee must save/restore r4+ (except r12) if it modifies them.  If VFP
42 * is present, registers s16-s31 (a/k/a d8-d15, a/k/a q4-q7) must be preserved,
43 * s0-s15 (d0-d7, q0-a3) do not need to be.
44 *
45 * Stack is "full descending".  Only the arguments that don't fit in the first 4
46 * registers are placed on the stack.  "sp" points at the first stacked argument
47 * (i.e. the 5th arg).
48 *
49 * Native ABI uses soft-float, single-precision results are in r0,
50 * double-precision results in r0-r1.
51 *
52 * In the EABI, "sp" must be 64-bit aligned on entry to a function, and any
53 * 64-bit quantities (long long, double) must be 64-bit aligned.
54 *
55 * Nterp notes:
56 *
57 * The following registers have fixed assignments:
58 *
59 *   reg nick      purpose
60 *   r5  rFP       interpreted frame pointer, used for accessing locals and args
61 *   r6  rREFS     base of object references of dex registers
62 *   r7  rINST     first 16-bit code unit of current instruction
63 *   r8  rMR       marking register
64 *   r9  rSELF     self (Thread) pointer
65 *   r10 rIBASE    interpreted instruction base pointer, used for computed goto
66 *   r11 rPC       interpreted program counter, used for fetching instructions
67 *
68 *   r4, ip, and lr can be used as temporary
69 *
70 * Note that r4 is a callee-save register in ARM EABI, but not in managed code.
71 *
72 */
73
74/* single-purpose registers, given names for clarity */
75#define CFI_DEX  11 // DWARF register number of the register holding dex-pc (rPC).
76#define CFI_TMP  0  // DWARF register number of the first argument register (r0).
77#define CFI_REFS 6
78#define rFP      r5
79#define rREFS    r6
80#define rINST    r7
81#define rSELF    r9
82#define rIBASE   r10
83#define rPC      r11
84
85// To avoid putting ifdefs arond the use of rMR, make sure it's defined.
86// IsNterpSupported returns false for configurations that don't have rMR (typically CMS).
87#ifndef rMR
88#define rMR r8
89#endif
90
91// Temporary registers while setting up a frame.
92#define rNEW_FP   r8
93#define rNEW_REFS r10
94#define CFI_NEW_REFS 10
95
96#define CALLEE_SAVES_SIZE (9 * 4 + 16 * 4)
97
98// +4 for the ArtMethod of the caller.
99#define OFFSET_TO_FIRST_ARGUMENT_IN_STACK (CALLEE_SAVES_SIZE + 4)
100
101/*
102 * Fetch the next instruction from rPC into rINST.  Does not advance rPC.
103 */
104.macro FETCH_INST
105    ldrh    rINST, [rPC]
106.endm
107
108/*
109 * Fetch the next instruction from the specified offset.  Advances rPC
110 * to point to the next instruction.  "count" is in 16-bit code units.
111 *
112 * Because of the limited size of immediate constants on ARM, this is only
113 * suitable for small forward movements (i.e. don't try to implement "goto"
114 * with this).
115 *
116 * This must come AFTER anything that can throw an exception, or the
117 * exception catch may miss.  (This also implies that it must come after
118 * EXPORT_PC.)
119 */
120.macro FETCH_ADVANCE_INST count
121    ldrh    rINST, [rPC, #((\count)*2)]!
122.endm
123
124/*
125 * Similar to FETCH_ADVANCE_INST, but does not update xPC.  Used to load
126 * rINST ahead of possible exception point.  Be sure to manually advance xPC
127 * later.
128 */
129.macro PREFETCH_INST count
130    ldrh    rINST, [rPC, #((\count)*2)]
131.endm
132
133/* Advance xPC by some number of code units. */
134.macro ADVANCE count
135  add  rPC, #((\count)*2)
136.endm
137
138/*
139 * Fetch the next instruction from an offset specified by "reg" and advance xPC.
140 * xPC to point to the next instruction.  "reg" must specify the distance
141 * in bytes, *not* 16-bit code units, and may be a signed value.
142 */
143.macro FETCH_ADVANCE_INST_RB reg
144    ldrh    rINST, [rPC, \reg]!
145.endm
146
147/*
148 * Fetch a half-word code unit from an offset past the current PC.  The
149 * "count" value is in 16-bit code units.  Does not advance xPC.
150 *
151 * The "_S" variant works the same but treats the value as signed.
152 */
153.macro FETCH reg, count
154    ldrh    \reg, [rPC, #((\count)*2)]
155.endm
156
157.macro FETCH_S reg, count
158    ldrsh   \reg, [rPC, #((\count)*2)]
159.endm
160
161/*
162 * Fetch one byte from an offset past the current PC.  Pass in the same
163 * "count" as you would for FETCH, and an additional 0/1 indicating which
164 * byte of the halfword you want (lo/hi).
165 */
166.macro FETCH_B reg, count, byte
167    ldrb     \reg, [rPC, #((\count)*2+(\byte))]
168.endm
169
170/*
171 * Put the instruction's opcode field into the specified register.
172 */
173.macro GET_INST_OPCODE reg
174    and     \reg, rINST, #255
175.endm
176
177/*
178 * Begin executing the opcode in _reg.  Clobbers reg
179 */
180
181.macro GOTO_OPCODE reg
182    add     pc, rIBASE, \reg, lsl #${handler_size_bits}
183.endm
184
185/*
186 * Get/set value from a Dalvik register.
187 */
188.macro GET_VREG reg, vreg
189    ldr     \reg, [rFP, \vreg, lsl #2]
190.endm
191.macro GET_VREG_OBJECT reg, vreg
192    ldr     \reg, [rREFS, \vreg, lsl #2]
193.endm
194.macro SET_VREG reg, vreg
195    str     \reg, [rFP, \vreg, lsl #2]
196    mov     \reg, #0
197    str     \reg, [rREFS, \vreg, lsl #2]
198.endm
199.macro SET_VREG_OBJECT reg, vreg
200    str     \reg, [rFP, \vreg, lsl #2]
201    str     \reg, [rREFS, \vreg, lsl #2]
202.endm
203.macro SET_VREG_FLOAT reg, vreg, tmpreg
204    add     \tmpreg, rFP, \vreg, lsl #2
205    vstr    \reg, [\tmpreg]
206    mov     \tmpreg, #0
207    str     \tmpreg, [rREFS, \vreg, lsl #2]
208.endm
209.macro GET_VREG_WIDE_BY_ADDR reg0, reg1, addr
210    ldmia \addr, {\reg0, \reg1}
211.endm
212.macro SET_VREG_WIDE_BY_ADDR reg0, reg1, addr
213    stmia \addr, {\reg0, \reg1}
214.endm
215.macro GET_VREG_FLOAT sreg, vreg
216    ldr  \vreg, [rFP, \vreg, lsl #2]
217    vmov \sreg, \vreg
218.endm
219.macro GET_VREG_FLOAT_BY_ADDR reg, addr
220    vldr \reg, [\addr]
221.endm
222.macro SET_VREG_FLOAT_BY_ADDR reg, addr
223    vstr \reg, [\addr]
224.endm
225.macro GET_VREG_DOUBLE_BY_ADDR reg, addr
226    vldr \reg, [\addr]
227.endm
228.macro SET_VREG_DOUBLE_BY_ADDR reg, addr
229    vstr \reg, [\addr]
230.endm
231.macro SET_VREG_SHADOW reg, vreg
232    str     \reg, [rREFS, \vreg, lsl #2]
233.endm
234.macro CLEAR_SHADOW_PAIR vreg, tmp1, tmp2
235    mov     \tmp1, #0
236    add     \tmp2, \vreg, #1
237    SET_VREG_SHADOW \tmp1, \vreg
238    SET_VREG_SHADOW \tmp1, \tmp2
239.endm
240.macro VREG_INDEX_TO_ADDR reg, vreg
241    add     \reg, rFP, \vreg, lsl #2
242.endm
243
244// An assembly entry for nterp.
245.macro OAT_ENTRY name
246    .arm
247    .type \name, #function
248    .hidden \name
249    .global \name
250    .balign 16
251\name:
252.endm
253
254.macro SIZE name
255    .size \name, .-\name
256.endm
257
258.macro NAME_START name
259    .arm
260    .type \name, #function
261    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
262    .global \name
263    /* Cache alignment for function entry */
264    .balign 16
265\name:
266.endm
267
268.macro NAME_END name
269  SIZE \name
270.endm
271
272// Macro for defining entrypoints into runtime. We don't need to save registers
273// (we're not holding references there), but there is no
274// kDontSave runtime method. So just use the kSaveRefsOnly runtime method.
275.macro NTERP_TRAMPOLINE name, helper
276ENTRY \name
277  SETUP_SAVE_REFS_ONLY_FRAME ip
278  bl \helper
279  RESTORE_SAVE_REFS_ONLY_FRAME
280  REFRESH_MARKING_REGISTER
281  ldr ip, [rSELF, #THREAD_EXCEPTION_OFFSET]  @ Get exception field.
282  cmp ip, #0
283  bne nterp_deliver_pending_exception
284  bx lr
285END \name
286.endm
287
288.macro CLEAR_STATIC_VOLATILE_MARKER reg
289  and \reg, \reg, #-2
290.endm
291
292.macro CLEAR_INSTANCE_VOLATILE_MARKER reg
293  rsb \reg, \reg, #0
294.endm
295
296.macro EXPORT_PC
297    str    rPC, [rREFS, #-8]
298.endm
299
300.macro BRANCH
301    add rPC, rPC, rINST, lsl #1
302    // Update method counter and do a suspend check if the branch is negative or zero.
303    cmp rINST, #0
304    ble 2f
3051:
306    FETCH_INST                          // load rINST
307    GET_INST_OPCODE ip                  // extract opcode from rINST
308    GOTO_OPCODE ip                      // jump to next instruction
3092:
310    ldr r0, [sp]
311    ldrh r2, [r0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
312    cmp r2, #NTERP_HOTNESS_VALUE
313    beq NterpHandleHotnessOverflow
314    add r2, r2, #-1
315    strh r2, [r0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
316    DO_SUSPEND_CHECK continue_label=1b
317    b 1b
318.endm
319
320.macro TEST_IF_MARKING label
321    cmp rMR, #0
322    bne \label
323.endm
324
325// Expects:
326// - ip and lr to be available.
327// Outputs:
328// - \registers contains the dex registers size
329// - \outs contains the outs size
330// - if load_ins is 1, \ins contains the ins
331// - \code_item is replaced with a pointer to the instructions
332.macro FETCH_CODE_ITEM_INFO code_item, registers, outs, ins, load_ins
333    tst \code_item, #1
334    beq 5f
335    bic \code_item, \code_item, #1 // Remove the extra bit that marks it's a compact dex file
336    ldrh lr, [\code_item, #COMPACT_CODE_ITEM_FIELDS_OFFSET]
337    ubfx \registers, lr, #COMPACT_CODE_ITEM_REGISTERS_SIZE_SHIFT, #4
338    ubfx \outs, lr, #COMPACT_CODE_ITEM_OUTS_SIZE_SHIFT, #4
339    .if \load_ins
340    ubfx \ins, lr, #COMPACT_CODE_ITEM_INS_SIZE_SHIFT, #4
341    .else
342    ubfx ip, lr, #COMPACT_CODE_ITEM_INS_SIZE_SHIFT, #4
343    add \registers, \registers, ip
344    .endif
345
346    ldrh lr, [\code_item, #COMPACT_CODE_ITEM_FLAGS_OFFSET]
347    tst lr, #COMPACT_CODE_ITEM_REGISTERS_INS_OUTS_FLAGS
348    beq 4f
349    mov ip, \code_item
350    tst lr, #COMPACT_CODE_ITEM_INSNS_FLAG
351    beq 1f
352    sub ip, ip, #4
3531:
354    tst lr, #COMPACT_CODE_ITEM_REGISTERS_FLAG
355    beq 2f
356    ldrh lr, [ip, #-2]!
357    add \registers, \registers, lr
358    ldrh lr, [\code_item, #COMPACT_CODE_ITEM_FLAGS_OFFSET]
3592:
360    tst lr, #COMPACT_CODE_ITEM_INS_FLAG
361    beq 3f
362    ldrh lr, [ip, #-2]!
363    .if \load_ins
364    add \ins, \ins, lr
365    .else
366    add \registers, \registers, lr
367    .endif
368    ldrh lr, [\code_item, #COMPACT_CODE_ITEM_FLAGS_OFFSET]
3693:
370    tst lr, #COMPACT_CODE_ITEM_OUTS_FLAG
371    beq 4f
372    ldrh lr, [ip, #-2]!
373    add \outs, \outs, lr
3744:
375    .if \load_ins
376    add \registers, \registers, \ins
377    .endif
378    add \code_item, \code_item, #COMPACT_CODE_ITEM_INSNS_OFFSET
379    b 6f
3805:
381    // Fetch dex register size.
382    ldrh \registers, [\code_item, #CODE_ITEM_REGISTERS_SIZE_OFFSET]
383    // Fetch outs size.
384    ldrh \outs, [\code_item, #CODE_ITEM_OUTS_SIZE_OFFSET]
385    .if \load_ins
386    ldrh \ins, [\code_item, #CODE_ITEM_INS_SIZE_OFFSET]
387    .endif
388    add \code_item, \code_item, #CODE_ITEM_INSNS_OFFSET
3896:
390.endm
391
392// Setup the stack to start executing the method. Expects:
393// - r0 to contain the ArtMethod
394// - \code_item to already contain the code item
395// - rINST, ip, lr to be available
396//
397// Outputs
398// - rINST contains the dex registers size
399// - ip contains the old stack pointer.
400// - \code_item is replaced with a pointer to the instructions
401// - if load_ins is 1, r4 contains the ins
402//
403.macro SETUP_STACK_FRAME code_item, refs, fp, cfi_refs, load_ins
404    FETCH_CODE_ITEM_INFO \code_item, rINST, \refs, r4, \load_ins
405
406    // Compute required frame size: ((2 * rINST) + \refs) * 4 + 12
407    // 12 is for saving the previous frame, pc, and method being executed.
408    add ip, \refs, rINST, lsl #1
409
410    // Compute new stack pointer in lr
411    sub lr, sp, #12
412    sub lr, lr, ip, lsl #2
413    // Alignment
414    and lr, lr, #-16
415
416    // Set reference and dex registers.
417    add \refs, lr, \refs, lsl #2
418    add \refs, \refs, #12
419    add \fp, \refs, rINST, lsl #2
420
421    // Now setup the stack pointer.
422    mov ip, sp
423    .cfi_def_cfa_register ip
424    mov sp, lr
425    str ip, [\refs, #-4]
426    CFI_DEF_CFA_BREG_PLUS_UCONST \cfi_refs, -4, CALLEE_SAVES_SIZE
427
428    // Save the ArtMethod, and use r0 as a temporary.
429    str r0, [sp]
430
431    // Put nulls in reference frame.
432    cmp rINST, #0
433    beq 2f
434    mov lr, \refs
435    mov r0, #0
4361:
437    str r0, [lr], #4
438    str r0, [lr], #4  // May clear vreg[0].
439    cmp lr, \fp
440    blo 1b
4412:
442    ldr r0, [sp]  // Reload the ArtMethod, expected by the callers.
443.endm
444
445// Increase method hotness and do suspend check before starting executing the method.
446.macro START_EXECUTING_INSTRUCTIONS
447    ldr r0, [sp]
448    ldrh r2, [r0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
449    cmp r2, #NTERP_HOTNESS_VALUE
450    beq 3f
451    add r2, r2, #-1
452    strh r2, [r0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
4531:
454    DO_SUSPEND_CHECK continue_label=2f
4552:
456    FETCH_INST
457    GET_INST_OPCODE ip
458    GOTO_OPCODE ip
4593:
460    CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot=4f, if_not_hot=1b
4614:
462    mov r1, #0
463    mov r2, rFP
464    bl nterp_hot_method
465    b 2b
466.endm
467
468.macro SPILL_ALL_CALLEE_SAVES
469    SPILL_ALL_CALLEE_SAVE_GPRS                    @ 9 words (36 bytes) of callee saves.
470    vpush {s16-s31}                               @ 16 words (64 bytes) of floats.
471    .cfi_adjust_cfa_offset 64
472.endm
473
474.macro RESTORE_ALL_CALLEE_SAVES lr_to_pc=0
475    vpop {s16-s31}
476    .cfi_adjust_cfa_offset -64
477    pop {r4-r7}
478    .cfi_adjust_cfa_offset -16
479    .cfi_restore r4
480    .cfi_restore r5
481    .cfi_restore r6
482    .cfi_restore r7
483    // Don't restore r8, the marking register gets updated when coming back from runtime.
484    add sp, sp, #4
485    .cfi_adjust_cfa_offset -4
486    .if \lr_to_pc
487    pop {r9-r11, pc}  @ 9 words of callee saves and args.
488    .cfi_adjust_cfa_offset -16
489    .else
490    pop {r9-r11, lr}  @ 9 words of callee saves and args.
491    .cfi_adjust_cfa_offset -16
492    .cfi_restore r9
493    .cfi_restore r10
494    .cfi_restore r11
495    .cfi_restore lr
496    .endif
497.endm
498
499// Helper to setup the stack after doing a nterp to nterp call. This will setup:
500// - rNEW_FP: the new pointer to dex registers
501// - rNEW_REFS: the new pointer to references
502// - rPC: the new PC pointer to execute
503// - r2: value in instruction to decode the number of arguments.
504// - r3: first dex register for range invokes, up to 4 arguments for non-range invokes.
505// - r4: top of dex register array
506//
507// The method expects:
508// - r0 to contain the ArtMethod
509// - r4 to contain the code item
510.macro SETUP_STACK_FOR_INVOKE
511   // We do the same stack overflow check as the compiler. See CanMethodUseNterp
512   // in how we limit the maximum nterp frame size.
513   sub ip, sp, #STACK_OVERFLOW_RESERVED_BYTES
514   ldr ip, [ip]
515
516   // Spill all callee saves to have a consistent stack frame whether we
517   // are called by compiled code or nterp.
518   SPILL_ALL_CALLEE_SAVES
519
520   // Setup the frame.
521   SETUP_STACK_FRAME r4, rNEW_REFS, rNEW_FP, CFI_NEW_REFS, load_ins=0
522
523   // Fetch instruction information before replacing rPC.
524   FETCH_B r2, 0, 1
525   FETCH r3, 2
526
527   // Set the dex pc pointer.
528   mov rPC, r4
529
530   // Make r4 point to the top of the dex register array.
531   add r4, rNEW_FP, rINST, lsl #2
532
533   CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
534.endm
535
536// Setup arguments based on a non-range nterp to nterp call, and start executing
537// the method. We expect:
538// - rNEW_FP: the new pointer to dex registers
539// - rPC: the new PC pointer to execute
540// - r2: number of arguments (bits 4-7), 5th argument if any (bits 0-3)
541// - r3: up to four dex register arguments
542// - r4: top of dex register array
543// - r1: receiver if non-static.
544//
545// Uses r0 and rINST as temporaries.
546.macro SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
547   // /* op vA, vB, {vC...vG} */
548   .if \is_static
549   asrs   r0, r2, #4
550   beq    6f
551   .else
552   asr    r0, r2, #4
553   .endif
554   mov rINST, #-4
555   cmp r0, #2
556   blt 1f
557   beq 2f
558   cmp r0, #4
559   blt 3f
560   beq 4f
561
562  // We use a decrementing rINST to store references relative
563  // to rNEW_FP and dex registers relative to r4
564  //
565  // TODO: We could set up rINST as the number of registers (this can be an additional output from
566  // SETUP_STACK_FOR_INVOKE) and then just decrement it by one before copying each arg.
567  // Maybe even introduce macros NEW_VREG_ADDRESS/NEW_VREG_REF_ADDRESS.
5685:
569   and         r2, r2, #15
570   GET_VREG_OBJECT r0, r2
571   str         r0, [rNEW_FP, rINST]
572   GET_VREG    r0, r2
573   str         r0, [r4, rINST]
574   sub         rINST, rINST, #4
5754:
576   asr         r2, r3, #12
577   GET_VREG_OBJECT r0, r2
578   str         r0, [rNEW_FP, rINST]
579   GET_VREG    r0, r2
580   str         r0, [r4, rINST]
581   sub         rINST, rINST, #4
5823:
583   ubfx        r2, r3, #8, #4
584   GET_VREG_OBJECT r0, r2
585   str         r0, [rNEW_FP, rINST]
586   GET_VREG    r0, r2
587   str         r0, [r4, rINST]
588   sub         rINST, rINST, #4
5892:
590   ubfx        r2, r3, #4, #4
591   GET_VREG_OBJECT r0, r2
592   str         r0, [rNEW_FP, rINST]
593   GET_VREG    r0, r2
594   str         r0, [r4, rINST]
595   .if !\is_string_init
596   sub         rINST, rINST, #4
597   .endif
5981:
599   .if \is_string_init
600   // Ignore the first argument
601   .elseif \is_static
602   and         r2, r3, #0xf
603   GET_VREG_OBJECT r0, r2
604   str         r0, [rNEW_FP, rINST]
605   GET_VREG    r0, r2
606   str         r0, [r4, rINST]
607   .else
608   str         r1, [rNEW_FP, rINST]
609   str         r1, [r4, rINST]
610   .endif
611
6126:
613   // Start executing the method.
614   mov rFP, rNEW_FP
615   mov rREFS, rNEW_REFS
616   CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -4, CALLEE_SAVES_SIZE
617   // r8 was used for setting up the frame, restore it now.
618   REFRESH_MARKING_REGISTER
619   // Branch to the main handler, which will reload rIBASE,
620   // that was used for setting up the frame.
621   b .Lexecute_instructions
622.endm
623
624// Setup arguments based on a range nterp to nterp call, and start executing
625// the method.
626// - rNEW_FP: the new pointer to dex registers
627// - rNEW_REFS: the new pointer to references
628// - rPC: the new PC pointer to execute
629// - r2: number of arguments
630// - r3: first dex register
631// - r4: top of dex register array
632// - r1: receiver if non-static.
633//
634// Expects r0 to be available.
635.macro SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
636   mov r0, #-4
637   .if \is_string_init
638   // Ignore the first argument
639   sub r2, r2, #1
640   add r3, r3, #1
641   .elseif !\is_static
642   sub r2, r2, #1
643   add r3, r3, #1
644   .endif
645
646   cmp r2, #0
647   beq 2f
648   add rREFS, rREFS, r3, lsl #2  // pointer to first argument in reference array
649   add rREFS, rREFS, r2, lsl #2    // pointer to last argument in reference array
650   add rFP, rFP, r3, lsl #2     // pointer to first argument in register array
651   add rFP, rFP, r2, lsl #2      // pointer to last argument in register array
6521:
653   ldr  r3, [rREFS, #-4]!
654   str  r3, [rNEW_FP, r0]
655   subs r2, r2, 1
656   ldr  r3, [rFP, #-4]!
657   str  r3, [r4, r0]
658   sub r0, r0, 4
659   bne 1b
6602:
661   .if \is_string_init
662   // Ignore first argument
663   .elseif !\is_static
664   str r1, [rNEW_FP, r0]
665   str r1, [r4, r0]
666   .endif
667   mov rFP, rNEW_FP
668   mov rREFS, rNEW_REFS
669   CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -4, CALLEE_SAVES_SIZE
670   // r8 was used for setting up the frame, restore it now.
671   REFRESH_MARKING_REGISTER
672   // Branch to the main handler, which will reload rIBASE,
673   // that was used for setting up the frame.
674   b .Lexecute_instructions
675.endm
676
677.macro GET_SHORTY dest, is_interface, is_polymorphic, is_custom
678   push {r0-r3}
679   .if \is_polymorphic
680   ldr r0, [sp, #16]
681   mov r1, rPC
682   bl NterpGetShortyFromInvokePolymorphic
683   .elseif \is_custom
684   ldr r0, [sp, #16]
685   mov r1, rPC
686   bl NterpGetShortyFromInvokeCustom
687   .elseif \is_interface
688   ldr r0, [sp, #16]
689   FETCH r1, 1
690   bl NterpGetShortyFromMethodId
691   .else
692   bl NterpGetShorty
693   .endif
694   mov \dest, r0
695   pop {r0-r3}
696.endm
697
698// Input:  r0 contains the ArtMethod
699// Output: r4 contains the code item
700.macro GET_CODE_ITEM
701   ldr r4, [r0, #ART_METHOD_DATA_OFFSET_32]
702.endm
703
704.macro DO_ENTRY_POINT_CHECK call_compiled_code, name
705   // On entry, the method is r0, the instance is r1
706   ldr r2, .Lfetch_nterp_\name
707.Lfetch_location_\name:
708   // Note that this won't work for thumb.
709   sub r2, pc, r2
710   ldr r3, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32]
711   cmp r2, r3
712   bne  \call_compiled_code
713.endm
714
715// Expects ip and lr to be available.
716.macro UPDATE_REGISTERS_FOR_STRING_INIT old_value, new_value
717   mov ip, #0
7181:
719   GET_VREG_OBJECT lr, ip
720   cmp lr, \old_value
721   bne 2f
722   SET_VREG_OBJECT \new_value, ip
7232:
724   add ip, ip, #1
725   add lr, rREFS, ip, lsl #2
726   cmp lr, rFP
727   bne 1b
728.endm
729
730// Puts the next floating point argument into the expected register,
731// fetching values based on a non-range invoke.
732// Uses ip and lr.
733.macro LOOP_OVER_SHORTY_LOADING_FPS dreg, sreg, inst, shorty, arg_index, finished, if_double
7341: // LOOP
735    ldrb ip, [\shorty], #1          // Load next character in shorty, and increment.
736    cmp ip, #0
737    beq \finished                   // if (ip == '\0') goto finished
738    cmp ip, #68                    // if (ip == 'D') goto FOUND_DOUBLE
739    beq 2f
740    cmp ip, #70                    // if (ip == 'F') goto FOUND_FLOAT
741    beq 3f
742    lsr \inst, \inst, #4
743    add \arg_index, \arg_index, #1
744    //  Handle extra argument in arg array taken by a long.
745    cmp ip, #74                   // if (ip != 'J') goto LOOP
746    bne 1b
747    lsr \inst, \inst, #4
748    add \arg_index, \arg_index, #1
749    b 1b                        // goto LOOP
7502:  // FOUND_DOUBLE
751    and ip, \inst, #0xf
752    GET_VREG ip, ip
753    lsr \inst, \inst, #4
754    add \arg_index, \arg_index, #1
755    cmp \arg_index, #4
756    beq 5f
757    and lr, \inst, #0xf
758    lsr \inst, \inst, #4
759    add \arg_index, \arg_index, #1
760    b 6f
7615:
762    FETCH_B lr, 0, 1
763    and lr, lr, #0xf
7646:
765    GET_VREG lr, lr
766    vmov \dreg, ip, lr
767    b \if_double
7683:  // FOUND_FLOAT
769    cmp \arg_index, #4
770    beq 7f
771    and ip, \inst, #0xf
772    lsr \inst, \inst, #4
773    add \arg_index, \arg_index, #1
774    b 8f
7757:
776    FETCH_B ip, 0, 1
777    and ip, ip, #0xf
7788:
779    GET_VREG_FLOAT \sreg, ip
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.
785.macro LOOP_OVER_SHORTY_LOADING_GPRS gpr_reg, inst, shorty, arg_index, finished, if_long, is_r3
7861: // LOOP
787    ldrb ip, [\shorty], #1         // Load next character in shorty, and increment.
788    cmp ip, #0
789    beq \finished                   // if (ip == '\0') goto finished
790    cmp ip, #74                    // if (ip == 'J') goto FOUND_LONG
791    beq 2f
792    cmp ip, #70                    // if (ip == 'F') goto SKIP_FLOAT
793    beq 3f
794    cmp ip, #68                    // if (ip == 'D') goto SKIP_DOUBLE
795    beq 4f
796    cmp \arg_index, #4
797    beq 7f
798    and ip, \inst, #0xf
799    lsr \inst, \inst, #4
800    add \arg_index, \arg_index, #1
801    b 8f
8027:
803    FETCH_B ip, 0, 1
804    and ip, ip, #0xf
8058:
806    GET_VREG \gpr_reg, ip
807    b 5f
8082:  // FOUND_LONG
809    .if \is_r3
810    // Put back shorty and exit
811    sub \shorty, \shorty, #1
812    b 5f
813    .endif
814    and ip, \inst, #0xf
815    GET_VREG ip, ip
816    // The only one possible for non-range long is r2-r3
817    mov r2, ip
818    lsr \inst, \inst, #4
819    add \arg_index, \arg_index, #1
820    cmp \arg_index, #4
821    beq 9f
822    and ip, \inst, #0xf
823    lsr \inst, \inst, #4
824    b 10f
8259:
826    FETCH_B ip, 0, 1
827    and ip, ip, #0xf
82810:
829    GET_VREG ip, ip
830    // The only one possible for non-range long is r2-r3
831    mov r3, ip
832    add \arg_index, \arg_index, #1
833    b \if_long
8343:  // SKIP_FLOAT
835    lsr \inst, \inst, #4
836    add \arg_index, \arg_index, #1
837    b 1b
8384:  // SKIP_DOUBLE
839    lsr \inst, \inst, #8
840    add \arg_index, \arg_index, #2
841    b 1b
8425:
843.endm
844
845// Puts the next int/long/object argument in the expected stack slot,
846// fetching values based on a non-range invoke.
847// Uses ip as temporary.
848.macro LOOP_OVER_SHORTY_LOADING_INTs shorty, inst, arg_index, finished, is_string_init
8491: // LOOP
850    ldrb ip, [\shorty], #1         // Load next character in shorty, and increment.
851    cmp ip, #0
852    beq \finished                  // if (ip == '\0') goto finished
853    cmp ip, #74                    // if (ip == 'J') goto FOUND_LONG
854    beq 2f
855    cmp ip, #70                    // if (ip == 'F') goto SKIP_FLOAT
856    beq 3f
857    cmp ip, #68                    // if (ip == 'D') goto SKIP_DOUBLE
858    beq 4f
859    .if \is_string_init
860    cmp \arg_index, #4
861    .else
862    cmp \arg_index, #(4+1)         // +1 for ArtMethod
863    .endif
864    beq 7f
865    and ip, \inst, #0xf
866    lsr \inst, \inst, #4
867    b 8f
8687:
869    FETCH_B ip, 0, 1
870    and ip, ip, #0xf
8718:
872    GET_VREG ip, ip
873    str ip, [sp, \arg_index, lsl #2]
874    add \arg_index, \arg_index, #1
875    b 1b
8762:  // FOUND_LONG
877    and ip, \inst, #0xf
878    GET_VREG ip, ip
879    str ip, [sp, \arg_index, lsl #2]
880    lsr \inst, \inst, #4
881    add \arg_index, \arg_index, #1
882    .if \is_string_init
883    cmp \arg_index, #4
884    .else
885    cmp \arg_index, #(4+1)         // +1 for ArtMethod
886    .endif
887    beq 9f
888    and ip, \inst, #0xf
889    lsr \inst, \inst, #4
890    b 10f
8919:
892    FETCH_B ip, 0, 1
893    and ip, ip, #0xf
89410:
895    GET_VREG ip, ip
896    str ip, [sp, \arg_index, lsl #2]
897    add \arg_index, \arg_index, #1
898    b 1b
8993:  // SKIP_FLOAT
900    lsr \inst, \inst, #4
901    add \arg_index, \arg_index, #1
902    b 1b
9034:  // SKIP_DOUBLE
904    lsr \inst, \inst, #8
905    add \arg_index, \arg_index, #2
906    b 1b
907.endm
908
909.macro SETUP_RETURN_VALUE shorty
910   ldrb ip, [\shorty]
911   cmp ip, #68       // Test if result type char == 'D'.
912   beq 1f
913   cmp ip, #70       // Test if result type char == 'F'.
914   bne 2f
915   vmov r0, s0
916   b 2f
9171:
918   vmov r0, r1, d0
9192:
920.endm
921
922.macro GET_SHORTY_SLOW_PATH dest, is_interface
923   // Save all registers that can hold arguments in the fast path.
924   vpush {s0}
925   push {r0-r2}
926   .if \is_interface
927   ldr r0, [sp, #16]
928   FETCH r1, 1
929   bl NterpGetShortyFromMethodId
930   .else
931   bl NterpGetShorty
932   .endif
933   mov \dest, r0
934   pop {r0-r2}
935   vpop {s0}
936.endm
937
938.macro COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
939   .if \is_polymorphic
940   // We always go to compiled code for polymorphic calls.
941   .elseif \is_custom
942   // We always go to compiled code for custom calls.
943   .else
944     DO_ENTRY_POINT_CHECK .Lcall_compiled_code_\suffix, \suffix
945     GET_CODE_ITEM
946     .if \is_string_init
947     bl nterp_to_nterp_string_init_non_range
948     .elseif \is_static
949     bl nterp_to_nterp_static_non_range
950     .else
951     bl nterp_to_nterp_instance_non_range
952     .endif
953     b .Ldone_return_\suffix
954.Lfetch_nterp_\suffix:
955    .word   (.Lfetch_location_\suffix+8) - ExecuteNterpImpl
956   .endif
957
958.Lcall_compiled_code_\suffix:
959   .if \is_polymorphic
960   // No fast path for polymorphic calls.
961   .elseif \is_custom
962   // No fast path for custom calls.
963   .elseif \is_string_init
964   // No fast path for string.init.
965   .else
966     ldr ip, [r0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
967     tst ip, #ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG
968     beq .Lfast_path_with_few_args_\suffix
969     FETCH_B rINST, 0, 1
970     .if \is_static
971     asrs lr, rINST, #4
972     beq .Linvoke_fast_path_\suffix
973     .else
974     asr lr, rINST, #4
975     cmp lr, #1
976     beq .Linvoke_fast_path_\suffix
977     .endif
978     FETCH ip, 2
979     cmp lr, #2
980     .if \is_static
981     blt .Lone_arg_fast_path_\suffix
982     .endif
983     beq .Ltwo_args_fast_path_\suffix
984     cmp lr, #4
985     blt .Lthree_args_fast_path_\suffix
986     beq .Lfour_args_fast_path_\suffix
987     and         rINST, rINST, #15
988     GET_VREG    rINST, rINST
989     str         rINST, [sp, #(4 + 4 * 4)]
990.Lfour_args_fast_path_\suffix:
991     asr         rINST, ip, #12
992     GET_VREG    rINST, rINST
993     str         rINST, [sp, #(4 + 3 * 4)]
994.Lthree_args_fast_path_\suffix:
995     ubfx        rINST, ip, #8, #4
996     GET_VREG    r3, rINST
997.Ltwo_args_fast_path_\suffix:
998     ubfx        rINST, ip, #4, #4
999     GET_VREG    r2, rINST
1000.Lone_arg_fast_path_\suffix:
1001     .if \is_static
1002     and         rINST, ip, #0xf
1003     GET_VREG    r1, rINST
1004     .else
1005     // First argument already in r1.
1006     .endif
1007.Linvoke_fast_path_\suffix:
1008     .if \is_interface
1009     // Setup hidden argument.
1010     mov ip, r4
1011     .endif
1012     ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32]
1013     blx lr
1014     FETCH_ADVANCE_INST 3
1015     GET_INST_OPCODE ip
1016     GOTO_OPCODE ip
1017
1018.Lfast_path_with_few_args_\suffix:
1019     // Fast path when we have zero or one argument (modulo 'this'). If there
1020     // is one argument, we can put it in both floating point and core register.
1021     FETCH_B r2, 0, 1
1022     asr r2, r2, #4  // number of arguments
1023     .if \is_static
1024     cmp r2, #1
1025     blt .Linvoke_with_few_args_\suffix
1026     bne .Lget_shorty_\suffix
1027     FETCH r2, 2
1028     and r2, r2, #0xf  // dex register of first argument
1029     GET_VREG r1, r2
1030     vmov s0, r1
1031     .else
1032     cmp r2, #2
1033     blt .Linvoke_with_few_args_\suffix
1034     bne .Lget_shorty_\suffix
1035     FETCH r2, 2
1036     ubfx r2, r2, #4, #4  // dex register of second argument
1037     GET_VREG r2, r2
1038     vmov s0, r2
1039     .endif
1040.Linvoke_with_few_args_\suffix:
1041     // Check if the next instruction is move-result or move-result-wide.
1042     // If it is, we fetch the shorty and jump to the regular invocation.
1043     FETCH r3, 3
1044     and r3, r3, #0xfe
1045     cmp r3, #0x0a
1046     beq .Lget_shorty_and_invoke_\suffix
1047     .if \is_interface
1048     // Setup hidden argument.
1049     mov ip, r4
1050     .endif
1051     ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32]
1052     blx lr
1053     FETCH_ADVANCE_INST 3
1054     GET_INST_OPCODE ip
1055     GOTO_OPCODE ip
1056.Lget_shorty_and_invoke_\suffix:
1057     .if \is_interface
1058     // Save hidden argument.
1059     vmov s16, r4
1060     .endif
1061     GET_SHORTY_SLOW_PATH rINST, \is_interface
1062     b .Lgpr_setup_finished_\suffix
1063   .endif
1064
1065.Lget_shorty_\suffix:
1066   .if \is_interface
1067   // Save hidden argument.
1068   vmov s16, r4
1069   .endif
1070   GET_SHORTY rINST, \is_interface, \is_polymorphic, \is_custom
1071   // From this point:
1072   // - rINST contains shorty (in callee-save to switch over return value after call).
1073   // - r0 contains method
1074   // - r1 contains 'this' pointer for instance method.
1075   // We need three registers.
1076   add r3, rINST, #1  // shorty + 1  ; ie skip return arg character
1077   FETCH r2, 2 // arguments
1078   .if \is_string_init
1079   lsr r2, r2, #4
1080   mov r4, #1       // ignore first argument
1081   .elseif \is_static
1082   mov r4, #0      // arg_index
1083   .else
1084   lsr r2, r2, #4
1085   mov r4, #1       // ignore first argument
1086   .endif
1087   LOOP_OVER_SHORTY_LOADING_FPS d0, s0, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Ld1_s2_\suffix
1088.Ld1_s1_\suffix:
1089   LOOP_OVER_SHORTY_LOADING_FPS d1, s1, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Ld2_s1_\suffix
1090.Ld1_s2_\suffix:
1091   LOOP_OVER_SHORTY_LOADING_FPS d1, s2, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Ls4_\suffix
1092.Ld2_s3_\suffix:
1093   LOOP_OVER_SHORTY_LOADING_FPS d2, s3, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Lxmm_setup_finished_\suffix
1094   b .Ls4_\suffix
1095.Ld2_s1_\suffix:
1096   LOOP_OVER_SHORTY_LOADING_FPS d2, s1, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Lxmm_setup_finished_\suffix
1097.Ls4_\suffix:
1098   // If we arrive here, we can only have a float.
1099   LOOP_OVER_SHORTY_LOADING_FPS d2, s4, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Lxmm_setup_finished_\suffix
1100.Lxmm_setup_finished_\suffix:
1101   add r4, rINST, #1  // shorty + 1  ; ie skip return arg character
1102   FETCH r8, 2 // arguments
1103   .if \is_string_init
1104   lsr r8, r8, #4
1105   mov lr, #1       // ignore first argument
1106   LOOP_OVER_SHORTY_LOADING_GPRS r1, r8, r4, lr, .Lgpr_setup_finished_\suffix, .Lif_long_\suffix, is_r3=0
1107   .elseif \is_static
1108   mov lr, #0      // arg_index
1109   LOOP_OVER_SHORTY_LOADING_GPRS r1, r8, r4, lr, .Lgpr_setup_finished_\suffix, .Lif_long_\suffix, is_r3=0
1110   .else
1111   lsr r8, r8, #4
1112   mov lr, #1       // ignore first argument
1113   .endif
1114   LOOP_OVER_SHORTY_LOADING_GPRS r2, r8, r4, lr, .Lgpr_setup_finished_\suffix, .Lif_long_\suffix, is_r3=0
1115   LOOP_OVER_SHORTY_LOADING_GPRS r3, r8, r4, lr, .Lgpr_setup_finished_\suffix, .Lif_long_\suffix, is_r3=1
1116.Lif_long_\suffix:
1117   // Store in the outs array (stored above the ArtMethod in the stack). We only do this for non-string-init
1118   // calls as the index is already adjusted above.
1119   .if !\is_string_init
1120   add lr, lr, #1
1121   .endif
1122   LOOP_OVER_SHORTY_LOADING_INTs r4, r8, lr, .Lgpr_setup_finished_\suffix, \is_string_init
1123.Lgpr_setup_finished_\suffix:
1124   REFRESH_MARKING_REGISTER // r8 was used when setting parameters, restore it.
1125   .if \is_polymorphic
1126   bl art_quick_invoke_polymorphic
1127   .elseif \is_custom
1128   bl art_quick_invoke_custom
1129   .else
1130      .if \is_interface
1131      // Setup hidden argument.
1132      vmov ip, s16
1133      .endif
1134      ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32]
1135      blx lr
1136   .endif
1137   SETUP_RETURN_VALUE rINST
1138.Ldone_return_\suffix:
1139   /* resume execution of caller */
1140   .if \is_string_init
1141   FETCH ip, 2 // arguments
1142   and ip, ip, #0xf
1143   GET_VREG r1, ip
1144   UPDATE_REGISTERS_FOR_STRING_INIT r1, r0
1145   .endif
1146
1147   .if \is_polymorphic
1148   FETCH_ADVANCE_INST 4
1149   .else
1150   FETCH_ADVANCE_INST 3
1151   .endif
1152   GET_INST_OPCODE ip
1153   GOTO_OPCODE ip
1154.endm
1155
1156// Puts the next int/long/object argument in the expected register,
1157// fetching values based on a range invoke.
1158// Uses ip as temporary.
1159.macro LOOP_RANGE_OVER_SHORTY_LOADING_GPRS reg32, shorty, arg_index, stack_index, finished, if_long, is_r3
11601: // LOOP
1161    ldrb ip, [\shorty], #1         // Load next character in shorty, and increment.
1162    cmp ip, #0
1163    beq \finished                  // if (ip == '\0') goto finished
1164    cmp ip, #74                    // if (ip == 'J') goto FOUND_LONG
1165    beq 2f
1166    cmp ip, #70                    // if (ip == 'F') goto SKIP_FLOAT
1167    beq 3f
1168    cmp ip, #68                    // if (ip == 'D') goto SKIP_DOUBLE
1169    beq 4f
1170    GET_VREG \reg32, \arg_index
1171    add \arg_index, \arg_index, #1
1172    add \stack_index, \stack_index, #1
1173    b 5f
11742:  // FOUND_LONG
1175    .if \is_r3
1176    // Put back shorty and jump to \if_long
1177    sub \shorty, \shorty, #1
1178    .else
1179    GET_VREG r2, \arg_index
1180    add \arg_index, \arg_index, #1
1181    add \stack_index, \stack_index, #1
1182    GET_VREG r3, \arg_index
1183    add \arg_index, \arg_index, #1
1184    add \stack_index, \stack_index, #1
1185    .endif
1186    b \if_long
11873:  // SKIP_FLOAT
1188    add \arg_index, \arg_index, #1
1189    add \stack_index, \stack_index, #1
1190    b 1b
11914:  // SKIP_DOUBLE
1192    add \arg_index, \arg_index, #2
1193    add \stack_index, \stack_index, #2
1194    b 1b
11955:
1196.endm
1197
1198// Puts the next int/long/object argument in the expected stack slot,
1199// fetching values based on a range invoke.
1200// Uses ip as temporary.
1201.macro LOOP_RANGE_OVER_INTs shorty, arg_index, stack_index, finished
12021: // LOOP
1203    ldrb ip, [\shorty], #1         // Load next character in shorty, and increment.
1204    cmp ip, #0
1205    beq \finished                     // if (ip == '\0') goto finished
1206    cmp ip, #74                    // if (ip == 'J') goto FOUND_LONG
1207    beq 2f
1208    cmp ip, #70                    // if (ip == 'F') goto SKIP_FLOAT
1209    beq 3f
1210    cmp ip, #68                    // if (ip == 'D') goto SKIP_DOUBLE
1211    beq 4f
1212    GET_VREG ip, \arg_index
1213    str ip, [sp, \stack_index, lsl #2]
1214    add \arg_index, \arg_index, #1
1215    add \stack_index, \stack_index, #1
1216    b 1b
12172:  // FOUND_LONG
1218    GET_VREG ip, \arg_index
1219    str ip, [sp, \stack_index, lsl #2]
1220    add \arg_index, \arg_index, #1
1221    add \stack_index, \stack_index, #1
1222    GET_VREG ip, \arg_index
1223    str ip, [sp, \stack_index, lsl #2]
1224    add \arg_index, \arg_index, #1
1225    add \stack_index, \stack_index, #1
1226    b 1b
12273:  // SKIP_FLOAT
1228    add \arg_index, \arg_index, #1
1229    add \stack_index, \stack_index, #1
1230    b 1b
12314:  // SKIP_DOUBLE
1232    add \arg_index, \arg_index, #2
1233    add \stack_index, \stack_index, #2
1234    b 1b
1235.endm
1236
1237.macro COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
1238   .if \is_polymorphic
1239   // We always go to compiled code for polymorphic calls.
1240   .elseif \is_custom
1241   // We always go to compiled code for custom calls.
1242   .else
1243     DO_ENTRY_POINT_CHECK .Lcall_compiled_code_range_\suffix, range_\suffix
1244     GET_CODE_ITEM
1245     .if \is_string_init
1246     bl nterp_to_nterp_string_init_range
1247     .elseif \is_static
1248     bl nterp_to_nterp_static_range
1249     .else
1250     bl nterp_to_nterp_instance_range
1251     .endif
1252     b .Ldone_return_range_\suffix
1253.Lfetch_nterp_range_\suffix:
1254    .word   (.Lfetch_location_range_\suffix+8) - ExecuteNterpImpl
1255   .endif
1256
1257.Lcall_compiled_code_range_\suffix:
1258   .if \is_polymorphic
1259   // No fast path for polymorphic calls.
1260   .elseif \is_custom
1261   // No fast path for custom calls.
1262   .elseif \is_string_init
1263   // No fast path for string.init.
1264   .else
1265     ldr ip, [r0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
1266     tst ip, #ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG
1267     beq .Lfast_path_with_few_args_range_\suffix
1268     FETCH_B ip, 0, 1  // Number of arguments
1269     .if \is_static
1270     cmp ip, #0
1271     .else
1272     cmp ip, #1
1273     .endif
1274     beq .Linvoke_fast_path_range_\suffix
1275     FETCH lr, 2  // dex register of first argument
1276     add lr, rFP, lr, lsl #2  // location of first dex register value.
1277     .if \is_static
1278     cmp ip, #2
1279     blt .Lone_arg_fast_path_range_\suffix
1280     beq .Ltwo_args_fast_path_range_\suffix
1281     cmp ip, #3
1282     .else
1283     cmp ip, #3
1284     blt .Ltwo_args_fast_path_range_\suffix
1285     .endif
1286     beq .Lthree_args_fast_path_range_\suffix
1287     add rINST, sp, #4  // Add space for the ArtMethod
1288
1289.Lloop_over_fast_path_range_\suffix:
1290     sub ip, ip, #1
1291     ldr r3, [lr, ip, lsl #2]
1292     str r3, [rINST, ip, lsl #2]
1293     cmp ip, #3
1294     bne .Lloop_over_fast_path_range_\suffix
1295
1296.Lthree_args_fast_path_range_\suffix:
1297     ldr r3, [lr, #8]
1298.Ltwo_args_fast_path_range_\suffix:
1299     ldr r2, [lr, #4]
1300.Lone_arg_fast_path_range_\suffix:
1301     .if \is_static
1302     ldr r1, [lr, #0]
1303     .else
1304     // First argument already in r1.
1305     .endif
1306.Linvoke_fast_path_range_\suffix:
1307     .if \is_interface
1308     // Setup hidden argument.
1309     mov ip, r4
1310     .endif
1311     ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32]
1312     blx lr
1313     FETCH_ADVANCE_INST 3
1314     GET_INST_OPCODE ip
1315     GOTO_OPCODE ip
1316
1317.Lfast_path_with_few_args_range_\suffix:
1318     // Fast path when we have zero or one argument (modulo 'this'). If there
1319     // is one argument, we can put it in both floating point and core register.
1320     FETCH_B r2, 0, 1 // number of arguments
1321     .if \is_static
1322     cmp r2, #1
1323     blt .Linvoke_with_few_args_range_\suffix
1324     bne .Lget_shorty_range_\suffix
1325     FETCH r3, 2  // dex register of first argument
1326     GET_VREG r1, r3
1327     vmov s0, r1
1328     .else
1329     cmp r2, #2
1330     blt .Linvoke_with_few_args_range_\suffix
1331     bne .Lget_shorty_range_\suffix
1332     FETCH r3, 2  // dex register of first argument
1333     add r3, r3, #1  // Add 1 for next argument
1334     GET_VREG r2, r3
1335     vmov s0, r2
1336     .endif
1337.Linvoke_with_few_args_range_\suffix:
1338     // Check if the next instruction is move-result or move-result-wide.
1339     // If it is, we fetch the shorty and jump to the regular invocation.
1340     FETCH r3, 3
1341     and r3, r3, #0xfe
1342     cmp r3, #0x0a
1343     beq .Lget_shorty_and_invoke_range_\suffix
1344     .if \is_interface
1345     // Setup hidden argument.
1346     mov ip, r4
1347     .endif
1348     ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32]
1349     blx lr
1350     FETCH_ADVANCE_INST 3
1351     GET_INST_OPCODE ip
1352     GOTO_OPCODE ip
1353.Lget_shorty_and_invoke_range_\suffix:
1354     .if \is_interface
1355     // Save hidden argument.
1356     vmov s16, r4
1357     .endif
1358     GET_SHORTY_SLOW_PATH rINST, \is_interface
1359     b .Lgpr_setup_finished_range_\suffix
1360   .endif
1361
1362.Lget_shorty_range_\suffix:
1363   .if \is_interface
1364   // Save hidden argument.
1365   vmov s16, r4
1366   .endif
1367   GET_SHORTY rINST, \is_interface, \is_polymorphic, \is_custom
1368   // From this point:
1369   // - rINST contains shorty (in callee-save to switch over return value after call).
1370   // - r0 contains method
1371   // - r1 contains 'this' pointer for instance method.
1372   //
1373   // Save r0 and r1 before calling NterpSetupArm32Fprs.
1374   push {r0, r1}
1375   add r0, rINST, #1  // shorty + 1  ; ie skip return arg character
1376   FETCH r1, 2 // arguments
1377   .if \is_string_init
1378   add r1, r1, #1  // arg start index
1379   mov r2, #1       // index in stack
1380   .elseif \is_static
1381   mov r2, #0       // index in stack
1382   .else
1383   add r1, r1, #1  // arg start index
1384   mov r2, #1       // index in stack
1385   .endif
1386   vpush {s0-s15}
1387   mov r3, sp
1388   // Pass the stack address for arguments, +16 for fprs, +2 for saved registers,
1389   // +1 for ArtMethod.
1390   add lr, sp, #((16 + 2 + 1) * 4)
1391   push {rFP, lr}
1392   bl NterpSetupArm32Fprs
1393   add sp, sp, #8
1394   vpop {s0-s15}
1395   pop {r0, r1}
1396.Lxmm_setup_finished_range_\suffix:
1397   add r8, rINST, #1  // shorty + 1  ; ie skip return arg character
1398   FETCH lr, 2 // arguments
1399   .if \is_string_init
1400   add lr, lr, #1  // arg start index
1401   mov r4, #0      // index in stack
1402   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r1, r8, lr, r4, .Lgpr_setup_finished_range_\suffix, .Lif_long_range_\suffix, is_r3=0
1403   .elseif \is_static
1404   mov r4, #0      // index in stack
1405   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r1, r8, lr, r4, .Lgpr_setup_finished_range_\suffix, .Lif_long_range_\suffix, is_r3=0
1406   .else
1407   add lr, lr, #1  // arg start index
1408   mov r4, #1       // index in stack
1409   .endif
1410   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r2, r8, lr, r4, .Lgpr_setup_finished_range_\suffix, .Lif_long_range_\suffix, is_r3=0
1411   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r3, r8, lr, r4, .Lgpr_setup_finished_range_\suffix, .Lif_long_range_\suffix, is_r3=1
1412.Lif_long_range_\suffix:
1413   // Add 1 word for the ArtMethod stored before the outs.
1414   add r4, r4, #1
1415   LOOP_RANGE_OVER_INTs r8, lr, r4, .Lgpr_setup_finished_range_\suffix
1416.Lgpr_setup_finished_range_\suffix:
1417   REFRESH_MARKING_REGISTER // r8 was used when setting parameters, restore it.
1418   .if \is_polymorphic
1419   bl art_quick_invoke_polymorphic
1420   .elseif \is_custom
1421   bl art_quick_invoke_custom
1422   .else
1423      .if \is_interface
1424      // Setup hidden argument.
1425      vmov ip, s16
1426      .endif
1427      ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32]
1428      blx lr
1429   .endif
1430   SETUP_RETURN_VALUE rINST
1431.Ldone_return_range_\suffix:
1432   /* resume execution of caller */
1433   .if \is_string_init
1434   FETCH ip, 2 // arguments
1435   GET_VREG r1, ip
1436   UPDATE_REGISTERS_FOR_STRING_INIT r1, r0
1437   .endif
1438
1439   .if \is_polymorphic
1440    FETCH_ADVANCE_INST 4
1441   .else
1442   FETCH_ADVANCE_INST 3
1443   .endif
1444   GET_INST_OPCODE ip
1445   GOTO_OPCODE ip
1446.endm
1447
1448.macro POISON_HEAP_REF_IF_OBJECT is_object, rRef
1449   .if \is_object
1450   POISON_HEAP_REF \rRef
1451   .endif
1452.endm
1453
1454.macro WRITE_BARRIER_IF_OBJECT is_object, value, holder, label, tmp
1455   .if \is_object
1456   // In T32, we would use `SMART_CBZ \value, \label`
1457   cmp     \value, #0
1458   beq     \label
1459   ldr     ip, [rSELF, #THREAD_CARD_TABLE_OFFSET]
1460   lsr     \tmp, \holder, #CARD_TABLE_CARD_SHIFT
1461   strb    ip, [ip, \tmp]
1462\label:
1463   .endif
1464.endm
1465
1466.macro LDREXD_STREXD_LOOP addr, load1, load2, store1, store2, tmp, label
1467\label:
1468   ldrexd  \load1, \load2, [\addr]
1469   strexd  \tmp, \store1, \store2, [\addr]
1470   cmp     \tmp, #0
1471   bne     \label
1472.endm
1473
1474.macro ATOMIC_LOAD64 addr, load1, load2, tmp, label
1475   LDREXD_STREXD_LOOP \addr, \load1, \load2, \load1, \load2, \tmp, \label
1476.endm
1477
1478.macro ATOMIC_STORE64 addr, store1, store2, tmp1, tmp2, label
1479   LDREXD_STREXD_LOOP \addr, \tmp1, \tmp2, \store1, \store2, \tmp1, \label
1480.endm
1481
1482// Puts the next int/long/object parameter passed in physical register
1483// in the expected dex register array entry, and in case of object in the
1484// expected reference array entry.
1485// Uses ip as temporary.
1486.macro LOOP_OVER_SHORTY_STORING_GPRS gpr_32, shorty, arg_offset, regs, refs, finished, if_long, is_r3
14871: // LOOP
1488    ldrb ip, [\shorty], #1       // Load next character in shorty, and increment.
1489    cmp ip, #0
1490    beq \finished            // if (ip == '\0') goto finished
1491    cmp ip, #74                  // if (ip == 'J') goto FOUND_LONG
1492    beq 2f
1493    cmp ip, #70                  // if (ip == 'F') goto SKIP_FLOAT
1494    beq 3f
1495    cmp ip, #68                  // if (ip == 'D') goto SKIP_DOUBLE
1496    beq 4f
1497    str \gpr_32, [\regs, \arg_offset]
1498    cmp ip, #76                  // if (ip != 'L') goto NOT_REFERENCE
1499    bne 6f
1500    str \gpr_32, [\refs, \arg_offset]
15016:  // NOT_REFERENCE
1502    add \arg_offset, \arg_offset, #4
1503    b 5f
15042:  // FOUND_LONG
1505    .if \is_r3
1506    // Put back shorty and jump to \if_long
1507    sub \shorty, \shorty, #1
1508    .else
1509    // A long can only be in r2, r3
1510    str r2, [\regs, \arg_offset]
1511    add \arg_offset, \arg_offset, #4
1512    str r3, [\regs, \arg_offset]
1513    add \arg_offset, \arg_offset, #4
1514    .endif
1515    b \if_long
15163:  // SKIP_FLOAT
1517    add \arg_offset, \arg_offset, #4
1518    b 1b
15194:  // SKIP_DOUBLE
1520    add \arg_offset, \arg_offset, #8
1521    b 1b
15225:
1523.endm
1524
1525// Puts the next int/long/object parameter passed in stack
1526// in the expected dex register array entry, and in case of object in the
1527// expected reference array entry.
1528.macro LOOP_OVER_INTs shorty, arg_offset, regs, refs, stack_ptr, tmp1, tmp2, finished
15291: // LOOP
1530    ldrb \tmp1, [\shorty], #1       // Load next character in shorty, and increment.
1531    cmp \tmp1, #0
1532    beq \finished                   // if (\tmp1 == '\0') goto finished
1533    cmp \tmp1, #74                  // if (\tmp1 == 'J') goto FOUND_LONG
1534    beq 2f
1535    cmp \tmp1, #70                  // if (\tmp1 == 'F') goto SKIP_FLOAT
1536    beq 3f
1537    cmp \tmp1, #68                  // if (\tmp1 == 'D') goto SKIP_DOUBLE
1538    beq 4f
1539    add \tmp2, \stack_ptr, \arg_offset
1540    ldr \tmp2, [\tmp2,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1541    str \tmp2, [\regs, \arg_offset]
1542    cmp \tmp1, #76                  // if (\tmp1 != 'L') goto loop
1543    bne 3f
1544    str \tmp2, [\refs, \arg_offset]
1545    add \arg_offset, \arg_offset, #4
1546    b 1b
15472:  // FOUND_LONG
1548    add \tmp1, \stack_ptr, \arg_offset
1549    ldr \tmp1, [\tmp1,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1550    str \tmp1, [\regs, \arg_offset]
1551    add \arg_offset, \arg_offset, #4
1552    add \tmp1, \stack_ptr, \arg_offset
1553    ldr \tmp1, [\tmp1,  #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1554    str \tmp1, [\regs, \arg_offset]
1555    add \arg_offset, \arg_offset, #4
1556    b 1b
15573:  // SKIP_FLOAT
1558    add \arg_offset, \arg_offset, #4
1559    b 1b
15604:  // SKIP_DOUBLE
1561    add \arg_offset, \arg_offset, #8
1562    b 1b
1563.endm
1564
1565.macro SETUP_REFERENCE_PARAMETER_IN_GPR gpr32, regs, refs, ins, arg_offset, finished
1566    str \gpr32, [\regs, \arg_offset]
1567    subs \ins, \ins, #1
1568    str \gpr32, [\refs, \arg_offset]
1569    add \arg_offset, \arg_offset, #4
1570    beq \finished
1571.endm
1572
1573.macro SETUP_REFERENCE_PARAMETERS_IN_STACK regs, refs, ins, stack_ptr, arg_offset
15741:
1575    ldr ip, [\stack_ptr, \arg_offset]
1576    subs \ins, \ins, #1
1577    str ip, [\regs, \arg_offset]
1578    str ip, [\refs, \arg_offset]
1579    add \arg_offset, \arg_offset, #4
1580    bne 1b
1581.endm
1582
1583.macro DO_SUSPEND_CHECK continue_label
1584    // Otherwise, do a suspend check.
1585    ldr ip, [rSELF, #THREAD_FLAGS_OFFSET]
1586    tst ip, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
1587    beq \continue_label
1588    EXPORT_PC
1589    bl    art_quick_test_suspend
1590.endm
1591
1592.macro CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot, if_not_hot
1593    ldr ip, [r0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
1594    tst ip, #ART_METHOD_IS_MEMORY_SHARED_FLAG
1595    beq \if_hot
1596    ldr ip, [rSELF, #THREAD_SHARED_METHOD_HOTNESS_OFFSET]
1597    cmp ip, #0
1598    beq \if_hot
1599    add ip, ip, #-1
1600    str ip, [rSELF, #THREAD_SHARED_METHOD_HOTNESS_OFFSET]
1601    b \if_not_hot
1602.endm
1603
1604
1605%def entry():
1606/*
1607 * ArtMethod entry point.
1608 *
1609 * On entry:
1610 *  r0   ArtMethod* callee
1611 *  rest  method parameters
1612 */
1613
1614OAT_ENTRY ExecuteNterpWithClinitImpl
1615    .cfi_startproc
1616    // For simplicity, we don't do a read barrier here, but instead rely
1617    // on art_quick_resolution_trampoline to always have a suspend point before
1618    // calling back here.
1619    ldr r4, [r0, ART_METHOD_DECLARING_CLASS_OFFSET]
1620    ldr ip, [r4, MIRROR_CLASS_STATUS_OFFSET]
1621    cmp ip, #MIRROR_CLASS_STATUS_VISIBLY_INITIALIZED_SHIFTED
1622    bcs ExecuteNterpImpl
1623    cmp ip, #MIRROR_CLASS_STATUS_INITIALIZED_SHIFTED
1624    blo .Linitializing_check
1625    dmb ish
1626    b ExecuteNterpImpl
1627.Linitializing_check:
1628    cmp ip, #MIRROR_CLASS_STATUS_INITIALIZING_SHIFTED
1629    blo art_quick_resolution_trampoline
1630    ldr r4, [r4, #MIRROR_CLASS_CLINIT_THREAD_ID_OFFSET]
1631    ldr ip, [rSELF, #THREAD_TID_OFFSET]
1632    cmp r4, ip
1633    beq ExecuteNterpImpl
1634    b art_quick_resolution_trampoline
1635    .cfi_endproc
1636    .type EndExecuteNterpWithClinitImpl, #function
1637    .hidden EndExecuteNterpWithClinitImpl
1638    .global EndExecuteNterpWithClinitImpl
1639EndExecuteNterpWithClinitImpl:
1640
1641OAT_ENTRY ExecuteNterpImpl
1642    .cfi_startproc
1643    sub ip, sp, #STACK_OVERFLOW_RESERVED_BYTES
1644    ldr ip, [ip]
1645    /* Spill callee save regs */
1646    SPILL_ALL_CALLEE_SAVES
1647
1648    ldr rPC, [r0, #ART_METHOD_DATA_OFFSET_32]
1649
1650    // Setup the stack for executing the method.
1651    SETUP_STACK_FRAME rPC, rREFS, rFP, CFI_REFS, load_ins=1
1652
1653    // Setup the parameters
1654    cmp r4, #0
1655    beq .Lxmm_setup_finished
1656
1657    sub rINST, rINST, r4
1658    ldr r8, [r0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
1659    lsl rINST, rINST, #2 // rINST is now the offset for inputs into the registers array.
1660    mov rIBASE, ip // rIBASE contains the old stack pointer
1661
1662    tst r8, #ART_METHOD_NTERP_ENTRY_POINT_FAST_PATH_FLAG
1663    beq .Lsetup_slow_path
1664    // Setup pointer to inputs in FP and pointer to inputs in REFS
1665    add lr, rFP, rINST
1666    add r8, rREFS, rINST
1667    mov r0, #0
1668    SETUP_REFERENCE_PARAMETER_IN_GPR r1, lr, r8, r4, r0, .Lxmm_setup_finished
1669    SETUP_REFERENCE_PARAMETER_IN_GPR r2, lr, r8, r4, r0, .Lxmm_setup_finished
1670    SETUP_REFERENCE_PARAMETER_IN_GPR r3, lr, r8, r4, r0, .Lxmm_setup_finished
1671    add rIBASE, rIBASE, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK
1672    SETUP_REFERENCE_PARAMETERS_IN_STACK lr, r8, r4, rIBASE, r0
1673    b .Lxmm_setup_finished
1674
1675.Lsetup_slow_path:
1676    // If the method is not static and there is one argument ('this'), we don't need to fetch the
1677    // shorty.
1678    tst r8, #ART_METHOD_IS_STATIC_FLAG
1679    bne .Lsetup_with_shorty
1680    str r1, [rFP, rINST]
1681    str r1, [rREFS, rINST]
1682    cmp r4, #1
1683    beq .Lxmm_setup_finished
1684
1685.Lsetup_with_shorty:
1686    // Save arguments that were passed before calling into the runtime.
1687    // No need to save r0 (ArtMethod) as we're not using it later in this code.
1688    // Save r4 for stack aligment.
1689    // TODO: Get shorty in a better way and remove below
1690    push {r1-r4}
1691    vpush {s0-s15}
1692    bl NterpGetShorty
1693    vpop {s0-s15}
1694    pop {r1-r4}
1695
1696    mov ip, r8
1697    add r8, rREFS, rINST
1698    add r7, rFP, rINST
1699    mov r4, #0
1700    // Setup shorty, pointer to inputs in FP and pointer to inputs in REFS
1701    add lr, r0, #1  // shorty + 1  ; ie skip return arg character
1702    tst ip, #ART_METHOD_IS_STATIC_FLAG
1703    bne .Lhandle_static_method
1704    add r7, r7, #4
1705    add r8, r8, #4
1706    add rIBASE, rIBASE, #4
1707    b .Lcontinue_setup_gprs
1708.Lhandle_static_method:
1709    LOOP_OVER_SHORTY_STORING_GPRS r1, lr, r4, r7, r8, .Lgpr_setup_finished, .Lif_long, is_r3=0
1710.Lcontinue_setup_gprs:
1711    LOOP_OVER_SHORTY_STORING_GPRS r2, lr, r4, r7, r8, .Lgpr_setup_finished, .Lif_long, is_r3=0
1712    LOOP_OVER_SHORTY_STORING_GPRS r3, lr, r4, r7, r8, .Lgpr_setup_finished, .Lif_long, is_r3=1
1713.Lif_long:
1714    LOOP_OVER_INTs lr, r4, r7, r8, rIBASE, ip, r1, .Lgpr_setup_finished
1715.Lgpr_setup_finished:
1716    add r0, r0, #1  // shorty + 1  ; ie skip return arg character
1717    mov r1, r7
1718    add r2, rIBASE, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK
1719    vpush {s0-s15}
1720    mov r3, sp
1721    bl NterpStoreArm32Fprs
1722    add sp, sp, #(16 * 4)
1723.Lxmm_setup_finished:
1724    CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
1725    // r8 was used for setting up the frame, restore it now.
1726    REFRESH_MARKING_REGISTER
1727.Lexecute_instructions:
1728    // Set rIBASE
1729    adr rIBASE, artNterpAsmInstructionStart
1730    /* start executing the instruction at rPC */
1731    START_EXECUTING_INSTRUCTIONS
1732    /* NOTE: no fallthrough */
1733    // cfi info continues, and covers the whole nterp implementation.
1734    SIZE ExecuteNterpImpl
1735
1736%def opcode_pre():
1737
1738%def fetch_from_thread_cache(dest_reg, miss_label):
1739   // Fetch some information from the thread cache.
1740   // Uses ip and lr as temporaries.
1741   add      ip, rSELF, #THREAD_INTERPRETER_CACHE_OFFSET       // cache address
1742   ubfx     lr, rPC, #2, #THREAD_INTERPRETER_CACHE_SIZE_LOG2  // entry index
1743   add      ip, ip, lr, lsl #3             // entry address within the cache
1744   // In T32, we would use `ldrd ip, \dest_reg, [ip]`
1745   ldr      ${dest_reg}, [ip, #4]          // value (offset)
1746   ldr      ip, [ip]                       // entry key (pc)
1747   cmp      ip, rPC
1748   bne      ${miss_label}
1749
1750%def footer():
1751/*
1752 * ===========================================================================
1753 *  Common subroutines and data
1754 * ===========================================================================
1755 */
1756
1757    .text
1758    .align  2
1759
1760// Enclose all code below in a symbol (which gets printed in backtraces).
1761NAME_START nterp_helper
1762
1763// Note: mterp also uses the common_* names below for helpers, but that's OK
1764// as the assembler compiled each interpreter separately.
1765common_errDivideByZero:
1766    EXPORT_PC
1767    bl art_quick_throw_div_zero
1768
1769// Expect index in r1, length in r3
1770common_errArrayIndex:
1771    EXPORT_PC
1772    mov r0, r1
1773    mov r1, r3
1774    bl art_quick_throw_array_bounds
1775
1776common_errNullObject:
1777    EXPORT_PC
1778    bl art_quick_throw_null_pointer_exception
1779
1780NterpCommonInvokeStatic:
1781    COMMON_INVOKE_NON_RANGE is_static=1, suffix="invokeStatic"
1782
1783NterpCommonInvokeStaticRange:
1784    COMMON_INVOKE_RANGE is_static=1, suffix="invokeStatic"
1785
1786NterpCommonInvokeInstance:
1787    COMMON_INVOKE_NON_RANGE suffix="invokeInstance"
1788
1789NterpCommonInvokeInstanceRange:
1790    COMMON_INVOKE_RANGE suffix="invokeInstance"
1791
1792NterpCommonInvokeInterface:
1793    COMMON_INVOKE_NON_RANGE is_interface=1, suffix="invokeInterface"
1794
1795NterpCommonInvokeInterfaceRange:
1796    COMMON_INVOKE_RANGE is_interface=1, suffix="invokeInterface"
1797
1798NterpCommonInvokePolymorphic:
1799    COMMON_INVOKE_NON_RANGE is_polymorphic=1, suffix="invokePolymorphic"
1800
1801NterpCommonInvokePolymorphicRange:
1802    COMMON_INVOKE_RANGE is_polymorphic=1, suffix="invokePolymorphic"
1803
1804NterpCommonInvokeCustom:
1805    COMMON_INVOKE_NON_RANGE is_static=1, is_custom=1, suffix="invokeCustom"
1806
1807NterpCommonInvokeCustomRange:
1808    COMMON_INVOKE_RANGE is_static=1, is_custom=1, suffix="invokeCustom"
1809
1810NterpHandleStringInit:
1811   COMMON_INVOKE_NON_RANGE is_string_init=1, suffix="stringInit"
1812
1813NterpHandleStringInitRange:
1814   COMMON_INVOKE_RANGE is_string_init=1, suffix="stringInit"
1815
1816
1817NterpHandleHotnessOverflow:
1818    CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot=1f, if_not_hot=5f
18191:
1820    mov r1, rPC
1821    mov r2, rFP
1822    bl nterp_hot_method
1823    cmp r0, #0
1824    bne 3f
18252:
1826    FETCH_INST                          // load rINST
1827    GET_INST_OPCODE ip                  // extract opcode from rINST
1828    GOTO_OPCODE ip                      // jump to next instruction
18293:
1830    // Drop the current frame.
1831    ldr ip, [rREFS, #-4]
1832    mov sp, ip
1833    .cfi_def_cfa sp, CALLEE_SAVES_SIZE
1834
1835    // The transition frame of type SaveAllCalleeSaves saves r4, r8, and r9,
1836    // but not managed ABI. So we need to restore callee-saves of the nterp frame,
1837    // and save managed ABI callee saves, which will be restored by the callee upon
1838    // return.
1839
1840    RESTORE_ALL_CALLEE_SAVES
1841    push {r5-r7, r10-r11, lr}
1842   .cfi_adjust_cfa_offset 24
1843   .cfi_rel_offset r5, 0
1844   .cfi_rel_offset r6, 4
1845   .cfi_rel_offset r7, 8
1846   .cfi_rel_offset r10, 12
1847   .cfi_rel_offset r11, 16
1848   .cfi_rel_offset lr, 20
1849    vpush {s16-s31}
1850    .cfi_adjust_cfa_offset 64
1851
1852    // Setup the new frame
1853    ldr r1, [r0, #OSR_DATA_FRAME_SIZE]
1854    // Given stack size contains all callee saved registers, remove them.
1855    sub r1, r1, #(CALLEE_SAVES_SIZE - 12)
1856
1857    // We know r1 cannot be 0, as it at least contains the ArtMethod.
1858
1859    // Remember CFA in a callee-save register.
1860    mov rINST, sp
1861    .cfi_def_cfa_register rINST
1862
1863    sub sp, sp, r1
1864
1865    add r2, r0, #OSR_DATA_MEMORY
18664:
1867    sub r1, r1, #4
1868    ldr ip, [r2, r1]
1869    str ip, [sp, r1]
1870    cmp r1, #0
1871    bne 4b
1872
1873    // Fetch the native PC to jump to and save it in a callee-save register.
1874    ldr rFP, [r0, #OSR_DATA_NATIVE_PC]
1875
1876    // Free the memory holding OSR Data.
1877    bl free
1878
1879    // Jump to the compiled code.
1880    bx rFP
18815:
1882    DO_SUSPEND_CHECK continue_label=2b
1883    b 2b
1884
1885// This is the logical end of ExecuteNterpImpl, where the frame info applies.
1886// EndExecuteNterpImpl includes the methods below as we want the runtime to
1887// see them as part of the Nterp PCs.
1888.cfi_endproc
1889
1890nterp_to_nterp_static_non_range:
1891    .cfi_startproc
1892    SETUP_STACK_FOR_INVOKE
1893    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0
1894    .cfi_endproc
1895
1896nterp_to_nterp_string_init_non_range:
1897    .cfi_startproc
1898    SETUP_STACK_FOR_INVOKE
1899    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1
1900    .cfi_endproc
1901
1902nterp_to_nterp_instance_non_range:
1903    .cfi_startproc
1904    SETUP_STACK_FOR_INVOKE
1905    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
1906    .cfi_endproc
1907
1908nterp_to_nterp_static_range:
1909    .cfi_startproc
1910    SETUP_STACK_FOR_INVOKE
1911    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0
1912    .cfi_endproc
1913
1914nterp_to_nterp_string_init_range:
1915    .cfi_startproc
1916    SETUP_STACK_FOR_INVOKE
1917    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1
1918    .cfi_endproc
1919
1920nterp_to_nterp_instance_range:
1921    .cfi_startproc
1922    SETUP_STACK_FOR_INVOKE
1923    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
1924    .cfi_endproc
1925
1926NAME_END nterp_helper
1927
1928// This is the end of PCs contained by the OatQuickMethodHeader created for the interpreter
1929// entry point.
1930    .type EndExecuteNterpImpl, #function
1931    .hidden EndExecuteNterpImpl
1932    .global EndExecuteNterpImpl
1933EndExecuteNterpImpl:
1934
1935/*
1936 * Convert the double in r0/r1 to a long in r0/r1.
1937 *
1938 * We have to clip values to long min/max per the specification.  The
1939 * expected common case is a "reasonable" value that converts directly
1940 * to modest integer.  The EABI convert function isn't doing this for us.
1941 */
1942ENTRY nterp_d2l_doconv
1943    ubfx    r2, r1, #20, #11            @ grab the exponent
1944    movw    r3, #0x43e
1945    cmp     r2, r3                      @ MINLONG < x > MAXLONG?
1946    bhs     d2l_special_cases
1947    b       __aeabi_d2lz                @ tail call to convert double to long
1948d2l_special_cases:
1949    movw    r3, #0x7ff
1950    cmp     r2, r3
1951    beq     d2l_maybeNaN                @ NaN?
1952d2l_notNaN:
1953    adds    r1, r1, r1                  @ sign bit to carry
1954    mov     r0, #0xffffffff             @ assume maxlong for lsw
1955    mov     r1, #0x7fffffff             @ assume maxlong for msw
1956    adc     r0, r0, #0
1957    adc     r1, r1, #0                  @ convert maxlong to minlong if exp negative
1958    bx      lr                          @ return
1959d2l_maybeNaN:
1960    orrs    r3, r0, r1, lsl #12
1961    beq     d2l_notNaN                  @ if fraction is non-zero, it's a NaN
1962    mov     r0, #0
1963    mov     r1, #0
1964    bx      lr                          @ return 0 for NaN
1965END nterp_d2l_doconv
1966
1967/*
1968 * Convert the float in r0 to a long in r0/r1.
1969 *
1970 * We have to clip values to long min/max per the specification.  The
1971 * expected common case is a "reasonable" value that converts directly
1972 * to modest integer.  The EABI convert function isn't doing this for us.
1973 */
1974ENTRY nterp_f2l_doconv
1975    ubfx    r2, r0, #23, #8             @ grab the exponent
1976    cmp     r2, #0xbe                   @ MININT < x > MAXINT?
1977    bhs     f2l_special_cases
1978    b       __aeabi_f2lz                @ tail call to convert float to long
1979f2l_special_cases:
1980    cmp     r2, #0xff                   @ NaN or infinity?
1981    beq     f2l_maybeNaN
1982f2l_notNaN:
1983    adds    r0, r0, r0                  @ sign bit to carry
1984    mov     r0, #0xffffffff             @ assume maxlong for lsw
1985    mov     r1, #0x7fffffff             @ assume maxlong for msw
1986    adc     r0, r0, #0
1987    adc     r1, r1, #0                  @ convert maxlong to minlong if exp negative
1988    bx      lr                          @ return
1989f2l_maybeNaN:
1990    lsls    r3, r0, #9
1991    beq     f2l_notNaN                  @ if fraction is non-zero, it's a NaN
1992    mov     r0, #0
1993    mov     r1, #0
1994    bx      lr                          @ return 0 for NaN
1995END nterp_f2l_doconv
1996
1997// Entrypoints into runtime.
1998NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField
1999NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset
2000NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray
2001NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange
2002NTERP_TRAMPOLINE nterp_get_class, NterpGetClass
2003NTERP_TRAMPOLINE nterp_allocate_object, NterpAllocateObject
2004NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod
2005NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod
2006NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject
2007
2008ENTRY nterp_deliver_pending_exception
2009    DELIVER_PENDING_EXCEPTION
2010END nterp_deliver_pending_exception
2011
2012// gen_mterp.py will inline the following definitions
2013// within [ExecuteNterpImpl, EndExecuteNterpImpl).
2014%def instruction_end():
2015
2016    .type artNterpAsmInstructionEnd, #function
2017    .hidden artNterpAsmInstructionEnd
2018    .global artNterpAsmInstructionEnd
2019artNterpAsmInstructionEnd:
2020    // artNterpAsmInstructionEnd is used as landing pad for exception handling.
2021    FETCH_INST
2022    GET_INST_OPCODE ip
2023    GOTO_OPCODE ip
2024
2025%def instruction_start():
2026
2027    .type artNterpAsmInstructionStart, #function
2028    .hidden artNterpAsmInstructionStart
2029    .global artNterpAsmInstructionStart
2030artNterpAsmInstructionStart = .L_op_nop
2031    .text
2032
2033%def opcode_name_prefix():
2034%   return "nterp_"
2035%def opcode_start():
2036    NAME_START nterp_${opcode}
2037    # Explicitly restore CFA, just in case the previous opcode clobbered it (by .cfi_def_*).
2038    CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -4, CALLEE_SAVES_SIZE
2039%def opcode_end():
2040    NAME_END nterp_${opcode}
2041    // Advance to the end of this handler. Causes error if we are past that point.
2042    .org nterp_${opcode} + NTERP_HANDLER_SIZE  // ${opcode} handler is too big!
2043%def opcode_slow_path_start(name):
2044    NAME_START ${name}
2045%def opcode_slow_path_end(name):
2046    NAME_END ${name}
2047