1%def header():
2/*
3 * Copyright (C) 2016 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#define zero $$0  /* always zero */
19#define AT   $$at /* assembler temp */
20#define v0   $$2  /* return value */
21#define v1   $$3
22#define a0   $$4  /* argument registers */
23#define a1   $$5
24#define a2   $$6
25#define a3   $$7
26#define a4   $$8  /* expanded register arguments */
27#define a5   $$9
28#define a6   $$10
29#define a7   $$11
30#define ta0  $$8  /* alias */
31#define ta1  $$9
32#define ta2  $$10
33#define ta3  $$11
34#define t0   $$12 /* temp registers (not saved across subroutine calls) */
35#define t1   $$13
36#define t2   $$14
37#define t3   $$15
38
39#define s0   $$16 /* saved across subroutine calls (callee saved) */
40#define s1   $$17
41#define s2   $$18
42#define s3   $$19
43#define s4   $$20
44#define s5   $$21
45#define s6   $$22
46#define s7   $$23
47#define t8   $$24 /* two more temp registers */
48#define t9   $$25
49#define k0   $$26 /* kernel temporary */
50#define k1   $$27
51#define gp   $$28 /* global pointer */
52#define sp   $$29 /* stack pointer */
53#define s8   $$30 /* one more callee saved */
54#define ra   $$31 /* return address */
55
56#define f0   $$f0
57#define f1   $$f1
58#define f2   $$f2
59#define f3   $$f3
60#define f12  $$f12
61#define f13  $$f13
62
63/*
64 * It looks like the GNU assembler currently does not support the blec and bgtc
65 * idioms, which should translate into bgec and bltc respectively with swapped
66 * left and right register operands.
67 * TODO: remove these macros when the assembler is fixed.
68 */
69.macro blec lreg, rreg, target
70    bgec    \rreg, \lreg, \target
71.endm
72.macro bgtc lreg, rreg, target
73    bltc    \rreg, \lreg, \target
74.endm
75
76/*
77Mterp and MIPS64 notes:
78
79The following registers have fixed assignments:
80
81  reg nick      purpose
82  s0  rPC       interpreted program counter, used for fetching instructions
83  s1  rFP       interpreted frame pointer, used for accessing locals and args
84  s2  rSELF     self (Thread) pointer
85  s3  rINST     first 16-bit code unit of current instruction
86  s4  rIBASE    interpreted instruction base pointer, used for computed goto
87  s5  rREFS     base of object references in shadow frame  (ideally, we'll get rid of this later).
88  s6  rPROFILE  jit profile hotness countdown
89*/
90
91/* During bringup, we'll use the shadow frame model instead of rFP */
92/* single-purpose registers, given names for clarity */
93#define rPC      s0
94#define CFI_DEX  16  // DWARF register number of the register holding dex-pc (s0).
95#define CFI_TMP  4   // DWARF register number of the first argument register (a0).
96#define rFP      s1
97#define rSELF    s2
98#define rINST    s3
99#define rIBASE   s4
100#define rREFS    s5
101#define rPROFILE s6
102
103/*
104 * This is a #include, not a %include, because we want the C pre-processor
105 * to expand the macros into assembler assignment statements.
106 */
107#include "asm_support.h"
108#include "interpreter/cfi_asm_support.h"
109
110/*
111 * Instead of holding a pointer to the shadow frame, we keep rFP at the base of the vregs.  So,
112 * to access other shadow frame fields, we need to use a backwards offset.  Define those here.
113 */
114#define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET)
115#define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET)
116#define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET)
117#define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET)
118#define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
119#define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
120#define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
121#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET)
122#define OFF_FP_SHADOWFRAME OFF_FP(0)
123
124#define MTERP_PROFILE_BRANCHES 1
125#define MTERP_LOGGING 0
126
127/*
128 * "export" the PC to dex_pc field in the shadow frame, f/b/o future exception objects.  Must
129 * be done *before* something throws.
130 *
131 * It's okay to do this more than once.
132 *
133 * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped
134 * dex byte codes.  However, the rest of the runtime expects dex pc to be an instruction
135 * offset into the code_items_[] array.  For effiency, we will "export" the
136 * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC
137 * to convert to a dex pc when needed.
138 */
139.macro EXPORT_PC
140    sd      rPC, OFF_FP_DEX_PC_PTR(rFP)
141.endm
142
143/*
144 * Refresh handler table.
145 */
146.macro REFRESH_IBASE
147    ld      rIBASE, THREAD_CURRENT_IBASE_OFFSET(rSELF)
148.endm
149
150/*
151 * Fetch the next instruction from rPC into rINST.  Does not advance rPC.
152 */
153.macro FETCH_INST
154    lhu     rINST, 0(rPC)
155.endm
156
157/* Advance rPC by some number of code units. */
158.macro ADVANCE count
159    daddu   rPC, rPC, (\count) * 2
160.endm
161
162/*
163 * Fetch the next instruction from an offset specified by _reg and advance xPC.
164 * xPC to point to the next instruction.  "_reg" must specify the distance
165 * in bytes, *not* 16-bit code units, and may be a signed value.  Must not set flags.
166 *
167 */
168.macro FETCH_ADVANCE_INST_RB reg
169    daddu   rPC, rPC, \reg
170    FETCH_INST
171.endm
172
173/*
174 * Fetch the next instruction from the specified offset.  Advances rPC
175 * to point to the next instruction.
176 *
177 * This must come AFTER anything that can throw an exception, or the
178 * exception catch may miss.  (This also implies that it must come after
179 * EXPORT_PC.)
180 */
181.macro FETCH_ADVANCE_INST count
182    ADVANCE \count
183    FETCH_INST
184.endm
185
186/*
187 * Similar to FETCH_ADVANCE_INST, but does not update rPC.  Used to load
188 * rINST ahead of possible exception point.  Be sure to manually advance rPC
189 * later.
190 */
191.macro PREFETCH_INST count
192    lhu     rINST, ((\count) * 2)(rPC)
193.endm
194
195/*
196 * Put the instruction's opcode field into the specified register.
197 */
198.macro GET_INST_OPCODE reg
199    and     \reg, rINST, 255
200.endm
201
202/*
203 * Begin executing the opcode in _reg.
204 */
205.macro GOTO_OPCODE reg
206    .set noat
207    sll     AT, \reg, 7
208    daddu   AT, rIBASE, AT
209    jic     AT, 0
210    .set at
211.endm
212
213/*
214 * Get/set the 32-bit value from a Dalvik register.
215 * Note, GET_VREG does sign extension to 64 bits while
216 * GET_VREG_U does zero extension to 64 bits.
217 * One is useful for arithmetic while the other is
218 * useful for storing the result value as 64-bit.
219 */
220.macro GET_VREG reg, vreg
221    .set noat
222    dlsa    AT, \vreg, rFP, 2
223    lw      \reg, 0(AT)
224    .set at
225.endm
226.macro GET_VREG_U reg, vreg
227    .set noat
228    dlsa    AT, \vreg, rFP, 2
229    lwu     \reg, 0(AT)
230    .set at
231.endm
232.macro GET_VREG_FLOAT reg, vreg
233    .set noat
234    dlsa    AT, \vreg, rFP, 2
235    lwc1    \reg, 0(AT)
236    .set at
237.endm
238.macro SET_VREG reg, vreg
239    .set noat
240    dlsa    AT, \vreg, rFP, 2
241    sw      \reg, 0(AT)
242    dlsa    AT, \vreg, rREFS, 2
243    sw      zero, 0(AT)
244    .set at
245.endm
246.macro SET_VREG_OBJECT reg, vreg
247    .set noat
248    dlsa    AT, \vreg, rFP, 2
249    sw      \reg, 0(AT)
250    dlsa    AT, \vreg, rREFS, 2
251    sw      \reg, 0(AT)
252    .set at
253.endm
254.macro SET_VREG_FLOAT reg, vreg
255    .set noat
256    dlsa    AT, \vreg, rFP, 2
257    swc1    \reg, 0(AT)
258    dlsa    AT, \vreg, rREFS, 2
259    sw      zero, 0(AT)
260    .set at
261.endm
262
263/*
264 * Get/set the 64-bit value from a Dalvik register.
265 * Avoid unaligned memory accesses.
266 * Note, SET_VREG_WIDE clobbers the register containing the value being stored.
267 * Note, SET_VREG_DOUBLE clobbers the register containing the Dalvik register number.
268 */
269.macro GET_VREG_WIDE reg, vreg
270    .set noat
271    dlsa    AT, \vreg, rFP, 2
272    lw      \reg, 0(AT)
273    lw      AT, 4(AT)
274    dinsu   \reg, AT, 32, 32
275    .set at
276.endm
277.macro GET_VREG_DOUBLE reg, vreg
278    .set noat
279    dlsa    AT, \vreg, rFP, 2
280    lwc1    \reg, 0(AT)
281    lw      AT, 4(AT)
282    mthc1   AT, \reg
283    .set at
284.endm
285.macro SET_VREG_WIDE reg, vreg
286    .set noat
287    dlsa    AT, \vreg, rFP, 2
288    sw      \reg, 0(AT)
289    drotr32 \reg, \reg, 0
290    sw      \reg, 4(AT)
291    dlsa    AT, \vreg, rREFS, 2
292    sw      zero, 0(AT)
293    sw      zero, 4(AT)
294    .set at
295.endm
296.macro SET_VREG_DOUBLE reg, vreg
297    .set noat
298    dlsa    AT, \vreg, rREFS, 2
299    sw      zero, 0(AT)
300    sw      zero, 4(AT)
301    dlsa    AT, \vreg, rFP, 2
302    swc1    \reg, 0(AT)
303    mfhc1   \vreg, \reg
304    sw      \vreg, 4(AT)
305    .set at
306.endm
307
308/*
309 * On-stack offsets for spilling/unspilling callee-saved registers
310 * and the frame size.
311 */
312#define STACK_OFFSET_RA 0
313#define STACK_OFFSET_GP 8
314#define STACK_OFFSET_S0 16
315#define STACK_OFFSET_S1 24
316#define STACK_OFFSET_S2 32
317#define STACK_OFFSET_S3 40
318#define STACK_OFFSET_S4 48
319#define STACK_OFFSET_S5 56
320#define STACK_OFFSET_S6 64
321#define STACK_SIZE      80    /* needs 16 byte alignment */
322
323/* Constants for float/double_to_int/long conversions */
324#define INT_MIN             0x80000000
325#define INT_MIN_AS_FLOAT    0xCF000000
326#define INT_MIN_AS_DOUBLE   0xC1E0000000000000
327#define LONG_MIN            0x8000000000000000
328#define LONG_MIN_AS_FLOAT   0xDF000000
329#define LONG_MIN_AS_DOUBLE  0xC3E0000000000000
330
331%def entry():
332/*
333 * Copyright (C) 2016 The Android Open Source Project
334 *
335 * Licensed under the Apache License, Version 2.0 (the "License");
336 * you may not use this file except in compliance with the License.
337 * You may obtain a copy of the License at
338 *
339 *      http://www.apache.org/licenses/LICENSE-2.0
340 *
341 * Unless required by applicable law or agreed to in writing, software
342 * distributed under the License is distributed on an "AS IS" BASIS,
343 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
344 * See the License for the specific language governing permissions and
345 * limitations under the License.
346 */
347
348/*
349 * Interpreter entry point.
350 */
351
352    .set    reorder
353
354    .text
355    .global ExecuteMterpImpl
356    .type   ExecuteMterpImpl, %function
357    .balign 16
358/*
359 * On entry:
360 *  a0  Thread* self
361 *  a1  dex_instructions
362 *  a2  ShadowFrame
363 *  a3  JValue* result_register
364 *
365 */
366ExecuteMterpImpl:
367    .cfi_startproc
368    .cpsetup t9, t8, ExecuteMterpImpl
369
370    .cfi_def_cfa sp, 0
371    daddu   sp, sp, -STACK_SIZE
372    .cfi_adjust_cfa_offset STACK_SIZE
373
374    sd      t8, STACK_OFFSET_GP(sp)
375    .cfi_rel_offset 28, STACK_OFFSET_GP
376    sd      ra, STACK_OFFSET_RA(sp)
377    .cfi_rel_offset 31, STACK_OFFSET_RA
378
379    sd      s0, STACK_OFFSET_S0(sp)
380    .cfi_rel_offset 16, STACK_OFFSET_S0
381    sd      s1, STACK_OFFSET_S1(sp)
382    .cfi_rel_offset 17, STACK_OFFSET_S1
383    sd      s2, STACK_OFFSET_S2(sp)
384    .cfi_rel_offset 18, STACK_OFFSET_S2
385    sd      s3, STACK_OFFSET_S3(sp)
386    .cfi_rel_offset 19, STACK_OFFSET_S3
387    sd      s4, STACK_OFFSET_S4(sp)
388    .cfi_rel_offset 20, STACK_OFFSET_S4
389    sd      s5, STACK_OFFSET_S5(sp)
390    .cfi_rel_offset 21, STACK_OFFSET_S5
391    sd      s6, STACK_OFFSET_S6(sp)
392    .cfi_rel_offset 22, STACK_OFFSET_S6
393
394    /* Remember the return register */
395    sd      a3, SHADOWFRAME_RESULT_REGISTER_OFFSET(a2)
396
397    /* Remember the dex instruction pointer */
398    sd      a1, SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET(a2)
399
400    /* set up "named" registers */
401    move    rSELF, a0
402    daddu   rFP, a2, SHADOWFRAME_VREGS_OFFSET
403    lw      v0, SHADOWFRAME_NUMBER_OF_VREGS_OFFSET(a2)
404    dlsa    rREFS, v0, rFP, 2
405    lw      v0, SHADOWFRAME_DEX_PC_OFFSET(a2)
406    dlsa    rPC, v0, a1, 1
407    CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
408    EXPORT_PC
409
410    /* Starting ibase */
411    REFRESH_IBASE
412
413    /* Set up for backwards branches & osr profiling */
414    ld      a0, OFF_FP_METHOD(rFP)
415    daddu   a1, rFP, OFF_FP_SHADOWFRAME
416    move    a2, rSELF
417    jal     MterpSetUpHotnessCountdown
418    move    rPROFILE, v0                # Starting hotness countdown to rPROFILE
419
420    /* start executing the instruction at rPC */
421    FETCH_INST
422    GET_INST_OPCODE v0
423    GOTO_OPCODE v0
424
425    /* NOTE: no fallthrough */
426
427%def dchecks_before_helper():
428    // Call C++ to do debug checks and return to the handler using tail call.
429    .extern MterpCheckBefore
430    dla     t9, MterpCheckBefore
431    move    a0, rSELF
432    daddu   a1, rFP, OFF_FP_SHADOWFRAME
433    move    a2, rPC
434    jalr    zero, t9                            # (self, shadow_frame, dex_pc_ptr) Note: tail call.
435
436%def opcode_pre():
437%  add_helper(dchecks_before_helper, "mterp_dchecks_before_helper")
438    #if !defined(NDEBUG)
439    jal    SYMBOL(mterp_dchecks_before_helper)
440    #endif
441
442%def fallback():
443/* Transfer stub to alternate interpreter */
444    b       MterpFallback
445
446%def helpers():
447%  pass
448
449%def footer():
450/*
451 * We've detected a condition that will result in an exception, but the exception
452 * has not yet been thrown.  Just bail out to the reference interpreter to deal with it.
453 * TUNING: for consistency, we may want to just go ahead and handle these here.
454 */
455
456    .extern MterpLogDivideByZeroException
457common_errDivideByZero:
458    EXPORT_PC
459#if MTERP_LOGGING
460    move    a0, rSELF
461    daddu   a1, rFP, OFF_FP_SHADOWFRAME
462    jal     MterpLogDivideByZeroException
463#endif
464    b       MterpCommonFallback
465
466    .extern MterpLogArrayIndexException
467common_errArrayIndex:
468    EXPORT_PC
469#if MTERP_LOGGING
470    move    a0, rSELF
471    daddu   a1, rFP, OFF_FP_SHADOWFRAME
472    jal     MterpLogArrayIndexException
473#endif
474    b       MterpCommonFallback
475
476    .extern MterpLogNullObjectException
477common_errNullObject:
478    EXPORT_PC
479#if MTERP_LOGGING
480    move    a0, rSELF
481    daddu   a1, rFP, OFF_FP_SHADOWFRAME
482    jal     MterpLogNullObjectException
483#endif
484    b       MterpCommonFallback
485
486/*
487 * If we're here, something is out of the ordinary.  If there is a pending
488 * exception, handle it.  Otherwise, roll back and retry with the reference
489 * interpreter.
490 */
491MterpPossibleException:
492    ld      a0, THREAD_EXCEPTION_OFFSET(rSELF)
493    beqzc   a0, MterpFallback                       # If not, fall back to reference interpreter.
494    /* intentional fallthrough - handle pending exception. */
495/*
496 * On return from a runtime helper routine, we've found a pending exception.
497 * Can we handle it here - or need to bail out to caller?
498 *
499 */
500    .extern MterpHandleException
501    .extern MterpShouldSwitchInterpreters
502MterpException:
503    move    a0, rSELF
504    daddu   a1, rFP, OFF_FP_SHADOWFRAME
505    jal     MterpHandleException                    # (self, shadow_frame)
506    beqzc   v0, MterpExceptionReturn                # no local catch, back to caller.
507    ld      a0, OFF_FP_DEX_INSTRUCTIONS(rFP)
508    lwu     a1, OFF_FP_DEX_PC(rFP)
509    REFRESH_IBASE
510    dlsa    rPC, a1, a0, 1                          # generate new dex_pc_ptr
511    /* Do we need to switch interpreters? */
512    jal     MterpShouldSwitchInterpreters
513    bnezc   v0, MterpFallback
514    /* resume execution at catch block */
515    EXPORT_PC
516    FETCH_INST
517    GET_INST_OPCODE v0
518    GOTO_OPCODE v0
519    /* NOTE: no fallthrough */
520
521/*
522 * Common handling for branches with support for Jit profiling.
523 * On entry:
524 *    rINST          <= signed offset
525 *    rPROFILE       <= signed hotness countdown (expanded to 64 bits)
526 *
527 * We have quite a few different cases for branch profiling, OSR detection and
528 * suspend check support here.
529 *
530 * Taken backward branches:
531 *    If profiling active, do hotness countdown and report if we hit zero.
532 *    If in osr check mode, see if our target is a compiled loop header entry and do OSR if so.
533 *    Is there a pending suspend request?  If so, suspend.
534 *
535 * Taken forward branches and not-taken backward branches:
536 *    If in osr check mode, see if our target is a compiled loop header entry and do OSR if so.
537 *
538 * Our most common case is expected to be a taken backward branch with active jit profiling,
539 * but no full OSR check and no pending suspend request.
540 * Next most common case is not-taken branch with no full OSR check.
541 *
542 */
543MterpCommonTakenBranchNoFlags:
544    bgtzc   rINST, .L_forward_branch    # don't add forward branches to hotness
545/*
546 * We need to subtract 1 from positive values and we should not see 0 here,
547 * so we may use the result of the comparison with -1.
548 */
549    li      v0, JIT_CHECK_OSR
550    beqc    rPROFILE, v0, .L_osr_check
551    bltc    rPROFILE, v0, .L_resume_backward_branch
552    dsubu   rPROFILE, 1
553    beqzc   rPROFILE, .L_add_batch      # counted down to zero - report
554.L_resume_backward_branch:
555    lw      ra, THREAD_FLAGS_OFFSET(rSELF)
556    REFRESH_IBASE
557    daddu   a2, rINST, rINST            # a2<- byte offset
558    FETCH_ADVANCE_INST_RB a2            # update rPC, load rINST
559    and     ra, THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
560    bnezc   ra, .L_suspend_request_pending
561    GET_INST_OPCODE v0                  # extract opcode from rINST
562    GOTO_OPCODE v0                      # jump to next instruction
563
564.L_suspend_request_pending:
565    EXPORT_PC
566    move    a0, rSELF
567    jal     MterpSuspendCheck           # (self)
568    bnezc   v0, MterpFallback
569    REFRESH_IBASE                       # might have changed during suspend
570    GET_INST_OPCODE v0                  # extract opcode from rINST
571    GOTO_OPCODE v0                      # jump to next instruction
572
573.L_no_count_backwards:
574    li      v0, JIT_CHECK_OSR           # check for possible OSR re-entry
575    bnec    rPROFILE, v0, .L_resume_backward_branch
576.L_osr_check:
577    move    a0, rSELF
578    daddu   a1, rFP, OFF_FP_SHADOWFRAME
579    move    a2, rINST
580    EXPORT_PC
581    jal MterpMaybeDoOnStackReplacement  # (self, shadow_frame, offset)
582    bnezc   v0, MterpOnStackReplacement
583    b       .L_resume_backward_branch
584
585.L_forward_branch:
586    li      v0, JIT_CHECK_OSR           # check for possible OSR re-entry
587    beqc    rPROFILE, v0, .L_check_osr_forward
588.L_resume_forward_branch:
589    daddu   a2, rINST, rINST            # a2<- byte offset
590    FETCH_ADVANCE_INST_RB a2            # update rPC, load rINST
591    GET_INST_OPCODE v0                  # extract opcode from rINST
592    GOTO_OPCODE v0                      # jump to next instruction
593
594.L_check_osr_forward:
595    move    a0, rSELF
596    daddu   a1, rFP, OFF_FP_SHADOWFRAME
597    move    a2, rINST
598    EXPORT_PC
599    jal     MterpMaybeDoOnStackReplacement # (self, shadow_frame, offset)
600    bnezc   v0, MterpOnStackReplacement
601    b       .L_resume_forward_branch
602
603.L_add_batch:
604    daddu   a1, rFP, OFF_FP_SHADOWFRAME
605    sh      rPROFILE, SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET(a1)
606    ld      a0, OFF_FP_METHOD(rFP)
607    move    a2, rSELF
608    jal     MterpAddHotnessBatch        # (method, shadow_frame, self)
609    move    rPROFILE, v0                # restore new hotness countdown to rPROFILE
610    b       .L_no_count_backwards
611
612/*
613 * Entered from the conditional branch handlers when OSR check request active on
614 * not-taken path.  All Dalvik not-taken conditional branch offsets are 2.
615 */
616.L_check_not_taken_osr:
617    move    a0, rSELF
618    daddu   a1, rFP, OFF_FP_SHADOWFRAME
619    li      a2, 2
620    EXPORT_PC
621    jal     MterpMaybeDoOnStackReplacement # (self, shadow_frame, offset)
622    bnezc   v0, MterpOnStackReplacement
623    FETCH_ADVANCE_INST 2
624    GET_INST_OPCODE v0                  # extract opcode from rINST
625    GOTO_OPCODE v0                      # jump to next instruction
626
627/*
628 * On-stack replacement has happened, and now we've returned from the compiled method.
629 */
630MterpOnStackReplacement:
631#if MTERP_LOGGING
632    move    a0, rSELF
633    daddu   a1, rFP, OFF_FP_SHADOWFRAME
634    move    a2, rINST                               # rINST contains offset
635    jal     MterpLogOSR
636#endif
637    li      v0, 1                                   # Signal normal return
638    b       MterpDone
639
640/*
641 * Bail out to reference interpreter.
642 */
643    .extern MterpLogFallback
644MterpFallback:
645    EXPORT_PC
646#if MTERP_LOGGING
647    move    a0, rSELF
648    daddu   a1, rFP, OFF_FP_SHADOWFRAME
649    jal     MterpLogFallback
650#endif
651MterpCommonFallback:
652    li      v0, 0                                   # signal retry with reference interpreter.
653    b       MterpDone
654
655/*
656 * We pushed some registers on the stack in ExecuteMterpImpl, then saved
657 * SP and RA.  Here we restore SP, restore the registers, and then restore
658 * RA to PC.
659 *
660 * On entry:
661 *  uint32_t* rFP  (should still be live, pointer to base of vregs)
662 */
663MterpExceptionReturn:
664    li      v0, 1                                   # signal return to caller.
665    b       MterpDone
666/*
667 * Returned value is expected in a0 and if it's not 64-bit, the 32 most
668 * significant bits of a0 must be zero-extended or sign-extended
669 * depending on the return type.
670 */
671MterpReturn:
672    ld      a2, OFF_FP_RESULT_REGISTER(rFP)
673    sd      a0, 0(a2)
674    li      v0, 1                                   # signal return to caller.
675MterpDone:
676/*
677 * At this point, we expect rPROFILE to be non-zero.  If negative, hotness is disabled or we're
678 * checking for OSR.  If greater than zero, we might have unreported hotness to register
679 * (the difference between the ending rPROFILE and the cached hotness counter).  rPROFILE
680 * should only reach zero immediately after a hotness decrement, and is then reset to either
681 * a negative special state or the new non-zero countdown value.
682 */
683    blez    rPROFILE, .L_pop_and_return # if > 0, we may have some counts to report.
684
685MterpProfileActive:
686    move    rINST, v0                   # stash return value
687    /* Report cached hotness counts */
688    ld      a0, OFF_FP_METHOD(rFP)
689    daddu   a1, rFP, OFF_FP_SHADOWFRAME
690    move    a2, rSELF
691    sh      rPROFILE, SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET(a1)
692    jal     MterpAddHotnessBatch        # (method, shadow_frame, self)
693    move    v0, rINST                   # restore return value
694
695.L_pop_and_return:
696    ld      s6, STACK_OFFSET_S6(sp)
697    .cfi_restore 22
698    ld      s5, STACK_OFFSET_S5(sp)
699    .cfi_restore 21
700    ld      s4, STACK_OFFSET_S4(sp)
701    .cfi_restore 20
702    ld      s3, STACK_OFFSET_S3(sp)
703    .cfi_restore 19
704    ld      s2, STACK_OFFSET_S2(sp)
705    .cfi_restore 18
706    ld      s1, STACK_OFFSET_S1(sp)
707    .cfi_restore 17
708    ld      s0, STACK_OFFSET_S0(sp)
709    .cfi_restore 16
710
711    ld      ra, STACK_OFFSET_RA(sp)
712    .cfi_restore 31
713
714    ld      t8, STACK_OFFSET_GP(sp)
715    .cpreturn
716    .cfi_restore 28
717
718    .set    noreorder
719    jr      ra
720    daddu   sp, sp, STACK_SIZE
721    .cfi_adjust_cfa_offset -STACK_SIZE
722
723    .cfi_endproc
724    .set    reorder
725    .size ExecuteMterpImpl, .-ExecuteMterpImpl
726
727%def instruction_end():
728
729    .global artMterpAsmInstructionEnd
730artMterpAsmInstructionEnd:
731
732%def instruction_start():
733
734    .global artMterpAsmInstructionStart
735artMterpAsmInstructionStart = .L_op_nop
736    .text
737
738%def opcode_start():
739%  pass
740%def opcode_end():
741%  pass
742%def helper_start(name):
743    ENTRY ${name}
744%def helper_end(name):
745    END ${name}
746