blob: a3a67444abb3c8ee861688000bafc80b6d25eaf9 [file] [log] [blame]
Douglas Leung200f0402016-02-25 20:05:47 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 Art assembly interpreter notes:
19
20 First validate assembly code by implementing ExecuteXXXImpl() style body (doesn't
21 handle invoke, allows higher-level code to create frame & shadow frame.
22
23 Once that's working, support direct entry code & eliminate shadow frame (and
24 excess locals allocation.
25
26 Some (hopefully) temporary ugliness. We'll treat rFP as pointing to the
27 base of the vreg array within the shadow frame. Access the other fields,
28 dex_pc_, method_ and number_of_vregs_ via negative offsets. For now, we'll continue
29 the shadow frame mechanism of double-storing object references - via rFP &
30 number_of_vregs_.
31
32 */
33
34#include "asm_support.h"
35
36#if (__mips==32) && (__mips_isa_rev>=2)
37#define MIPS32REVGE2 /* mips32r2 and greater */
38#if (__mips==32) && (__mips_isa_rev>=5)
39#define FPU64 /* 64 bit FPU */
40#if (__mips==32) && (__mips_isa_rev>=6)
41#define MIPS32REVGE6 /* mips32r6 and greater */
42#endif
43#endif
44#endif
45
46/* MIPS definitions and declarations
47
48 reg nick purpose
49 s0 rPC interpreted program counter, used for fetching instructions
50 s1 rFP interpreted frame pointer, used for accessing locals and args
51 s2 rSELF self (Thread) pointer
52 s3 rIBASE interpreted instruction base pointer, used for computed goto
53 s4 rINST first 16-bit code unit of current instruction
Douglas Leung020b18a2016-06-03 18:05:35 -070054 s5 rOBJ object pointer
Douglas Leung200f0402016-02-25 20:05:47 -080055 s6 rREFS base of object references in shadow frame (ideally, we'll get rid of this later).
Douglas Leung020b18a2016-06-03 18:05:35 -070056 s7 rTEMP used as temp storage that can survive a function call
57 s8 rPROFILE branch profiling countdown
58
Douglas Leung200f0402016-02-25 20:05:47 -080059*/
60
61/* single-purpose registers, given names for clarity */
62#define rPC s0
63#define rFP s1
64#define rSELF s2
65#define rIBASE s3
66#define rINST s4
67#define rOBJ s5
68#define rREFS s6
69#define rTEMP s7
Douglas Leung020b18a2016-06-03 18:05:35 -070070#define rPROFILE s8
Douglas Leung200f0402016-02-25 20:05:47 -080071
72#define rARG0 a0
73#define rARG1 a1
74#define rARG2 a2
75#define rARG3 a3
76#define rRESULT0 v0
77#define rRESULT1 v1
78
79/* GP register definitions */
80#define zero $$0 /* always zero */
81#define AT $$at /* assembler temp */
82#define v0 $$2 /* return value */
83#define v1 $$3
84#define a0 $$4 /* argument registers */
85#define a1 $$5
86#define a2 $$6
87#define a3 $$7
88#define t0 $$8 /* temp registers (not saved across subroutine calls) */
89#define t1 $$9
90#define t2 $$10
91#define t3 $$11
92#define t4 $$12
93#define t5 $$13
94#define t6 $$14
95#define t7 $$15
96#define ta0 $$12 /* alias */
97#define ta1 $$13
98#define ta2 $$14
99#define ta3 $$15
100#define s0 $$16 /* saved across subroutine calls (callee saved) */
101#define s1 $$17
102#define s2 $$18
103#define s3 $$19
104#define s4 $$20
105#define s5 $$21
106#define s6 $$22
107#define s7 $$23
108#define t8 $$24 /* two more temp registers */
109#define t9 $$25
110#define k0 $$26 /* kernel temporary */
111#define k1 $$27
112#define gp $$28 /* global pointer */
113#define sp $$29 /* stack pointer */
114#define s8 $$30 /* one more callee saved */
115#define ra $$31 /* return address */
116
117/* FP register definitions */
118#define fv0 $$f0
119#define fv0f $$f1
120#define fv1 $$f2
121#define fv1f $$f3
122#define fa0 $$f12
123#define fa0f $$f13
124#define fa1 $$f14
125#define fa1f $$f15
126#define ft0 $$f4
127#define ft0f $$f5
128#define ft1 $$f6
129#define ft1f $$f7
130#define ft2 $$f8
131#define ft2f $$f9
132#define ft3 $$f10
133#define ft3f $$f11
134#define ft4 $$f16
135#define ft4f $$f17
136#define ft5 $$f18
137#define ft5f $$f19
138#define fs0 $$f20
139#define fs0f $$f21
140#define fs1 $$f22
141#define fs1f $$f23
142#define fs2 $$f24
143#define fs2f $$f25
144#define fs3 $$f26
145#define fs3f $$f27
146#define fs4 $$f28
147#define fs4f $$f29
148#define fs5 $$f30
149#define fs5f $$f31
150
151#ifndef MIPS32REVGE6
152#define fcc0 $$fcc0
153#define fcc1 $$fcc1
154#endif
155
156/*
157 * Instead of holding a pointer to the shadow frame, we keep rFP at the base of the vregs. So,
158 * to access other shadow frame fields, we need to use a backwards offset. Define those here.
159 */
160#define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET)
161#define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET)
162#define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET)
163#define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET)
164#define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
165#define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
166#define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
167#define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET)
Douglas Leung020b18a2016-06-03 18:05:35 -0700168#define OFF_FP_SHADOWFRAME OFF_FP(0)
Douglas Leung200f0402016-02-25 20:05:47 -0800169
170#define MTERP_PROFILE_BRANCHES 1
171#define MTERP_LOGGING 0
172
173/*
174 * "export" the PC to dex_pc field in the shadow frame, f/b/o future exception objects. Must
175 * be done *before* something throws.
176 *
177 * It's okay to do this more than once.
178 *
179 * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped
180 * dex byte codes. However, the rest of the runtime expects dex pc to be an instruction
181 * offset into the code_items_[] array. For effiency, we will "export" the
182 * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC
183 * to convert to a dex pc when needed.
184 */
185#define EXPORT_PC() \
186 sw rPC, OFF_FP_DEX_PC_PTR(rFP)
187
188#define EXPORT_DEX_PC(tmp) \
189 lw tmp, OFF_FP_CODE_ITEM(rFP) \
190 sw rPC, OFF_FP_DEX_PC_PTR(rFP) \
191 addu tmp, CODEITEM_INSNS_OFFSET \
192 subu tmp, rPC, tmp \
193 sra tmp, tmp, 1 \
194 sw tmp, OFF_FP_DEX_PC(rFP)
195
196/*
197 * Fetch the next instruction from rPC into rINST. Does not advance rPC.
198 */
199#define FETCH_INST() lhu rINST, (rPC)
200
201/*
202 * Fetch the next instruction from the specified offset. Advances rPC
203 * to point to the next instruction. "_count" is in 16-bit code units.
204 *
205 * This must come AFTER anything that can throw an exception, or the
206 * exception catch may miss. (This also implies that it must come after
207 * EXPORT_PC().)
208 */
209#define FETCH_ADVANCE_INST(_count) lhu rINST, ((_count)*2)(rPC); \
210 addu rPC, rPC, ((_count) * 2)
211
212/*
213 * The operation performed here is similar to FETCH_ADVANCE_INST, except the
214 * src and dest registers are parameterized (not hard-wired to rPC and rINST).
215 */
216#define PREFETCH_ADVANCE_INST(_dreg, _sreg, _count) \
217 lhu _dreg, ((_count)*2)(_sreg) ; \
218 addu _sreg, _sreg, (_count)*2
219
220/*
221 * Similar to FETCH_ADVANCE_INST, but does not update rPC. Used to load
222 * rINST ahead of possible exception point. Be sure to manually advance rPC
223 * later.
224 */
225#define PREFETCH_INST(_count) lhu rINST, ((_count)*2)(rPC)
226
227/* Advance rPC by some number of code units. */
228#define ADVANCE(_count) addu rPC, rPC, ((_count) * 2)
229
230/*
231 * Fetch the next instruction from an offset specified by rd. Updates
232 * rPC to point to the next instruction. "rd" must specify the distance
233 * in bytes, *not* 16-bit code units, and may be a signed value.
234 */
235#define FETCH_ADVANCE_INST_RB(rd) addu rPC, rPC, rd; \
236 lhu rINST, (rPC)
237
238/*
239 * Fetch a half-word code unit from an offset past the current PC. The
240 * "_count" value is in 16-bit code units. Does not advance rPC.
241 *
242 * The "_S" variant works the same but treats the value as signed.
243 */
244#define FETCH(rd, _count) lhu rd, ((_count) * 2)(rPC)
245#define FETCH_S(rd, _count) lh rd, ((_count) * 2)(rPC)
246
247/*
248 * Fetch one byte from an offset past the current PC. Pass in the same
249 * "_count" as you would for FETCH, and an additional 0/1 indicating which
250 * byte of the halfword you want (lo/hi).
251 */
252#define FETCH_B(rd, _count, _byte) lbu rd, ((_count) * 2 + _byte)(rPC)
253
254/*
255 * Put the instruction's opcode field into the specified register.
256 */
257#define GET_INST_OPCODE(rd) and rd, rINST, 0xFF
258
259/*
260 * Put the prefetched instruction's opcode field into the specified register.
261 */
262#define GET_PREFETCHED_OPCODE(dreg, sreg) andi dreg, sreg, 255
263
264/*
265 * Begin executing the opcode in rd.
266 */
267#define GOTO_OPCODE(rd) sll rd, rd, ${handler_size_bits}; \
268 addu rd, rIBASE, rd; \
269 jalr zero, rd
270
271#define GOTO_OPCODE_BASE(_base, rd) sll rd, rd, ${handler_size_bits}; \
272 addu rd, _base, rd; \
273 jalr zero, rd
274
275/*
276 * Get/set the 32-bit value from a Dalvik register.
277 */
278#define GET_VREG(rd, rix) LOAD_eas2(rd, rFP, rix)
279
280#define GET_VREG_F(rd, rix) EAS2(AT, rFP, rix); \
281 .set noat; l.s rd, (AT); .set at
282
283#define SET_VREG(rd, rix) .set noat; \
284 sll AT, rix, 2; \
285 addu t8, rFP, AT; \
286 sw rd, 0(t8); \
287 addu t8, rREFS, AT; \
288 .set at; \
289 sw zero, 0(t8)
290
291#define SET_VREG64(rlo, rhi, rix) .set noat; \
292 sll AT, rix, 2; \
293 addu t8, rFP, AT; \
294 sw rlo, 0(t8); \
295 sw rhi, 4(t8); \
296 addu t8, rREFS, AT; \
297 .set at; \
298 sw zero, 0(t8); \
299 sw zero, 4(t8)
300
301#ifdef FPU64
302#define SET_VREG64_F(rlo, rhi, rix) .set noat; \
303 sll AT, rix, 2; \
304 addu t8, rREFS, AT; \
305 sw zero, 0(t8); \
306 sw zero, 4(t8); \
307 addu t8, rFP, AT; \
308 mfhc1 AT, rlo; \
309 sw AT, 4(t8); \
310 .set at; \
311 s.s rlo, 0(t8)
312#else
313#define SET_VREG64_F(rlo, rhi, rix) .set noat; \
314 sll AT, rix, 2; \
315 addu t8, rFP, AT; \
316 s.s rlo, 0(t8); \
317 s.s rhi, 4(t8); \
318 addu t8, rREFS, AT; \
319 .set at; \
320 sw zero, 0(t8); \
321 sw zero, 4(t8)
322#endif
323
324#define SET_VREG_OBJECT(rd, rix) .set noat; \
325 sll AT, rix, 2; \
326 addu t8, rFP, AT; \
327 sw rd, 0(t8); \
328 addu t8, rREFS, AT; \
329 .set at; \
330 sw rd, 0(t8)
331
332/* Combination of the SET_VREG and GOTO_OPCODE functions to save 1 instruction */
333#define SET_VREG_GOTO(rd, rix, dst) .set noreorder; \
334 sll dst, dst, ${handler_size_bits}; \
335 addu dst, rIBASE, dst; \
336 .set noat; \
337 sll AT, rix, 2; \
338 addu t8, rFP, AT; \
339 sw rd, 0(t8); \
340 addu t8, rREFS, AT; \
341 .set at; \
342 jalr zero, dst; \
343 sw zero, 0(t8); \
344 .set reorder
345
346/* Combination of the SET_VREG64 and GOTO_OPCODE functions to save 1 instruction */
347#define SET_VREG64_GOTO(rlo, rhi, rix, dst) .set noreorder; \
348 sll dst, dst, ${handler_size_bits}; \
349 addu dst, rIBASE, dst; \
350 .set noat; \
351 sll AT, rix, 2; \
352 addu t8, rFP, AT; \
353 sw rlo, 0(t8); \
354 sw rhi, 4(t8); \
355 addu t8, rREFS, AT; \
356 .set at; \
357 sw zero, 0(t8); \
358 jalr zero, dst; \
359 sw zero, 4(t8); \
360 .set reorder
361
362#define SET_VREG_F(rd, rix) .set noat; \
363 sll AT, rix, 2; \
364 addu t8, rFP, AT; \
365 s.s rd, 0(t8); \
366 addu t8, rREFS, AT; \
367 .set at; \
368 sw zero, 0(t8)
369
370#define GET_OPA(rd) srl rd, rINST, 8
371#ifdef MIPS32REVGE2
372#define GET_OPA4(rd) ext rd, rINST, 8, 4
373#else
374#define GET_OPA4(rd) GET_OPA(rd); and rd, 0xf
375#endif
376#define GET_OPB(rd) srl rd, rINST, 12
377
378/*
379 * Form an Effective Address rd = rbase + roff<<n;
380 * Uses reg AT
381 */
382#define EASN(rd, rbase, roff, rshift) .set noat; \
383 sll AT, roff, rshift; \
384 addu rd, rbase, AT; \
385 .set at
386
387#define EAS1(rd, rbase, roff) EASN(rd, rbase, roff, 1)
388#define EAS2(rd, rbase, roff) EASN(rd, rbase, roff, 2)
389#define EAS3(rd, rbase, roff) EASN(rd, rbase, roff, 3)
390#define EAS4(rd, rbase, roff) EASN(rd, rbase, roff, 4)
391
392/*
393 * Form an Effective Shift Right rd = rbase + roff>>n;
394 * Uses reg AT
395 */
396#define ESRN(rd, rbase, roff, rshift) .set noat; \
397 srl AT, roff, rshift; \
398 addu rd, rbase, AT; \
399 .set at
400
401#define LOAD_eas2(rd, rbase, roff) EAS2(AT, rbase, roff); \
402 .set noat; lw rd, 0(AT); .set at
403
404#define STORE_eas2(rd, rbase, roff) EAS2(AT, rbase, roff); \
405 .set noat; sw rd, 0(AT); .set at
406
407#define LOAD_RB_OFF(rd, rbase, off) lw rd, off(rbase)
408#define STORE_RB_OFF(rd, rbase, off) sw rd, off(rbase)
409
410#define STORE64_off(rlo, rhi, rbase, off) sw rlo, off(rbase); \
411 sw rhi, (off+4)(rbase)
412#define LOAD64_off(rlo, rhi, rbase, off) lw rlo, off(rbase); \
413 lw rhi, (off+4)(rbase)
414
415#define STORE64(rlo, rhi, rbase) STORE64_off(rlo, rhi, rbase, 0)
416#define LOAD64(rlo, rhi, rbase) LOAD64_off(rlo, rhi, rbase, 0)
417
418#ifdef FPU64
419#define STORE64_off_F(rlo, rhi, rbase, off) s.s rlo, off(rbase); \
420 .set noat; \
421 mfhc1 AT, rlo; \
422 sw AT, (off+4)(rbase); \
423 .set at
424#define LOAD64_off_F(rlo, rhi, rbase, off) l.s rlo, off(rbase); \
425 .set noat; \
426 lw AT, (off+4)(rbase); \
427 mthc1 AT, rlo; \
428 .set at
429#else
430#define STORE64_off_F(rlo, rhi, rbase, off) s.s rlo, off(rbase); \
431 s.s rhi, (off+4)(rbase)
432#define LOAD64_off_F(rlo, rhi, rbase, off) l.s rlo, off(rbase); \
433 l.s rhi, (off+4)(rbase)
434#endif
435
436#define STORE64_F(rlo, rhi, rbase) STORE64_off_F(rlo, rhi, rbase, 0)
437#define LOAD64_F(rlo, rhi, rbase) LOAD64_off_F(rlo, rhi, rbase, 0)
438
439
440#define LOAD_base_offMirrorArray_length(rd, rbase) LOAD_RB_OFF(rd, rbase, MIRROR_ARRAY_LENGTH_OFFSET)
441
442#define STACK_STORE(rd, off) sw rd, off(sp)
443#define STACK_LOAD(rd, off) lw rd, off(sp)
444#define CREATE_STACK(n) subu sp, sp, n
445#define DELETE_STACK(n) addu sp, sp, n
446
447#define LOAD_ADDR(dest, addr) la dest, addr
448#define LOAD_IMM(dest, imm) li dest, imm
449#define MOVE_REG(dest, src) move dest, src
450#define STACK_SIZE 128
451
452#define STACK_OFFSET_ARG04 16
453#define STACK_OFFSET_ARG05 20
454#define STACK_OFFSET_ARG06 24
455#define STACK_OFFSET_ARG07 28
456#define STACK_OFFSET_GP 84
457
458#define JAL(n) jal n
459#define BAL(n) bal n
460
461/*
462 * FP register usage restrictions:
463 * 1) We don't use the callee save FP registers so we don't have to save them.
464 * 2) We don't use the odd FP registers so we can share code with mips32r6.
465 */
466#define STACK_STORE_FULL() CREATE_STACK(STACK_SIZE); \
467 STACK_STORE(ra, 124); \
468 STACK_STORE(s8, 120); \
469 STACK_STORE(s0, 116); \
470 STACK_STORE(s1, 112); \
471 STACK_STORE(s2, 108); \
472 STACK_STORE(s3, 104); \
473 STACK_STORE(s4, 100); \
474 STACK_STORE(s5, 96); \
475 STACK_STORE(s6, 92); \
476 STACK_STORE(s7, 88);
477
478#define STACK_LOAD_FULL() STACK_LOAD(gp, STACK_OFFSET_GP); \
479 STACK_LOAD(s7, 88); \
480 STACK_LOAD(s6, 92); \
481 STACK_LOAD(s5, 96); \
482 STACK_LOAD(s4, 100); \
483 STACK_LOAD(s3, 104); \
484 STACK_LOAD(s2, 108); \
485 STACK_LOAD(s1, 112); \
486 STACK_LOAD(s0, 116); \
487 STACK_LOAD(s8, 120); \
488 STACK_LOAD(ra, 124); \
489 DELETE_STACK(STACK_SIZE)
Douglas Leung020b18a2016-06-03 18:05:35 -0700490
491#define REFRESH_IBASE() \
492 lw rIBASE, THREAD_CURRENT_IBASE_OFFSET(rSELF)