• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1%def header():
2/*
3 * Copyright (C) 2021 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/asm_support_x86.S"
24
25/**
26 * x86 ABI general notes:
27 *
28 * Caller save set:
29 *      eax, ebx, edx, ecx, st(0)-st(7)
30 * Callee save set:
31 *      esi, edi, ebp
32 * Return regs:
33 *      32-bit in eax
34 *      64-bit in edx:eax (low-order 32 in eax)
35 *      fp on top of fp stack st(0)
36 *
37 * Stack must be 16-byte aligned to support SSE in native code.
38 */
39
40#define ARG3        %ebx
41#define ARG2        %edx
42#define ARG1        %ecx
43#define ARG0        %eax
44
45/*
46 * single-purpose registers, given names for clarity
47 */
48#define rSELF    %fs
49#define rPC      %esi
50#define CFI_DEX  6  // DWARF register number of the register holding dex-pc (esi).
51#define CFI_TMP  0  // DWARF register number of the first argument register (eax).
52#define rFP      %edi
53#define rINST    %ebx
54#define rINSTw   %bx
55#define rINSTbh  %bh
56#define rINSTbl  %bl
57#define rIBASE   %edx
58#define rREFS    %ebp
59#define CFI_REFS 5 // DWARF register number of the reference array (ebp).
60
61// Temporary registers while setting up a frame.
62#define rNEW_FP   %ecx
63#define rNEW_REFS %eax
64#define CFI_NEW_REFS 0
65
66#define LOCAL0 4
67#define LOCAL1 8
68#define LOCAL2 12
69
70/*
71 * Get/set the 32-bit value from a Dalvik register.
72 */
73#define VREG_ADDRESS(_vreg) (rFP,_vreg,4)
74#define VREG_HIGH_ADDRESS(_vreg) 4(rFP,_vreg,4)
75#define VREG_REF_ADDRESS(_vreg) (rREFS,_vreg,4)
76#define VREG_REF_HIGH_ADDRESS(_vreg) 4(rREFS,_vreg,4)
77
78.macro GET_VREG _reg _vreg
79    movl    VREG_ADDRESS(\_vreg), \_reg
80.endm
81
82.macro GET_VREG_OBJECT _reg _vreg
83    movl    VREG_REF_ADDRESS(\_vreg), \_reg
84.endm
85
86/* Read wide value to xmm. */
87.macro GET_WIDE_FP_VREG _reg _vreg
88    movq    VREG_ADDRESS(\_vreg), \_reg
89.endm
90
91.macro SET_VREG _reg _vreg
92    movl    \_reg, VREG_ADDRESS(\_vreg)
93    movl    MACRO_LITERAL(0), VREG_REF_ADDRESS(\_vreg)
94.endm
95
96/* Write wide value from xmm. xmm is clobbered. */
97.macro SET_WIDE_FP_VREG _reg _vreg
98    movq    \_reg, VREG_ADDRESS(\_vreg)
99    pxor    \_reg, \_reg
100    movq    \_reg, VREG_REF_ADDRESS(\_vreg)
101.endm
102
103.macro SET_VREG_OBJECT _reg _vreg
104    movl    \_reg, VREG_ADDRESS(\_vreg)
105    movl    \_reg, VREG_REF_ADDRESS(\_vreg)
106.endm
107
108.macro GET_VREG_HIGH _reg _vreg
109    movl    VREG_HIGH_ADDRESS(\_vreg), \_reg
110.endm
111
112.macro SET_VREG_HIGH _reg _vreg
113    movl    \_reg, VREG_HIGH_ADDRESS(\_vreg)
114    movl    MACRO_LITERAL(0), VREG_REF_HIGH_ADDRESS(\_vreg)
115.endm
116
117.macro CLEAR_REF _vreg
118    movl    MACRO_LITERAL(0), VREG_REF_ADDRESS(\_vreg)
119.endm
120
121.macro CLEAR_WIDE_REF _vreg
122    movl    MACRO_LITERAL(0), VREG_REF_ADDRESS(\_vreg)
123    movl    MACRO_LITERAL(0), VREG_REF_HIGH_ADDRESS(\_vreg)
124.endm
125
126.macro GET_VREG_XMMs _xmmreg _vreg
127    movss VREG_ADDRESS(\_vreg), \_xmmreg
128.endm
129.macro GET_VREG_XMMd _xmmreg _vreg
130    movsd VREG_ADDRESS(\_vreg), \_xmmreg
131.endm
132.macro SET_VREG_XMMs _xmmreg _vreg
133    movss \_xmmreg, VREG_ADDRESS(\_vreg)
134.endm
135.macro SET_VREG_XMMd _xmmreg _vreg
136    movsd \_xmmreg, VREG_ADDRESS(\_vreg)
137.endm
138
139// Includes the return address implicitly pushed on stack by 'call'.
140#define CALLEE_SAVES_SIZE (3 * 4 + 1 * 4)
141
142#define PARAMETERS_SAVES_SIZE (4 * 4)
143
144// +4 for the ArtMethod of the caller.
145#define OFFSET_TO_FIRST_ARGUMENT_IN_STACK (CALLEE_SAVES_SIZE + PARAMETERS_SAVES_SIZE + 4)
146
147/*
148 * Refresh rINST.
149 * At enter to handler rINST does not contain the opcode number.
150 * However some utilities require the full value, so this macro
151 * restores the opcode number.
152 */
153.macro REFRESH_INST _opnum
154    movb    rINSTbl, rINSTbh
155    movb    $$\_opnum, rINSTbl
156.endm
157
158/*
159 * Fetch the next instruction from rPC into rINSTw.  Does not advance rPC.
160 */
161.macro FETCH_INST
162    movzwl  (rPC), rINST
163.endm
164
165.macro FETCH_INST_CLEAR_OPCODE
166    movzbl 1(rPC), rINST
167.endm
168
169/*
170 * Remove opcode from rINST, compute the address of handler and jump to it.
171 */
172.macro GOTO_NEXT
173    movzx   rINSTbl,%ecx
174    movzbl  rINSTbh,rINST
175    shll    MACRO_LITERAL(${handler_size_bits}), %ecx
176    addl    rIBASE, %ecx
177    jmp     *%ecx
178.endm
179
180/*
181 * Advance rPC by instruction count.
182 */
183.macro ADVANCE_PC _count
184    leal    2*\_count(rPC), rPC
185.endm
186
187/*
188 * Advance rPC by instruction count, fetch instruction and jump to handler.
189 */
190.macro ADVANCE_PC_FETCH_AND_GOTO_NEXT _count
191    ADVANCE_PC \_count
192    FETCH_INST
193    GOTO_NEXT
194.endm
195
196.macro NTERP_DEF_CFA cfi_reg
197    CFI_DEF_CFA_BREG_PLUS_UCONST \cfi_reg, -4, CALLEE_SAVES_SIZE + PARAMETERS_SAVES_SIZE
198.endm
199
200.macro RESTORE_IBASE
201    call 0f
2020:
203    popl rIBASE
204    addl MACRO_LITERAL(SYMBOL(artNterpAsmInstructionStart) - 0b), rIBASE
205.endm
206
207.macro SPILL_ALL_CORE_PARAMETERS
208    PUSH_ARG eax
209    PUSH_ARG ecx
210    PUSH_ARG edx
211    PUSH_ARG ebx
212.endm
213
214.macro RESTORE_ALL_CORE_PARAMETERS
215    POP_ARG ebx
216    POP_ARG edx
217    POP_ARG ecx
218    POP_ARG eax
219.endm
220
221.macro DROP_PARAMETERS_SAVES
222    addl $$(PARAMETERS_SAVES_SIZE), %esp
223.endm
224
225.macro SAVE_WIDE_RETURN
226    movl %edx, LOCAL2(%esp)
227.endm
228
229.macro LOAD_WIDE_RETURN reg
230    movl LOCAL2(%esp), \reg
231.endm
232
233// An assembly entry that has a OatQuickMethodHeader prefix.
234.macro OAT_ENTRY name, end
235    FUNCTION_TYPE(\name)
236    ASM_HIDDEN SYMBOL(\name)
237    .global SYMBOL(\name)
238    .balign 16
239    // Padding of 3 * 4 bytes to get 16 bytes alignment of code entry.
240    .long 0
241    .long 0
242    .long 0
243    // OatQuickMethodHeader. Note that the top two bits must be clear.
244    .long (SYMBOL(\end) - SYMBOL(\name))
245SYMBOL(\name):
246.endm
247
248.macro ENTRY name
249    .text
250    ASM_HIDDEN SYMBOL(\name)
251    .global SYMBOL(\name)
252    FUNCTION_TYPE(\name)
253SYMBOL(\name):
254.endm
255
256.macro END name
257    SIZE(\name)
258.endm
259
260// Macro for defining entrypoints into runtime. We don't need to save registers
261// (we're not holding references there), but there is no
262// kDontSave runtime method. So just use the kSaveRefsOnly runtime method.
263.macro NTERP_TRAMPOLINE name, helper
264DEFINE_FUNCTION \name
265  movd %ebx, %xmm0
266  SETUP_SAVE_REFS_ONLY_FRAME ebx
267  movd %xmm0, %ebx
268  PUSH_ARG ebx
269  PUSH_ARG edx
270  PUSH_ARG ecx
271  PUSH_ARG eax
272  call \helper
273  addl MACRO_LITERAL(16), %esp
274  CFI_ADJUST_CFA_OFFSET(-16)
275  RESTORE_IBASE
276  FETCH_INST_CLEAR_OPCODE
277  RESTORE_SAVE_REFS_ONLY_FRAME
278  cmpl LITERAL(0), %fs:THREAD_EXCEPTION_OFFSET
279  jne nterp_deliver_pending_exception
280  ret
281END_FUNCTION \name
282.endm
283
284.macro CLEAR_VOLATILE_MARKER reg
285  andl MACRO_LITERAL(-2), \reg
286.endm
287
288.macro EXPORT_PC
289    movl    rPC, -8(rREFS)
290.endm
291
292.macro FETCH_PC
293    movl    -8(rREFS), rPC
294.endm
295
296
297.macro BRANCH
298    leal    (rPC, rINST, 2), rPC
299    // Update method counter and do a suspend check if the branch is negative or zero.
300    testl rINST, rINST
301    jle 3f
3022:
303    FETCH_INST
304    GOTO_NEXT
3053:
306    movl (%esp), %eax
307    movzwl ART_METHOD_HOTNESS_COUNT_OFFSET(%eax), %ecx
308#if (NTERP_HOTNESS_VALUE != 0)
309#error Expected 0 for hotness value
310#endif
311    // If the counter is at zero, handle this in the runtime.
312    testw %cx, %cx
313    je NterpHandleHotnessOverflow
314    // Update counter.
315    addl $$-1, %ecx
316    movw %cx, ART_METHOD_HOTNESS_COUNT_OFFSET(%eax)
317    DO_SUSPEND_CHECK continue_label=2b
318.endm
319
320// Expects:
321// - edx, and eax to be available.
322// Outputs:
323// - \registers contains the dex registers size
324// - \outs contains the outs size
325// - if load_ins is 1, \ins contains the ins
326// - \code_item is replaced with a pointer to the instructions
327.macro FETCH_CODE_ITEM_INFO code_item, registers, outs, ins, load_ins
328    testl MACRO_LITERAL(1), \code_item
329    je 5f
330    andl $$-2, \code_item  // Remove the extra bit that marks it's a compact dex file.
331    movzwl COMPACT_CODE_ITEM_FIELDS_OFFSET(\code_item), %edx
332    movl %edx, \registers
333    sarl $$COMPACT_CODE_ITEM_REGISTERS_SIZE_SHIFT, \registers
334    andl $$0xf, \registers
335    movl %edx, \outs
336    sarl $$COMPACT_CODE_ITEM_OUTS_SIZE_SHIFT, \outs
337    andl $$0xf, \outs
338    .if \load_ins
339    movl %edx, \ins
340    sarl $$COMPACT_CODE_ITEM_INS_SIZE_SHIFT, \ins
341    andl $$0xf, \ins
342    .else
343    movl %edx, %eax
344    sarl $$COMPACT_CODE_ITEM_INS_SIZE_SHIFT, %eax
345    andl $$0xf, %eax
346    addl %eax, \registers
347    .endif
348    testw $$COMPACT_CODE_ITEM_REGISTERS_INS_OUTS_FLAGS, COMPACT_CODE_ITEM_FLAGS_OFFSET(\code_item)
349    je 4f
350    movl \code_item, %eax
351    testw $$COMPACT_CODE_ITEM_INSNS_FLAG, COMPACT_CODE_ITEM_FLAGS_OFFSET(\code_item)
352    je 1f
353    subl $$4, %eax
3541:
355    testw $$COMPACT_CODE_ITEM_REGISTERS_FLAG, COMPACT_CODE_ITEM_FLAGS_OFFSET(\code_item)
356    je 2f
357    subl $$2, %eax
358    movzwl (%eax), %edx
359    addl %edx, \registers
3602:
361    testw $$COMPACT_CODE_ITEM_INS_FLAG, COMPACT_CODE_ITEM_FLAGS_OFFSET(\code_item)
362    je 3f
363    subl $$2, %eax
364    movzwl (%eax), %edx
365    .if \load_ins
366    addl %edx, \ins
367    .else
368    addl %edx, \registers
369    .endif
3703:
371    testw $$COMPACT_CODE_ITEM_OUTS_FLAG, COMPACT_CODE_ITEM_FLAGS_OFFSET(\code_item)
372    je 4f
373    subl $$2, %eax
374    movzwl (%eax), %edx
375    addl %edx, \outs
3764:
377    .if \load_ins
378    addl \ins, \registers
379    .endif
380    addl $$COMPACT_CODE_ITEM_INSNS_OFFSET, \code_item
381    jmp 6f
3825:
383    // Fetch dex register size.
384    movzwl CODE_ITEM_REGISTERS_SIZE_OFFSET(\code_item), \registers
385    // Fetch outs size.
386    movzwl CODE_ITEM_OUTS_SIZE_OFFSET(\code_item), \outs
387    .if \load_ins
388    movzwl CODE_ITEM_INS_SIZE_OFFSET(\code_item), \ins
389    .endif
390    addl $$CODE_ITEM_INSNS_OFFSET, \code_item
3916:
392.endm
393
394// Setup the stack to start executing the method. Expects:
395// - eax, edx, and ebx to be available.
396//
397// Inputs
398// - code_item: where the code item is
399// - refs: register where the pointer to dex references will be
400// - fp: register where the pointer to dex values will be
401// - cfi_refs: CFI register number of refs
402// - load_ins: whether to store the 'ins' value of the code item in esi
403//
404// Outputs
405// - ebx contains the dex registers size
406// - edx contains the old stack pointer.
407// - \code_item is replace with a pointer to the instructions
408// - if load_ins is 1, esi contains the ins
409.macro SETUP_STACK_FRAME code_item, refs, fp, cfi_refs, load_ins
410    FETCH_CODE_ITEM_INFO \code_item, %ebx, \refs, %esi, \load_ins
411
412    movl $$3, %eax
413    cmpl $$2, \refs
414    cmovle %eax, \refs
415
416    // Compute required frame size for dex registers: ((2 * ebx) + refs)
417    leal (\refs, %ebx, 2), %edx
418    sall $$2, %edx
419
420    // Compute new stack pointer in fp: add 12 for saving the previous frame,
421    // pc, and method being executed.
422    leal -12(%esp), \fp
423    subl %edx, \fp
424    // Alignment
425    andl $$-16, \fp
426
427    // Now setup the stack pointer.
428    movl %esp, %edx
429    CFI_DEF_CFA_REGISTER(edx)
430    movl \fp, %esp
431
432    leal 12(%esp, \refs, 4), \refs
433    leal (\refs, %ebx, 4), \fp
434
435    // Save old stack pointer.
436    movl %edx, -4(\refs)
437    NTERP_DEF_CFA \cfi_refs
438
439    // Save ArtMethod.
440    movl 12(%edx), %eax
441    movl %eax, (%esp)
442
443    // Put nulls in reference frame.
444    testl %ebx, %ebx
445    je 2f
446    movl \refs, %eax
4471:
448    movl $$0, (%eax)
449    addl $$4, %eax
450    cmpl %eax, \fp
451    jne 1b
4522:
453.endm
454
455// Puts the next floating point argument into the expected register,
456// fetching values based on a non-range invoke.
457// Uses eax as temporary.
458//
459// TODO: We could simplify a lot of code by loading the G argument into
460// the "inst" register. Given that we enter the handler with "1(rPC)" in
461// the rINST, we can just add rINST<<16 to the args and we don't even
462// need to pass "arg_index" around.
463.macro LOOP_OVER_SHORTY_LOADING_XMMS xmm_reg, inst, shorty, arg_index, finished
4641: // LOOP
465    movb (REG_VAR(shorty)), %al             // al := *shorty
466    addl MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
467    cmpb MACRO_LITERAL(0), %al              // if (al == '\0') goto finished
468    je VAR(finished)
469    cmpb MACRO_LITERAL(68), %al             // if (al == 'D') goto FOUND_DOUBLE
470    je 2f
471    cmpb MACRO_LITERAL(70), %al             // if (al == 'F') goto FOUND_FLOAT
472    je 3f
473    shrl MACRO_LITERAL(4), REG_VAR(inst)
474    addl MACRO_LITERAL(1), REG_VAR(arg_index)
475    //  Handle extra argument in arg array taken by a long.
476    cmpb MACRO_LITERAL(74), %al   // if (al != 'J') goto LOOP
477    jne 1b
478    shrl MACRO_LITERAL(4), REG_VAR(inst)
479    addl MACRO_LITERAL(1), REG_VAR(arg_index)
480    jmp 1b                        // goto LOOP
4812:  // FOUND_DOUBLE
482    subl MACRO_LITERAL(8), %esp
483    movl REG_VAR(inst), %eax
484    andl MACRO_LITERAL(0xf), %eax
485    GET_VREG %eax, %eax
486    movl %eax, (%esp)
487    shrl MACRO_LITERAL(4), REG_VAR(inst)
488    addl MACRO_LITERAL(1), REG_VAR(arg_index)
489    cmpl MACRO_LITERAL(4), REG_VAR(arg_index)
490    je 5f
491    movl REG_VAR(inst), %eax
492    andl MACRO_LITERAL(0xf), %eax
493    shrl MACRO_LITERAL(4), REG_VAR(inst)
494    addl MACRO_LITERAL(1), REG_VAR(arg_index)
495    jmp 6f
4965:
497    movzbl 1(rPC), %eax
498    andl MACRO_LITERAL(0xf), %eax
4996:
500    GET_VREG %eax, %eax
501    movl %eax, 4(%esp)
502    movq (%esp), REG_VAR(xmm_reg)
503    addl MACRO_LITERAL(8), %esp
504    jmp 4f
5053:  // FOUND_FLOAT
506    cmpl MACRO_LITERAL(4), REG_VAR(arg_index)
507    je 7f
508    movl REG_VAR(inst), %eax
509    andl MACRO_LITERAL(0xf), %eax
510    shrl MACRO_LITERAL(4), REG_VAR(inst)
511    addl MACRO_LITERAL(1), REG_VAR(arg_index)
512    jmp 8f
5137:
514    movzbl 1(rPC), %eax
515    andl MACRO_LITERAL(0xf), %eax
5168:
517    GET_VREG_XMMs REG_VAR(xmm_reg), %eax
5184:
519.endm
520
521// Puts the next int/long/object argument in the expected register,
522// fetching values based on a non-range invoke.
523// Uses eax as temporary.
524.macro LOOP_OVER_SHORTY_LOADING_GPRS gpr_reg, gpr_long_reg, inst, shorty, arg_index, finished, if_long, is_ebx
5251: // LOOP
526    movb (REG_VAR(shorty)), %al   // al := *shorty
527    addl MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
528    cmpb MACRO_LITERAL(0), %al    // if (al == '\0') goto finished
529    je  VAR(finished)
530    cmpb MACRO_LITERAL(74), %al   // if (al == 'J') goto FOUND_LONG
531    je 2f
532    cmpb MACRO_LITERAL(70), %al   // if (al == 'F') goto SKIP_FLOAT
533    je 3f
534    cmpb MACRO_LITERAL(68), %al   // if (al == 'D') goto SKIP_DOUBLE
535    je 4f
536    cmpl MACRO_LITERAL(4), REG_VAR(arg_index)
537    je 7f
538    movl REG_VAR(inst), %eax
539    andl MACRO_LITERAL(0xf), %eax
540    shrl MACRO_LITERAL(4), REG_VAR(inst)
541    addl MACRO_LITERAL(1), REG_VAR(arg_index)
542    jmp 8f
5437:
544    // Fetch PC
545    movl LOCAL1(%esp), %eax
546    movl -8(%eax), %eax
547    movzbl 1(%eax), %eax
548    andl MACRO_LITERAL(0xf), %eax
5498:
550    GET_VREG REG_VAR(gpr_reg), %eax
551    jmp 5f
5522:  // FOUND_LONG
553    .if \is_ebx
554    // Put back shorty and exit
555    subl MACRO_LITERAL(1), REG_VAR(shorty)
556    jmp 5f
557    .else
558    movl REG_VAR(inst), %eax
559    andl MACRO_LITERAL(0xf), %eax
560    GET_VREG REG_VAR(gpr_reg), %eax
561    shrl MACRO_LITERAL(4), REG_VAR(inst)
562    addl MACRO_LITERAL(1), REG_VAR(arg_index)
563    cmpl MACRO_LITERAL(4), REG_VAR(arg_index)
564    je 9f
565    movl REG_VAR(inst), %eax
566    andl MACRO_LITERAL(0xf), %eax
567    shrl MACRO_LITERAL(4), REG_VAR(inst)
568    addl MACRO_LITERAL(1), REG_VAR(arg_index)
569    jmp 10f
5709:
571    // Fetch PC
572    movl LOCAL1(%esp), %eax
573    movl -8(%eax), %eax
574    movzbl 1(%eax), %eax
575    andl MACRO_LITERAL(0xf), %eax
57610:
577    GET_VREG REG_VAR(gpr_long_reg), %eax
578    jmp \if_long
579    .endif
5803:  // SKIP_FLOAT
581    shrl MACRO_LITERAL(4), REG_VAR(inst)
582    addl MACRO_LITERAL(1), REG_VAR(arg_index)
583    jmp 1b
5844:  // SKIP_DOUBLE
585    shrl MACRO_LITERAL(8), REG_VAR(inst)
586    addl MACRO_LITERAL(2), REG_VAR(arg_index)
587    jmp 1b
5885:
589.endm
590
591// Puts the next int/long/object argument in the expected stack slot,
592// fetching values based on a non-range invoke.
593// Uses eax as temporary.
594.macro LOOP_OVER_SHORTY_LOADING_INTS stack_offset, shorty, inst, arg_index, finished, is_string_init
5951:  // LOOP
596    movb (REG_VAR(shorty)), %al   // al := *shorty
597    addl MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
598    cmpb MACRO_LITERAL(0), %al    // if (al == '\0') goto finished
599    je  VAR(finished)
600    cmpb MACRO_LITERAL(74), %al   // if (al == 'J') goto FOUND_LONG
601    je 2f
602    cmpb MACRO_LITERAL(70), %al   // if (al == 'F') goto SKIP_FLOAT
603    je 3f
604    cmpb MACRO_LITERAL(68), %al   // if (al == 'D') goto SKIP_DOUBLE
605    je 4f
606    .if \is_string_init
607    cmpl MACRO_LITERAL(3), REG_VAR(arg_index)
608    .else
609    cmpl MACRO_LITERAL(4), REG_VAR(arg_index)
610    .endif
611    je 7f
612    movl REG_VAR(inst), %eax
613    andl MACRO_LITERAL(0xf), %eax
614    shrl MACRO_LITERAL(4), REG_VAR(inst)
615    jmp 8f
6167:
617    // Fetch PC.
618    movl (LOCAL1 + \stack_offset)(%esp), %eax
619    movl -8(%eax), %eax
620    movzbl 1(%eax), %eax
621    andl MACRO_LITERAL(0xf), %eax
6228:
623    GET_VREG %eax, %eax
624    // Add 4 for the ArtMethod.
625    movl %eax, (4 + \stack_offset)(%esp, REG_VAR(arg_index), 4)
626    addl MACRO_LITERAL(1), REG_VAR(arg_index)
627    jmp 1b
6282:  // FOUND_LONG
629    movl REG_VAR(inst), %eax
630    andl MACRO_LITERAL(0xf), %eax
631    GET_VREG %eax, %eax
632    // Add 4 for the ArtMethod.
633    movl %eax, (4 + \stack_offset)(%esp, REG_VAR(arg_index), 4)
634    shrl MACRO_LITERAL(4), REG_VAR(inst)
635    addl MACRO_LITERAL(1), REG_VAR(arg_index)
636    .if \is_string_init
637    cmpl MACRO_LITERAL(3), REG_VAR(arg_index)
638    .else
639    cmpl MACRO_LITERAL(4), REG_VAR(arg_index)
640    .endif
641    je 9f
642    movl REG_VAR(inst), %eax
643    andl MACRO_LITERAL(0xf), %eax
644    shrl MACRO_LITERAL(4), REG_VAR(inst)
645    jmp 10f
6469:
647    // Fetch PC.
648    movl (LOCAL1 + \stack_offset)(%esp), %eax
649    movl -8(%eax), %eax
650    movzbl 1(%eax), %eax
651    andl MACRO_LITERAL(0xf), %eax
65210:
653    GET_VREG %eax, %eax
654    // +4 for the ArtMethod.
655    movl %eax, (4 + \stack_offset)(%esp, REG_VAR(arg_index), 4)
656    addl MACRO_LITERAL(1), REG_VAR(arg_index)
657    jmp 1b
6583:  // SKIP_FLOAT
659    shrl MACRO_LITERAL(4), REG_VAR(inst)
660    addl MACRO_LITERAL(1), REG_VAR(arg_index)
661    jmp 1b
6624:  // SKIP_DOUBLE
663    shrl MACRO_LITERAL(8), REG_VAR(inst)
664    addl MACRO_LITERAL(2), REG_VAR(arg_index)
665    jmp 1b
666.endm
667
668// Puts the next floating point argument into the expected register,
669// fetching values based on a range invoke.
670// Uses eax as temporary.
671.macro LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm_reg, shorty, arg_index, stack_index, finished
6721: // LOOP
673    movb (REG_VAR(shorty)), %al             // al := *shorty
674    addl MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
675    cmpb MACRO_LITERAL(0), %al              // if (al == '\0') goto finished
676    je VAR(finished)
677    cmpb MACRO_LITERAL(68), %al             // if (al == 'D') goto FOUND_DOUBLE
678    je 2f
679    cmpb MACRO_LITERAL(70), %al             // if (al == 'F') goto FOUND_FLOAT
680    je 3f
681    addl MACRO_LITERAL(1), REG_VAR(arg_index)
682    addl MACRO_LITERAL(1), REG_VAR(stack_index)
683    //  Handle extra argument in arg array taken by a long.
684    cmpb MACRO_LITERAL(74), %al   // if (al != 'J') goto LOOP
685    jne 1b
686    addl MACRO_LITERAL(1), REG_VAR(arg_index)
687    addl MACRO_LITERAL(1), REG_VAR(stack_index)
688    jmp 1b                        // goto LOOP
6892:  // FOUND_DOUBLE
690    GET_VREG_XMMd REG_VAR(xmm_reg), REG_VAR(arg_index)
691    addl MACRO_LITERAL(2), REG_VAR(arg_index)
692    addl MACRO_LITERAL(2), REG_VAR(stack_index)
693    jmp 4f
6943:  // FOUND_FLOAT
695    GET_VREG_XMMs REG_VAR(xmm_reg), REG_VAR(arg_index)
696    addl MACRO_LITERAL(1), REG_VAR(arg_index)
697    add MACRO_LITERAL(1), REG_VAR(stack_index)
6984:
699.endm
700
701// Puts the next floating point argument into the expected stack slot,
702// fetching values based on a range invoke.
703// Uses eax as temporary.
704//
705// TODO: We could just copy all the vregs to the stack slots in a simple loop
706// (or REP MOVSD) without looking at the shorty at all. (We could also drop
707// the "stack_index" from the macros for loading registers.) We could also do
708// that conditionally if argument word count > 3; otherwise we know that all
709// args fit into registers.
710.macro LOOP_RANGE_OVER_FPs shorty, arg_index, stack_index, finished
7111: // LOOP
712    movb (REG_VAR(shorty)), %al             // bl := *shorty
713    addl MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
714    cmpb MACRO_LITERAL(0), %al              // if (al == '\0') goto finished
715    je VAR(finished)
716    cmpb MACRO_LITERAL(68), %al             // if (al == 'D') goto FOUND_DOUBLE
717    je 2f
718    cmpb MACRO_LITERAL(70), %al             // if (al == 'F') goto FOUND_FLOAT
719    je 3f
720    addl MACRO_LITERAL(1), REG_VAR(arg_index)
721    addl MACRO_LITERAL(1), REG_VAR(stack_index)
722    //  Handle extra argument in arg array taken by a long.
723    cmpb MACRO_LITERAL(74), %al   // if (al != 'J') goto LOOP
724    jne 1b
725    addl MACRO_LITERAL(1), REG_VAR(arg_index)
726    addl MACRO_LITERAL(1), REG_VAR(stack_index)
727    jmp 1b                        // goto LOOP
7282:  // FOUND_DOUBLE
729    movq (rFP, REG_VAR(arg_index), 4), %xmm4
730    movq %xmm4, 4(%esp, REG_VAR(stack_index), 4)
731    addl MACRO_LITERAL(2), REG_VAR(arg_index)
732    addl MACRO_LITERAL(2), REG_VAR(stack_index)
733    jmp 1b
7343:  // FOUND_FLOAT
735    movl (rFP, REG_VAR(arg_index), 4), %eax
736    movl %eax, 4(%esp, REG_VAR(stack_index), 4)
737    addl MACRO_LITERAL(1), REG_VAR(arg_index)
738    addl MACRO_LITERAL(1), REG_VAR(stack_index)
739    jmp 1b
740.endm
741
742// Puts the next int/long/object argument in the expected register,
743// fetching values based on a range invoke.
744// Uses eax as temporary.
745.macro LOOP_RANGE_OVER_SHORTY_LOADING_GPRS gpr_reg, gpr_long_reg, shorty, arg_index, stack_index, finished, if_long, is_ebx
7461: // LOOP
747    movb (REG_VAR(shorty)), %al             // al := *shorty
748    addl MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
749    cmpb MACRO_LITERAL(0), %al    // if (al == '\0') goto finished
750    je VAR(finished)
751    cmpb MACRO_LITERAL(74), %al   // if (al == 'J') goto FOUND_LONG
752    je 2f
753    cmpb MACRO_LITERAL(70), %al   // if (al == 'F') goto SKIP_FLOAT
754    je 3f
755    cmpb MACRO_LITERAL(68), %al   // if (al == 'D') goto SKIP_DOUBLE
756    je 4f
757    movl       (rFP, REG_VAR(arg_index), 4), REG_VAR(gpr_reg)
758    addl MACRO_LITERAL(1), REG_VAR(arg_index)
759    addl MACRO_LITERAL(1), REG_VAR(stack_index)
760    jmp 5f
7612:  // FOUND_LONG
762    .if \is_ebx
763    // Put back shorty and exit
764    subl MACRO_LITERAL(1), REG_VAR(shorty)
765    .else
766    movl (rFP, REG_VAR(arg_index), 4), REG_VAR(gpr_reg)
767    movl 4(rFP, REG_VAR(arg_index), 4), REG_VAR(gpr_long_reg)
768    addl MACRO_LITERAL(2), REG_VAR(arg_index)
769    addl MACRO_LITERAL(2), REG_VAR(stack_index)
770    .endif
771    jmp \if_long
7723:  // SKIP_FLOAT
773    addl MACRO_LITERAL(1), REG_VAR(arg_index)
774    addl MACRO_LITERAL(1), REG_VAR(stack_index)
775    jmp 1b
7764:  // SKIP_DOUBLE
777    addl MACRO_LITERAL(2), REG_VAR(arg_index)
778    addl MACRO_LITERAL(2), REG_VAR(stack_index)
779    jmp 1b
7805:
781.endm
782
783// Puts the next int/long/object argument in the expected stack slot,
784// fetching values based on a range invoke.
785// Uses eax as temporary.
786.macro LOOP_RANGE_OVER_INTs offset, shorty, arg_index, stack_index, finished
7871: // LOOP
788    movb (REG_VAR(shorty)), %al             // al := *shorty
789    addl MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
790    cmpb MACRO_LITERAL(0), %al    // if (al == '\0') goto finished
791    je  VAR(finished)
792    cmpb MACRO_LITERAL(74), %al   // if (al == 'J') goto FOUND_LONG
793    je 2f
794    cmpb MACRO_LITERAL(70), %al   // if (al == 'F') goto SKIP_FLOAT
795    je 3f
796    cmpb MACRO_LITERAL(68), %al   // if (al == 'D') goto SKIP_DOUBLE
797    je 4f
798    movl (rFP, REG_VAR(arg_index), 4), %eax
799    // Add 4 for the ArtMethod.
800    movl %eax, (4 + \offset)(%esp, REG_VAR(stack_index), 4)
8013:  // SKIP_FLOAT
802    addl MACRO_LITERAL(1), REG_VAR(arg_index)
803    addl MACRO_LITERAL(1), REG_VAR(stack_index)
804    jmp 1b
8052:  // FOUND_LONG
806    movl (rFP, REG_VAR(arg_index), 4), %eax
807    // Add 4 for the ArtMethod.
808    movl %eax, (4 + \offset)(%esp, REG_VAR(stack_index), 4)
809    movl 4(rFP, REG_VAR(arg_index), 4), %eax
810    // Add 4 for the ArtMethod and 4 for other half.
811    movl %eax, (4 + 4 + \offset)(%esp, REG_VAR(stack_index), 4)
8124:  // SKIP_DOUBLE
813    addl MACRO_LITERAL(2), REG_VAR(arg_index)
814    addl MACRO_LITERAL(2), REG_VAR(stack_index)
815    jmp 1b
816.endm
817
818// Puts the next floating point parameter passed in physical register
819// in the expected dex register array entry.
820// Uses eax as temporary.
821.macro LOOP_OVER_SHORTY_STORING_XMMS xmm_reg, shorty, arg_index, fp, finished
8221: // LOOP
823    movb (REG_VAR(shorty)), %al             // al := *shorty
824    addl MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
825    cmpb MACRO_LITERAL(0), %al              // if (al == '\0') goto finished
826    je VAR(finished)
827    cmpb MACRO_LITERAL(68), %al             // if (al == 'D') goto FOUND_DOUBLE
828    je 2f
829    cmpb MACRO_LITERAL(70), %al             // if (al == 'F') goto FOUND_FLOAT
830    je 3f
831    addl MACRO_LITERAL(1), REG_VAR(arg_index)
832    //  Handle extra argument in arg array taken by a long.
833    cmpb MACRO_LITERAL(74), %al   // if (al != 'J') goto LOOP
834    jne 1b
835    addl MACRO_LITERAL(1), REG_VAR(arg_index)
836    jmp 1b                        // goto LOOP
8372:  // FOUND_DOUBLE
838    movq REG_VAR(xmm_reg),(REG_VAR(fp), REG_VAR(arg_index), 4)
839    addl MACRO_LITERAL(2), REG_VAR(arg_index)
840    jmp 4f
8413:  // FOUND_FLOAT
842    movss REG_VAR(xmm_reg), (REG_VAR(fp), REG_VAR(arg_index), 4)
843    addl MACRO_LITERAL(1), REG_VAR(arg_index)
8444:
845.endm
846
847// Puts the next int/long/object parameter passed in physical register
848// in the expected dex register array entry, and in case of object in the
849// expected reference array entry.
850// Uses eax as temporary.
851.macro LOOP_OVER_SHORTY_STORING_GPRS offset, offset_long, stack_ptr, shorty, arg_index, regs, refs, finished, if_long, is_ebx
8521: // LOOP
853    movb (REG_VAR(shorty)), %al             // al := *shorty
854    addl MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
855    cmpb MACRO_LITERAL(0), %al    // if (al == '\0') goto finished
856    je  VAR(finished)
857    cmpb MACRO_LITERAL(74), %al   // if (al == 'J') goto FOUND_LONG
858    je 2f
859    cmpb MACRO_LITERAL(70), %al   // if (al == 'F') goto SKIP_FLOAT
860    je 3f
861    cmpb MACRO_LITERAL(68), %al   // if (al == 'D') goto SKIP_DOUBLE
862    je 4f
863    cmpb MACRO_LITERAL(76), %al   // if (al != 'L') goto NOT_REFERENCE
864    jne 6f
865    movl \offset(REG_VAR(stack_ptr)), %eax
866    movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 4)
867    movl %eax, (REG_VAR(refs), REG_VAR(arg_index), 4)
868    addl MACRO_LITERAL(1), REG_VAR(arg_index)
869    jmp 5f
8702:  // FOUND_LONG
871    .if \is_ebx
872    // Put back shorty and jump to \if_long
873    subl MACRO_LITERAL(1), REG_VAR(shorty)
874    .else
875    movl \offset(REG_VAR(stack_ptr)), %eax
876    movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 4)
877    movl \offset_long(REG_VAR(stack_ptr)), %eax
878    movl %eax, 4(REG_VAR(regs), REG_VAR(arg_index), 4)
879    addl MACRO_LITERAL(2), REG_VAR(arg_index)
880    .endif
881    jmp \if_long
8823:  // SKIP_FLOAT
883    addl MACRO_LITERAL(1), REG_VAR(arg_index)
884    jmp 1b
8854:  // SKIP_DOUBLE
886    addl MACRO_LITERAL(2), REG_VAR(arg_index)
887    jmp 1b
8886:  // NOT_REFERENCE
889    movl \offset(REG_VAR(stack_ptr)), %eax
890    movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 4)
891    addl MACRO_LITERAL(1), REG_VAR(arg_index)
8925:
893.endm
894
895// Puts the next floating point parameter passed in stack
896// in the expected dex register array entry.
897// Uses eax as temporary.
898//
899// TODO: Or we could just spill regs to the reserved slots in the caller's
900// frame and copy all regs in a simple loop. This time, however, we would
901// need to look at the shorty anyway to look for the references.
902// (The trade-off is different for passing arguments and receiving them.)
903.macro LOOP_OVER_FPs shorty, arg_index, regs, stack_ptr, finished
9041: // LOOP
905    movb (REG_VAR(shorty)), %al             // al := *shorty
906    addl MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
907    cmpb MACRO_LITERAL(0), %al              // if (al == '\0') goto finished
908    je VAR(finished)
909    cmpb MACRO_LITERAL(68), %al             // if (al == 'D') goto FOUND_DOUBLE
910    je 2f
911    cmpb MACRO_LITERAL(70), %al             // if (al == 'F') goto FOUND_FLOAT
912    je 3f
913    addl MACRO_LITERAL(1), REG_VAR(arg_index)
914    //  Handle extra argument in arg array taken by a long.
915    cmpb MACRO_LITERAL(74), %al   // if (al != 'J') goto LOOP
916    jne 1b
917    addl MACRO_LITERAL(1), REG_VAR(arg_index)
918    jmp 1b                        // goto LOOP
9192:  // FOUND_DOUBLE
920    movq OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 4), %xmm4
921    movq %xmm4, (REG_VAR(regs), REG_VAR(arg_index), 4)
922    addl MACRO_LITERAL(2), REG_VAR(arg_index)
923    jmp 1b
9243:  // FOUND_FLOAT
925    movl OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 4), %eax
926    movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 4)
927    addl MACRO_LITERAL(1), REG_VAR(arg_index)
928    jmp 1b
929.endm
930
931// Puts the next int/long/object parameter passed in stack
932// in the expected dex register array entry, and in case of object in the
933// expected reference array entry.
934// Uses eax as temporary.
935.macro LOOP_OVER_INTs shorty, arg_index, regs, refs, stack_ptr, finished
9361: // LOOP
937    movb (REG_VAR(shorty)), %al             // al := *shorty
938    addl MACRO_LITERAL(1), REG_VAR(shorty)  // shorty++
939    cmpb MACRO_LITERAL(0), %al    // if (al == '\0') goto finished
940    je  VAR(finished)
941    cmpb MACRO_LITERAL(74), %al   // if (al == 'J') goto FOUND_LONG
942    je 2f
943    cmpb MACRO_LITERAL(76), %al   // if (al == 'L') goto FOUND_REFERENCE
944    je 6f
945    cmpb MACRO_LITERAL(70), %al   // if (al == 'F') goto SKIP_FLOAT
946    je 3f
947    cmpb MACRO_LITERAL(68), %al   // if (al == 'D') goto SKIP_DOUBLE
948    je 4f
949    movl OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 4), %eax
950    movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 4)
951    addl MACRO_LITERAL(1), REG_VAR(arg_index)
952    jmp 1b
9536:  // FOUND_REFERENCE
954    movl OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 4), %eax
955    movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 4)
956    movl %eax, (REG_VAR(refs), REG_VAR(arg_index), 4)
9573:  // SKIP_FLOAT
958    addl MACRO_LITERAL(1), REG_VAR(arg_index)
959    jmp 1b
9602:  // FOUND_LONG
961    movl OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 4), %eax
962    movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 4)
963    movl (OFFSET_TO_FIRST_ARGUMENT_IN_STACK+4)(REG_VAR(stack_ptr), REG_VAR(arg_index), 4), %eax
964    movl %eax, 4(REG_VAR(regs), REG_VAR(arg_index), 4)
9654:  // SKIP_DOUBLE
966    addl MACRO_LITERAL(2), REG_VAR(arg_index)
967    jmp 1b
968.endm
969
970// Increase method hotness and do suspend check before starting executing the method.
971.macro START_EXECUTING_INSTRUCTIONS
972   movl (%esp), %eax
973   movzwl ART_METHOD_HOTNESS_COUNT_OFFSET(%eax), %ecx
974#if (NTERP_HOTNESS_VALUE != 0)
975#error Expected 0 for hotness value
976#endif
977   // If the counter is at zero, handle this in the runtime.
978   testl %ecx, %ecx
979   je 3f
980   // Update counter.
981   addl $$-1, %ecx
982   movw %cx, ART_METHOD_HOTNESS_COUNT_OFFSET(%eax)
9831:
984   testl $$(THREAD_SUSPEND_OR_CHECKPOINT_REQUEST), rSELF:THREAD_FLAGS_OFFSET
985   jz 2f
986   EXPORT_PC
987   call SYMBOL(art_quick_test_suspend)
988   RESTORE_IBASE
9892:
990   FETCH_INST
991   GOTO_NEXT
9923:
993   CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot=4f, if_not_hot=1b
9944:
995   movl $$0, ARG1
996   movl rFP, ARG2
997   call nterp_hot_method
998   jmp 2b
999.endm
1000
1001.macro SPILL_ALL_CALLEE_SAVES
1002    PUSH edi
1003    PUSH esi
1004    PUSH ebp
1005.endm
1006
1007.macro RESTORE_ALL_CALLEE_SAVES
1008    POP ebp
1009    POP esi
1010    POP edi
1011.endm
1012
1013.macro GET_SHORTY dest, is_interface, is_polymorphic, is_custom
1014   // Save eax (ArtMethod), ecx (potential this).
1015   push %eax
1016   push %ecx
1017   .if \is_polymorphic
1018   push rPC
1019   push 12(%esp)
1020   call SYMBOL(NterpGetShortyFromInvokePolymorphic)
1021   addl MACRO_LITERAL(8), %esp
1022   .elseif \is_custom
1023   push rPC
1024   push 12(%esp)
1025   call SYMBOL(NterpGetShortyFromInvokeCustom)
1026   addl MACRO_LITERAL(8), %esp
1027   .elseif \is_interface
1028   subl MACRO_LITERAL(16), %esp
1029   // Save interface method.
1030   movss %xmm7, (%esp)
1031   movzwl 2(rPC), %eax
1032   pushl %eax
1033   // Caller is at 8 (saved ArtMethod + ecx) + 16 + 4 (second argument)
1034   pushl 28(%esp)
1035   call SYMBOL(NterpGetShortyFromMethodId)
1036   // Restore interface method.
1037   movss 8(%esp), %xmm7
1038   addl MACRO_LITERAL(24), %esp
1039   .else
1040   subl MACRO_LITERAL(4), %esp  // Alignment
1041   push %eax
1042   call SYMBOL(NterpGetShorty)
1043   addl MACRO_LITERAL(8), %esp
1044   .endif
1045   movl %eax, \dest
1046   pop %ecx
1047   pop %eax
1048.endm
1049
1050.macro GET_SHORTY_SLOW_PATH dest, is_interface
1051   // Save all registers that can hold arguments in the fast path.
1052   pushl %eax
1053   pushl %ecx
1054   pushl %edx
1055   subl MACRO_LITERAL(4), %esp
1056   movss %xmm0, (%esp)
1057   .if \is_interface
1058   // Alignment.
1059   subl MACRO_LITERAL(8), %esp
1060   movzwl 2(rPC), %eax
1061   pushl %eax
1062   // Caller is at 16 (parameters) + 8 (alignment) + 4 (second argument).
1063   pushl 28(%esp)
1064   call SYMBOL(NterpGetShortyFromMethodId)
1065   movl %eax, \dest
1066   movss 16(%esp), %xmm0
1067   addl MACRO_LITERAL(20), %esp
1068   .else
1069   // Alignment.
1070   subl MACRO_LITERAL(12), %esp
1071   pushl %eax
1072   call SYMBOL(NterpGetShorty)
1073   movl %eax, \dest
1074   movss 16(%esp), %xmm0
1075   addl MACRO_LITERAL(20), %esp
1076   .endif
1077   popl %edx
1078   popl %ecx
1079   popl %eax
1080.endm
1081
1082// Uses ecx and edx as temporary
1083.macro UPDATE_REGISTERS_FOR_STRING_INIT old_value, new_value
1084   movl rREFS, %edx
1085   movl rFP, %ecx
10861:
1087   cmpl (%edx), \old_value
1088   jne 2f
1089   movl \new_value, (%edx)
1090   movl \new_value, (%ecx)
10912:
1092   addl $$4, %edx
1093   addl $$4, %ecx
1094   cmpl %edx, rFP
1095   jne 1b
1096.endm
1097
1098.macro DO_CALL is_polymorphic, is_custom
1099   .if \is_polymorphic
1100   call SYMBOL(art_quick_invoke_polymorphic)
1101   .elseif \is_custom
1102   call SYMBOL(art_quick_invoke_custom)
1103   .else
1104   call *ART_METHOD_QUICK_CODE_OFFSET_32(%eax)
1105   .endif
1106.endm
1107
1108.macro COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
1109   .if \is_polymorphic
1110   // No fast path for polymorphic calls.
1111   .elseif \is_custom
1112   // No fast path for custom calls.
1113   .elseif \is_string_init
1114   // No fast path for string.init.
1115   .else
1116     testl $$ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG, ART_METHOD_ACCESS_FLAGS_OFFSET(%eax)
1117     je .Lfast_path_with_few_args_\suffix
1118     movzbl 1(rPC), %edx
1119     movl %edx, %ebx
1120     shrl MACRO_LITERAL(4), %ebx # Number of arguments
1121     .if \is_static
1122     jz .Linvoke_fast_path_\suffix  # shl sets the Z flag
1123     .else
1124     cmpl MACRO_LITERAL(1), %ebx
1125     je .Linvoke_fast_path_\suffix
1126     .endif
1127     movzwl 4(rPC), %esi
1128     cmpl MACRO_LITERAL(2), %ebx
1129     .if \is_static
1130     jl .Lone_arg_fast_path_\suffix
1131     .endif
1132     je .Ltwo_args_fast_path_\suffix
1133     cmpl MACRO_LITERAL(4), %ebx
1134     jl .Lthree_args_fast_path_\suffix
1135     je .Lfour_args_fast_path_\suffix
1136
1137     andl        MACRO_LITERAL(0xf), %edx
1138     GET_VREG    %edx, %edx
1139     movl        %edx, (4 + 4 * 4)(%esp)
1140.Lfour_args_fast_path_\suffix:
1141     movl        %esi, %edx
1142     shrl        MACRO_LITERAL(12), %edx
1143     GET_VREG    %edx, %edx
1144     movl        %edx, (4 + 3 * 4)(%esp)
1145.Lthree_args_fast_path_\suffix:
1146     movl        %esi, %ebx
1147     shrl        MACRO_LITERAL(8), %ebx
1148     andl        MACRO_LITERAL(0xf), %ebx
1149     GET_VREG    %ebx, %ebx
1150.Ltwo_args_fast_path_\suffix:
1151     movl        %esi, %edx
1152     shrl        MACRO_LITERAL(4), %edx
1153     andl        MACRO_LITERAL(0xf), %edx
1154     GET_VREG    %edx, %edx
1155.Lone_arg_fast_path_\suffix:
1156     .if \is_static
1157     andl        MACRO_LITERAL(0xf), %esi
1158     GET_VREG    %ecx, %esi
1159     .else
1160     // First argument already in %ecx.
1161     .endif
1162.Linvoke_fast_path_\suffix:
1163     // Fetch PC before calling for proper stack unwinding.
1164     FETCH_PC
1165     call *ART_METHOD_QUICK_CODE_OFFSET_32(%eax) // Call the method.
1166     // In case of a long return, save the high half into LOCAL0
1167     SAVE_WIDE_RETURN
1168     RESTORE_IBASE
1169     ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
1170
1171.Lfast_path_with_few_args_\suffix:
1172     // Fast path when we have zero or one argument (modulo 'this'). If there
1173     // is one argument, we can put it in both floating point and core register.
1174     movzbl 1(rPC), %edx
1175     shrl MACRO_LITERAL(4), %edx # Number of arguments
1176     .if \is_static
1177     cmpl MACRO_LITERAL(1), %edx
1178     jl .Linvoke_with_few_args_\suffix
1179     jne .Lget_shorty_\suffix
1180     movzwl 4(rPC), %ecx
1181     andl MACRO_LITERAL(0xf), %ecx  // dex register of first argument
1182     GET_VREG %ecx, %ecx
1183     movd %ecx, %xmm0
1184     .else
1185     cmpl MACRO_LITERAL(2), %edx
1186     jl .Linvoke_with_few_args_\suffix
1187     jne .Lget_shorty_\suffix
1188     movzwl 4(rPC), %edx
1189     shrl MACRO_LITERAL(4), %edx
1190     andl MACRO_LITERAL(0xf), %edx  // dex register of second argument
1191     GET_VREG %edx, %edx
1192     movd %edx, %xmm0
1193     .endif
1194.Linvoke_with_few_args_\suffix:
1195     // Check if the next instruction is move-result or move-result-wide.
1196     // If it is, we fetch the shorty and jump to the regular invocation.
1197     movzwl  6(rPC), %ebx
1198     andl MACRO_LITERAL(0xfe), %ebx
1199     cmpl MACRO_LITERAL(0x0a), %ebx
1200     je .Lget_shorty_and_invoke_\suffix
1201     call *ART_METHOD_QUICK_CODE_OFFSET_32(%eax) // Call the method.
1202     RESTORE_IBASE
1203     ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
1204.Lget_shorty_and_invoke_\suffix:
1205     GET_SHORTY_SLOW_PATH %esi, \is_interface
1206     jmp .Lgpr_setup_finished_\suffix
1207   .endif
1208
1209.Lget_shorty_\suffix:
1210   GET_SHORTY %ebx, \is_interface, \is_polymorphic, \is_custom
1211   movl %eax, LOCAL0(%esp)
1212   movl %ebp, LOCAL1(%esp)
1213   movl %ebx, LOCAL2(%esp)
1214   // From this point:
1215   // - ebx contains shorty (in callee-save to switch over return value after call).
1216   // - eax, edx, and ebp are available
1217   // - ecx contains 'this' pointer for instance method.
1218   // TODO: ebp/rREFS is used for stack unwinding, can we find a way to preserve it?
1219   leal 1(%ebx), %edx  // shorty + 1  ; ie skip return arg character
1220   movzwl 4(rPC), %ebx // arguments
1221   .if \is_string_init
1222   shrl MACRO_LITERAL(4), %ebx
1223   movl $$1, %ebp       // ignore first argument
1224   .elseif \is_static
1225   movl $$0, %ebp       // arg_index
1226   .else
1227   shrl MACRO_LITERAL(4), %ebx
1228   movl $$1, %ebp       // arg_index
1229   .endif
1230   LOOP_OVER_SHORTY_LOADING_XMMS xmm0, ebx, edx, ebp, .Lxmm_setup_finished_\suffix
1231   LOOP_OVER_SHORTY_LOADING_XMMS xmm1, ebx, edx, ebp, .Lxmm_setup_finished_\suffix
1232   LOOP_OVER_SHORTY_LOADING_XMMS xmm2, ebx, edx, ebp, .Lxmm_setup_finished_\suffix
1233   LOOP_OVER_SHORTY_LOADING_XMMS xmm3, ebx, edx, ebp, .Lxmm_setup_finished_\suffix
1234   // We know this can only be a float.
1235   movb (%edx), %al                        // al := *shorty
1236   cmpb MACRO_LITERAL(70), %al             // if (al != 'F') goto finished
1237   jne .Lxmm_setup_finished_\suffix
1238   movzbl 1(rPC), %eax
1239   andl MACRO_LITERAL(0xf), %eax
1240   GET_VREG %eax, %eax
1241   // Add four for the ArtMethod.
1242   movl %eax, 4(%esp, %ebp, 4)
1243   // We know there is no more argument, jump to the call.
1244   jmp .Lrestore_saved_values_\suffix
1245.Lxmm_setup_finished_\suffix:
1246   // Reload rREFS for fetching the PC.
1247   movl LOCAL1(%esp), %ebp
1248   // Reload shorty
1249   movl LOCAL2(%esp), %ebx
1250   FETCH_PC
1251   leal 1(%ebx), %ebx  // shorty + 1  ; ie skip return arg character
1252   movzwl 4(rPC), %esi // arguments
1253   .if \is_string_init
1254   movl $$0, %ebp       // arg_index
1255   shrl MACRO_LITERAL(4), %esi
1256   LOOP_OVER_SHORTY_LOADING_GPRS ecx, edx, esi, ebx, ebp, .Lrestore_saved_values_\suffix, .Lif_long_ebx_\suffix, is_ebx=0
1257   .elseif \is_static
1258   movl $$0, %ebp       // arg_index
1259   LOOP_OVER_SHORTY_LOADING_GPRS ecx, edx, esi, ebx, ebp, .Lrestore_saved_values_\suffix, .Lif_long_ebx_\suffix, is_ebx=0
1260   .else
1261   shrl MACRO_LITERAL(4), %esi
1262   movl $$1, %ebp       // arg_index
1263   .endif
1264   // For long argument, store second half in eax to not overwrite the shorty.
1265   LOOP_OVER_SHORTY_LOADING_GPRS edx, eax, esi, ebx, ebp, .Lrestore_saved_values_\suffix, .Lif_long_\suffix, is_ebx=0
1266.Lif_long_ebx_\suffix:
1267   // Store in eax to not overwrite the shorty.
1268   LOOP_OVER_SHORTY_LOADING_GPRS eax, eax, esi, ebx, ebp, .Lrestore_saved_values_\suffix, .Lif_long_\suffix, is_ebx=1
1269.Lif_long_\suffix:
1270   // Save shorty, as LOOP_OVER_SHORTY_LOADING_INTS might overwrite the LOCAL2 slot for a long argument.
1271   pushl LOCAL2(%esp)
1272   pushl %eax
1273   LOOP_OVER_SHORTY_LOADING_INTS 8, ebx, esi, ebp, .Lrestore_ebx_\suffix, \is_string_init
1274.Lrestore_ebx_\suffix:
1275   popl %ebx
1276   popl %esi
1277   movl LOCAL0(%esp), %eax
1278   movl LOCAL1(%esp), %ebp
1279   jmp .Lgpr_setup_finished_\suffix
1280.Lrestore_saved_values_\suffix:
1281   movl LOCAL0(%esp), %eax
1282   movl LOCAL1(%esp), %ebp
1283   movl LOCAL2(%esp), %esi
1284.Lgpr_setup_finished_\suffix:
1285   // Look at the shorty now, as we'll want %esi to have the PC for proper stack unwinding
1286   // and we're running out of callee-save registers.
1287   cmpb LITERAL(68), (%esi)       // Test if result type char == 'D'.
1288   je .Linvoke_double_\suffix
1289   cmpb LITERAL(70), (%esi)       // Test if result type char == 'F'.
1290   je .Linvoke_float_\suffix
1291   FETCH_PC
1292   DO_CALL \is_polymorphic, \is_custom
1293   SAVE_WIDE_RETURN
1294.Ldone_return_\suffix:
1295   /* resume execution of caller */
1296   .if \is_string_init
1297   movzwl 4(rPC), %ecx // arguments
1298   andl $$0xf, %ecx
1299   GET_VREG rINST, %ecx
1300   UPDATE_REGISTERS_FOR_STRING_INIT rINST, %eax
1301   .endif
1302   RESTORE_IBASE
1303
1304   .if \is_polymorphic
1305   ADVANCE_PC_FETCH_AND_GOTO_NEXT 4
1306   .else
1307   ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
1308   .endif
1309
1310.Linvoke_double_\suffix:
1311   FETCH_PC
1312   DO_CALL \is_polymorphic, \is_custom
1313   movq %xmm0, LOCAL1(%esp)
1314   movl LOCAL1(%esp), %eax
1315   jmp .Ldone_return_\suffix
1316.Linvoke_float_\suffix:
1317   FETCH_PC
1318   DO_CALL \is_polymorphic, \is_custom
1319   movd %xmm0, %eax
1320   jmp .Ldone_return_\suffix
1321.endm
1322
1323.macro COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
1324   .if \is_polymorphic
1325   // No fast path for polymorphic calls.
1326   .elseif \is_custom
1327   // No fast path for custom calls.
1328   .elseif \is_string_init
1329   // No fast path for string.init.
1330   .else
1331     testl $$ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG, ART_METHOD_ACCESS_FLAGS_OFFSET(%eax)
1332     je .Lfast_path_with_few_args_range_\suffix
1333     movzbl 1(rPC), %edx  // number of arguments
1334     .if \is_static
1335     testl %edx, %edx
1336     je .Linvoke_fast_path_range_\suffix
1337     .else
1338     cmpl MACRO_LITERAL(1), %edx
1339     je .Linvoke_fast_path_range_\suffix
1340     .endif
1341     movzwl 4(rPC), %ebx  // dex register of first argument
1342     leal (rFP, %ebx, 4), %esi  // location of first dex register value
1343     cmpl MACRO_LITERAL(2), %edx
1344     .if \is_static
1345     jl .Lone_arg_fast_path_range_\suffix
1346     .endif
1347     je .Ltwo_args_fast_path_range_\suffix
1348     cmp MACRO_LITERAL(4), %edx
1349     jl .Lthree_args_fast_path_range_\suffix
1350
1351.Lloop_over_fast_path_range_\suffix:
1352     subl MACRO_LITERAL(1), %edx
1353     movl (%esi, %edx, 4), %ebx
1354     movl %ebx, 4(%esp, %edx, 4)  // Add 4 for the ArtMethod
1355     cmpl MACRO_LITERAL(3), %edx
1356     jne .Lloop_over_fast_path_range_\suffix
1357
1358.Lthree_args_fast_path_range_\suffix:
1359     movl 8(%esi), %ebx
1360.Ltwo_args_fast_path_range_\suffix:
1361     movl 4(%esi), %edx
1362.Lone_arg_fast_path_range_\suffix:
1363     .if \is_static
1364     movl 0(%esi), %ecx
1365     .else
1366     // First argument already in %ecx.
1367     .endif
1368.Linvoke_fast_path_range_\suffix:
1369     FETCH_PC
1370     call *ART_METHOD_QUICK_CODE_OFFSET_32(%eax) // Call the method.
1371     SAVE_WIDE_RETURN
1372     RESTORE_IBASE
1373     ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
1374
1375.Lfast_path_with_few_args_range_\suffix:
1376     // Fast path when we have zero or one argument (modulo 'this'). If there
1377     // is one argument, we can put it in both floating point and core register.
1378     movzbl 1(rPC), %ebx # Number of arguments
1379     .if \is_static
1380     cmpl MACRO_LITERAL(1), %ebx
1381     jl .Linvoke_with_few_args_range_\suffix
1382     jne .Lget_shorty_range_\suffix
1383     movzwl 4(rPC), %ebx  // Dex register of first argument
1384     GET_VREG %ecx, %ebx
1385     movd %ecx, %xmm0
1386     .else
1387     cmpl MACRO_LITERAL(2), %ebx
1388     jl .Linvoke_with_few_args_range_\suffix
1389     jne .Lget_shorty_range_\suffix
1390     movzwl 4(rPC), %ebx
1391     addl MACRO_LITERAL(1), %ebx  // dex register of second argument
1392     GET_VREG %edx, %ebx
1393     movd %edx, %xmm0
1394     .endif
1395.Linvoke_with_few_args_range_\suffix:
1396     // Check if the next instruction is move-result or move-result-wide.
1397     // If it is, we fetch the shorty and jump to the regular invocation.
1398     movzwl  6(rPC), %ebx
1399     and MACRO_LITERAL(0xfe), %ebx
1400     cmpl MACRO_LITERAL(0x0a), %ebx
1401     je .Lget_shorty_and_invoke_range_\suffix
1402     call *ART_METHOD_QUICK_CODE_OFFSET_32(%eax) // Call the method.
1403     RESTORE_IBASE
1404     ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
1405.Lget_shorty_and_invoke_range_\suffix:
1406     GET_SHORTY_SLOW_PATH %esi, \is_interface
1407     jmp .Lgpr_setup_finished_range_\suffix
1408   .endif
1409
1410.Lget_shorty_range_\suffix:
1411   GET_SHORTY %ebx, \is_interface, \is_polymorphic, \is_custom
1412   movl %eax, LOCAL0(%esp)
1413   movl %ebp, LOCAL1(%esp)
1414   movl %ebx, LOCAL2(%esp)
1415   // From this point:
1416   // - ebx contains shorty (in callee-save to switch over return value after call).
1417   // - eax, edx, ebx, and ebp are available.
1418   // - ecx contains 'this' pointer for instance method.
1419   // TODO: ebp/rREFS is used for stack unwinding, can we find a way to preserve it?
1420   leal 1(%ebx), %edx  // shorty + 1  ; ie skip return arg character
1421   movzwl 4(rPC), %ebx // arg start index
1422   .if \is_string_init
1423   addl $$1, %ebx       // arg start index
1424   movl $$0, %ebp       // index in stack
1425   .elseif \is_static
1426   movl $$0, %ebp       // index in stack
1427   .else
1428   addl $$1, %ebx       // arg start index
1429   movl $$1, %ebp       // index in stack
1430   .endif
1431   LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm0, edx, ebx, ebp, .Lxmm_setup_finished_range_\suffix
1432   LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm1, edx, ebx, ebp, .Lxmm_setup_finished_range_\suffix
1433   LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm2, edx, ebx, ebp, .Lxmm_setup_finished_range_\suffix
1434   LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm3, edx, ebx, ebp, .Lxmm_setup_finished_range_\suffix
1435   LOOP_RANGE_OVER_FPs edx, ebx, ebp, .Lxmm_setup_finished_range_\suffix
1436.Lxmm_setup_finished_range_\suffix:
1437   // Reload rREFS for fetching the PC.
1438   movl LOCAL1(%esp), %ebp
1439   // Reload shorty
1440   movl LOCAL2(%esp), %ebx
1441   FETCH_PC
1442   leal 1(%ebx), %ebx  // shorty + 1  ; ie skip return arg character
1443   // From this point:
1444   // - ebx contains shorty
1445   // - eax and ebp are available.
1446   // - ecx contains 'this' pointer for instance method.
1447   movzwl 4(rPC), %ebp // arg start index
1448   // rPC (esi) is now available
1449   .if \is_string_init
1450   addl $$1, %ebp       // arg start index
1451   movl $$0, %esi       // index in stack
1452   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS ecx, edx, ebx, ebp, esi, .Lrestore_saved_values_range_\suffix, .Lif_long_ebx_range_\suffix, is_ebx=0
1453   .elseif \is_static
1454   movl $$0, %esi // index in stack
1455   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS ecx, edx, ebx, ebp, esi, .Lrestore_saved_values_range_\suffix, .Lif_long_ebx_range_\suffix, is_ebx=0
1456   .else
1457   addl $$1, %ebp // arg start index
1458   movl $$1, %esi // index in stack
1459   .endif
1460   // For long argument, store second half in eax to not overwrite the shorty.
1461   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS edx, eax, ebx, ebp, esi, .Lrestore_saved_values_range_\suffix, .Lif_long_range_\suffix, is_ebx=0
1462.Lif_long_ebx_range_\suffix:
1463   // Store in eax to not overwrite the shorty.
1464   LOOP_RANGE_OVER_SHORTY_LOADING_GPRS eax, eax, ebx, ebp, esi, .Lrestore_saved_values_range_\suffix, .Lif_long_range_\suffix, is_ebx=1
1465.Lif_long_range_\suffix:
1466   // Save shorty, as LOOP_RANGE_OVER_SHORTY_LOADING_INTS might overwrite the LOCAL2 slot for a long argument.
1467   pushl LOCAL2(%esp)
1468   pushl %eax
1469   LOOP_RANGE_OVER_INTs 8, ebx, ebp, esi, .Lrestore_ebx_range_\suffix
1470.Lrestore_ebx_range_\suffix:
1471   popl %ebx
1472   popl %esi
1473   movl LOCAL0(%esp), %eax
1474   movl LOCAL1(%esp), %ebp
1475   jmp .Lgpr_setup_finished_range_\suffix
1476
1477.Lrestore_saved_values_range_\suffix:
1478   movl LOCAL0(%esp), %eax
1479   movl LOCAL1(%esp), %ebp
1480   // Save shorty in callee-save register
1481   movl LOCAL2(%esp), %esi
1482
1483.Lgpr_setup_finished_range_\suffix:
1484   cmpb LITERAL(68), (%esi)       // Test if result type char == 'D'.
1485   je .Lreturn_range_double_\suffix
1486   cmpb LITERAL(70), (%esi)       // Test if result type char == 'F'.
1487   je .Lreturn_range_float_\suffix
1488
1489   FETCH_PC
1490   DO_CALL \is_polymorphic, \is_custom
1491   SAVE_WIDE_RETURN
1492.Ldone_return_range_\suffix:
1493   /* resume execution of caller */
1494   .if \is_string_init
1495   movzwl 4(rPC), %ecx // arguments
1496   GET_VREG rINST, %ecx
1497   UPDATE_REGISTERS_FOR_STRING_INIT rINST, %eax
1498   .endif
1499   RESTORE_IBASE
1500   .if \is_polymorphic
1501   ADVANCE_PC_FETCH_AND_GOTO_NEXT 4
1502   .else
1503   ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
1504   .endif
1505.Lreturn_range_double_\suffix:
1506   FETCH_PC
1507   DO_CALL \is_polymorphic, \is_custom
1508   movq %xmm0, LOCAL1(%esp)
1509   movl LOCAL1(%esp), %eax
1510   jmp .Ldone_return_range_\suffix
1511.Lreturn_range_float_\suffix:
1512   FETCH_PC
1513   DO_CALL \is_polymorphic, \is_custom
1514   movd %xmm0, %eax
1515   jmp .Ldone_return_range_\suffix
1516.endm
1517
1518// Helper for static field get.
1519.macro OP_SGET load="movl", wide="0"
1520   // Fast-path which gets the field from thread-local cache.
1521%  fetch_from_thread_cache("%eax", miss_label="2f")
15221:
1523   movl ART_FIELD_OFFSET_OFFSET(%eax), %ecx
1524   movl ART_FIELD_DECLARING_CLASS_OFFSET(%eax), %eax
1525   cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1526   jne 3f
15274:
1528   .if \wide
1529   addl %ecx, %eax
1530   \load (%eax), %ecx
1531   SET_VREG %ecx, rINST            # fp[A] <- value
1532   \load 4(%eax), %ecx
1533   SET_VREG_HIGH %ecx, rINST
1534   .else
1535   \load (%eax, %ecx, 1), %eax
1536   SET_VREG %eax, rINST            # fp[A] <- value
1537   .endif
1538   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
15392:
1540   EXPORT_PC
1541   movl rSELF:THREAD_SELF_OFFSET, ARG0
1542   movl 0(%esp), ARG1
1543   movl rPC, ARG2
1544   movl $$0, ARG3
1545   call nterp_get_static_field
1546   .if !\wide
1547   CLEAR_VOLATILE_MARKER %eax
1548   jmp 1b
1549   .else
1550   testl MACRO_LITERAL(1), %eax
1551   je 1b
1552   CLEAR_VOLATILE_MARKER %eax
1553   movl ART_FIELD_OFFSET_OFFSET(%eax), %ecx
1554   movl ART_FIELD_DECLARING_CLASS_OFFSET(%eax), %eax
1555   cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1556   jne 5f
15576:
1558   movsd (%eax, %ecx, 1), %xmm0
1559   SET_WIDE_FP_VREG %xmm0, rINST
1560   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
15615:
1562   call art_quick_read_barrier_mark_reg00
1563   jmp 6b
1564   .endif
15653:
1566   call art_quick_read_barrier_mark_reg00
1567   jmp 4b
1568.endm
1569
1570// Helper for static field put.
1571.macro OP_SPUT rINST_reg="rINST", store="movl", wide="0":
1572   // Fast-path which gets the field from thread-local cache.
1573%  fetch_from_thread_cache("%eax", miss_label="2f")
15741:
1575   movl ART_FIELD_OFFSET_OFFSET(%eax), %ecx
1576   movl ART_FIELD_DECLARING_CLASS_OFFSET(%eax), %eax
1577   cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1578   jne 3f
15794:
1580   .if \wide
1581   addl %ecx, %eax
1582   GET_VREG %ecx, rINST                  # rINST <- v[A]
1583   movl %ecx, (%eax)
1584   GET_VREG_HIGH %ecx, rINST
1585   movl %ecx, 4(%eax)
1586   .else
1587   GET_VREG rINST, rINST                  # rINST <- v[A]
1588   \store    \rINST_reg, (%eax,%ecx,1)
1589   .endif
1590   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
15912:
1592   EXPORT_PC
1593   movl rSELF:THREAD_SELF_OFFSET, ARG0
1594   movl 0(%esp), ARG1
1595   movl rPC, ARG2
1596   movl $$0, ARG3
1597   call nterp_get_static_field
1598   testl MACRO_LITERAL(1), %eax
1599   je 1b
1600   // Clear the marker that we put for volatile fields.
1601   CLEAR_VOLATILE_MARKER %eax
1602   movl ART_FIELD_OFFSET_OFFSET(%eax), %ecx
1603   movl ART_FIELD_DECLARING_CLASS_OFFSET(%eax), %eax
1604   cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1605   jne 6f
16065:
1607   .if \wide
1608   addl %ecx, %eax
1609   GET_WIDE_FP_VREG %xmm0, rINST
1610   movsd %xmm0, (%eax)
1611   .else
1612   GET_VREG rINST, rINST                  # rINST <- v[A]
1613   \store    \rINST_reg, (%eax,%ecx,1)
1614   .endif
1615   lock addl $$0, (%esp)
1616   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
16173:
1618   call art_quick_read_barrier_mark_reg00
1619   jmp 4b
16206:
1621   call art_quick_read_barrier_mark_reg00
1622   jmp 5b
1623.endm
1624
1625
1626.macro OP_IPUT_INTERNAL rINST_reg="rINST", store="movl", wide="0", volatile="0":
1627   movzbl  rINSTbl, %ecx                   # ecx <- BA
1628   sarl    $$4, %ecx                       # ecx <- B
1629   GET_VREG %ecx, %ecx                     # vB (object we're operating on)
1630   testl   %ecx, %ecx                      # is object null?
1631   je      common_errNullObject
1632   andb    $$0xf, rINSTbl                  # rINST <- A
1633   .if \wide
1634   addl %ecx, %eax
1635   GET_WIDE_FP_VREG %xmm0, rINST
1636   movsd %xmm0, (%eax)
1637   .else
1638   GET_VREG rINST, rINST                  # rINST <- v[A]
1639   \store \rINST_reg, (%ecx,%eax,1)
1640   .endif
1641.endm
1642
1643// Helper for instance field put.
1644.macro OP_IPUT rINST_reg="rINST", store="movl", wide="0":
1645   // Fast-path which gets the field from thread-local cache.
1646%  fetch_from_thread_cache("%eax", miss_label="2f")
16471:
1648   OP_IPUT_INTERNAL \rINST_reg, \store, \wide, volatile=0
1649   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
16502:
1651   EXPORT_PC
1652   movl rSELF:THREAD_SELF_OFFSET, ARG0
1653   movl 0(%esp), ARG1
1654   movl rPC, ARG2
1655   movl $$0, ARG3
1656   call nterp_get_instance_field_offset
1657   testl %eax, %eax
1658   jns 1b
1659   negl %eax
1660   OP_IPUT_INTERNAL \rINST_reg, \store, \wide, volatile=1
1661   lock addl $$0, (%esp)
1662   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
1663.endm
1664
1665// Helper for instance field get.
1666.macro OP_IGET load="movl", wide="0"
1667   // Fast-path which gets the field from thread-local cache.
1668%  fetch_from_thread_cache("%eax", miss_label="2f")
16691:
1670   movl    rINST, %ecx                     # ecx <- BA
1671   sarl    $$4, %ecx                       # ecx <- B
1672   GET_VREG %ecx, %ecx                     # vB (object we're operating on)
1673   testl   %ecx, %ecx                      # is object null?
1674   je      common_errNullObject
1675   andb    $$0xf,rINSTbl                   # rINST <- A
1676   .if \wide
1677   addl %ecx, %eax
1678   \load (%eax), %ecx
1679   SET_VREG %ecx, rINST
1680   \load 4(%eax), %ecx
1681   SET_VREG_HIGH %ecx, rINST
1682   .else
1683   \load (%ecx,%eax,1), %eax
1684   SET_VREG %eax, rINST                    # fp[A] <- value
1685   .endif
1686   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
16872:
1688   EXPORT_PC
1689   movl rSELF:THREAD_SELF_OFFSET, ARG0
1690   movl 0(%esp), ARG1
1691   movl rPC, ARG2
1692   movl $$0, ARG3
1693   call nterp_get_instance_field_offset
1694   testl %eax, %eax
1695   jns 1b
1696   negl %eax
1697   .if !\wide
1698   jmp 1b
1699   .else
1700   movl    rINST, %ecx                     # ecx <- BA
1701   sarl    $$4, %ecx                       # ecx <- B
1702   GET_VREG %ecx, %ecx                     # vB (object we're operating on)
1703   testl   %ecx, %ecx                      # is object null?
1704   je      common_errNullObject
1705   andb    $$0xf,rINSTbl                   # rINST <- A
1706   movsd (%eax, %ecx, 1), %xmm0
1707   SET_WIDE_FP_VREG %xmm0, rINST
1708   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
1709   .endif
1710.endm
1711
1712// Store a reference parameter into our dex register frame.
1713// Uses xmm4 as temporary.
1714.macro SETUP_REFERENCE_PARAMETER_IN_GPR offset, stack_ptr, regs, refs, ins, arg_offset, finished
1715    movss \offset(REG_VAR(stack_ptr)), %xmm4
1716    movss %xmm4, (REG_VAR(regs), REG_VAR(arg_offset))
1717    movss %xmm4, (REG_VAR(refs), REG_VAR(arg_offset))
1718    addl MACRO_LITERAL(4), REG_VAR(arg_offset)
1719    subl MACRO_LITERAL(1), REG_VAR(ins)
1720    je \finished
1721.endm
1722
1723// Store a reference parameter into our dex register frame.
1724// Uses xmm4 as temporary.
1725.macro SETUP_REFERENCE_PARAMETERS_IN_STACK stack_ptr, regs, refs, ins, arg_offset
17261:
1727    movss OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_offset)), %xmm4
1728    movss %xmm4, (REG_VAR(regs), REG_VAR(arg_offset))
1729    movss %xmm4, (REG_VAR(refs), REG_VAR(arg_offset))
1730    addl MACRO_LITERAL(4), REG_VAR(arg_offset)
1731    subl MACRO_LITERAL(1), REG_VAR(ins)
1732    jne 1b
1733.endm
1734
1735.macro DO_SUSPEND_CHECK continue_label
1736    testl   $$(THREAD_SUSPEND_OR_CHECKPOINT_REQUEST), rSELF:THREAD_FLAGS_OFFSET
1737    jz      \continue_label
1738    jmp     NterpCallSuspendAndGotoNext
1739.endm
1740
1741.macro CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot, if_not_hot
1742    testl $$ART_METHOD_IS_MEMORY_SHARED_FLAG, ART_METHOD_ACCESS_FLAGS_OFFSET(%eax)
1743    jz \if_hot
1744    movzwl rSELF:THREAD_SHARED_METHOD_HOTNESS_OFFSET, %ecx
1745    testl %ecx, %ecx
1746    je \if_hot
1747    addl $$-1, %ecx
1748    movw %cx, rSELF:THREAD_SHARED_METHOD_HOTNESS_OFFSET
1749    jmp \if_not_hot
1750.endm
1751
1752
1753%def entry():
1754/*
1755 * ArtMethod entry point.
1756 *
1757 * On entry:
1758 *  eax   ArtMethod* callee
1759 *  rest  method parameters
1760 */
1761
1762OAT_ENTRY ExecuteNterpWithClinitImpl, EndExecuteNterpWithClinitImpl
1763    push %esi
1764    // For simplicity, we don't do a read barrier here, but instead rely
1765    // on art_quick_resolution_trampoline to always have a suspend point before
1766    // calling back here.
1767    movl ART_METHOD_DECLARING_CLASS_OFFSET(%eax), %esi
1768    cmpb $$(MIRROR_CLASS_IS_VISIBLY_INITIALIZED_VALUE), MIRROR_CLASS_IS_VISIBLY_INITIALIZED_OFFSET(%esi)
1769    jae .Lcontinue_execute_nterp
1770    cmpb  $$(MIRROR_CLASS_IS_INITIALIZING_VALUE), MIRROR_CLASS_IS_VISIBLY_INITIALIZED_OFFSET(%esi)
1771    jb .Linvoke_trampoline
1772    movl MIRROR_CLASS_CLINIT_THREAD_ID_OFFSET(%esi), %esi
1773    cmpl %esi, rSELF:THREAD_TID_OFFSET
1774    je .Lcontinue_execute_nterp
1775.Linvoke_trampoline:
1776    pop %esi
1777    jmp art_quick_resolution_trampoline
1778.Lcontinue_execute_nterp:
1779    pop %esi
1780    jmp ExecuteNterpImpl
1781EndExecuteNterpWithClinitImpl:
1782
1783OAT_ENTRY ExecuteNterpImpl, EndExecuteNterpImpl
1784    .cfi_startproc
1785    .cfi_def_cfa esp, 4
1786    testl %eax, -STACK_OVERFLOW_RESERVED_BYTES(%esp)
1787    // Spill callee save regs
1788    SPILL_ALL_CALLEE_SAVES
1789
1790    // Make argument registers available.
1791    SPILL_ALL_CORE_PARAMETERS
1792
1793    // Fetch code item.
1794    movl ART_METHOD_DATA_OFFSET_32(%eax), %ecx
1795
1796    // Setup the stack for executing the method.
1797    SETUP_STACK_FRAME %ecx, rREFS, rFP, CFI_REFS, load_ins=1
1798
1799    // Save the PC
1800    movl %ecx, -8(rREFS)
1801
1802    // Setup the parameters
1803    testl %esi, %esi
1804    je .Lxmm_setup_finished
1805
1806    subl %esi, %ebx
1807    sall $$2, %ebx // ebx is now the offset for inputs into the registers array.
1808
1809    // Reload ArtMethod.
1810    movl (%esp), %eax
1811    testl $$ART_METHOD_NTERP_ENTRY_POINT_FAST_PATH_FLAG, ART_METHOD_ACCESS_FLAGS_OFFSET(%eax)
1812    je .Lsetup_slow_path
1813    leal (rREFS, %ebx, 1), %ecx
1814    leal (rFP, %ebx, 1), %ebx
1815    movl $$0, %eax
1816
1817    // edx is the old stack pointer
1818    SETUP_REFERENCE_PARAMETER_IN_GPR 8, edx, ebx, ecx, esi, eax, .Lxmm_setup_finished
1819    SETUP_REFERENCE_PARAMETER_IN_GPR 4, edx, ebx, ecx, esi, eax, .Lxmm_setup_finished
1820    SETUP_REFERENCE_PARAMETER_IN_GPR 0, edx, ebx, ecx, esi, eax, .Lxmm_setup_finished
1821    SETUP_REFERENCE_PARAMETERS_IN_STACK edx, ebx, ecx, esi, eax
1822    jmp .Lxmm_setup_finished
1823
1824.Lsetup_slow_path:
1825    // If the method is not static and there is one argument ('this'), we don't need to fetch the
1826    // shorty.
1827    testl $$ART_METHOD_IS_STATIC_FLAG, ART_METHOD_ACCESS_FLAGS_OFFSET(%eax)
1828    jne .Lsetup_with_shorty
1829
1830    // Record 'this'.
1831    movl 8(%edx), %eax
1832    movl %eax, (rFP, %ebx)
1833    movl %eax, (rREFS, %ebx)
1834
1835    cmpl $$1, %esi
1836    je .Lxmm_setup_finished
1837
1838.Lsetup_with_shorty:
1839    // Save xmm registers. Core registers have already been saved.
1840    subl MACRO_LITERAL(4 * 8), %esp
1841    movq %xmm0, 0(%esp)
1842    movq %xmm1, 8(%esp)
1843    movq %xmm2, 16(%esp)
1844    movq %xmm3, 24(%esp)
1845    subl MACRO_LITERAL(12), %esp
1846    pushl (4 * 8 + 12)(%esp)
1847    call SYMBOL(NterpGetShorty)
1848    addl MACRO_LITERAL(16), %esp
1849
1850    // Restore xmm registers
1851    movq 0(%esp), %xmm0
1852    movq 8(%esp), %xmm1
1853    movq 16(%esp), %xmm2
1854    movq 24(%esp), %xmm3
1855    addl MACRO_LITERAL(4 * 8), %esp
1856
1857    // Reload the old stack pointer.
1858    movl -4(rREFS), %edx
1859    // TODO: Get shorty in a better way and remove above
1860
1861    movl $$0, %esi
1862    movl (%esp), %ecx
1863    testl $$ART_METHOD_IS_STATIC_FLAG, ART_METHOD_ACCESS_FLAGS_OFFSET(%ecx)
1864
1865    // Note the leal and movl below don't change the flags.
1866    leal (rFP, %ebx, 1), %ecx
1867    leal (rREFS, %ebx, 1), %ebx
1868    // Save rFP (%edi), we're using it as temporary below.
1869    movl rFP, LOCAL1(%esp)
1870    leal 1(%eax), %edi  // shorty + 1  ; ie skip return arg character
1871    // Save shorty + 1
1872    movl %edi, LOCAL2(%esp)
1873    jne .Lhandle_static_method
1874    addl $$4, %ecx
1875    addl $$4, %ebx
1876    addl $$4, %edx
1877    LOOP_OVER_SHORTY_STORING_GPRS 0, -4, edx, edi, esi, ecx, ebx, .Lgpr_setup_finished, .Lif_long, is_ebx=0
1878    LOOP_OVER_SHORTY_STORING_GPRS -4, 0, edx, edi, esi, ecx, ebx, .Lgpr_setup_finished, .Lif_long, is_ebx=1
1879    jmp .Lif_long
1880.Lhandle_static_method:
1881    LOOP_OVER_SHORTY_STORING_GPRS 8, 4, edx, edi, esi, ecx, ebx, .Lgpr_setup_finished, .Lif_long_ebx, is_ebx=0
1882    LOOP_OVER_SHORTY_STORING_GPRS 4, 0, edx, edi, esi, ecx, ebx, .Lgpr_setup_finished, .Lif_long, is_ebx=0
1883.Lif_long_ebx:
1884    LOOP_OVER_SHORTY_STORING_GPRS 0, 0, edx, edi, esi, ecx, ebx, .Lgpr_setup_finished, .Lif_long, is_ebx=1
1885.Lif_long:
1886    LOOP_OVER_INTs edi, esi, ecx, ebx, edx, .Lgpr_setup_finished
1887.Lgpr_setup_finished:
1888    // Restore shorty + 1
1889    movl LOCAL2(%esp), %edi
1890    movl $$0, %esi // reset counter
1891    LOOP_OVER_SHORTY_STORING_XMMS xmm0, edi, esi, ecx, .Lrestore_fp
1892    LOOP_OVER_SHORTY_STORING_XMMS xmm1, edi, esi, ecx, .Lrestore_fp
1893    LOOP_OVER_SHORTY_STORING_XMMS xmm2, edi, esi, ecx, .Lrestore_fp
1894    LOOP_OVER_SHORTY_STORING_XMMS xmm3, edi, esi, ecx, .Lrestore_fp
1895    LOOP_OVER_FPs edi, esi, ecx, edx, .Lrestore_fp
1896.Lrestore_fp:
1897    movl LOCAL1(%esp), rFP
1898.Lxmm_setup_finished:
1899    FETCH_PC
1900    CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
1901    // Set rIBASE
1902    RESTORE_IBASE
1903    /* start executing the instruction at rPC */
1904    START_EXECUTING_INSTRUCTIONS
1905    /* NOTE: no fallthrough */
1906    // cfi info continues, and covers the whole nterp implementation.
1907    END ExecuteNterpImpl
1908
1909%def opcode_pre():
1910
1911%def fetch_from_thread_cache(dest_reg, miss_label):
1912   // Fetch some information from the thread cache.
1913   // Uses eax, and ecx as temporaries.
1914   movl rSELF:THREAD_SELF_OFFSET, %eax
1915   movl rPC, %ecx
1916   sall MACRO_LITERAL(THREAD_INTERPRETER_CACHE_SIZE_SHIFT), %ecx
1917   andl MACRO_LITERAL(THREAD_INTERPRETER_CACHE_SIZE_MASK), %ecx
1918   cmpl THREAD_INTERPRETER_CACHE_OFFSET(%eax, %ecx, 1), rPC
1919   jne  ${miss_label}
1920   movl __SIZEOF_POINTER__+THREAD_INTERPRETER_CACHE_OFFSET(%eax, %ecx, 1), ${dest_reg}
1921
1922%def footer():
1923/*
1924 * ===========================================================================
1925 *  Common subroutines and data
1926 * ===========================================================================
1927 */
1928
1929    .text
1930    .align  2
1931
1932// Enclose all code below in a symbol (which gets printed in backtraces).
1933ENTRY nterp_helper
1934
1935// Note: mterp also uses the common_* names below for helpers, but that's OK
1936// as the assembler compiled each interpreter separately.
1937common_errDivideByZero:
1938    EXPORT_PC
1939    call art_quick_throw_div_zero
1940
1941// Expect array in eax, index in ecx.
1942common_errArrayIndex:
1943    EXPORT_PC
1944    movl MIRROR_ARRAY_LENGTH_OFFSET(%eax), %edx
1945    movl %ecx, %eax
1946    movl %edx, %ecx
1947    call art_quick_throw_array_bounds
1948
1949common_errNullObject:
1950    EXPORT_PC
1951    call art_quick_throw_null_pointer_exception
1952
1953NterpCommonInvokeStatic:
1954    COMMON_INVOKE_NON_RANGE is_static=1, is_interface=0, suffix="invokeStatic"
1955
1956NterpCommonInvokeStaticRange:
1957    COMMON_INVOKE_RANGE is_static=1, is_interface=0, suffix="invokeStatic"
1958
1959NterpCommonInvokeInstance:
1960    COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="invokeInstance"
1961
1962NterpCommonInvokeInstanceRange:
1963    COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="invokeInstance"
1964
1965NterpCommonInvokeInterface:
1966    COMMON_INVOKE_NON_RANGE is_static=0, is_interface=1, suffix="invokeInterface"
1967
1968NterpCommonInvokeInterfaceRange:
1969    COMMON_INVOKE_RANGE is_static=0, is_interface=1, suffix="invokeInterface"
1970
1971NterpCommonInvokePolymorphic:
1972    COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, is_polymorphic=1, suffix="invokePolymorphic"
1973
1974NterpCommonInvokePolymorphicRange:
1975    COMMON_INVOKE_RANGE is_static=0, is_interface=0, is_polymorphic=1, suffix="invokePolymorphic"
1976
1977NterpCommonInvokeCustom:
1978    COMMON_INVOKE_NON_RANGE is_static=1, is_interface=0, is_polymorphic=0, is_custom=1, suffix="invokeCustom"
1979
1980NterpCommonInvokeCustomRange:
1981    COMMON_INVOKE_RANGE is_static=1, is_interface=0, is_polymorphic=0, is_custom=1, suffix="invokeCustom"
1982
1983NterpHandleStringInit:
1984   COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, is_string_init=1, suffix="stringInit"
1985
1986NterpHandleStringInitRange:
1987   COMMON_INVOKE_RANGE is_static=0, is_interface=0, is_string_init=1, suffix="stringInit"
1988
1989NterpNewInstance:
1990   EXPORT_PC
1991   // Fast-path which gets the class from thread-local cache.
1992%  fetch_from_thread_cache("%eax", miss_label="2f")
1993   cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
1994   jne 3f
19954:
1996   call *rSELF:THREAD_ALLOC_OBJECT_ENTRYPOINT_OFFSET
1997   RESTORE_IBASE
1998   FETCH_INST_CLEAR_OPCODE
19991:
2000   SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
2001   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
20022:
2003   movl rSELF:THREAD_SELF_OFFSET, ARG0
2004   movl 0(%esp), ARG1
2005   movl rPC, ARG2
2006   call nterp_allocate_object
2007   jmp 1b
20083:
2009   // 00 is %eax
2010   call art_quick_read_barrier_mark_reg00
2011   jmp 4b
2012
2013NterpNewArray:
2014   /* new-array vA, vB, class@CCCC */
2015   EXPORT_PC
2016   // Fast-path which gets the class from thread-local cache.
2017%  fetch_from_thread_cache("%eax", miss_label="2f")
2018   cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
2019   jne 3f
20201:
2021   movzbl  rINSTbl, %ecx
2022   sarl    $$4, %ecx                         # ecx<- B
2023   GET_VREG %ecx %ecx                        # ecx<- vB (array length)
2024   call *rSELF:THREAD_ALLOC_ARRAY_ENTRYPOINT_OFFSET
2025   RESTORE_IBASE
2026   FETCH_INST_CLEAR_OPCODE
2027   andb    $$0xf, rINSTbl                   # rINST<- A
2028   SET_VREG_OBJECT %eax, rINST              # fp[A] <- value
2029   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
20302:
2031   movl rSELF:THREAD_SELF_OFFSET, ARG0
2032   movl 0(%esp), ARG1
2033   movl rPC, ARG2
2034   call nterp_get_class
2035   jmp 1b
20363:
2037   // 00 is %eax
2038   call art_quick_read_barrier_mark_reg00
2039   jmp 1b
2040
2041NterpPutObjectInstanceField:
2042   // Fast-path which gets the field from thread-local cache.
2043%  fetch_from_thread_cache("%eax", miss_label="2f")
20441:
2045   movl    rINST, %ecx                     # ecx <- BA
2046   andl    $$0xf, %ecx                     # ecx <- A
2047   GET_VREG %ecx, %ecx                     # ecx <- v[A]
2048   sarl    $$4, rINST
2049   GET_VREG rINST, rINST                   # vB (object we're operating on)
2050   testl   rINST, rINST                    # is object null?
2051   je      common_errNullObject
2052   movl %ecx, (rINST, %eax, 1)
2053   testl %ecx, %ecx
2054   je 4f
2055   movl rSELF:THREAD_CARD_TABLE_OFFSET, %eax
2056   shrl $$CARD_TABLE_CARD_SHIFT, rINST
2057   movb %al, (%eax, rINST, 1)
20584:
2059   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
20602:
2061   EXPORT_PC
2062   // Fetch the value, needed by nterp_get_instance_field_offset.
2063   movl    rINST, %ecx                     # ecx <- BA
2064   andl    $$0xf, %ecx                     # ecx <- A
2065   GET_VREG ARG3, %ecx                     # ecx <- v[A]
2066   movl rSELF:THREAD_SELF_OFFSET, ARG0
2067   movl 0(%esp), ARG1
2068   movl rPC, ARG2
2069   call nterp_get_instance_field_offset
2070   testl %eax, %eax
2071   jns 1b
2072   negl %eax
2073   // Reload the value as it may have moved.
2074   movl    rINST, %ecx                     # ecx <- BA
2075   andl    $$0xf, %ecx                     # ecx <- A
2076   GET_VREG %ecx, %ecx                     # ecx <- v[A]
2077   sarl    $$4, rINST
2078   GET_VREG rINST, rINST                   # vB (object we're operating on)
2079   testl   rINST, rINST                    # is object null?
2080   je      common_errNullObject
2081   movl %ecx, (rINST, %eax, 1)
2082   testl %ecx, %ecx
2083   je 5f
2084   movl rSELF:THREAD_CARD_TABLE_OFFSET, %eax
2085   shrl $$CARD_TABLE_CARD_SHIFT, rINST
2086   movb %al, (%eax, rINST, 1)
20875:
2088   lock addl $$0, (%esp)
2089   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
2090
2091NterpGetObjectInstanceField:
2092   // Fast-path which gets the field from thread-local cache.
2093%  fetch_from_thread_cache("%eax", miss_label="2f")
20941:
2095   movl    rINST, %ecx                     # ecx <- BA
2096   sarl    $$4, %ecx                       # ecx <- B
2097   GET_VREG %ecx, %ecx                     # vB (object we're operating on)
2098   testl   %ecx, %ecx                      # is object null?
2099   je      common_errNullObject
2100   testb $$READ_BARRIER_TEST_VALUE, GRAY_BYTE_OFFSET(%ecx)
2101   movl (%ecx,%eax,1), %eax
2102   jnz 3f
21034:
2104   andb    $$0xf,rINSTbl                   # rINST <- A
2105   SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
2106   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
21072:
2108   EXPORT_PC
2109   movl rSELF:THREAD_SELF_OFFSET, ARG0
2110   movl 0(%esp), ARG1
2111   movl rPC, ARG2
2112   movl $$0, ARG3
2113   call nterp_get_instance_field_offset
2114   testl %eax, %eax
2115   jns 1b
2116   // For volatile fields, we return a negative offset. Remove the sign
2117   // and no need for any barrier thanks to the memory model.
2118   negl %eax
2119   jmp 1b
21203:
2121   // reg00 is eax
2122   call art_quick_read_barrier_mark_reg00
2123   jmp 4b
2124
2125NterpPutObjectStaticField:
2126   GET_VREG rINST, rINST
2127   // Fast-path which gets the field from thread-local cache.
2128%  fetch_from_thread_cache("%eax", miss_label="2f")
21291:
2130   movl ART_FIELD_OFFSET_OFFSET(%eax), %ecx
2131   movl ART_FIELD_DECLARING_CLASS_OFFSET(%eax), %eax
2132   cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
2133   jne 3f
21345:
2135   movl rINST, (%eax, %ecx, 1)
2136   testl rINST, rINST
2137   je 4f
2138   movl rSELF:THREAD_CARD_TABLE_OFFSET, %ecx
2139   shrl $$CARD_TABLE_CARD_SHIFT, %eax
2140   movb %cl, (%ecx, %eax, 1)
21414:
2142   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
21432:
2144   EXPORT_PC
2145   movl rSELF:THREAD_SELF_OFFSET, ARG0
2146   movl 0(%esp), ARG1
2147   movl rPC, ARG2
2148   movl rINST, ARG3
2149   call nterp_get_static_field
2150   // Reload the value as it may have moved.
2151   GET_VREG rINST, rINST
2152   testl MACRO_LITERAL(1), %eax
2153   je 1b
2154   CLEAR_VOLATILE_MARKER %eax
2155   movl ART_FIELD_OFFSET_OFFSET(%eax), %ecx
2156   movl ART_FIELD_DECLARING_CLASS_OFFSET(%eax), %eax
2157   cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
2158   jne 7f
21596:
2160   movl rINST, (%eax, %ecx, 1)
2161   testl rINST, rINST
2162   je 8f
2163   movl rSELF:THREAD_CARD_TABLE_OFFSET, %ecx
2164   shrl $$CARD_TABLE_CARD_SHIFT, %eax
2165   movb %cl, (%ecx, %eax, 1)
21668:
2167   lock addl $$0, (%esp)
2168   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
21693:
2170   call art_quick_read_barrier_mark_reg00
2171   jmp 5b
21727:
2173   call art_quick_read_barrier_mark_reg00
2174   jmp 6b
2175
2176NterpGetObjectStaticField:
2177   // Fast-path which gets the field from thread-local cache.
2178%  fetch_from_thread_cache("%eax", miss_label="2f")
21791:
2180   movl ART_FIELD_OFFSET_OFFSET(%eax), %ecx
2181   movl ART_FIELD_DECLARING_CLASS_OFFSET(%eax), %eax
2182   cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
2183   jne 5f
21846:
2185   testb $$READ_BARRIER_TEST_VALUE, GRAY_BYTE_OFFSET(%eax)
2186   movl (%eax, %ecx, 1), %eax
2187   jnz 3f
21884:
2189   SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
2190   ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
21912:
2192   EXPORT_PC
2193   movl rSELF:THREAD_SELF_OFFSET, ARG0
2194   movl 0(%esp), ARG1
2195   movl rPC, ARG2
2196   movl $$0, ARG3
2197   call nterp_get_static_field
2198   CLEAR_VOLATILE_MARKER %eax
2199   jmp 1b
22003:
2201   call art_quick_read_barrier_mark_reg00
2202   jmp 4b
22035:
2204   call art_quick_read_barrier_mark_reg00
2205   jmp 6b
2206
2207NterpGetBooleanStaticField:
2208  OP_SGET load="movzbl", wide=0
2209
2210NterpGetByteStaticField:
2211  OP_SGET load="movsbl", wide=0
2212
2213NterpGetCharStaticField:
2214  OP_SGET load="movzwl", wide=0
2215
2216NterpGetShortStaticField:
2217  OP_SGET load="movswl", wide=0
2218
2219NterpGetWideStaticField:
2220  OP_SGET load="movl", wide=1
2221
2222NterpGetIntStaticField:
2223  OP_SGET load="movl", wide=0
2224
2225NterpPutStaticField:
2226  OP_SPUT rINST_reg=rINST, store="movl", wide=0
2227
2228NterpPutBooleanStaticField:
2229NterpPutByteStaticField:
2230  OP_SPUT rINST_reg=rINSTbl, store="movb", wide=0
2231
2232NterpPutCharStaticField:
2233NterpPutShortStaticField:
2234  OP_SPUT rINST_reg=rINSTw, store="movw", wide=0
2235
2236NterpPutWideStaticField:
2237  OP_SPUT rINST_reg=rINST, store="movl", wide=1
2238
2239NterpPutInstanceField:
2240  OP_IPUT rINST_reg=rINST, store="movl", wide=0
2241
2242NterpPutBooleanInstanceField:
2243NterpPutByteInstanceField:
2244  OP_IPUT rINST_reg=rINSTbl, store="movb", wide=0
2245
2246NterpPutCharInstanceField:
2247NterpPutShortInstanceField:
2248  OP_IPUT rINST_reg=rINSTw, store="movw", wide=0
2249
2250NterpPutWideInstanceField:
2251  OP_IPUT rINST_reg=rINST, store="movl", wide=1
2252
2253NterpGetBooleanInstanceField:
2254  OP_IGET load="movzbl", wide=0
2255
2256NterpGetByteInstanceField:
2257  OP_IGET load="movsbl", wide=0
2258
2259NterpGetCharInstanceField:
2260  OP_IGET load="movzwl", wide=0
2261
2262NterpGetShortInstanceField:
2263  OP_IGET load="movswl", wide=0
2264
2265NterpGetWideInstanceField:
2266  OP_IGET load="movl", wide=1
2267
2268NterpGetInstanceField:
2269  OP_IGET load="movl", wide=0
2270
2271NterpCallSuspendAndGotoNext:
2272    EXPORT_PC
2273    // Save branch offset.
2274    movl rINST, LOCAL0(%esp)
2275    call SYMBOL(art_quick_test_suspend)
2276    RESTORE_IBASE
2277    movl LOCAL0(%esp), rINST
2278    FETCH_INST
2279    GOTO_NEXT
2280
2281NterpHandleHotnessOverflow:
2282    CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot=1f, if_not_hot=4f
22831:
2284    movl rPC, %ecx
2285    movl rFP, ARG2
2286    // Save next PC.
2287    movl %ecx, LOCAL0(%esp)
2288    call nterp_hot_method
2289    testl %eax, %eax
2290    jne 3f
2291    // Fetch next PC.
2292    mov LOCAL0(%esp), rPC
22932:
2294    FETCH_INST
2295    GOTO_NEXT
22963:
2297    // Drop the current frame.
2298    movl -4(rREFS), %esp
2299    CFI_DEF_CFA(esp, PARAMETERS_SAVES_SIZE+CALLEE_SAVES_SIZE)
2300    DROP_PARAMETERS_SAVES
2301    CFI_DEF_CFA(esp, CALLEE_SAVES_SIZE)
2302
2303    // Setup the new frame
2304    movl OSR_DATA_FRAME_SIZE(%eax), %ecx
2305    // Given stack size contains all callee saved registers, remove them.
2306    subl $$CALLEE_SAVES_SIZE, %ecx
2307
2308    // Remember CFA.
2309    movl %esp, %ebp
2310    CFI_DEF_CFA_REGISTER(ebp)
2311
2312    subl %ecx, %esp
2313    movl %esp, %edi               // edi := beginning of stack
2314    leal OSR_DATA_MEMORY(%eax), %esi  // esi := memory to copy
2315    rep movsb                     // while (ecx--) { *edi++ = *esi++ }
2316
2317    // Fetch the native PC to jump to and save it in stack.
2318    pushl OSR_DATA_NATIVE_PC(%eax)
2319    CFI_ADJUST_CFA_OFFSET(4)
2320
2321    subl MACRO_LITERAL(8), %esp
2322    CFI_ADJUST_CFA_OFFSET(8)
2323    pushl %eax
2324    CFI_ADJUST_CFA_OFFSET(4)
2325    // Free the memory holding OSR Data.
2326    call SYMBOL(NterpFree)
2327    addl MACRO_LITERAL(12), %esp
2328    CFI_ADJUST_CFA_OFFSET(-12)
2329
2330    // Jump to the compiled code.
2331    ret
23324:
2333    DO_SUSPEND_CHECK continue_label=2b
2334
2335
2336NterpHandleInvokeInterfaceOnObjectMethodRange:
2337   shrl $$16, %eax
2338   movl MIRROR_CLASS_VTABLE_OFFSET_32(%edx, %eax, 4), %eax
2339   jmp NterpCommonInvokeInstanceRange
2340
2341NterpHandleInvokeInterfaceOnObjectMethod:
2342   shrl $$16, %eax
2343   movl MIRROR_CLASS_VTABLE_OFFSET_32(%edx, %eax, 4), %eax
2344   jmp NterpCommonInvokeInstance
2345
2346// This is the logical end of ExecuteNterpImpl, where the frame info applies.
2347// EndExecuteNterpImpl includes the methods below as we want the runtime to
2348// see them as part of the Nterp PCs.
2349.cfi_endproc
2350
2351END nterp_helper
2352
2353// This is the end of PCs contained by the OatQuickMethodHeader created for the interpreter
2354// entry point.
2355    FUNCTION_TYPE(EndExecuteNterpImpl)
2356    ASM_HIDDEN SYMBOL(EndExecuteNterpImpl)
2357    .global SYMBOL(EndExecuteNterpImpl)
2358SYMBOL(EndExecuteNterpImpl):
2359
2360// Entrypoints into runtime.
2361NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField
2362NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset
2363NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray
2364NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange
2365NTERP_TRAMPOLINE nterp_get_class, NterpGetClass
2366NTERP_TRAMPOLINE nterp_allocate_object, NterpAllocateObject
2367NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod
2368NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod
2369NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject
2370
2371DEFINE_FUNCTION nterp_deliver_pending_exception
2372    DELIVER_PENDING_EXCEPTION
2373END_FUNCTION nterp_deliver_pending_exception
2374
2375// gen_mterp.py will inline the following definitions
2376// within [ExecuteNterpImpl, EndExecuteNterpImpl).
2377%def instruction_end():
2378
2379    FUNCTION_TYPE(artNterpAsmInstructionEnd)
2380    ASM_HIDDEN SYMBOL(artNterpAsmInstructionEnd)
2381    .global SYMBOL(artNterpAsmInstructionEnd)
2382SYMBOL(artNterpAsmInstructionEnd):
2383    // artNterpAsmInstructionEnd is used as landing pad for exception handling.
2384    RESTORE_IBASE
2385    FETCH_INST
2386    GOTO_NEXT
2387
2388%def instruction_start():
2389
2390    FUNCTION_TYPE(artNterpAsmInstructionStart)
2391    ASM_HIDDEN SYMBOL(artNterpAsmInstructionStart)
2392    .global SYMBOL(artNterpAsmInstructionStart)
2393SYMBOL(artNterpAsmInstructionStart) = .L_op_nop
2394    .text
2395
2396%def opcode_name_prefix():
2397%   return "nterp_"
2398%def opcode_start():
2399    ENTRY nterp_${opcode}
2400%def opcode_end():
2401    END nterp_${opcode}
2402    // Advance to the end of this handler. Causes error if we are past that point.
2403    .org nterp_${opcode} + NTERP_HANDLER_SIZE  // ${opcode} handler is too big!
2404%def opcode_slow_path_start(name):
2405    ENTRY ${name}
2406%def opcode_slow_path_end(name):
2407    END ${name}
2408