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/*
19  Art assembly interpreter notes:
20
21  First validate assembly code by implementing ExecuteXXXImpl() style body (doesn't
22  handle invoke, allows higher-level code to create frame & shadow frame.
23
24  Once that's working, support direct entry code & eliminate shadow frame (and
25  excess locals allocation.
26
27  Some (hopefully) temporary ugliness.  We'll treat rFP as pointing to the
28  base of the vreg array within the shadow frame.  Access the other fields,
29  dex_pc_, method_ and number_of_vregs_ via negative offsets.  For now, we'll continue
30  the shadow frame mechanism of double-storing object references - via rFP &
31  number_of_vregs_.
32
33 */
34
35#include "asm_support.h"
36#include "interpreter/cfi_asm_support.h"
37
38#if (__mips==32) && (__mips_isa_rev>=2)
39#define MIPS32REVGE2    /* mips32r2 and greater */
40#if (__mips==32) && (__mips_isa_rev>=5)
41#define FPU64           /* 64 bit FPU */
42#if (__mips==32) && (__mips_isa_rev>=6)
43#define MIPS32REVGE6    /* mips32r6 and greater */
44#endif
45#endif
46#endif
47
48/* MIPS definitions and declarations
49
50   reg  nick      purpose
51   s0   rPC       interpreted program counter, used for fetching instructions
52   s1   rFP       interpreted frame pointer, used for accessing locals and args
53   s2   rSELF     self (Thread) pointer
54   s3   rIBASE    interpreted instruction base pointer, used for computed goto
55   s4   rINST     first 16-bit code unit of current instruction
56   s5   rOBJ      object pointer
57   s6   rREFS     base of object references in shadow frame (ideally, we'll get rid of this later).
58   s7   rTEMP     used as temp storage that can survive a function call
59   s8   rPROFILE  branch profiling countdown
60
61*/
62
63/* single-purpose registers, given names for clarity */
64#define rPC s0
65#define CFI_DEX 16  // DWARF register number of the register holding dex-pc (s0).
66#define CFI_TMP 4   // DWARF register number of the first argument register (a0).
67#define rFP s1
68#define rSELF s2
69#define rIBASE s3
70#define rINST s4
71#define rOBJ s5
72#define rREFS s6
73#define rTEMP s7
74#define rPROFILE s8
75
76#define rARG0 a0
77#define rARG1 a1
78#define rARG2 a2
79#define rARG3 a3
80#define rRESULT0 v0
81#define rRESULT1 v1
82
83/* GP register definitions */
84#define zero    $$0      /* always zero */
85#define AT      $$at     /* assembler temp */
86#define v0      $$2      /* return value */
87#define v1      $$3
88#define a0      $$4      /* argument registers */
89#define a1      $$5
90#define a2      $$6
91#define a3      $$7
92#define t0      $$8      /* temp registers (not saved across subroutine calls) */
93#define t1      $$9
94#define t2      $$10
95#define t3      $$11
96#define t4      $$12
97#define t5      $$13
98#define t6      $$14
99#define t7      $$15
100#define ta0     $$12     /* alias */
101#define ta1     $$13
102#define ta2     $$14
103#define ta3     $$15
104#define s0      $$16     /* saved across subroutine calls (callee saved) */
105#define s1      $$17
106#define s2      $$18
107#define s3      $$19
108#define s4      $$20
109#define s5      $$21
110#define s6      $$22
111#define s7      $$23
112#define t8      $$24     /* two more temp registers */
113#define t9      $$25
114#define k0      $$26     /* kernel temporary */
115#define k1      $$27
116#define gp      $$28     /* global pointer */
117#define sp      $$29     /* stack pointer */
118#define s8      $$30     /* one more callee saved */
119#define ra      $$31     /* return address */
120
121/* FP register definitions */
122#define fv0    $$f0
123#define fv0f   $$f1
124#define fv1    $$f2
125#define fv1f   $$f3
126#define fa0    $$f12
127#define fa0f   $$f13
128#define fa1    $$f14
129#define fa1f   $$f15
130#define ft0    $$f4
131#define ft0f   $$f5
132#define ft1    $$f6
133#define ft1f   $$f7
134#define ft2    $$f8
135#define ft2f   $$f9
136#define ft3    $$f10
137#define ft3f   $$f11
138#define ft4    $$f16
139#define ft4f   $$f17
140#define ft5    $$f18
141#define ft5f   $$f19
142#define fs0    $$f20
143#define fs0f   $$f21
144#define fs1    $$f22
145#define fs1f   $$f23
146#define fs2    $$f24
147#define fs2f   $$f25
148#define fs3    $$f26
149#define fs3f   $$f27
150#define fs4    $$f28
151#define fs4f   $$f29
152#define fs5    $$f30
153#define fs5f   $$f31
154
155#ifndef MIPS32REVGE6
156#define fcc0   $$fcc0
157#define fcc1   $$fcc1
158#endif
159
160#ifdef MIPS32REVGE2
161#define SEB(rd, rt) \
162    seb       rd, rt
163#define SEH(rd, rt) \
164    seh       rd, rt
165#define INSERT_HIGH_HALF(rd_lo, rt_hi) \
166    ins       rd_lo, rt_hi, 16, 16
167#else
168#define SEB(rd, rt) \
169    sll       rd, rt, 24; \
170    sra       rd, rd, 24
171#define SEH(rd, rt) \
172    sll       rd, rt, 16; \
173    sra       rd, rd, 16
174/* Clobbers rt_hi on pre-R2. */
175#define INSERT_HIGH_HALF(rd_lo, rt_hi) \
176    sll       rt_hi, rt_hi, 16; \
177    or        rd_lo, rt_hi
178#endif
179
180#ifdef FPU64
181#define MOVE_TO_FPU_HIGH(r, flo, fhi) \
182    mthc1     r, flo
183#else
184#define MOVE_TO_FPU_HIGH(r, flo, fhi) \
185    mtc1      r, fhi
186#endif
187
188#ifdef MIPS32REVGE6
189#define JR(rt) \
190    jic       rt, 0
191#define LSA(rd, rs, rt, sa) \
192    .if sa; \
193    lsa       rd, rs, rt, sa; \
194    .else; \
195    addu      rd, rs, rt; \
196    .endif
197#else
198#define JR(rt) \
199    jalr      zero, rt
200#define LSA(rd, rs, rt, sa) \
201    .if sa; \
202    .set      push; \
203    .set      noat; \
204    sll       AT, rs, sa; \
205    addu      rd, AT, rt; \
206    .set      pop; \
207    .else; \
208    addu      rd, rs, rt; \
209    .endif
210#endif
211
212/*
213 * Instead of holding a pointer to the shadow frame, we keep rFP at the base of the vregs.  So,
214 * to access other shadow frame fields, we need to use a backwards offset.  Define those here.
215 */
216#define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET)
217#define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET)
218#define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET)
219#define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET)
220#define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
221#define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
222#define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
223#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET)
224#define OFF_FP_SHADOWFRAME OFF_FP(0)
225
226#define MTERP_PROFILE_BRANCHES 1
227#define MTERP_LOGGING 0
228
229/*
230 * "export" the PC to dex_pc field in the shadow frame, f/b/o future exception objects.  Must
231 * be done *before* something throws.
232 *
233 * It's okay to do this more than once.
234 *
235 * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped
236 * dex byte codes.  However, the rest of the runtime expects dex pc to be an instruction
237 * offset into the code_items_[] array.  For effiency, we will "export" the
238 * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC
239 * to convert to a dex pc when needed.
240 */
241#define EXPORT_PC() \
242    sw        rPC, OFF_FP_DEX_PC_PTR(rFP)
243
244#define EXPORT_DEX_PC(tmp) \
245    lw        tmp, OFF_FP_DEX_INSTRUCTIONS(rFP); \
246    sw        rPC, OFF_FP_DEX_PC_PTR(rFP); \
247    subu      tmp, rPC, tmp; \
248    sra       tmp, tmp, 1; \
249    sw        tmp, OFF_FP_DEX_PC(rFP)
250
251/*
252 * Fetch the next instruction from rPC into rINST.  Does not advance rPC.
253 */
254#define FETCH_INST() lhu rINST, (rPC)
255
256/*
257 * Fetch the next instruction from the specified offset.  Advances rPC
258 * to point to the next instruction.  "_count" is in 16-bit code units.
259 *
260 * This must come AFTER anything that can throw an exception, or the
261 * exception catch may miss.  (This also implies that it must come after
262 * EXPORT_PC().)
263 */
264#define FETCH_ADVANCE_INST(_count) \
265    lhu       rINST, ((_count)*2)(rPC); \
266    addu      rPC, rPC, ((_count) * 2)
267
268/*
269 * Similar to FETCH_ADVANCE_INST, but does not update rPC.  Used to load
270 * rINST ahead of possible exception point.  Be sure to manually advance rPC
271 * later.
272 */
273#define PREFETCH_INST(_count) lhu rINST, ((_count)*2)(rPC)
274
275/* Advance rPC by some number of code units. */
276#define ADVANCE(_count) addu rPC, rPC, ((_count) * 2)
277
278/*
279 * Fetch the next instruction from an offset specified by rd.  Updates
280 * rPC to point to the next instruction.  "rd" must specify the distance
281 * in bytes, *not* 16-bit code units, and may be a signed value.
282 */
283#define FETCH_ADVANCE_INST_RB(rd) \
284    addu      rPC, rPC, rd; \
285    lhu       rINST, (rPC)
286
287/*
288 * Fetch a half-word code unit from an offset past the current PC.  The
289 * "_count" value is in 16-bit code units.  Does not advance rPC.
290 *
291 * The "_S" variant works the same but treats the value as signed.
292 */
293#define FETCH(rd, _count) lhu rd, ((_count) * 2)(rPC)
294#define FETCH_S(rd, _count) lh rd, ((_count) * 2)(rPC)
295
296/*
297 * Fetch one byte from an offset past the current PC.  Pass in the same
298 * "_count" as you would for FETCH, and an additional 0/1 indicating which
299 * byte of the halfword you want (lo/hi).
300 */
301#define FETCH_B(rd, _count, _byte) lbu rd, ((_count) * 2 + _byte)(rPC)
302
303/*
304 * Put the instruction's opcode field into the specified register.
305 */
306#define GET_INST_OPCODE(rd) and rd, rINST, 0xFF
307
308/*
309 * Transform opcode into branch target address.
310 */
311#define GET_OPCODE_TARGET(rd) \
312    sll       rd, rd, ${handler_size_bits}; \
313    addu      rd, rIBASE, rd
314
315/*
316 * Begin executing the opcode in rd.
317 */
318#define GOTO_OPCODE(rd) \
319    GET_OPCODE_TARGET(rd); \
320    JR(rd)
321
322/*
323 * Get/set the 32-bit value from a Dalvik register.
324 */
325#define GET_VREG(rd, rix) LOAD_eas2(rd, rFP, rix)
326
327#define GET_VREG_F(rd, rix) \
328    .set noat; \
329    EAS2(AT, rFP, rix); \
330    l.s       rd, (AT); \
331    .set at
332
333#ifdef MIPS32REVGE6
334#define SET_VREG(rd, rix) \
335    lsa       t8, rix, rFP, 2; \
336    sw        rd, 0(t8); \
337    lsa       t8, rix, rREFS, 2; \
338    sw        zero, 0(t8)
339#else
340#define SET_VREG(rd, rix) \
341    .set noat; \
342    sll       AT, rix, 2; \
343    addu      t8, rFP, AT; \
344    sw        rd, 0(t8); \
345    addu      t8, rREFS, AT; \
346    .set at; \
347    sw        zero, 0(t8)
348#endif
349
350#ifdef MIPS32REVGE6
351#define SET_VREG_OBJECT(rd, rix) \
352    lsa       t8, rix, rFP, 2; \
353    sw        rd, 0(t8); \
354    lsa       t8, rix, rREFS, 2; \
355    sw        rd, 0(t8)
356#else
357#define SET_VREG_OBJECT(rd, rix) \
358    .set noat; \
359    sll       AT, rix, 2; \
360    addu      t8, rFP, AT; \
361    sw        rd, 0(t8); \
362    addu      t8, rREFS, AT; \
363    .set at; \
364    sw        rd, 0(t8)
365#endif
366
367#ifdef MIPS32REVGE6
368#define SET_VREG64(rlo, rhi, rix) \
369    lsa       t8, rix, rFP, 2; \
370    sw        rlo, 0(t8); \
371    sw        rhi, 4(t8); \
372    lsa       t8, rix, rREFS, 2; \
373    sw        zero, 0(t8); \
374    sw        zero, 4(t8)
375#else
376#define SET_VREG64(rlo, rhi, rix) \
377    .set noat; \
378    sll       AT, rix, 2; \
379    addu      t8, rFP, AT; \
380    sw        rlo, 0(t8); \
381    sw        rhi, 4(t8); \
382    addu      t8, rREFS, AT; \
383    .set at; \
384    sw        zero, 0(t8); \
385    sw        zero, 4(t8)
386#endif
387
388#ifdef MIPS32REVGE6
389#define SET_VREG_F(rd, rix) \
390    lsa       t8, rix, rFP, 2; \
391    s.s       rd, 0(t8); \
392    lsa       t8, rix, rREFS, 2; \
393    sw        zero, 0(t8)
394#else
395#define SET_VREG_F(rd, rix) \
396    .set noat; \
397    sll       AT, rix, 2; \
398    addu      t8, rFP, AT; \
399    s.s       rd, 0(t8); \
400    addu      t8, rREFS, AT; \
401    .set at; \
402    sw        zero, 0(t8)
403#endif
404
405#ifdef MIPS32REVGE6
406#define SET_VREG64_F(rlo, rhi, rix) \
407    lsa       t8, rix, rFP, 2; \
408    .set noat; \
409    mfhc1     AT, rlo; \
410    s.s       rlo, 0(t8); \
411    sw        AT, 4(t8); \
412    .set at; \
413    lsa       t8, rix, rREFS, 2; \
414    sw        zero, 0(t8); \
415    sw        zero, 4(t8)
416#elif defined(FPU64)
417#define SET_VREG64_F(rlo, rhi, rix) \
418    .set noat; \
419    sll       AT, rix, 2; \
420    addu      t8, rREFS, AT; \
421    sw        zero, 0(t8); \
422    sw        zero, 4(t8); \
423    addu      t8, rFP, AT; \
424    mfhc1     AT, rlo; \
425    sw        AT, 4(t8); \
426    .set at; \
427    s.s       rlo, 0(t8)
428#else
429#define SET_VREG64_F(rlo, rhi, rix) \
430    .set noat; \
431    sll       AT, rix, 2; \
432    addu      t8, rFP, AT; \
433    s.s       rlo, 0(t8); \
434    s.s       rhi, 4(t8); \
435    addu      t8, rREFS, AT; \
436    .set at; \
437    sw        zero, 0(t8); \
438    sw        zero, 4(t8)
439#endif
440
441/* Combination of the SET_VREG and GOTO_OPCODE functions to save 1 instruction */
442#ifdef MIPS32REVGE6
443#define SET_VREG_GOTO(rd, rix, dst) \
444    .set noreorder; \
445    GET_OPCODE_TARGET(dst); \
446    lsa       t8, rix, rFP, 2; \
447    sw        rd, 0(t8); \
448    lsa       t8, rix, rREFS, 2; \
449    jalr      zero, dst; \
450    sw        zero, 0(t8); \
451    .set reorder
452#else
453#define SET_VREG_GOTO(rd, rix, dst) \
454    .set noreorder; \
455    GET_OPCODE_TARGET(dst); \
456    .set noat; \
457    sll       AT, rix, 2; \
458    addu      t8, rFP, AT; \
459    sw        rd, 0(t8); \
460    addu      t8, rREFS, AT; \
461    .set at; \
462    jalr      zero, dst; \
463    sw        zero, 0(t8); \
464    .set reorder
465#endif
466
467/* Combination of the SET_VREG_OBJECT and GOTO_OPCODE functions to save 1 instruction */
468#ifdef MIPS32REVGE6
469#define SET_VREG_OBJECT_GOTO(rd, rix, dst) \
470    .set noreorder; \
471    GET_OPCODE_TARGET(dst); \
472    lsa       t8, rix, rFP, 2; \
473    sw        rd, 0(t8); \
474    lsa       t8, rix, rREFS, 2; \
475    jalr      zero, dst; \
476    sw        rd, 0(t8); \
477    .set reorder
478#else
479#define SET_VREG_OBJECT_GOTO(rd, rix, dst) \
480    .set noreorder; \
481    GET_OPCODE_TARGET(dst); \
482    .set noat; \
483    sll       AT, rix, 2; \
484    addu      t8, rFP, AT; \
485    sw        rd, 0(t8); \
486    addu      t8, rREFS, AT; \
487    .set at; \
488    jalr      zero, dst; \
489    sw        rd, 0(t8); \
490    .set reorder
491#endif
492
493/* Combination of the SET_VREG64 and GOTO_OPCODE functions to save 1 instruction */
494#ifdef MIPS32REVGE6
495#define SET_VREG64_GOTO(rlo, rhi, rix, dst) \
496    .set noreorder; \
497    GET_OPCODE_TARGET(dst); \
498    lsa       t8, rix, rFP, 2; \
499    sw        rlo, 0(t8); \
500    sw        rhi, 4(t8); \
501    lsa       t8, rix, rREFS, 2; \
502    sw        zero, 0(t8); \
503    jalr      zero, dst; \
504    sw        zero, 4(t8); \
505    .set reorder
506#else
507#define SET_VREG64_GOTO(rlo, rhi, rix, dst) \
508    .set noreorder; \
509    GET_OPCODE_TARGET(dst); \
510    .set noat; \
511    sll       AT, rix, 2; \
512    addu      t8, rFP, AT; \
513    sw        rlo, 0(t8); \
514    sw        rhi, 4(t8); \
515    addu      t8, rREFS, AT; \
516    .set at; \
517    sw        zero, 0(t8); \
518    jalr      zero, dst; \
519    sw        zero, 4(t8); \
520    .set reorder
521#endif
522
523/* Combination of the SET_VREG_F and GOTO_OPCODE functions to save 1 instruction */
524#ifdef MIPS32REVGE6
525#define SET_VREG_F_GOTO(rd, rix, dst) \
526    .set noreorder; \
527    GET_OPCODE_TARGET(dst); \
528    lsa       t8, rix, rFP, 2; \
529    s.s       rd, 0(t8); \
530    lsa       t8, rix, rREFS, 2; \
531    jalr      zero, dst; \
532    sw        zero, 0(t8); \
533    .set reorder
534#else
535#define SET_VREG_F_GOTO(rd, rix, dst) \
536    .set noreorder; \
537    GET_OPCODE_TARGET(dst); \
538    .set noat; \
539    sll       AT, rix, 2; \
540    addu      t8, rFP, AT; \
541    s.s       rd, 0(t8); \
542    addu      t8, rREFS, AT; \
543    .set at; \
544    jalr      zero, dst; \
545    sw        zero, 0(t8); \
546    .set reorder
547#endif
548
549/* Combination of the SET_VREG64_F and GOTO_OPCODE functions to save 1 instruction */
550#ifdef MIPS32REVGE6
551#define SET_VREG64_F_GOTO(rlo, rhi, rix, dst) \
552    .set noreorder; \
553    GET_OPCODE_TARGET(dst); \
554    lsa       t8, rix, rFP, 2; \
555    .set noat; \
556    mfhc1     AT, rlo; \
557    s.s       rlo, 0(t8); \
558    sw        AT, 4(t8); \
559    .set at; \
560    lsa       t8, rix, rREFS, 2; \
561    sw        zero, 0(t8); \
562    jalr      zero, dst; \
563    sw        zero, 4(t8); \
564    .set reorder
565#elif defined(FPU64)
566#define SET_VREG64_F_GOTO(rlo, rhi, rix, dst) \
567    .set noreorder; \
568    GET_OPCODE_TARGET(dst); \
569    .set noat; \
570    sll       AT, rix, 2; \
571    addu      t8, rREFS, AT; \
572    sw        zero, 0(t8); \
573    sw        zero, 4(t8); \
574    addu      t8, rFP, AT; \
575    mfhc1     AT, rlo; \
576    sw        AT, 4(t8); \
577    .set at; \
578    jalr      zero, dst; \
579    s.s       rlo, 0(t8); \
580    .set reorder
581#else
582#define SET_VREG64_F_GOTO(rlo, rhi, rix, dst) \
583    .set noreorder; \
584    GET_OPCODE_TARGET(dst); \
585    .set noat; \
586    sll       AT, rix, 2; \
587    addu      t8, rFP, AT; \
588    s.s       rlo, 0(t8); \
589    s.s       rhi, 4(t8); \
590    addu      t8, rREFS, AT; \
591    .set at; \
592    sw        zero, 0(t8); \
593    jalr      zero, dst; \
594    sw        zero, 4(t8); \
595    .set reorder
596#endif
597
598#define GET_OPA(rd) srl rd, rINST, 8
599#ifdef MIPS32REVGE2
600#define GET_OPA4(rd) ext rd, rINST, 8, 4
601#else
602#define GET_OPA4(rd) GET_OPA(rd); and rd, 0xf
603#endif
604#define GET_OPB(rd) srl rd, rINST, 12
605
606/*
607 * Form an Effective Address rd = rbase + roff<<shift;
608 * Uses reg AT on pre-R6.
609 */
610#define EASN(rd, rbase, roff, shift) LSA(rd, roff, rbase, shift)
611
612#define EAS1(rd, rbase, roff) EASN(rd, rbase, roff, 1)
613#define EAS2(rd, rbase, roff) EASN(rd, rbase, roff, 2)
614#define EAS3(rd, rbase, roff) EASN(rd, rbase, roff, 3)
615#define EAS4(rd, rbase, roff) EASN(rd, rbase, roff, 4)
616
617#define LOAD_eas2(rd, rbase, roff) \
618    .set noat; \
619    EAS2(AT, rbase, roff); \
620    lw        rd, 0(AT); \
621    .set at
622
623#define STORE_eas2(rd, rbase, roff) \
624    .set noat; \
625    EAS2(AT, rbase, roff); \
626    sw        rd, 0(AT); \
627    .set at
628
629#define LOAD_RB_OFF(rd, rbase, off) lw rd, off(rbase)
630#define STORE_RB_OFF(rd, rbase, off) sw rd, off(rbase)
631
632#define STORE64_off(rlo, rhi, rbase, off) \
633    sw        rlo, off(rbase); \
634    sw        rhi, (off+4)(rbase)
635#define LOAD64_off(rlo, rhi, rbase, off) \
636    lw        rlo, off(rbase); \
637    lw        rhi, (off+4)(rbase)
638
639#define STORE64(rlo, rhi, rbase) STORE64_off(rlo, rhi, rbase, 0)
640#define LOAD64(rlo, rhi, rbase) LOAD64_off(rlo, rhi, rbase, 0)
641
642#ifdef FPU64
643#define STORE64_off_F(rlo, rhi, rbase, off) \
644    s.s       rlo, off(rbase); \
645    .set noat; \
646    mfhc1     AT, rlo; \
647    sw        AT, (off+4)(rbase); \
648    .set at
649#define LOAD64_off_F(rlo, rhi, rbase, off) \
650    l.s       rlo, off(rbase); \
651    .set noat; \
652    lw        AT, (off+4)(rbase); \
653    mthc1     AT, rlo; \
654    .set at
655#else
656#define STORE64_off_F(rlo, rhi, rbase, off) \
657    s.s       rlo, off(rbase); \
658    s.s       rhi, (off+4)(rbase)
659#define LOAD64_off_F(rlo, rhi, rbase, off) \
660    l.s       rlo, off(rbase); \
661    l.s       rhi, (off+4)(rbase)
662#endif
663
664#define STORE64_F(rlo, rhi, rbase) STORE64_off_F(rlo, rhi, rbase, 0)
665#define LOAD64_F(rlo, rhi, rbase) LOAD64_off_F(rlo, rhi, rbase, 0)
666
667#define LOAD_base_offMirrorArray_length(rd, rbase) LOAD_RB_OFF(rd, rbase, MIRROR_ARRAY_LENGTH_OFFSET)
668
669#define STACK_STORE(rd, off) sw rd, off(sp)
670#define STACK_LOAD(rd, off) lw rd, off(sp)
671#define CREATE_STACK(n) subu sp, sp, n
672#define DELETE_STACK(n) addu sp, sp, n
673
674#define LOAD_ADDR(dest, addr) la dest, addr
675#define LOAD_IMM(dest, imm) li dest, imm
676#define MOVE_REG(dest, src) move dest, src
677#define STACK_SIZE 128
678
679#define STACK_OFFSET_ARG04 16
680#define STACK_OFFSET_ARG05 20
681#define STACK_OFFSET_ARG06 24
682#define STACK_OFFSET_ARG07 28
683#define STACK_OFFSET_GP    84
684
685#define JAL(n) jal n
686#define BAL(n) bal n
687
688/*
689 * FP register usage restrictions:
690 * 1) We don't use the callee save FP registers so we don't have to save them.
691 * 2) We don't use the odd FP registers so we can share code with mips32r6.
692 */
693#define STACK_STORE_FULL() CREATE_STACK(STACK_SIZE); \
694    STACK_STORE(ra, 124); \
695    STACK_STORE(s8, 120); \
696    STACK_STORE(s0, 116); \
697    STACK_STORE(s1, 112); \
698    STACK_STORE(s2, 108); \
699    STACK_STORE(s3, 104); \
700    STACK_STORE(s4, 100); \
701    STACK_STORE(s5, 96); \
702    STACK_STORE(s6, 92); \
703    STACK_STORE(s7, 88);
704
705#define STACK_LOAD_FULL() STACK_LOAD(gp, STACK_OFFSET_GP); \
706    STACK_LOAD(s7, 88); \
707    STACK_LOAD(s6, 92); \
708    STACK_LOAD(s5, 96); \
709    STACK_LOAD(s4, 100); \
710    STACK_LOAD(s3, 104); \
711    STACK_LOAD(s2, 108); \
712    STACK_LOAD(s1, 112); \
713    STACK_LOAD(s0, 116); \
714    STACK_LOAD(s8, 120); \
715    STACK_LOAD(ra, 124); \
716    DELETE_STACK(STACK_SIZE)
717
718#define REFRESH_IBASE() \
719    lw        rIBASE, THREAD_CURRENT_IBASE_OFFSET(rSELF)
720
721/* Constants for float/double_to_int/long conversions */
722#define INT_MIN                 0x80000000
723#define INT_MIN_AS_FLOAT        0xCF000000
724#define INT_MIN_AS_DOUBLE_HIGH  0xC1E00000
725#define LONG_MIN_HIGH           0x80000000
726#define LONG_MIN_AS_FLOAT       0xDF000000
727#define LONG_MIN_AS_DOUBLE_HIGH 0xC3E00000
728
729%def entry():
730/*
731 * Copyright (C) 2016 The Android Open Source Project
732 *
733 * Licensed under the Apache License, Version 2.0 (the "License");
734 * you may not use this file except in compliance with the License.
735 * You may obtain a copy of the License at
736 *
737 *      http://www.apache.org/licenses/LICENSE-2.0
738 *
739 * Unless required by applicable law or agreed to in writing, software
740 * distributed under the License is distributed on an "AS IS" BASIS,
741 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
742 * See the License for the specific language governing permissions and
743 * limitations under the License.
744 */
745/*
746 * Interpreter entry point.
747 */
748
749    .text
750    .align 2
751    .global ExecuteMterpImpl
752    .ent    ExecuteMterpImpl
753    .frame sp, STACK_SIZE, ra
754/*
755 * On entry:
756 *  a0  Thread* self
757 *  a1  dex_instructions
758 *  a2  ShadowFrame
759 *  a3  JValue* result_register
760 *
761 */
762
763ExecuteMterpImpl:
764    .cfi_startproc
765    .set noreorder
766    .cpload t9
767    .set reorder
768/* Save to the stack. Frame size = STACK_SIZE */
769    STACK_STORE_FULL()
770/* This directive will make sure all subsequent jal restore gp at a known offset */
771    .cprestore STACK_OFFSET_GP
772
773    /* Remember the return register */
774    sw      a3, SHADOWFRAME_RESULT_REGISTER_OFFSET(a2)
775
776    /* Remember the dex instruction pointer */
777    sw      a1, SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET(a2)
778
779    /* set up "named" registers */
780    move    rSELF, a0
781    lw      a0, SHADOWFRAME_NUMBER_OF_VREGS_OFFSET(a2)
782    addu    rFP, a2, SHADOWFRAME_VREGS_OFFSET     # point to vregs.
783    EAS2(rREFS, rFP, a0)                          # point to reference array in shadow frame
784    lw      a0, SHADOWFRAME_DEX_PC_OFFSET(a2)     # Get starting dex_pc
785    EAS1(rPC, a1, a0)                             # Create direct pointer to 1st dex opcode
786    CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
787
788    EXPORT_PC()
789
790    /* Starting ibase */
791    lw      rIBASE, THREAD_CURRENT_IBASE_OFFSET(rSELF)
792
793    /* Set up for backwards branches & osr profiling */
794    lw      a0, OFF_FP_METHOD(rFP)
795    addu    a1, rFP, OFF_FP_SHADOWFRAME
796    move    a2, rSELF
797    JAL(MterpSetUpHotnessCountdown)        # (method, shadow_frame, self)
798    move    rPROFILE, v0                   # Starting hotness countdown to rPROFILE
799
800    /* start executing the instruction at rPC */
801    FETCH_INST()                           # load rINST from rPC
802    GET_INST_OPCODE(t0)                    # extract opcode from rINST
803    GOTO_OPCODE(t0)                        # jump to next instruction
804    /* NOTE: no fallthrough */
805
806%def dchecks_before_helper():
807    // Call C++ to do debug checks and return to the handler using tail call.
808    .extern MterpCheckBefore
809    move   a0, rSELF                    # arg0
810    addu   a1, rFP, OFF_FP_SHADOWFRAME  # arg1
811    move   a2, rPC
812    la     t9, MterpCheckBefore
813    jalr   zero, t9                     # Tail call to Mterp(self, shadow_frame, dex_pc_ptr)
814
815%def opcode_pre():
816%  add_helper(dchecks_before_helper, "mterp_dchecks_before_helper")
817    #if !defined(NDEBUG)
818    jal    SYMBOL(mterp_dchecks_before_helper)
819    #endif
820
821%def fallback():
822/* Transfer stub to alternate interpreter */
823    b    MterpFallback
824
825%def helpers():
826%  op_float_to_long_helper_code()
827%  op_double_to_long_helper_code()
828%  op_mul_long_helper_code()
829%  op_shl_long_helper_code()
830%  op_shr_long_helper_code()
831%  op_ushr_long_helper_code()
832%  op_shl_long_2addr_helper_code()
833%  op_shr_long_2addr_helper_code()
834%  op_ushr_long_2addr_helper_code()
835
836%def footer():
837/*
838 * ===========================================================================
839 *  Common subroutines and data
840 * ===========================================================================
841 */
842
843    .text
844    .align 2
845
846/*
847 * We've detected a condition that will result in an exception, but the exception
848 * has not yet been thrown.  Just bail out to the reference interpreter to deal with it.
849 * TUNING: for consistency, we may want to just go ahead and handle these here.
850 */
851common_errDivideByZero:
852    EXPORT_PC()
853#if MTERP_LOGGING
854    move  a0, rSELF
855    addu  a1, rFP, OFF_FP_SHADOWFRAME
856    JAL(MterpLogDivideByZeroException)
857#endif
858    b MterpCommonFallback
859
860common_errArrayIndex:
861    EXPORT_PC()
862#if MTERP_LOGGING
863    move  a0, rSELF
864    addu  a1, rFP, OFF_FP_SHADOWFRAME
865    JAL(MterpLogArrayIndexException)
866#endif
867    b MterpCommonFallback
868
869common_errNegativeArraySize:
870    EXPORT_PC()
871#if MTERP_LOGGING
872    move  a0, rSELF
873    addu  a1, rFP, OFF_FP_SHADOWFRAME
874    JAL(MterpLogNegativeArraySizeException)
875#endif
876    b MterpCommonFallback
877
878common_errNoSuchMethod:
879    EXPORT_PC()
880#if MTERP_LOGGING
881    move  a0, rSELF
882    addu  a1, rFP, OFF_FP_SHADOWFRAME
883    JAL(MterpLogNoSuchMethodException)
884#endif
885    b MterpCommonFallback
886
887common_errNullObject:
888    EXPORT_PC()
889#if MTERP_LOGGING
890    move  a0, rSELF
891    addu  a1, rFP, OFF_FP_SHADOWFRAME
892    JAL(MterpLogNullObjectException)
893#endif
894    b MterpCommonFallback
895
896common_exceptionThrown:
897    EXPORT_PC()
898#if MTERP_LOGGING
899    move  a0, rSELF
900    addu  a1, rFP, OFF_FP_SHADOWFRAME
901    JAL(MterpLogExceptionThrownException)
902#endif
903    b MterpCommonFallback
904
905MterpSuspendFallback:
906    EXPORT_PC()
907#if MTERP_LOGGING
908    move  a0, rSELF
909    addu  a1, rFP, OFF_FP_SHADOWFRAME
910    lw    a2, THREAD_FLAGS_OFFSET(rSELF)
911    JAL(MterpLogSuspendFallback)
912#endif
913    b MterpCommonFallback
914
915/*
916 * If we're here, something is out of the ordinary.  If there is a pending
917 * exception, handle it.  Otherwise, roll back and retry with the reference
918 * interpreter.
919 */
920MterpPossibleException:
921    lw      a0, THREAD_EXCEPTION_OFFSET(rSELF)
922    beqz    a0, MterpFallback          # If exception, fall back to reference interpreter.
923    /* intentional fallthrough - handle pending exception. */
924/*
925 * On return from a runtime helper routine, we've found a pending exception.
926 * Can we handle it here - or need to bail out to caller?
927 *
928 */
929MterpException:
930    move    a0, rSELF
931    addu    a1, rFP, OFF_FP_SHADOWFRAME
932    JAL(MterpHandleException)                    # (self, shadow_frame)
933    beqz    v0, MterpExceptionReturn             # no local catch, back to caller.
934    lw      a0, OFF_FP_DEX_INSTRUCTIONS(rFP)
935    lw      a1, OFF_FP_DEX_PC(rFP)
936    lw      rIBASE, THREAD_CURRENT_IBASE_OFFSET(rSELF)
937    EAS1(rPC, a0, a1)                            # generate new dex_pc_ptr
938    /* Do we need to switch interpreters? */
939    JAL(MterpShouldSwitchInterpreters)
940    bnez    v0, MterpFallback
941    /* resume execution at catch block */
942    EXPORT_PC()
943    FETCH_INST()
944    GET_INST_OPCODE(t0)
945    GOTO_OPCODE(t0)
946    /* NOTE: no fallthrough */
947
948/*
949 * Common handling for branches with support for Jit profiling.
950 * On entry:
951 *    rINST          <= signed offset
952 *    rPROFILE       <= signed hotness countdown (expanded to 32 bits)
953 *
954 * We have quite a few different cases for branch profiling, OSR detection and
955 * suspend check support here.
956 *
957 * Taken backward branches:
958 *    If profiling active, do hotness countdown and report if we hit zero.
959 *    If in osr check mode, see if our target is a compiled loop header entry and do OSR if so.
960 *    Is there a pending suspend request?  If so, suspend.
961 *
962 * Taken forward branches and not-taken backward branches:
963 *    If in osr check mode, see if our target is a compiled loop header entry and do OSR if so.
964 *
965 * Our most common case is expected to be a taken backward branch with active jit profiling,
966 * but no full OSR check and no pending suspend request.
967 * Next most common case is not-taken branch with no full OSR check.
968 */
969MterpCommonTakenBranchNoFlags:
970    bgtz    rINST, .L_forward_branch    # don't add forward branches to hotness
971/*
972 * We need to subtract 1 from positive values and we should not see 0 here,
973 * so we may use the result of the comparison with -1.
974 */
975#if JIT_CHECK_OSR != -1
976#  error "JIT_CHECK_OSR must be -1."
977#endif
978    li      t0, JIT_CHECK_OSR
979    beq     rPROFILE, t0, .L_osr_check
980    blt     rPROFILE, t0, .L_resume_backward_branch
981    subu    rPROFILE, 1
982    beqz    rPROFILE, .L_add_batch      # counted down to zero - report
983.L_resume_backward_branch:
984    lw      ra, THREAD_FLAGS_OFFSET(rSELF)
985    REFRESH_IBASE()
986    addu    a2, rINST, rINST            # a2<- byte offset
987    FETCH_ADVANCE_INST_RB(a2)           # update rPC, load rINST
988    and     ra, THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
989    bnez    ra, .L_suspend_request_pending
990    GET_INST_OPCODE(t0)                 # extract opcode from rINST
991    GOTO_OPCODE(t0)                     # jump to next instruction
992
993.L_suspend_request_pending:
994    EXPORT_PC()
995    move    a0, rSELF
996    JAL(MterpSuspendCheck)              # (self)
997    bnez    v0, MterpFallback
998    REFRESH_IBASE()                     # might have changed during suspend
999    GET_INST_OPCODE(t0)                 # extract opcode from rINST
1000    GOTO_OPCODE(t0)                     # jump to next instruction
1001
1002.L_no_count_backwards:
1003    li      t0, JIT_CHECK_OSR           # check for possible OSR re-entry
1004    bne     rPROFILE, t0, .L_resume_backward_branch
1005.L_osr_check:
1006    move    a0, rSELF
1007    addu    a1, rFP, OFF_FP_SHADOWFRAME
1008    move    a2, rINST
1009    EXPORT_PC()
1010    JAL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
1011    bnez    v0, MterpOnStackReplacement
1012    b       .L_resume_backward_branch
1013
1014.L_forward_branch:
1015    li      t0, JIT_CHECK_OSR           # check for possible OSR re-entry
1016    beq     rPROFILE, t0, .L_check_osr_forward
1017.L_resume_forward_branch:
1018    add     a2, rINST, rINST            # a2<- byte offset
1019    FETCH_ADVANCE_INST_RB(a2)           # update rPC, load rINST
1020    GET_INST_OPCODE(t0)                 # extract opcode from rINST
1021    GOTO_OPCODE(t0)                     # jump to next instruction
1022
1023.L_check_osr_forward:
1024    move    a0, rSELF
1025    addu    a1, rFP, OFF_FP_SHADOWFRAME
1026    move    a2, rINST
1027    EXPORT_PC()
1028    JAL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
1029    bnez    v0, MterpOnStackReplacement
1030    b       .L_resume_forward_branch
1031
1032.L_add_batch:
1033    addu    a1, rFP, OFF_FP_SHADOWFRAME
1034    sh      rPROFILE, SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET(a1)
1035    lw      a0, OFF_FP_METHOD(rFP)
1036    move    a2, rSELF
1037    JAL(MterpAddHotnessBatch)           # (method, shadow_frame, self)
1038    move    rPROFILE, v0                # restore new hotness countdown to rPROFILE
1039    b       .L_no_count_backwards
1040
1041/*
1042 * Entered from the conditional branch handlers when OSR check request active on
1043 * not-taken path.  All Dalvik not-taken conditional branch offsets are 2.
1044 */
1045.L_check_not_taken_osr:
1046    move    a0, rSELF
1047    addu    a1, rFP, OFF_FP_SHADOWFRAME
1048    li      a2, 2
1049    EXPORT_PC()
1050    JAL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
1051    bnez    v0, MterpOnStackReplacement
1052    FETCH_ADVANCE_INST(2)
1053    GET_INST_OPCODE(t0)                 # extract opcode from rINST
1054    GOTO_OPCODE(t0)                     # jump to next instruction
1055
1056/*
1057 * On-stack replacement has happened, and now we've returned from the compiled method.
1058 */
1059MterpOnStackReplacement:
1060#if MTERP_LOGGING
1061    move    a0, rSELF
1062    addu    a1, rFP, OFF_FP_SHADOWFRAME
1063    move    a2, rINST
1064    JAL(MterpLogOSR)
1065#endif
1066    li      v0, 1                       # Signal normal return
1067    b       MterpDone
1068
1069/*
1070 * Bail out to reference interpreter.
1071 */
1072MterpFallback:
1073    EXPORT_PC()
1074#if MTERP_LOGGING
1075    move  a0, rSELF
1076    addu  a1, rFP, OFF_FP_SHADOWFRAME
1077    JAL(MterpLogFallback)
1078#endif
1079MterpCommonFallback:
1080    move    v0, zero                    # signal retry with reference interpreter.
1081    b       MterpDone
1082/*
1083 * We pushed some registers on the stack in ExecuteMterpImpl, then saved
1084 * SP and LR.  Here we restore SP, restore the registers, and then restore
1085 * LR to PC.
1086 *
1087 * On entry:
1088 *  uint32_t* rFP  (should still be live, pointer to base of vregs)
1089 */
1090MterpExceptionReturn:
1091    li      v0, 1                       # signal return to caller.
1092    b       MterpDone
1093MterpReturn:
1094    lw      a2, OFF_FP_RESULT_REGISTER(rFP)
1095    sw      v0, 0(a2)
1096    sw      v1, 4(a2)
1097    li      v0, 1                       # signal return to caller.
1098MterpDone:
1099/*
1100 * At this point, we expect rPROFILE to be non-zero.  If negative, hotness is disabled or we're
1101 * checking for OSR.  If greater than zero, we might have unreported hotness to register
1102 * (the difference between the ending rPROFILE and the cached hotness counter).  rPROFILE
1103 * should only reach zero immediately after a hotness decrement, and is then reset to either
1104 * a negative special state or the new non-zero countdown value.
1105 */
1106    blez    rPROFILE, .L_pop_and_return # if > 0, we may have some counts to report.
1107
1108MterpProfileActive:
1109    move    rINST, v0                   # stash return value
1110    /* Report cached hotness counts */
1111    lw      a0, OFF_FP_METHOD(rFP)
1112    addu    a1, rFP, OFF_FP_SHADOWFRAME
1113    move    a2, rSELF
1114    sh      rPROFILE, SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET(a1)
1115    JAL(MterpAddHotnessBatch)           # (method, shadow_frame, self)
1116    move    v0, rINST                   # restore return value
1117
1118.L_pop_and_return:
1119/* Restore from the stack and return. Frame size = STACK_SIZE */
1120    STACK_LOAD_FULL()
1121    jalr    zero, ra
1122
1123    .cfi_endproc
1124    .end ExecuteMterpImpl
1125
1126%def instruction_end():
1127
1128    .global artMterpAsmInstructionEnd
1129artMterpAsmInstructionEnd:
1130
1131%def instruction_start():
1132
1133    .global artMterpAsmInstructionStart
1134artMterpAsmInstructionStart = .L_op_nop
1135    .text
1136
1137%def opcode_start():
1138%  pass
1139%def opcode_end():
1140%  pass
1141%def helper_start(name):
1142    ENTRY ${name}
1143%def helper_end(name):
1144    END ${name}
1145