1%def header():
2/*
3 * Copyright (C) 2019 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/x86_64/asm_support_x86_64.S"
24#include "interpreter/cfi_asm_support.h"
25
26/**
27 * x86_64 ABI general notes:
28 *
29 * Caller save set:
30 *    rax, rdx, rcx, rsi, rdi, r8-r11, st(0)-st(7)
31 * Callee save set:
32 *    rbx, rbp, r12-r15
33 * Return regs:
34 *    32-bit in eax
35 *    64-bit in rax
36 *    fp on xmm0
37 *
38 * First 8 fp parameters came in xmm0-xmm7.
39 * First 6 non-fp parameters came in rdi, rsi, rdx, rcx, r8, r9.
40 * Other parameters passed on stack, pushed right-to-left.  On entry to target, first
41 * param is at 8(%esp).
42 *
43 * Stack must be 16-byte aligned to support SSE in native code.
44 */
45
46#define IN_ARG3        %rcx
47#define IN_ARG2        %rdx
48#define IN_ARG1        %rsi
49#define IN_ARG0        %rdi
50/* Out Args  */
51#define OUT_ARG3       %rcx
52#define OUT_ARG2       %rdx
53#define OUT_ARG1       %rsi
54#define OUT_ARG0       %rdi
55#define OUT_32_ARG3    %ecx
56#define OUT_32_ARG2    %edx
57#define OUT_32_ARG1    %esi
58#define OUT_32_ARG0    %edi
59#define OUT_FP_ARG1    %xmm1
60#define OUT_FP_ARG0    %xmm0
61
62/*
63 * single-purpose registers, given names for clarity
64 */
65#define rSELF    %gs
66#define rPC      %r12
67#define CFI_DEX  12 // DWARF register number of the register holding dex-pc (rPC).
68#define CFI_TMP  5  // DWARF register number of the first argument register (rdi).
69#define rFP      %r13
70#define rINST    %ebx
71#define rINSTq   %rbx
72#define rINSTw   %bx
73#define rINSTbh  %bh
74#define rINSTbl  %bl
75#define rIBASE   %r14
76#define rREFS    %r15
77#define CFI_REFS 15 // DWARF register number of the reference array (r15).
78
79// Temporary registers while setting up a frame.
80#define rNEW_FP   %r8
81#define rNEW_REFS %r9
82#define CFI_NEW_REFS 9
83
84/*
85 * Get/set the 32-bit value from a Dalvik register.
86 */
87#define VREG_ADDRESS(_vreg) (rFP,_vreg,4)
88#define VREG_HIGH_ADDRESS(_vreg) 4(rFP,_vreg,4)
89#define VREG_REF_ADDRESS(_vreg) (rREFS,_vreg,4)
90#define VREG_REF_HIGH_ADDRESS(_vreg) 4(rREFS,_vreg,4)
91
92// Includes the return address implictly pushed on stack by 'call'.
93#define CALLEE_SAVES_SIZE (6 * 8 + 4 * 8 + 1 * 8)
94
95// +8 for the ArtMethod of the caller.
96#define OFFSET_TO_FIRST_ARGUMENT_IN_STACK (CALLEE_SAVES_SIZE + 8)
97
98/*
99 * Refresh rINST.
100 * At enter to handler rINST does not contain the opcode number.
101 * However some utilities require the full value, so this macro
102 * restores the opcode number.
103 */
104.macro REFRESH_INST _opnum
105    movb    rINSTbl, rINSTbh
106    movb    $$\_opnum, rINSTbl
107.endm
108
109/*
110 * Fetch the next instruction from rPC into rINSTw.  Does not advance rPC.
111 */
112.macro FETCH_INST
113    movzwq  (rPC), rINSTq
114.endm
115
116/*
117 * Remove opcode from rINST, compute the address of handler and jump to it.
118 */
119.macro GOTO_NEXT
120    movzx   rINSTbl,%ecx
121    movzbl  rINSTbh,rINST
122    shll    MACRO_LITERAL(${handler_size_bits}), %ecx
123    addq    rIBASE, %rcx
124    jmp     *%rcx
125.endm
126
127/*
128 * Advance rPC by instruction count.
129 */
130.macro ADVANCE_PC _count
131    leaq    2*\_count(rPC), rPC
132.endm
133
134/*
135 * Advance rPC by instruction count, fetch instruction and jump to handler.
136 */
137.macro ADVANCE_PC_FETCH_AND_GOTO_NEXT _count
138    ADVANCE_PC \_count
139    FETCH_INST
140    GOTO_NEXT
141.endm
142
143.macro GET_VREG _reg _vreg
144    movl    VREG_ADDRESS(\_vreg), \_reg
145.endm
146
147.macro GET_VREG_OBJECT _reg _vreg
148    movl    VREG_REF_ADDRESS(\_vreg), \_reg
149.endm
150
151/* Read wide value. */
152.macro GET_WIDE_VREG _reg _vreg
153    movq    VREG_ADDRESS(\_vreg), \_reg
154.endm
155
156.macro SET_VREG _reg _vreg
157    movl    \_reg, VREG_ADDRESS(\_vreg)
158    movl    MACRO_LITERAL(0), VREG_REF_ADDRESS(\_vreg)
159.endm
160
161/* Write wide value. reg is clobbered. */
162.macro SET_WIDE_VREG _reg _vreg
163    movq    \_reg, VREG_ADDRESS(\_vreg)
164    xorq    \_reg, \_reg
165    movq    \_reg, VREG_REF_ADDRESS(\_vreg)
166.endm
167
168.macro SET_VREG_OBJECT _reg _vreg
169    movl    \_reg, VREG_ADDRESS(\_vreg)
170    movl    \_reg, VREG_REF_ADDRESS(\_vreg)
171.endm
172
173.macro GET_VREG_HIGH _reg _vreg
174    movl    VREG_HIGH_ADDRESS(\_vreg), \_reg
175.endm
176
177.macro SET_VREG_HIGH _reg _vreg
178    movl    \_reg, VREG_HIGH_ADDRESS(\_vreg)
179    movl    MACRO_LITERAL(0), VREG_REF_HIGH_ADDRESS(\_vreg)
180.endm
181
182.macro CLEAR_REF _vreg
183    movl    MACRO_LITERAL(0), VREG_REF_ADDRESS(\_vreg)
184.endm
185
186.macro CLEAR_WIDE_REF _vreg
187    movl    MACRO_LITERAL(0), VREG_REF_ADDRESS(\_vreg)
188    movl    MACRO_LITERAL(0), VREG_REF_HIGH_ADDRESS(\_vreg)
189.endm
190
191.macro GET_VREG_XMMs _xmmreg _vreg
192    movss VREG_ADDRESS(\_vreg), \_xmmreg
193.endm
194.macro GET_VREG_XMMd _xmmreg _vreg
195    movsd VREG_ADDRESS(\_vreg), \_xmmreg
196.endm
197.macro SET_VREG_XMMs _xmmreg _vreg
198    movss \_xmmreg, VREG_ADDRESS(\_vreg)
199.endm
200.macro SET_VREG_XMMd _xmmreg _vreg
201    movsd \_xmmreg, VREG_ADDRESS(\_vreg)
202.endm
203
204// An assembly entry that has a OatQuickMethodHeader prefix.
205.macro OAT_ENTRY name, end
206    FUNCTION_TYPE(\name)
207    ASM_HIDDEN SYMBOL(\name)
208    .global SYMBOL(\name)
209    .balign 16
210    .long 0
211    .long (SYMBOL(\end) - SYMBOL(\name))
212SYMBOL(\name):
213.endm
214
215.macro ENTRY name
216    .text
217    ASM_HIDDEN SYMBOL(\name)
218    .global SYMBOL(\name)
219    FUNCTION_TYPE(\name)
220SYMBOL(\name):
221.endm
222
223.macro END name
224    SIZE(\name)
225.endm
226
227// Macro for defining entrypoints into runtime. We don't need to save registers
228// (we're not holding references there), but there is no
229// kDontSave runtime method. So just use the kSaveRefsOnly runtime method.
230.macro NTERP_TRAMPOLINE name, helper
231DEFINE_FUNCTION \name
232  SETUP_SAVE_REFS_ONLY_FRAME
233  call \helper
234  RESTORE_SAVE_REFS_ONLY_FRAME
235  RETURN_OR_DELIVER_PENDING_EXCEPTION
236END_FUNCTION \name
237.endm
238
239.macro CLEAR_VOLATILE_MARKER reg
240  andq MACRO_LITERAL(-2), \reg
241.endm
242
243.macro EXPORT_PC
244    movq    rPC, -16(rREFS)
245.endm
246
247
248.macro BRANCH
249    // Update method counter and do a suspend check if the branch is negative.
250    testq rINSTq, rINSTq
251    js 3f
2522:
253    leaq    (rPC, rINSTq, 2), rPC
254    FETCH_INST
255    GOTO_NEXT
2563:
257    movq (%rsp), %rdi
258    addw $$1, ART_METHOD_HOTNESS_COUNT_OFFSET(%rdi)
259    // If the counter overflows, handle this in the runtime.
260    jo NterpHandleHotnessOverflow
261    // Otherwise, do a suspend check.
262    testl   $$(THREAD_SUSPEND_OR_CHECKPOINT_REQUEST), rSELF:THREAD_FLAGS_OFFSET
263    jz      2b
264    EXPORT_PC
265    call    SYMBOL(art_quick_test_suspend)
266    jmp 2b
267.endm
268
269// Setup the stack to start executing the method. Expects:
270// - rdi to contain the ArtMethod
271// - rbx, r10, r11 to be available.
272//
273// Outputs
274// - rbx contains the dex registers size
275// - r11 contains the old stack pointer.
276.macro SETUP_STACK_FRAME code_item, refs, fp, cfi_refs
277    // Fetch dex register size.
278    movzwl CODE_ITEM_REGISTERS_SIZE_OFFSET(\code_item), %ebx
279    // Fetch outs size.
280    movzwq CODE_ITEM_OUTS_SIZE_OFFSET(\code_item), \refs
281
282    // Compute required frame size for dex registers: ((2 * ebx) + refs)
283    leaq (\refs, %rbx, 2), %r11
284    salq $$2, %r11
285
286    // Compute new stack pointer in r10: add 24 for saving the previous frame,
287    // pc, and method being executed.
288    leaq -24(%rsp), %r10
289    subq %r11, %r10
290    // Alignment
291    andq $$-16, %r10
292
293    // Set reference and dex registers.
294    leaq 24(%r10, \refs, 4), \refs
295    leaq (\refs, %rbx, 4), \fp
296
297    // Now setup the stack pointer.
298    movq %rsp, %r11
299    CFI_DEF_CFA_REGISTER(r11)
300    movq %r10, %rsp
301    movq %r11, -8(\refs)
302    CFI_DEFINE_CFA_DEREF(\cfi_refs, -8, (6 + 4 + 1) * 8)
303
304    // Put nulls in reference frame.
305    testl %ebx, %ebx
306    je 2f
307    movq \refs, %r10
3081:
309    movl $$0, (%r10)
310    addq $$4, %r10
311    cmpq %r10, \fp
312    jne 1b
3132:
314    // Save the ArtMethod.
315    movq %rdi, (%rsp)
316.endm
317
318// Puts the next floating point argument into the expected register,
319// fetching values based on a non-range invoke.
320// Uses rax as temporary.
321//
322// TODO: We could simplify a lot of code by loading the G argument into
323// the "inst" register. Given that we enter the handler with "1(rPC)" in
324// the rINST, we can just add rINST<<16 to the args and we don't even
325// need to pass "arg_index" around.
326.macro LOOP_OVER_SHORTY_LOADING_XMMS xmm_reg, inst, shorty, arg_index, finished
3271: // LOOP
328    movb (REG_VAR(shorty)), %al             // bl := *shorty
329    addq MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
330    cmpb MACRO_LITERAL(0), %al              // if (al == '\0') goto finished
331    je VAR(finished)
332    cmpb MACRO_LITERAL(68), %al             // if (al == 'D') goto FOUND_DOUBLE
333    je 2f
334    cmpb MACRO_LITERAL(70), %al             // if (al == 'F') goto FOUND_FLOAT
335    je 3f
336    shrq MACRO_LITERAL(4), REG_VAR(inst)
337    addq MACRO_LITERAL(1), REG_VAR(arg_index)
338    //  Handle extra argument in arg array taken by a long.
339    cmpb MACRO_LITERAL(74), %al   // if (al != 'J') goto LOOP
340    jne 1b
341    shrq MACRO_LITERAL(4), REG_VAR(inst)
342    addq MACRO_LITERAL(1), REG_VAR(arg_index)
343    jmp 1b                        // goto LOOP
3442:  // FOUND_DOUBLE
345    subq MACRO_LITERAL(8), %rsp
346    movq REG_VAR(inst), %rax
347    andq MACRO_LITERAL(0xf), %rax
348    GET_VREG %eax, %rax
349    movl %eax, (%rsp)
350    shrq MACRO_LITERAL(4), REG_VAR(inst)
351    addq MACRO_LITERAL(1), REG_VAR(arg_index)
352    cmpq MACRO_LITERAL(4), REG_VAR(arg_index)
353    je 5f
354    movq REG_VAR(inst), %rax
355    andq MACRO_LITERAL(0xf), %rax
356    shrq MACRO_LITERAL(4), REG_VAR(inst)
357    addq MACRO_LITERAL(1), REG_VAR(arg_index)
358    jmp 6f
3595:
360    movzbl 1(rPC), %eax
361    andq MACRO_LITERAL(0xf), %rax
3626:
363    GET_VREG %eax, %rax
364    movl %eax, 4(%rsp)
365    movsd (%rsp), REG_VAR(xmm_reg)
366    addq MACRO_LITERAL(8), %rsp
367    jmp 4f
3683:  // FOUND_FLOAT
369    cmpq MACRO_LITERAL(4), REG_VAR(arg_index)
370    je 7f
371    movq REG_VAR(inst), %rax
372    andq MACRO_LITERAL(0xf), %rax
373    shrq MACRO_LITERAL(4), REG_VAR(inst)
374    addq MACRO_LITERAL(1), REG_VAR(arg_index)
375    jmp 8f
3767:
377    movzbl 1(rPC), %eax
378    andq MACRO_LITERAL(0xf), %rax
3798:
380    GET_VREG_XMMs REG_VAR(xmm_reg), %rax
3814:
382.endm
383
384// Puts the next int/long/object argument in the expected register,
385// fetching values based on a non-range invoke.
386// Uses rax as temporary.
387.macro LOOP_OVER_SHORTY_LOADING_GPRS gpr_reg64, gpr_reg32, inst, shorty, arg_index, finished
3881: // LOOP
389    movb (REG_VAR(shorty)), %al   // bl := *shorty
390    addq MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
391    cmpb MACRO_LITERAL(0), %al    // if (al == '\0') goto finished
392    je  VAR(finished)
393    cmpb MACRO_LITERAL(74), %al   // if (al == 'J') goto FOUND_LONG
394    je 2f
395    cmpb MACRO_LITERAL(70), %al   // if (al == 'F') goto SKIP_FLOAT
396    je 3f
397    cmpb MACRO_LITERAL(68), %al   // if (al == 'D') goto SKIP_DOUBLE
398    je 4f
399    cmpq MACRO_LITERAL(4), REG_VAR(arg_index)
400    je 7f
401    movq REG_VAR(inst), %rax
402    andq MACRO_LITERAL(0xf), %rax
403    shrq MACRO_LITERAL(4), REG_VAR(inst)
404    addq MACRO_LITERAL(1), REG_VAR(arg_index)
405    jmp 8f
4067:
407    movzbl 1(rPC), %eax
408    andq MACRO_LITERAL(0xf), %rax
4098:
410    GET_VREG REG_VAR(gpr_reg32), %rax
411    jmp 5f
4122:  // FOUND_LONG
413    subq MACRO_LITERAL(8), %rsp
414    movq REG_VAR(inst), %rax
415    andq MACRO_LITERAL(0xf), %rax
416    GET_VREG %eax, %rax
417    movl %eax, (%rsp)
418    shrq MACRO_LITERAL(4), REG_VAR(inst)
419    addq MACRO_LITERAL(1), REG_VAR(arg_index)
420    cmpq MACRO_LITERAL(4), REG_VAR(arg_index)
421    je 9f
422    movq REG_VAR(inst), %rax
423    andq MACRO_LITERAL(0xf), %rax
424    shrq MACRO_LITERAL(4), REG_VAR(inst)
425    addq MACRO_LITERAL(1), REG_VAR(arg_index)
426    jmp 10f
4279:
428    movzbl 1(rPC), %eax
429    andq MACRO_LITERAL(0xf), %rax
43010:
431    GET_VREG %eax, %rax
432    movl %eax, 4(%rsp)
433    movq (%rsp), REG_VAR(gpr_reg64)
434    addq MACRO_LITERAL(8), %rsp
435    jmp 5f
4363:  // SKIP_FLOAT
437    shrq MACRO_LITERAL(4), REG_VAR(inst)
438    addq MACRO_LITERAL(1), REG_VAR(arg_index)
439    jmp 1b
4404:  // SKIP_DOUBLE
441    shrq MACRO_LITERAL(4), REG_VAR(inst)
442    addq MACRO_LITERAL(1), REG_VAR(arg_index)
443    cmpq MACRO_LITERAL(4), REG_VAR(arg_index)
444    je 1b
445    shrq MACRO_LITERAL(4), REG_VAR(inst)
446    addq MACRO_LITERAL(1), REG_VAR(arg_index)
447    jmp 1b
4485:
449.endm
450
451// Puts the next floating point argument into the expected register,
452// fetching values based on a range invoke.
453// Uses rax as temporary.
454.macro LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm_reg, shorty, arg_index, stack_index, finished
4551: // LOOP
456    movb (REG_VAR(shorty)), %al             // bl := *shorty
457    addq MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
458    cmpb MACRO_LITERAL(0), %al              // if (al == '\0') goto finished
459    je VAR(finished)
460    cmpb MACRO_LITERAL(68), %al             // if (al == 'D') goto FOUND_DOUBLE
461    je 2f
462    cmpb MACRO_LITERAL(70), %al             // if (al == 'F') goto FOUND_FLOAT
463    je 3f
464    addq MACRO_LITERAL(1), REG_VAR(arg_index)
465    addq MACRO_LITERAL(1), REG_VAR(stack_index)
466    //  Handle extra argument in arg array taken by a long.
467    cmpb MACRO_LITERAL(74), %al   // if (al != 'J') goto LOOP
468    jne 1b
469    addq MACRO_LITERAL(1), REG_VAR(arg_index)
470    addq MACRO_LITERAL(1), REG_VAR(stack_index)
471    jmp 1b                        // goto LOOP
4722:  // FOUND_DOUBLE
473    GET_VREG_XMMd REG_VAR(xmm_reg), REG_VAR(arg_index)
474    addq MACRO_LITERAL(2), REG_VAR(arg_index)
475    addq MACRO_LITERAL(2), REG_VAR(stack_index)
476    jmp 4f
4773:  // FOUND_FLOAT
478    GET_VREG_XMMs REG_VAR(xmm_reg), REG_VAR(arg_index)
479    addq MACRO_LITERAL(1), REG_VAR(arg_index)
480    addq MACRO_LITERAL(1), REG_VAR(stack_index)
4814:
482.endm
483
484// Puts the next floating point argument into the expected stack slot,
485// fetching values based on a range invoke.
486// Uses rax as temporary.
487//
488// TODO: We could just copy all the vregs to the stack slots in a simple loop
489// (or REP MOVSD) without looking at the shorty at all. (We could also drop
490// the "stack_index" from the macros for loading registers.) We could also do
491// that conditionally if argument word count > 6; otherwise we know that all
492// args fit into registers.
493.macro LOOP_RANGE_OVER_FPs shorty, arg_index, stack_index, finished
4941: // LOOP
495    movb (REG_VAR(shorty)), %al             // bl := *shorty
496    addq MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
497    cmpb MACRO_LITERAL(0), %al              // if (al == '\0') goto finished
498    je VAR(finished)
499    cmpb MACRO_LITERAL(68), %al             // if (al == 'D') goto FOUND_DOUBLE
500    je 2f
501    cmpb MACRO_LITERAL(70), %al             // if (al == 'F') goto FOUND_FLOAT
502    je 3f
503    addq MACRO_LITERAL(1), REG_VAR(arg_index)
504    addq MACRO_LITERAL(1), REG_VAR(stack_index)
505    //  Handle extra argument in arg array taken by a long.
506    cmpb MACRO_LITERAL(74), %al   // if (al != 'J') goto LOOP
507    jne 1b
508    addq MACRO_LITERAL(1), REG_VAR(arg_index)
509    addq MACRO_LITERAL(1), REG_VAR(stack_index)
510    jmp 1b                        // goto LOOP
5112:  // FOUND_DOUBLE
512    movq (rFP, REG_VAR(arg_index), 4), %rax
513    movq %rax, 8(%rsp, REG_VAR(stack_index), 4)
514    addq MACRO_LITERAL(2), REG_VAR(arg_index)
515    addq MACRO_LITERAL(2), REG_VAR(stack_index)
516    jmp 1b
5173:  // FOUND_FLOAT
518    movl (rFP, REG_VAR(arg_index), 4), %eax
519    movl %eax, 8(%rsp, REG_VAR(stack_index), 4)
520    addq MACRO_LITERAL(1), REG_VAR(arg_index)
521    addq MACRO_LITERAL(1), REG_VAR(stack_index)
522    jmp 1b
523.endm
524
525// Puts the next int/long/object argument in the expected register,
526// fetching values based on a range invoke.
527// Uses rax as temporary.
528.macro LOOP_RANGE_OVER_SHORTY_LOADING_GPRS gpr_reg64, gpr_reg32, shorty, arg_index, stack_index, finished
5291: // LOOP
530    movb (REG_VAR(shorty)), %al             // bl := *shorty
531    addq MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
532    cmpb MACRO_LITERAL(0), %al    // if (al == '\0') goto finished
533    je  VAR(finished)
534    cmpb MACRO_LITERAL(74), %al   // if (al == 'J') goto FOUND_LONG
535    je 2f
536    cmpb MACRO_LITERAL(70), %al   // if (al == 'F') goto SKIP_FLOAT
537    je 3f
538    cmpb MACRO_LITERAL(68), %al   // if (al == 'D') goto SKIP_DOUBLE
539    je 4f
540    movl       (rFP, REG_VAR(arg_index), 4), REG_VAR(gpr_reg32)
541    addq MACRO_LITERAL(1), REG_VAR(arg_index)
542    addq MACRO_LITERAL(1), REG_VAR(stack_index)
543    jmp 5f
5442:  // FOUND_LONG
545    movq (rFP, REG_VAR(arg_index), 4), REG_VAR(gpr_reg64)
546    addq MACRO_LITERAL(2), REG_VAR(arg_index)
547    addq MACRO_LITERAL(2), REG_VAR(stack_index)
548    jmp 5f
5493:  // SKIP_FLOAT
550    addq MACRO_LITERAL(1), REG_VAR(arg_index)
551    addq MACRO_LITERAL(1), REG_VAR(stack_index)
552    jmp 1b
5534:  // SKIP_DOUBLE
554    addq MACRO_LITERAL(2), REG_VAR(arg_index)
555    addq MACRO_LITERAL(2), REG_VAR(stack_index)
556    jmp 1b
5575:
558.endm
559
560// Puts the next int/long/object argument in the expected stack slot,
561// fetching values based on a range invoke.
562// Uses rax as temporary.
563.macro LOOP_RANGE_OVER_INTs shorty, arg_index, stack_index, finished
5641: // LOOP
565    movb (REG_VAR(shorty)), %al             // al := *shorty
566    addq MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
567    cmpb MACRO_LITERAL(0), %al    // if (al == '\0') goto finished
568    je  VAR(finished)
569    cmpb MACRO_LITERAL(74), %al   // if (al == 'J') goto FOUND_LONG
570    je 2f
571    cmpb MACRO_LITERAL(70), %al   // if (al == 'F') goto SKIP_FLOAT
572    je 3f
573    cmpb MACRO_LITERAL(68), %al   // if (al == 'D') goto SKIP_DOUBLE
574    je 4f
575    movl (rFP, REG_VAR(arg_index), 4), %eax
576    movl %eax, 8(%rsp, REG_VAR(stack_index), 4)
577    addq MACRO_LITERAL(1), REG_VAR(arg_index)
578    addq MACRO_LITERAL(1), REG_VAR(stack_index)
579    jmp 1b
5802:  // FOUND_LONG
581    movq (rFP, REG_VAR(arg_index), 4), %rax
582    movq %rax, 8(%rsp, REG_VAR(stack_index), 4)
583    addq MACRO_LITERAL(2), REG_VAR(arg_index)
584    addq MACRO_LITERAL(2), REG_VAR(stack_index)
585    jmp 1b
5863:  // SKIP_FLOAT
587    addq MACRO_LITERAL(1), REG_VAR(arg_index)
588    addq MACRO_LITERAL(1), REG_VAR(stack_index)
589    jmp 1b
5904:  // SKIP_DOUBLE
591    addq MACRO_LITERAL(2), REG_VAR(arg_index)
592    addq MACRO_LITERAL(2), REG_VAR(stack_index)
593    jmp 1b
594.endm
595
596// Puts the next floating point parameter passed in physical register
597// in the expected dex register array entry.
598// Uses rax as temporary.
599.macro LOOP_OVER_SHORTY_STORING_XMMS xmm_reg, shorty, arg_index, fp, finished
6001: // LOOP
601    movb (REG_VAR(shorty)), %al             // al := *shorty
602    addq MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
603    cmpb MACRO_LITERAL(0), %al              // if (al == '\0') goto finished
604    je VAR(finished)
605    cmpb MACRO_LITERAL(68), %al             // if (al == 'D') goto FOUND_DOUBLE
606    je 2f
607    cmpb MACRO_LITERAL(70), %al             // if (al == 'F') goto FOUND_FLOAT
608    je 3f
609    addq MACRO_LITERAL(4), REG_VAR(arg_index)
610    //  Handle extra argument in arg array taken by a long.
611    cmpb MACRO_LITERAL(74), %al   // if (al != 'J') goto LOOP
612    jne 1b
613    addq MACRO_LITERAL(4), REG_VAR(arg_index)
614    jmp 1b                        // goto LOOP
6152:  // FOUND_DOUBLE
616    movsd REG_VAR(xmm_reg),(REG_VAR(fp), REG_VAR(arg_index), 1)
617    addq MACRO_LITERAL(8), REG_VAR(arg_index)
618    jmp 4f
6193:  // FOUND_FLOAT
620    movss REG_VAR(xmm_reg), (REG_VAR(fp), REG_VAR(arg_index), 1)
621    addq MACRO_LITERAL(4), REG_VAR(arg_index)
6224:
623.endm
624
625// Puts the next int/long/object parameter passed in physical register
626// in the expected dex register array entry, and in case of object in the
627// expected reference array entry.
628// Uses rax as temporary.
629.macro LOOP_OVER_SHORTY_STORING_GPRS gpr_reg64, gpr_reg32, shorty, arg_index, regs, refs, finished
6301: // LOOP
631    movb (REG_VAR(shorty)), %al             // bl := *shorty
632    addq MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
633    cmpb MACRO_LITERAL(0), %al    // if (al == '\0') goto finished
634    je  VAR(finished)
635    cmpb MACRO_LITERAL(74), %al   // if (al == 'J') goto FOUND_LONG
636    je 2f
637    cmpb MACRO_LITERAL(70), %al   // if (al == 'F') goto SKIP_FLOAT
638    je 3f
639    cmpb MACRO_LITERAL(68), %al   // if (al == 'D') goto SKIP_DOUBLE
640    je 4f
641    movl REG_VAR(gpr_reg32), (REG_VAR(regs), REG_VAR(arg_index), 1)
642    cmpb MACRO_LITERAL(76), %al   // if (al != 'L') goto NOT_REFERENCE
643    jne 6f
644    movl REG_VAR(gpr_reg32), (REG_VAR(refs), REG_VAR(arg_index), 1)
6456:  // NOT_REFERENCE
646    addq MACRO_LITERAL(4), REG_VAR(arg_index)
647    jmp 5f
6482:  // FOUND_LONG
649    movq REG_VAR(gpr_reg64), (REG_VAR(regs), REG_VAR(arg_index), 1)
650    addq MACRO_LITERAL(8), REG_VAR(arg_index)
651    jmp 5f
6523:  // SKIP_FLOAT
653    addq MACRO_LITERAL(4), REG_VAR(arg_index)
654    jmp 1b
6554:  // SKIP_DOUBLE
656    addq MACRO_LITERAL(8), REG_VAR(arg_index)
657    jmp 1b
6585:
659.endm
660
661// Puts the next floating point parameter passed in stack
662// in the expected dex register array entry.
663// Uses rax as temporary.
664//
665// TODO: Or we could just spill regs to the reserved slots in the caller's
666// frame and copy all regs in a simple loop. This time, however, we would
667// need to look at the shorty anyway to look for the references.
668// (The trade-off is different for passing arguments and receiving them.)
669.macro LOOP_OVER_FPs shorty, arg_index, regs, stack_ptr, finished
6701: // LOOP
671    movb (REG_VAR(shorty)), %al             // bl := *shorty
672    addq MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
673    cmpb MACRO_LITERAL(0), %al              // if (al == '\0') goto finished
674    je VAR(finished)
675    cmpb MACRO_LITERAL(68), %al             // if (al == 'D') goto FOUND_DOUBLE
676    je 2f
677    cmpb MACRO_LITERAL(70), %al             // if (al == 'F') goto FOUND_FLOAT
678    je 3f
679    addq MACRO_LITERAL(4), REG_VAR(arg_index)
680    //  Handle extra argument in arg array taken by a long.
681    cmpb MACRO_LITERAL(74), %al   // if (al != 'J') goto LOOP
682    jne 1b
683    addq MACRO_LITERAL(4), REG_VAR(arg_index)
684    jmp 1b                        // goto LOOP
6852:  // FOUND_DOUBLE
686    movq OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 1), %rax
687    movq %rax, (REG_VAR(regs), REG_VAR(arg_index), 1)
688    addq MACRO_LITERAL(8), REG_VAR(arg_index)
689    jmp 1b
6903:  // FOUND_FLOAT
691    movl OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 1), %eax
692    movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 1)
693    addq MACRO_LITERAL(4), REG_VAR(arg_index)
694    jmp 1b
695.endm
696
697// Puts the next int/long/object parameter passed in stack
698// in the expected dex register array entry, and in case of object in the
699// expected reference array entry.
700// Uses rax as temporary.
701.macro LOOP_OVER_INTs shorty, arg_index, regs, refs, stack_ptr, finished
7021: // LOOP
703    movb (REG_VAR(shorty)), %al             // bl := *shorty
704    addq MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
705    cmpb MACRO_LITERAL(0), %al    // if (al == '\0') goto finished
706    je  VAR(finished)
707    cmpb MACRO_LITERAL(74), %al   // if (al == 'J') goto FOUND_LONG
708    je 2f
709    cmpb MACRO_LITERAL(76), %al   // if (al == 'L') goto FOUND_REFERENCE
710    je 6f
711    cmpb MACRO_LITERAL(70), %al   // if (al == 'F') goto SKIP_FLOAT
712    je 3f
713    cmpb MACRO_LITERAL(68), %al   // if (al == 'D') goto SKIP_DOUBLE
714    je 4f
715    movl OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 1), %eax
716    movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 1)
717    addq MACRO_LITERAL(4), REG_VAR(arg_index)
718    jmp 1b
7196:  // FOUND_REFERENCE
720    movl OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 1), %eax
721    movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 1)
722    movl %eax, (REG_VAR(refs), REG_VAR(arg_index), 1)
723    addq MACRO_LITERAL(4), REG_VAR(arg_index)
724    jmp 1b
7252:  // FOUND_LONG
726    movq OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 1), %rax
727    movq %rax, (REG_VAR(regs), REG_VAR(arg_index), 1)
728    addq MACRO_LITERAL(8), REG_VAR(arg_index)
729    jmp 1b
7303:  // SKIP_FLOAT
731    addq MACRO_LITERAL(4), REG_VAR(arg_index)
732    jmp 1b
7334:  // SKIP_DOUBLE
734    addq MACRO_LITERAL(8), REG_VAR(arg_index)
735    jmp 1b
736.endm
737
738// Increase method hotness and do suspend check before starting executing the method.
739.macro START_EXECUTING_INSTRUCTIONS
740   movq (%rsp), %rdi
741   addw $$1, ART_METHOD_HOTNESS_COUNT_OFFSET(%rdi)
742   jo 2f
743   testl $$(THREAD_SUSPEND_OR_CHECKPOINT_REQUEST), rSELF:THREAD_FLAGS_OFFSET
744   jz 1f
745   EXPORT_PC
746   call SYMBOL(art_quick_test_suspend)
7471:
748   FETCH_INST
749   GOTO_NEXT
7502:
751   movq $$0, %rsi
752   movq rFP, %rdx
753   call nterp_hot_method
754   jmp 1b
755.endm
756
757.macro SPILL_ALL_CALLEE_SAVES
758    PUSH r15
759    PUSH r14
760    PUSH r13
761    PUSH r12
762    PUSH rbp
763    PUSH rbx
764    SETUP_FP_CALLEE_SAVE_FRAME
765.endm
766
767.macro RESTORE_ALL_CALLEE_SAVES
768    RESTORE_FP_CALLEE_SAVE_FRAME
769    POP rbx
770    POP rbp
771    POP r12
772    POP r13
773    POP r14
774    POP r15
775.endm
776
777// Helper to setup the stack after doing a nterp to nterp call. This will setup:
778// - rNEW_FP: the new pointer to dex registers
779// - rNEW_REFS: the new pointer to references
780// - rPC: the new PC pointer to execute
781// - edi: number of arguments
782// - ecx: first dex register
783.macro SETUP_STACK_FOR_INVOKE
784   // We do the same stack overflow check as the compiler. See CanMethodUseNterp
785   // in how we limit the maximum nterp frame size.
786   testq %rax, -STACK_OVERFLOW_RESERVED_BYTES(%rsp)
787
788   // Spill all callee saves to have a consistent stack frame whether we
789   // are called by compiled code or nterp.
790   SPILL_ALL_CALLEE_SAVES
791
792   // Setup the frame.
793   SETUP_STACK_FRAME %rax, rNEW_REFS, rNEW_FP, CFI_NEW_REFS
794   // Make r11 point to the top of the dex register array.
795   leaq (rNEW_FP, %rbx, 4), %r11
796
797   // Fetch instruction information before replacing rPC.
798   movzbl 1(rPC), %edi
799   movzwl 4(rPC), %ecx
800
801   // Set the dex pc pointer.
802   leaq CODE_ITEM_INSNS_OFFSET(%rax), rPC
803   CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
804.endm
805
806// Setup arguments based on a non-range nterp to nterp call, and start executing
807// the method. We expect:
808// - rNEW_FP: the new pointer to dex registers
809// - rNEW_REFS: the new pointer to references
810// - rPC: the new PC pointer to execute
811// - edi: number of arguments
812// - ecx: first dex register
813// - r11: top of dex register array
814// - esi: receiver if non-static.
815.macro SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
816   // Now all temporary registers (except r11 containing top of registers array)
817   // are available, copy the parameters.
818   // /* op vA, vB, {vC...vG} */
819   movl %edi, %eax
820   shrl $$4, %eax # Number of arguments
821   jz 6f  # shl sets the Z flag
822   movq MACRO_LITERAL(-1), %r10
823   cmpl MACRO_LITERAL(2), %eax
824   jl 1f
825   je 2f
826   cmpl MACRO_LITERAL(4), %eax
827   jl 3f
828   je 4f
829
830  // We use a decrementing r10 to store references relative
831  // to rNEW_FP and dex registers relative to r11.
832  //
833  // TODO: We could set up r10 as the number of registers (this can be an additional output from
834  // SETUP_STACK_FOR_INVOKE) and then just decrement it by one before copying each arg to
835  // (rNEW_FP, r10, 4) and (rNEW_REFS, r10, 4).
836  // Maybe even introduce macros NEW_VREG_ADDRESS/NEW_VREG_REF_ADDRESS.
8375:
838   andq        MACRO_LITERAL(15), %rdi
839   GET_VREG_OBJECT %edx, %rdi
840   movl        %edx, (rNEW_FP, %r10, 4)
841   GET_VREG    %edx, %rdi
842   movl        %edx, (%r11, %r10, 4)
843   subq        MACRO_LITERAL(1), %r10
8444:
845   movl        %ecx, %eax
846   shrl        MACRO_LITERAL(12), %eax
847   GET_VREG_OBJECT %edx, %rax
848   movl        %edx, (rNEW_FP, %r10, 4)
849   GET_VREG    %edx, %rax
850   movl        %edx, (%r11, %r10, 4)
851   subq        MACRO_LITERAL(1), %r10
8523:
853   movl        %ecx, %eax
854   shrl        MACRO_LITERAL(8), %eax
855   andl        MACRO_LITERAL(0xf), %eax
856   GET_VREG_OBJECT %edx, %rax
857   movl        %edx, (rNEW_FP, %r10, 4)
858   GET_VREG    %edx, %rax
859   movl        %edx, (%r11, %r10, 4)
860   subq        MACRO_LITERAL(1), %r10
8612:
862   movl        %ecx, %eax
863   shrl        MACRO_LITERAL(4), %eax
864   andl        MACRO_LITERAL(0xf), %eax
865   GET_VREG_OBJECT %edx, %rax
866   movl        %edx, (rNEW_FP, %r10, 4)
867   GET_VREG    %edx, %rax
868   movl        %edx, (%r11, %r10, 4)
869   subq        MACRO_LITERAL(1), %r10
8701:
871   .if \is_string_init
872   // Ignore the first argument
873   .elseif \is_static
874   movl        %ecx, %eax
875   andq        MACRO_LITERAL(0x000f), %rax
876   GET_VREG_OBJECT %edx, %rax
877   movl        %edx, (rNEW_FP, %r10, 4)
878   GET_VREG    %edx, %rax
879   movl        %edx, (%r11, %r10, 4)
880   .else
881   movl        %esi, (rNEW_FP, %r10, 4)
882   movl        %esi, (%r11, %r10, 4)
883   .endif
884
8856:
886   // Start executing the method.
887   movq rNEW_FP, rFP
888   movq rNEW_REFS, rREFS
889   CFI_DEFINE_CFA_DEREF(CFI_REFS, -8, (6 + 4 + 1) * 8)
890   START_EXECUTING_INSTRUCTIONS
891.endm
892
893// Setup arguments based on a range nterp to nterp call, and start executing
894// the method.
895.macro SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
896   // edi is number of arguments
897   // ecx is first register
898   movq MACRO_LITERAL(-4), %r10
899   .if \is_string_init
900   // Ignore the first argument
901   subl $$1, %edi
902   addl $$1, %ecx
903   .elseif !\is_static
904   subl $$1, %edi
905   addl $$1, %ecx
906   .endif
907
908   testl %edi, %edi
909   je 2f
910   leaq  (rREFS, %rcx, 4), %rax  # pointer to first argument in reference array
911   leaq  (%rax, %rdi, 4), %rax   # pointer to last argument in reference array
912   leaq  (rFP, %rcx, 4), %rcx    # pointer to first argument in register array
913   leaq  (%rcx, %rdi, 4), %rdi   # pointer to last argument in register array
914   // TODO: Same comment for copying arguments as in SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE.
9151:
916   movl  -4(%rax), %edx
917   movl  %edx, (rNEW_FP, %r10, 1)
918   movl  -4(%rdi), %edx
919   movl  %edx, (%r11, %r10, 1)
920   subq  MACRO_LITERAL(4), %r10
921   subq  MACRO_LITERAL(4), %rax
922   subq  MACRO_LITERAL(4), %rdi
923   cmpq  %rcx, %rdi
924   jne 1b
925
9262:
927   .if \is_string_init
928   // Ignore first argument
929   .elseif !\is_static
930   movl        %esi, (rNEW_FP, %r10, 1)
931   movl        %esi, (%r11, %r10, 1)
932   .endif
933   movq rNEW_FP, rFP
934   movq rNEW_REFS, rREFS
935   CFI_DEFINE_CFA_DEREF(CFI_REFS, -8, (6 + 4 + 1) * 8)
936   START_EXECUTING_INSTRUCTIONS
937.endm
938
939.macro GET_SHORTY dest, is_interface, is_polymorphic, is_custom
940   push %rdi
941   push %rsi
942   .if \is_polymorphic
943   movq 16(%rsp), %rdi
944   movq rPC, %rsi
945   call SYMBOL(NterpGetShortyFromInvokePolymorphic)
946   .elseif \is_custom
947   movq 16(%rsp), %rdi
948   movq rPC, %rsi
949   call SYMBOL(NterpGetShortyFromInvokeCustom)
950   .elseif \is_interface
951   movq 16(%rsp), %rdi
952   movzwl 2(rPC), %esi
953   call SYMBOL(NterpGetShortyFromMethodId)
954   .else
955   call SYMBOL(NterpGetShorty)
956   .endif
957   pop %rsi
958   pop %rdi
959   movq %rax, \dest
960.endm
961
962.macro DO_ENTRY_POINT_CHECK call_compiled_code
963   // On entry, the method is %rdi, the instance is %rsi
964   leaq ExecuteNterpImpl(%rip), %rax
965   cmpq %rax, ART_METHOD_QUICK_CODE_OFFSET_64(%rdi)
966   jne  VAR(call_compiled_code)
967
968   // TODO: Get code item in a better way and remove below
969   push %rdi
970   push %rsi
971   call SYMBOL(NterpGetCodeItem)
972   pop %rsi
973   pop %rdi
974   // TODO: Get code item in a better way and remove above
975.endm
976
977// Uses r9 and r10 as temporary
978.macro UPDATE_REGISTERS_FOR_STRING_INIT old_value, new_value
979   movq rREFS, %r9
980   movq rFP, %r10
9811:
982   cmpl (%r9), \old_value
983   jne 2f
984   movl \new_value, (%r9)
985   movl \new_value, (%r10)
9862:
987   addq $$4, %r9
988   addq $$4, %r10
989   cmpq %r9, rFP
990   jne 1b
991.endm
992
993.macro COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
994   .if \is_polymorphic
995   // We always go to compiled code for polymorphic calls.
996   .elseif \is_custom
997   // We always go to compiled code for custom calls.
998   .else
999     DO_ENTRY_POINT_CHECK .Lcall_compiled_code_\suffix
1000     .if \is_string_init
1001     call nterp_to_nterp_string_init_non_range
1002     .elseif \is_static
1003     call nterp_to_nterp_static_non_range
1004     .else
1005     call nterp_to_nterp_instance_non_range
1006     .endif
1007     jmp .Ldone_return_\suffix
1008   .endif
1009
1010.Lcall_compiled_code_\suffix:
1011   GET_SHORTY rINSTq, \is_interface, \is_polymorphic, \is_custom
1012   // From this point:
1013   // - rISNTq contains shorty (in callee-save to switch over return value after call).
1014   // - rdi contains method
1015   // - rsi contains 'this' pointer for instance method.
1016   leaq 1(rINSTq), %r9  // shorty + 1  ; ie skip return arg character
1017   movzwl 4(rPC), %r11d // arguments
1018   .if \is_string_init
1019   shrq MACRO_LITERAL(4), %r11
1020   movq $$1, %r10       // ignore first argument
1021   .elseif \is_static
1022   movq $$0, %r10       // arg_index
1023   .else
1024   shrq MACRO_LITERAL(4), %r11
1025   movq $$1, %r10       // arg_index
1026   .endif
1027   LOOP_OVER_SHORTY_LOADING_XMMS xmm0, r11, r9, r10, .Lxmm_setup_finished_\suffix
1028   LOOP_OVER_SHORTY_LOADING_XMMS xmm1, r11, r9, r10, .Lxmm_setup_finished_\suffix
1029   LOOP_OVER_SHORTY_LOADING_XMMS xmm2, r11, r9, r10, .Lxmm_setup_finished_\suffix
1030   LOOP_OVER_SHORTY_LOADING_XMMS xmm3, r11, r9, r10, .Lxmm_setup_finished_\suffix
1031   LOOP_OVER_SHORTY_LOADING_XMMS xmm4, r11, r9, r10, .Lxmm_setup_finished_\suffix
1032.Lxmm_setup_finished_\suffix:
1033   leaq 1(rINSTq), %r9  // shorty + 1  ; ie skip return arg character
1034   movzwl 4(rPC), %r11d // arguments
1035   .if \is_string_init
1036   movq $$1, %r10       // ignore first argument
1037   shrq MACRO_LITERAL(4), %r11
1038   LOOP_OVER_SHORTY_LOADING_GPRS rsi, esi, r11, r9, r10, .Lgpr_setup_finished_\suffix
1039   .elseif \is_static
1040   movq $$0, %r10       // arg_index
1041   LOOP_OVER_SHORTY_LOADING_GPRS rsi, esi, r11, r9, r10, .Lgpr_setup_finished_\suffix
1042   .else
1043   shrq MACRO_LITERAL(4), %r11
1044   movq $$1, %r10       // arg_index
1045   .endif
1046   LOOP_OVER_SHORTY_LOADING_GPRS rdx, edx, r11, r9, r10, .Lgpr_setup_finished_\suffix
1047   LOOP_OVER_SHORTY_LOADING_GPRS rcx, ecx, r11, r9, r10, .Lgpr_setup_finished_\suffix
1048   LOOP_OVER_SHORTY_LOADING_GPRS r8, r8d, r11, r9, r10, .Lgpr_setup_finished_\suffix
1049   LOOP_OVER_SHORTY_LOADING_GPRS r9, r9d, r11, r9, r10, .Lgpr_setup_finished_\suffix
1050.Lgpr_setup_finished_\suffix:
1051   .if \is_polymorphic
1052   call SYMBOL(art_quick_invoke_polymorphic)
1053   .elseif \is_custom
1054   call SYMBOL(art_quick_invoke_custom)
1055   .else
1056      .if \is_interface
1057      movzwl 2(rPC), %eax
1058      .endif
1059      call *ART_METHOD_QUICK_CODE_OFFSET_64(%rdi) // Call the method.
1060   .endif
1061   cmpb LITERAL(68), (rINSTq)       // Test if result type char == 'D'.
1062   je .Lreturn_double_\suffix
1063   cmpb LITERAL(70), (rINSTq)       // Test if result type char == 'F'.
1064   jne .Ldone_return_\suffix
1065.Lreturn_float_\suffix:
1066   movd %xmm0, %eax
1067   jmp .Ldone_return_\suffix
1068.Lreturn_double_\suffix:
1069   movq %xmm0, %rax
1070.Ldone_return_\suffix:
1071   /* resume execution of caller */
1072   .if \is_string_init
1073   movzwl 4(rPC), %r11d // arguments
1074   andq $$0xf, %r11
1075   GET_VREG %esi, %r11
1076   UPDATE_REGISTERS_FOR_STRING_INIT %esi, %eax
1077   .endif
1078
1079   .if \is_polymorphic
1080   ADVANCE_PC_FETCH_AND_GOTO_NEXT 4
1081   .else
1082   ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
1083   .endif
1084.endm
1085
1086.macro COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
1087   .if \is_polymorphic
1088   // We always go to compiled code for polymorphic calls.
1089   .elseif \is_custom
1090   // We always go to compiled code for custom calls.
1091   .else
1092     DO_ENTRY_POINT_CHECK .Lcall_compiled_code_range_\suffix
1093     .if \is_string_init
1094     call nterp_to_nterp_string_init_range
1095     .elseif \is_static
1096     call nterp_to_nterp_static_range
1097     .else
1098     call nterp_to_nterp_instance_range
1099     .endif
1100     jmp .Ldone_return_range_\suffix
1101   .endif
1102
1103.Lcall_compiled_code_range_\suffix:
1104   GET_SHORTY rINSTq, \is_interface, \is_polymorphic, \is_custom
1105   // From this point:
1106   // - rINSTq contains shorty (in callee-save to switch over return value after call).
1107   // - rdi contains method
1108   // - rsi contains 'this' pointer for instance method.
1109   leaq 1(rINSTq), %r9  // shorty + 1  ; ie skip return arg character
1110   movzwl 4(rPC), %r10d // arg start index
1111   .if \is_string_init
1112   addq $$1, %r10       // arg start index
1113   movq $$1, %rbp       // index in stack
1114   .elseif \is_static
1115   movq $$0, %rbp       // index in stack
1116   .else
1117   addq $$1, %r10       // arg start index
1118   movq $$1, %rbp       // index in stack
1119   .endif
1120   LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm0, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix
1121   LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm1, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix
1122   LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm2, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix
1123   LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm3, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix
1124   LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm4, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix
1125   LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm5, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix
1126   LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm6, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix
1127   LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm7, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix
1128   LOOP_RANGE_OVER_FPs r9, r10, rbp, .Lxmm_setup_finished_range_\suffix
1129.Lxmm_setup_finished_range_\suffix:
1130   leaq 1(%rbx), %r11  // shorty + 1  ; ie skip return arg character
1131   movzwl 4(rPC), %r10d // arg start index
1132   .if \is_string_init
1133   addq $$1, %r10       // arg start index
1134   movq $$1, %rbp       // index in stack
1135   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS rsi, esi, r11, r10, rbp, .Lgpr_setup_finished_\suffix
1136   .elseif \is_static
1137   movq $$0, %rbp // index in stack
1138   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS rsi, esi, r11, r10, rbp, .Lgpr_setup_finished_\suffix
1139   .else
1140   addq $$1, %r10       // arg start index
1141   movq $$1, %rbp // index in stack
1142   .endif
1143   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS rdx, edx, r11, r10, rbp, .Lgpr_setup_finished_range_\suffix
1144   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS rcx, ecx, r11, r10, rbp, .Lgpr_setup_finished_range_\suffix
1145   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r8, r8d, r11, r10, rbp, .Lgpr_setup_finished_range_\suffix
1146   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r9, r9d, r11, r10, rbp, .Lgpr_setup_finished_range_\suffix
1147   LOOP_RANGE_OVER_INTs r11, r10, rbp, .Lgpr_setup_finished_range_\suffix
1148
1149.Lgpr_setup_finished_range_\suffix:
1150   .if \is_polymorphic
1151   call SYMBOL(art_quick_invoke_polymorphic)
1152   .elseif \is_custom
1153   call SYMBOL(art_quick_invoke_custom)
1154   .else
1155     .if \is_interface
1156     movzwl 2(rPC), %eax
1157     .endif
1158     call *ART_METHOD_QUICK_CODE_OFFSET_64(%rdi) // Call the method.
1159   .endif
1160   cmpb LITERAL(68), (%rbx)       // Test if result type char == 'D'.
1161   je .Lreturn_range_double_\suffix
1162   cmpb LITERAL(70), (%rbx)       // Test if result type char == 'F'.
1163   je .Lreturn_range_float_\suffix
1164   /* resume execution of caller */
1165.Ldone_return_range_\suffix:
1166   .if \is_string_init
1167   movzwl 4(rPC), %r11d // arguments
1168   GET_VREG %esi, %r11
1169   UPDATE_REGISTERS_FOR_STRING_INIT %esi, %eax
1170   .endif
1171
1172   .if \is_polymorphic
1173   ADVANCE_PC_FETCH_AND_GOTO_NEXT 4
1174   .else
1175   ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
1176   .endif
1177.Lreturn_range_double_\suffix:
1178    movq %xmm0, %rax
1179    jmp .Ldone_return_range_\suffix
1180.Lreturn_range_float_\suffix:
1181    movd %xmm0, %eax
1182    jmp .Ldone_return_range_\suffix
1183.endm
1184
1185// Fetch some information from the thread cache.
1186// Uses rax, rdx, rcx as temporaries.
1187.macro FETCH_FROM_THREAD_CACHE dest_reg, slow_path
1188   movq rSELF:THREAD_SELF_OFFSET, %rax
1189   movq rPC, %rdx
1190   salq MACRO_LITERAL(THREAD_INTERPRETER_CACHE_SIZE_SHIFT), %rdx
1191   andq MACRO_LITERAL(THREAD_INTERPRETER_CACHE_SIZE_MASK), %rdx
1192   cmpq THREAD_INTERPRETER_CACHE_OFFSET(%rax, %rdx, 1), rPC
1193   jne \slow_path
1194   movq __SIZEOF_POINTER__+THREAD_INTERPRETER_CACHE_OFFSET(%rax, %rdx, 1), \dest_reg
1195.endm
1196
1197// Helper for static field get.
1198.macro OP_SGET load="movl", wide="0"
1199   // Fast-path which gets the field from thread-local cache.
1200   FETCH_FROM_THREAD_CACHE %rax, 2f
12011:
1202   movl ART_FIELD_OFFSET_OFFSET(%rax), %edx
1203   movl ART_FIELD_DECLARING_CLASS_OFFSET(%rax), %eax
1204   cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1205   jne 3f
12064:
1207   .if \wide
1208   movq (%eax,%edx,1), %rax
1209   SET_WIDE_VREG %rax, rINSTq              # fp[A] <- value
1210   .else
1211   \load (%eax, %edx, 1), %eax
1212   SET_VREG %eax, rINSTq            # fp[A] <- value
1213   .endif
1214   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
12152:
1216   movq rSELF:THREAD_SELF_OFFSET, %rdi
1217   movq 0(%rsp), %rsi
1218   movq rPC, %rdx
1219   EXPORT_PC
1220   call nterp_get_static_field
1221   // Clear the marker that we put for volatile fields. The x86 memory
1222   // model doesn't require a barrier.
1223   andq $$-2, %rax
1224   jmp 1b
12253:
1226   call art_quick_read_barrier_mark_reg00
1227   jmp 4b
1228.endm
1229
1230// Helper for static field put.
1231.macro OP_SPUT rINST_reg="rINST", store="movl", wide="0":
1232   // Fast-path which gets the field from thread-local cache.
1233   FETCH_FROM_THREAD_CACHE %rax, 2f
12341:
1235   movl ART_FIELD_OFFSET_OFFSET(%rax), %edx
1236   movl ART_FIELD_DECLARING_CLASS_OFFSET(%rax), %eax
1237   cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1238   jne 3f
12394:
1240   .if \wide
1241   GET_WIDE_VREG rINSTq, rINSTq           # rINST <- v[A]
1242   .else
1243   GET_VREG rINST, rINSTq                  # rINST <- v[A]
1244   .endif
1245   \store    \rINST_reg, (%rax,%rdx,1)
1246   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
12472:
1248   movq rSELF:THREAD_SELF_OFFSET, %rdi
1249   movq 0(%rsp), %rsi
1250   movq rPC, %rdx
1251   EXPORT_PC
1252   call nterp_get_static_field
1253   testq MACRO_LITERAL(1), %rax
1254   je 1b
1255   // Clear the marker that we put for volatile fields. The x86 memory
1256   // model doesn't require a barrier.
1257   CLEAR_VOLATILE_MARKER %rax
1258   movl ART_FIELD_OFFSET_OFFSET(%rax), %edx
1259   movl ART_FIELD_DECLARING_CLASS_OFFSET(%rax), %eax
1260   cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1261   jne 6f
12625:
1263   .if \wide
1264   GET_WIDE_VREG rINSTq, rINSTq           # rINST <- v[A]
1265   .else
1266   GET_VREG rINST, rINSTq                  # rINST <- v[A]
1267   .endif
1268   \store    \rINST_reg, (%rax,%rdx,1)
1269   lock addl $$0, (%rsp)
1270   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
12713:
1272   call art_quick_read_barrier_mark_reg00
1273   jmp 4b
12746:
1275   call art_quick_read_barrier_mark_reg00
1276   jmp 5b
1277.endm
1278
1279
1280.macro OP_IPUT_INTERNAL rINST_reg="rINST", store="movl", wide="0":
1281   movzbq  rINSTbl, %rcx                   # rcx <- BA
1282   sarl    $$4, %ecx                       # ecx <- B
1283   GET_VREG %ecx, %rcx                     # vB (object we're operating on)
1284   testl   %ecx, %ecx                      # is object null?
1285   je      common_errNullObject
1286   andb    $$0xf, rINSTbl                  # rINST <- A
1287   .if \wide
1288   GET_WIDE_VREG rINSTq, rINSTq              # rax<- fp[A]/fp[A+1]
1289   .else
1290   GET_VREG rINST, rINSTq                  # rINST <- v[A]
1291   .endif
1292   \store \rINST_reg, (%rcx,%rax,1)
1293.endm
1294
1295// Helper for instance field put.
1296.macro OP_IPUT rINST_reg="rINST", store="movl", wide="0":
1297   // Fast-path which gets the field from thread-local cache.
1298   FETCH_FROM_THREAD_CACHE %rax, 2f
12991:
1300   OP_IPUT_INTERNAL \rINST_reg, \store, \wide
1301   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
13022:
1303   movq rSELF:THREAD_SELF_OFFSET, %rdi
1304   movq 0(%rsp), %rsi
1305   movq rPC, %rdx
1306   EXPORT_PC
1307   call nterp_get_instance_field_offset
1308   testl %eax, %eax
1309   jns 1b
1310   negl %eax
1311   OP_IPUT_INTERNAL \rINST_reg, \store, \wide
1312   lock addl $$0, (%rsp)
1313   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
1314.endm
1315
1316// Helper for instance field get.
1317.macro OP_IGET load="movl", wide="0"
1318   // Fast-path which gets the field from thread-local cache.
1319   FETCH_FROM_THREAD_CACHE %rax, 2f
13201:
1321   movl    rINST, %ecx                     # rcx <- BA
1322   sarl    $$4, %ecx                       # ecx <- B
1323   GET_VREG %ecx, %rcx                     # vB (object we're operating on)
1324   testl   %ecx, %ecx                      # is object null?
1325   je      common_errNullObject
1326   andb    $$0xf,rINSTbl                   # rINST <- A
1327   .if \wide
1328   movq (%rcx,%rax,1), %rax
1329   SET_WIDE_VREG %rax, rINSTq              # fp[A] <- value
1330   .else
1331   \load (%rcx,%rax,1), %eax
1332   SET_VREG %eax, rINSTq                   # fp[A] <- value
1333   .endif
1334   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
13352:
1336   movq rSELF:THREAD_SELF_OFFSET, %rdi
1337   movq 0(%rsp), %rsi
1338   movq rPC, %rdx
1339   EXPORT_PC
1340   call nterp_get_instance_field_offset
1341   testl %eax, %eax
1342   jns 1b
1343   negl %eax
1344   jmp 1b
1345.endm
1346
1347%def entry():
1348/*
1349 * ArtMethod entry point.
1350 *
1351 * On entry:
1352 *  rdi   ArtMethod* callee
1353 *  rest  method parameters
1354 */
1355
1356OAT_ENTRY ExecuteNterpImpl, EndExecuteNterpImpl
1357    .cfi_startproc
1358    .cfi_def_cfa rsp, 8
1359    testq %rax, -STACK_OVERFLOW_RESERVED_BYTES(%rsp)
1360    /* Spill callee save regs */
1361    SPILL_ALL_CALLEE_SAVES
1362
1363    // TODO: Get shorty in a better way and remove below
1364    PUSH rdi
1365    PUSH rsi
1366    PUSH rdx
1367    PUSH rcx
1368    PUSH r8
1369    PUSH r9
1370
1371    // Save xmm registers + alignment.
1372    subq MACRO_LITERAL(8 * 8 + 8), %rsp
1373    CFI_ADJUST_CFA_OFFSET(8 * 8 + 8)
1374    movq %xmm0, 0(%rsp)
1375    movq %xmm1, 8(%rsp)
1376    movq %xmm2, 16(%rsp)
1377    movq %xmm3, 24(%rsp)
1378    movq %xmm4, 32(%rsp)
1379    movq %xmm5, 40(%rsp)
1380    movq %xmm6, 48(%rsp)
1381    movq %xmm7, 56(%rsp)
1382
1383    // Save method in callee-save rbx.
1384    movq %rdi, %rbx
1385    call SYMBOL(NterpGetShorty)
1386    // Save shorty in callee-save rbp.
1387    movq %rax, %rbp
1388    movq %rbx, %rdi
1389    call SYMBOL(NterpGetCodeItem)
1390    movq %rax, rPC
1391
1392    // Restore xmm registers + alignment.
1393    movq 0(%rsp), %xmm0
1394    movq 8(%rsp), %xmm1
1395    movq 16(%rsp), %xmm2
1396    movq 24(%rsp), %xmm3
1397    movq 32(%rsp), %xmm4
1398    movq 40(%rsp), %xmm5
1399    movq 48(%rsp), %xmm6
1400    movq 56(%rsp), %xmm7
1401    addq MACRO_LITERAL(8 * 8 + 8), %rsp
1402    CFI_ADJUST_CFA_OFFSET(-8 * 8 - 8)
1403
1404    POP r9
1405    POP r8
1406    POP rcx
1407    POP rdx
1408    POP rsi
1409    POP rdi
1410    // TODO: Get shorty in a better way and remove above
1411
1412    // Setup the stack for executing the method.
1413    SETUP_STACK_FRAME rPC, rREFS, rFP, CFI_REFS
1414
1415    // Setup the parameters
1416    movzwl CODE_ITEM_INS_SIZE_OFFSET(rPC), %r14d
1417    testl %r14d, %r14d
1418    je .Lxmm_setup_finished
1419
1420    subq %r14, %rbx
1421    salq $$2, %rbx // rbx is now the offset for inputs into the registers array.
1422
1423    testl $$ART_METHOD_IS_STATIC_FLAG, ART_METHOD_ACCESS_FLAGS_OFFSET(%rdi)
1424
1425    // Available: rdi, r10, r14
1426    // Note the leaq below don't change the flags.
1427    leaq 1(%rbp), %r10  // shorty + 1  ; ie skip return arg character
1428    leaq (rFP, %rbx, 1), %rdi
1429    leaq (rREFS, %rbx, 1), %rbx
1430    jne .Lhandle_static_method
1431    movl %esi, (%rdi)
1432    movl %esi, (%rbx)
1433    addq $$4, %rdi
1434    addq $$4, %rbx
1435    addq $$4, %r11
1436    movq $$0, %r14
1437    jmp .Lcontinue_setup_gprs
1438.Lhandle_static_method:
1439    movq $$0, %r14
1440    LOOP_OVER_SHORTY_STORING_GPRS rsi, esi, r10, r14, rdi, rbx, .Lgpr_setup_finished
1441.Lcontinue_setup_gprs:
1442    LOOP_OVER_SHORTY_STORING_GPRS rdx, edx, r10, r14, rdi, rbx, .Lgpr_setup_finished
1443    LOOP_OVER_SHORTY_STORING_GPRS rcx, ecx, r10, r14, rdi, rbx, .Lgpr_setup_finished
1444    LOOP_OVER_SHORTY_STORING_GPRS r8, r8d, r10, r14, rdi, rbx, .Lgpr_setup_finished
1445    LOOP_OVER_SHORTY_STORING_GPRS r9, r9d, r10, r14, rdi, rbx, .Lgpr_setup_finished
1446    LOOP_OVER_INTs r10, r14, rdi, rbx, r11, .Lgpr_setup_finished
1447.Lgpr_setup_finished:
1448    leaq 1(%rbp), %r10  // shorty + 1  ; ie skip return arg character
1449    movq $$0, %r14 // reset counter
1450    LOOP_OVER_SHORTY_STORING_XMMS xmm0, r10, r14, rdi, .Lxmm_setup_finished
1451    LOOP_OVER_SHORTY_STORING_XMMS xmm1, r10, r14, rdi, .Lxmm_setup_finished
1452    LOOP_OVER_SHORTY_STORING_XMMS xmm2, r10, r14, rdi, .Lxmm_setup_finished
1453    LOOP_OVER_SHORTY_STORING_XMMS xmm3, r10, r14, rdi, .Lxmm_setup_finished
1454    LOOP_OVER_SHORTY_STORING_XMMS xmm4, r10, r14, rdi, .Lxmm_setup_finished
1455    LOOP_OVER_SHORTY_STORING_XMMS xmm5, r10, r14, rdi, .Lxmm_setup_finished
1456    LOOP_OVER_SHORTY_STORING_XMMS xmm6, r10, r14, rdi, .Lxmm_setup_finished
1457    LOOP_OVER_SHORTY_STORING_XMMS xmm7, r10, r14, rdi, .Lxmm_setup_finished
1458    LOOP_OVER_FPs r10, r14, rdi, r11, .Lxmm_setup_finished
1459.Lxmm_setup_finished:
1460    // Set the dex pc pointer.
1461    addq $$CODE_ITEM_INSNS_OFFSET, rPC
1462    CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
1463
1464    // Set rIBASE
1465    leaq artNterpAsmInstructionStart(%rip), rIBASE
1466    /* start executing the instruction at rPC */
1467    START_EXECUTING_INSTRUCTIONS
1468    /* NOTE: no fallthrough */
1469    // cfi info continues, and covers the whole nterp implementation.
1470    END ExecuteNterpImpl
1471
1472%def opcode_pre():
1473
1474%def helpers():
1475
1476%def footer():
1477/*
1478 * ===========================================================================
1479 *  Common subroutines and data
1480 * ===========================================================================
1481 */
1482
1483    .text
1484    .align  2
1485
1486// Note: mterp also uses the common_* names below for helpers, but that's OK
1487// as the C compiler compiled each interpreter separately.
1488common_errDivideByZero:
1489    EXPORT_PC
1490    call art_quick_throw_div_zero
1491
1492common_errArrayIndex:
1493    EXPORT_PC
1494    movl MIRROR_ARRAY_LENGTH_OFFSET(%edi), %eax
1495    movl %esi, %edi
1496    movl %eax, %esi
1497    call art_quick_throw_array_bounds
1498
1499common_errNullObject:
1500    EXPORT_PC
1501    call art_quick_throw_null_pointer_exception
1502
1503NterpCommonInvokeStatic:
1504    COMMON_INVOKE_NON_RANGE is_static=1, is_interface=0, suffix="invokeStatic"
1505
1506NterpCommonInvokeStaticRange:
1507    COMMON_INVOKE_RANGE is_static=1, is_interface=0, suffix="invokeStatic"
1508
1509NterpCommonInvokeInstance:
1510    COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="invokeInstance"
1511
1512NterpCommonInvokeInstanceRange:
1513    COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="invokeInstance"
1514
1515NterpCommonInvokeInterface:
1516    COMMON_INVOKE_NON_RANGE is_static=0, is_interface=1, suffix="invokeInterface"
1517
1518NterpCommonInvokeInterfaceRange:
1519    COMMON_INVOKE_RANGE is_static=0, is_interface=1, suffix="invokeInterface"
1520
1521NterpCommonInvokePolymorphic:
1522    COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, is_string_init=0, is_polymorphic=1, suffix="invokePolymorphic"
1523
1524NterpCommonInvokePolymorphicRange:
1525    COMMON_INVOKE_RANGE is_static=0, is_interface=0, is_polymorphic=1, suffix="invokePolymorphic"
1526
1527NterpCommonInvokeCustom:
1528    COMMON_INVOKE_NON_RANGE is_static=1, is_interface=0, is_string_init=0, is_polymorphic=0, is_custom=1, suffix="invokeCustom"
1529
1530NterpCommonInvokeCustomRange:
1531    COMMON_INVOKE_RANGE is_static=1, is_interface=0, is_polymorphic=0, is_custom=1, suffix="invokeCustom"
1532
1533NterpHandleStringInit:
1534   COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, is_string_init=1, suffix="stringInit"
1535
1536NterpHandleStringInitRange:
1537   COMMON_INVOKE_RANGE is_static=0, is_interface=0, is_string_init=1, suffix="stringInit"
1538
1539NterpNewInstance:
1540   EXPORT_PC
1541   // Fast-path which gets the class from thread-local cache.
1542   FETCH_FROM_THREAD_CACHE %rdi, 2f
1543   cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1544   jne 3f
15454:
1546   callq *rSELF:THREAD_ALLOC_OBJECT_ENTRYPOINT_OFFSET
15471:
1548   SET_VREG_OBJECT %eax, rINSTq            # fp[A] <- value
1549   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
15502:
1551   movq rSELF:THREAD_SELF_OFFSET, %rdi
1552   movq 0(%rsp), %rsi
1553   movq rPC, %rdx
1554   call nterp_get_class_or_allocate_object
1555   jmp 1b
15563:
1557   // 07 is %rdi
1558   call art_quick_read_barrier_mark_reg07
1559   jmp 4b
1560
1561NterpNewArray:
1562   /* new-array vA, vB, class@CCCC */
1563   EXPORT_PC
1564   // Fast-path which gets the class from thread-local cache.
1565   FETCH_FROM_THREAD_CACHE %rdi, 2f
1566   cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1567   jne 3f
15681:
1569   movzbl  rINSTbl,%esi
1570   sarl    $$4,%esi                          # esi<- B
1571   GET_VREG %esi %rsi                        # esi<- vB (array length)
1572   andb    $$0xf,rINSTbl                     # rINST<- A
1573   callq *rSELF:THREAD_ALLOC_ARRAY_ENTRYPOINT_OFFSET
1574   SET_VREG_OBJECT %eax, rINSTq            # fp[A] <- value
1575   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
15762:
1577   movq rSELF:THREAD_SELF_OFFSET, %rdi
1578   movq 0(%rsp), %rsi
1579   movq rPC, %rdx
1580   call nterp_get_class_or_allocate_object
1581   movq %rax, %rdi
1582   jmp 1b
15833:
1584   // 07 is %rdi
1585   call art_quick_read_barrier_mark_reg07
1586   jmp 1b
1587
1588NterpPutObjectInstanceField:
1589   // Fast-path which gets the field from thread-local cache.
1590   FETCH_FROM_THREAD_CACHE %rax, 2f
15911:
1592   movzbq  rINSTbl, %rcx                   # rcx <- BA
1593   sarl    $$4, %ecx                       # ecx <- B
1594   GET_VREG %ecx, %rcx                     # vB (object we're operating on)
1595   testl   %ecx, %ecx                      # is object null?
1596   je      common_errNullObject
1597   andb    $$0xf, rINSTbl                  # rINST <- A
1598   GET_VREG rINST, rINSTq                  # rINST <- v[A]
1599   movl rINST, (%rcx,%rax,1)
1600   testl rINST, rINST
1601   je 4f
1602   movq rSELF:THREAD_CARD_TABLE_OFFSET, %rax
1603   shrq $$CARD_TABLE_CARD_SHIFT, %rcx
1604   movb %al, (%rax, %rcx, 1)
16054:
1606   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
16072:
1608   EXPORT_PC
1609   movq rSELF:THREAD_SELF_OFFSET, %rdi
1610   movq 0(%rsp), %rsi
1611   movq rPC, %rdx
1612   EXPORT_PC
1613   call nterp_get_instance_field_offset
1614   testl %eax, %eax
1615   jns 1b
1616   negl %eax
1617   movzbq  rINSTbl, %rcx                   # rcx <- BA
1618   sarl    $$4, %ecx                       # ecx <- B
1619   GET_VREG %ecx, %rcx                     # vB (object we're operating on)
1620   testl   %ecx, %ecx                      # is object null?
1621   je      common_errNullObject
1622   andb    $$0xf, rINSTbl                  # rINST <- A
1623   GET_VREG rINST, rINSTq                  # rINST <- v[A]
1624   movl rINST, (%rcx,%rax,1)
1625   testl rINST, rINST
1626   je 5f
1627   movq rSELF:THREAD_CARD_TABLE_OFFSET, %rax
1628   shrq $$CARD_TABLE_CARD_SHIFT, %rcx
1629   movb %al, (%rcx, %rax, 1)
16305:
1631   lock addl $$0, (%rsp)
1632   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
1633
1634NterpGetObjectInstanceField:
1635   // Fast-path which gets the field from thread-local cache.
1636   FETCH_FROM_THREAD_CACHE %rax, 2f
16371:
1638   movl    rINST, %ecx                     # rcx <- BA
1639   sarl    $$4, %ecx                       # ecx <- B
1640   GET_VREG %ecx, %rcx                     # vB (object we're operating on)
1641   testl   %ecx, %ecx                      # is object null?
1642   je      common_errNullObject
1643   testb $$READ_BARRIER_TEST_VALUE, GRAY_BYTE_OFFSET(%ecx)
1644   movl (%rcx,%rax,1), %eax
1645   jnz 3f
16464:
1647   andb    $$0xf,rINSTbl                   # rINST <- A
1648   SET_VREG_OBJECT %eax, rINSTq            # fp[A] <- value
1649   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
16502:
1651   EXPORT_PC
1652   movq rSELF:THREAD_SELF_OFFSET, %rdi
1653   movq 0(%rsp), %rsi
1654   movq rPC, %rdx
1655   EXPORT_PC
1656   call nterp_get_instance_field_offset
1657   testl %eax, %eax
1658   jns 1b
1659   // For volatile fields, we return a negative offset. Remove the sign
1660   // and no need for any barrier thanks to the memory model.
1661   negl %eax
1662   jmp 1b
16633:
1664   // reg00 is eax
1665   call art_quick_read_barrier_mark_reg00
1666   jmp 4b
1667
1668NterpPutObjectStaticField:
1669   // Fast-path which gets the field from thread-local cache.
1670   FETCH_FROM_THREAD_CACHE %rax, 2f
16711:
1672   movl ART_FIELD_OFFSET_OFFSET(%rax), %edx
1673   movl ART_FIELD_DECLARING_CLASS_OFFSET(%rax), %eax
1674   cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1675   jne 3f
16765:
1677   GET_VREG %ecx, rINSTq
1678   movl %ecx, (%eax, %edx, 1)
1679   testl %ecx, %ecx
1680   je 4f
1681   movq rSELF:THREAD_CARD_TABLE_OFFSET, %rcx
1682   shrq $$CARD_TABLE_CARD_SHIFT, %rax
1683   movb %cl, (%rax, %rcx, 1)
16844:
1685   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
16862:
1687   movq rSELF:THREAD_SELF_OFFSET, %rdi
1688   movq 0(%rsp), %rsi
1689   movq rPC, %rdx
1690   EXPORT_PC
1691   call nterp_get_static_field
1692   testq MACRO_LITERAL(1), %rax
1693   je 1b
1694   CLEAR_VOLATILE_MARKER %rax
1695   movl ART_FIELD_OFFSET_OFFSET(%rax), %edx
1696   movl ART_FIELD_DECLARING_CLASS_OFFSET(%rax), %eax
1697   cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1698   jne 7f
16996:
1700   movzbl rINSTbl, %ecx
1701   GET_VREG %ecx, %rcx
1702   movl %ecx, (%eax, %edx, 1)
1703   testl %ecx, %ecx
1704   je 8f
1705   movq rSELF:THREAD_CARD_TABLE_OFFSET, %rcx
1706   shrq $$CARD_TABLE_CARD_SHIFT, %rax
1707   movb %cl, (%rax, %rcx, 1)
17088:
1709   lock addl $$0, (%rsp)
1710   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
17113:
1712   call art_quick_read_barrier_mark_reg00
1713   jmp 5b
17147:
1715   call art_quick_read_barrier_mark_reg00
1716   jmp 6b
1717
1718NterpGetObjectStaticField:
1719   // Fast-path which gets the field from thread-local cache.
1720   FETCH_FROM_THREAD_CACHE %rax, 2f
17211:
1722   movl ART_FIELD_OFFSET_OFFSET(%rax), %edx
1723   movl ART_FIELD_DECLARING_CLASS_OFFSET(%rax), %eax
1724   cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1725   jne 5f
17266:
1727   testb $$READ_BARRIER_TEST_VALUE, GRAY_BYTE_OFFSET(%eax)
1728   movl (%eax, %edx, 1), %eax
1729   jnz 3f
17304:
1731   SET_VREG_OBJECT %eax, rINSTq            # fp[A] <- value
1732   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
17332:
1734   movq rSELF:THREAD_SELF_OFFSET, %rdi
1735   movq 0(%rsp), %rsi
1736   movq rPC, %rdx
1737   EXPORT_PC
1738   call nterp_get_static_field
1739   andq $$-2, %rax
1740   jmp 1b
17413:
1742   call art_quick_read_barrier_mark_reg00
1743   jmp 4b
17445:
1745   call art_quick_read_barrier_mark_reg00
1746   jmp 6b
1747
1748NterpGetBooleanStaticField:
1749  OP_SGET load="movsbl", wide=0
1750
1751NterpGetByteStaticField:
1752  OP_SGET load="movsbl", wide=0
1753
1754NterpGetCharStaticField:
1755  OP_SGET load="movzwl", wide=0
1756
1757NterpGetShortStaticField:
1758  OP_SGET load="movswl", wide=0
1759
1760NterpGetWideStaticField:
1761  OP_SGET load="movq", wide=1
1762
1763NterpGetIntStaticField:
1764  OP_SGET load="movl", wide=0
1765
1766NterpPutStaticField:
1767  OP_SPUT rINST_reg=rINST, store="movl", wide=0
1768
1769NterpPutBooleanStaticField:
1770NterpPutByteStaticField:
1771  OP_SPUT rINST_reg=rINSTbl, store="movb", wide=0
1772
1773NterpPutCharStaticField:
1774NterpPutShortStaticField:
1775  OP_SPUT rINST_reg=rINSTw, store="movw", wide=0
1776
1777NterpPutWideStaticField:
1778  OP_SPUT rINST_reg=rINSTq, store="movq", wide=1
1779
1780NterpPutInstanceField:
1781  OP_IPUT rINST_reg=rINST, store="movl", wide=0
1782
1783NterpPutBooleanInstanceField:
1784NterpPutByteInstanceField:
1785  OP_IPUT rINST_reg=rINSTbl, store="movb", wide=0
1786
1787NterpPutCharInstanceField:
1788NterpPutShortInstanceField:
1789  OP_IPUT rINST_reg=rINSTw, store="movw", wide=0
1790
1791NterpPutWideInstanceField:
1792  OP_IPUT rINST_reg=rINSTq, store="movq", wide=1
1793
1794NterpGetBooleanInstanceField:
1795  OP_IGET load="movzbl", wide=0
1796
1797NterpGetByteInstanceField:
1798  OP_IGET load="movsbl", wide=0
1799
1800NterpGetCharInstanceField:
1801  OP_IGET load="movzwl", wide=0
1802
1803NterpGetShortInstanceField:
1804  OP_IGET load="movswl", wide=0
1805
1806NterpGetWideInstanceField:
1807  OP_IGET load="movq", wide=1
1808
1809NterpGetInstanceField:
1810  OP_IGET load="movl", wide=0
1811
1812NterpInstanceOf:
1813    /* instance-of vA, vB, class@CCCC */
1814   // Fast-path which gets the class from thread-local cache.
1815   EXPORT_PC
1816   FETCH_FROM_THREAD_CACHE %rsi, 2f
1817   cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1818   jne 5f
18191:
1820   movzbl  rINSTbl,%edi
1821   sarl    $$4,%edi                          # edi<- B
1822   GET_VREG %edi %rdi                        # edi<- vB (object)
1823   andb    $$0xf,rINSTbl                     # rINST<- A
1824   testl %edi, %edi
1825   je 3f
1826   call art_quick_instance_of
1827   SET_VREG %eax, rINSTq            # fp[A] <- value
18284:
1829   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
18303:
1831   SET_VREG %edi, rINSTq            # fp[A] <-0
1832   jmp 4b
18332:
1834   movq rSELF:THREAD_SELF_OFFSET, %rdi
1835   movq 0(%rsp), %rsi
1836   movq rPC, %rdx
1837   call nterp_get_class_or_allocate_object
1838   movq %rax, %rsi
1839   jmp 1b
18405:
1841   // 06 is %rsi
1842   call art_quick_read_barrier_mark_reg06
1843   jmp 1b
1844
1845NterpCheckCast:
1846   // Fast-path which gets the class from thread-local cache.
1847   EXPORT_PC
1848   FETCH_FROM_THREAD_CACHE %rsi, 3f
1849   cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1850   jne 4f
18511:
1852   GET_VREG %edi, rINSTq
1853   testl %edi, %edi
1854   je 2f
1855   call art_quick_check_instance_of
18562:
1857   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
18583:
1859   movq rSELF:THREAD_SELF_OFFSET, %rdi
1860   movq 0(%rsp), %rsi
1861   movq rPC, %rdx
1862   call nterp_get_class_or_allocate_object
1863   movq %rax, %rsi
1864   jmp 1b
18654:
1866   // 06 is %rsi
1867   call art_quick_read_barrier_mark_reg06
1868   jmp 1b
1869
1870NterpHandleHotnessOverflow:
1871    leaq (rPC, rINSTq, 2), %rsi
1872    movq rFP, %rdx
1873    call nterp_hot_method
1874    testq %rax, %rax
1875    jne 1f
1876    leaq    (rPC, rINSTq, 2), rPC
1877    FETCH_INST
1878    GOTO_NEXT
18791:
1880    // Drop the current frame.
1881    movq -8(rREFS), %rsp
1882    CFI_DEF_CFA(rsp, CALLEE_SAVES_SIZE)
1883
1884    // Setup the new frame
1885    movq OSR_DATA_FRAME_SIZE(%rax), %rcx
1886    // Given stack size contains all callee saved registers, remove them.
1887    subq $$CALLEE_SAVES_SIZE, %rcx
1888
1889    // Remember CFA.
1890    movq %rsp, %rbp
1891    CFI_DEF_CFA_REGISTER(rbp)
1892
1893    subq %rcx, %rsp
1894    movq %rsp, %rdi               // rdi := beginning of stack
1895    leaq OSR_DATA_MEMORY(%rax), %rsi  // rsi := memory to copy
1896    rep movsb                     // while (rcx--) { *rdi++ = *rsi++ }
1897
1898    // Fetch the native PC to jump to and save it in a callee-save register.
1899    movq OSR_DATA_NATIVE_PC(%rax), %rbx
1900
1901    // Free the memory holding OSR Data.
1902    movq %rax, %rdi
1903    call free
1904
1905    // Jump to the compiled code.
1906    jmp *%rbx
1907
1908NterpHandleInvokeInterfaceOnObjectMethodRange:
1909   // First argument is the 'this' pointer.
1910   movzwl 4(rPC), %r11d // arguments
1911   movl (rFP, %r11, 4), %esi
1912   // Note: if esi is null, this will be handled by our SIGSEGV handler.
1913   movl MIRROR_OBJECT_CLASS_OFFSET(%esi), %edx
1914   movq MIRROR_CLASS_VTABLE_OFFSET_64(%edx, %eax, 8), %rdi
1915   jmp NterpCommonInvokeInstanceRange
1916
1917NterpHandleInvokeInterfaceOnObjectMethod:
1918   // First argument is the 'this' pointer.
1919   movzwl 4(rPC), %r11d // arguments
1920   andq MACRO_LITERAL(0xf), %r11
1921   movl (rFP, %r11, 4), %esi
1922   // Note: if esi is null, this will be handled by our SIGSEGV handler.
1923   movl MIRROR_OBJECT_CLASS_OFFSET(%esi), %edx
1924   movq MIRROR_CLASS_VTABLE_OFFSET_64(%edx, %eax, 8), %rdi
1925   jmp NterpCommonInvokeInstance
1926
1927// This is the logical end of ExecuteNterpImpl, where the frame info applies.
1928// EndExecuteNterpImpl includes the methods below as we want the runtime to
1929// see them as part of the Nterp PCs.
1930.cfi_endproc
1931
1932nterp_to_nterp_static_non_range:
1933    .cfi_startproc
1934    .cfi_def_cfa rsp, 8
1935    SETUP_STACK_FOR_INVOKE
1936    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0
1937    .cfi_endproc
1938
1939nterp_to_nterp_string_init_non_range:
1940    .cfi_startproc
1941    .cfi_def_cfa rsp, 8
1942    SETUP_STACK_FOR_INVOKE
1943    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1
1944    .cfi_endproc
1945
1946nterp_to_nterp_instance_non_range:
1947    .cfi_startproc
1948    .cfi_def_cfa rsp, 8
1949    SETUP_STACK_FOR_INVOKE
1950    SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
1951    .cfi_endproc
1952
1953nterp_to_nterp_static_range:
1954    .cfi_startproc
1955    .cfi_def_cfa rsp, 8
1956    SETUP_STACK_FOR_INVOKE
1957    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=1
1958    .cfi_endproc
1959
1960nterp_to_nterp_instance_range:
1961    .cfi_startproc
1962    .cfi_def_cfa rsp, 8
1963    SETUP_STACK_FOR_INVOKE
1964    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0
1965    .cfi_endproc
1966
1967nterp_to_nterp_string_init_range:
1968    .cfi_startproc
1969    .cfi_def_cfa rsp, 8
1970    SETUP_STACK_FOR_INVOKE
1971    SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1
1972    .cfi_endproc
1973
1974// This is the end of PCs contained by the OatQuickMethodHeader created for the interpreter
1975// entry point.
1976    FUNCTION_TYPE(EndExecuteNterpImpl)
1977    ASM_HIDDEN SYMBOL(EndExecuteNterpImpl)
1978    .global SYMBOL(EndExecuteNterpImpl)
1979SYMBOL(EndExecuteNterpImpl):
1980
1981// Entrypoints into runtime.
1982NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField
1983NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset
1984NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray
1985NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange
1986NTERP_TRAMPOLINE nterp_get_class_or_allocate_object, NterpGetClassOrAllocateObject
1987NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod
1988NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod
1989NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject
1990
1991// gen_mterp.py will inline the following definitions
1992// within [ExecuteNterpImpl, EndExecuteNterpImpl).
1993%def instruction_end():
1994
1995    FUNCTION_TYPE(artNterpAsmInstructionEnd)
1996    ASM_HIDDEN SYMBOL(artNterpAsmInstructionEnd)
1997    .global SYMBOL(artNterpAsmInstructionEnd)
1998SYMBOL(artNterpAsmInstructionEnd):
1999    // artNterpAsmInstructionEnd is used as landing pad for exception handling.
2000    FETCH_INST
2001    GOTO_NEXT
2002
2003%def instruction_start():
2004
2005    FUNCTION_TYPE(artNterpAsmInstructionStart)
2006    ASM_HIDDEN SYMBOL(artNterpAsmInstructionStart)
2007    .global SYMBOL(artNterpAsmInstructionStart)
2008SYMBOL(artNterpAsmInstructionStart) = .L_op_nop
2009    .text
2010
2011%def opcode_start():
2012    ENTRY nterp_${opcode}
2013%def opcode_end():
2014    END nterp_${opcode}
2015%def helper_start(name):
2016    ENTRY ${name}
2017%def helper_end(name):
2018    END ${name}
2019