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