1%def header(): 2/* 3 * Copyright (C) 2019 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18/* 19 * This is a #include, not a %include, because we want the C pre-processor 20 * to expand the macros into assembler assignment statements. 21 */ 22#include "asm_support.h" 23#include "arch/x86_64/asm_support_x86_64.S" 24#include "interpreter/cfi_asm_support.h" 25 26/** 27 * x86_64 ABI general notes: 28 * 29 * Caller save set: 30 * rax, rdx, rcx, rsi, rdi, r8-r11, st(0)-st(7) 31 * Callee save set: 32 * rbx, rbp, r12-r15 33 * Return regs: 34 * 32-bit in eax 35 * 64-bit in rax 36 * fp on xmm0 37 * 38 * First 8 fp parameters came in xmm0-xmm7. 39 * First 6 non-fp parameters came in rdi, rsi, rdx, rcx, r8, r9. 40 * Other parameters passed on stack, pushed right-to-left. On entry to target, first 41 * param is at 8(%esp). 42 * 43 * Stack must be 16-byte aligned to support SSE in native code. 44 */ 45 46#define IN_ARG3 %rcx 47#define IN_ARG2 %rdx 48#define IN_ARG1 %rsi 49#define IN_ARG0 %rdi 50/* Out Args */ 51#define OUT_ARG3 %rcx 52#define OUT_ARG2 %rdx 53#define OUT_ARG1 %rsi 54#define OUT_ARG0 %rdi 55#define OUT_32_ARG3 %ecx 56#define OUT_32_ARG2 %edx 57#define OUT_32_ARG1 %esi 58#define OUT_32_ARG0 %edi 59#define OUT_FP_ARG1 %xmm1 60#define OUT_FP_ARG0 %xmm0 61 62/* 63 * single-purpose registers, given names for clarity 64 */ 65#define rSELF %gs 66#define rPC %r12 67#define CFI_DEX 12 // DWARF register number of the register holding dex-pc (rPC). 68#define CFI_TMP 5 // DWARF register number of the first argument register (rdi). 69#define rFP %r13 70#define rINST %ebx 71#define rINSTq %rbx 72#define rINSTw %bx 73#define rINSTbh %bh 74#define rINSTbl %bl 75#define rIBASE %r14 76#define rREFS %r15 77#define CFI_REFS 15 // DWARF register number of the reference array (r15). 78 79// Temporary registers while setting up a frame. 80#define rNEW_FP %r8 81#define rNEW_REFS %r9 82#define CFI_NEW_REFS 9 83 84/* 85 * Get/set the 32-bit value from a Dalvik register. 86 */ 87#define VREG_ADDRESS(_vreg) (rFP,_vreg,4) 88#define VREG_HIGH_ADDRESS(_vreg) 4(rFP,_vreg,4) 89#define VREG_REF_ADDRESS(_vreg) (rREFS,_vreg,4) 90#define VREG_REF_HIGH_ADDRESS(_vreg) 4(rREFS,_vreg,4) 91 92// Includes the return address implictly pushed on stack by 'call'. 93#define CALLEE_SAVES_SIZE (6 * 8 + 4 * 8 + 1 * 8) 94 95// +8 for the ArtMethod of the caller. 96#define OFFSET_TO_FIRST_ARGUMENT_IN_STACK (CALLEE_SAVES_SIZE + 8) 97 98/* 99 * Refresh rINST. 100 * At enter to handler rINST does not contain the opcode number. 101 * However some utilities require the full value, so this macro 102 * restores the opcode number. 103 */ 104.macro REFRESH_INST _opnum 105 movb rINSTbl, rINSTbh 106 movb $$\_opnum, rINSTbl 107.endm 108 109/* 110 * Fetch the next instruction from rPC into rINSTw. Does not advance rPC. 111 */ 112.macro FETCH_INST 113 movzwq (rPC), rINSTq 114.endm 115 116/* 117 * Remove opcode from rINST, compute the address of handler and jump to it. 118 */ 119.macro GOTO_NEXT 120 movzx rINSTbl,%ecx 121 movzbl rINSTbh,rINST 122 shll MACRO_LITERAL(${handler_size_bits}), %ecx 123 addq rIBASE, %rcx 124 jmp *%rcx 125.endm 126 127/* 128 * Advance rPC by instruction count. 129 */ 130.macro ADVANCE_PC _count 131 leaq 2*\_count(rPC), rPC 132.endm 133 134/* 135 * Advance rPC by instruction count, fetch instruction and jump to handler. 136 */ 137.macro ADVANCE_PC_FETCH_AND_GOTO_NEXT _count 138 ADVANCE_PC \_count 139 FETCH_INST 140 GOTO_NEXT 141.endm 142 143.macro GET_VREG _reg _vreg 144 movl VREG_ADDRESS(\_vreg), \_reg 145.endm 146 147.macro GET_VREG_OBJECT _reg _vreg 148 movl VREG_REF_ADDRESS(\_vreg), \_reg 149.endm 150 151/* Read wide value. */ 152.macro GET_WIDE_VREG _reg _vreg 153 movq VREG_ADDRESS(\_vreg), \_reg 154.endm 155 156.macro SET_VREG _reg _vreg 157 movl \_reg, VREG_ADDRESS(\_vreg) 158 movl MACRO_LITERAL(0), VREG_REF_ADDRESS(\_vreg) 159.endm 160 161/* Write wide value. reg is clobbered. */ 162.macro SET_WIDE_VREG _reg _vreg 163 movq \_reg, VREG_ADDRESS(\_vreg) 164 xorq \_reg, \_reg 165 movq \_reg, VREG_REF_ADDRESS(\_vreg) 166.endm 167 168.macro SET_VREG_OBJECT _reg _vreg 169 movl \_reg, VREG_ADDRESS(\_vreg) 170 movl \_reg, VREG_REF_ADDRESS(\_vreg) 171.endm 172 173.macro GET_VREG_HIGH _reg _vreg 174 movl VREG_HIGH_ADDRESS(\_vreg), \_reg 175.endm 176 177.macro SET_VREG_HIGH _reg _vreg 178 movl \_reg, VREG_HIGH_ADDRESS(\_vreg) 179 movl MACRO_LITERAL(0), VREG_REF_HIGH_ADDRESS(\_vreg) 180.endm 181 182.macro CLEAR_REF _vreg 183 movl MACRO_LITERAL(0), VREG_REF_ADDRESS(\_vreg) 184.endm 185 186.macro CLEAR_WIDE_REF _vreg 187 movl MACRO_LITERAL(0), VREG_REF_ADDRESS(\_vreg) 188 movl MACRO_LITERAL(0), VREG_REF_HIGH_ADDRESS(\_vreg) 189.endm 190 191.macro GET_VREG_XMMs _xmmreg _vreg 192 movss VREG_ADDRESS(\_vreg), \_xmmreg 193.endm 194.macro GET_VREG_XMMd _xmmreg _vreg 195 movsd VREG_ADDRESS(\_vreg), \_xmmreg 196.endm 197.macro SET_VREG_XMMs _xmmreg _vreg 198 movss \_xmmreg, VREG_ADDRESS(\_vreg) 199.endm 200.macro SET_VREG_XMMd _xmmreg _vreg 201 movsd \_xmmreg, VREG_ADDRESS(\_vreg) 202.endm 203 204// An assembly entry that has a OatQuickMethodHeader prefix. 205.macro OAT_ENTRY name, end 206 FUNCTION_TYPE(\name) 207 ASM_HIDDEN SYMBOL(\name) 208 .global SYMBOL(\name) 209 .balign 16 210 .long 0 211 .long (SYMBOL(\end) - SYMBOL(\name)) 212SYMBOL(\name): 213.endm 214 215.macro ENTRY name 216 .text 217 ASM_HIDDEN SYMBOL(\name) 218 .global SYMBOL(\name) 219 FUNCTION_TYPE(\name) 220SYMBOL(\name): 221.endm 222 223.macro END name 224 SIZE(\name) 225.endm 226 227// Macro for defining entrypoints into runtime. We don't need to save registers 228// (we're not holding references there), but there is no 229// kDontSave runtime method. So just use the kSaveRefsOnly runtime method. 230.macro NTERP_TRAMPOLINE name, helper 231DEFINE_FUNCTION \name 232 SETUP_SAVE_REFS_ONLY_FRAME 233 call \helper 234 RESTORE_SAVE_REFS_ONLY_FRAME 235 RETURN_OR_DELIVER_PENDING_EXCEPTION 236END_FUNCTION \name 237.endm 238 239.macro CLEAR_VOLATILE_MARKER reg 240 andq MACRO_LITERAL(-2), \reg 241.endm 242 243.macro EXPORT_PC 244 movq rPC, -16(rREFS) 245.endm 246 247 248.macro BRANCH 249 // Update method counter and do a suspend check if the branch is negative. 250 testq rINSTq, rINSTq 251 js 3f 2522: 253 leaq (rPC, rINSTq, 2), rPC 254 FETCH_INST 255 GOTO_NEXT 2563: 257 movq (%rsp), %rdi 258 addw $$1, ART_METHOD_HOTNESS_COUNT_OFFSET(%rdi) 259 // If the counter overflows, handle this in the runtime. 260 jo NterpHandleHotnessOverflow 261 // Otherwise, do a suspend check. 262 testl $$(THREAD_SUSPEND_OR_CHECKPOINT_REQUEST), rSELF:THREAD_FLAGS_OFFSET 263 jz 2b 264 EXPORT_PC 265 call SYMBOL(art_quick_test_suspend) 266 jmp 2b 267.endm 268 269// Setup the stack to start executing the method. Expects: 270// - rdi to contain the ArtMethod 271// - rbx, r10, r11 to be available. 272// 273// Outputs 274// - rbx contains the dex registers size 275// - r11 contains the old stack pointer. 276.macro SETUP_STACK_FRAME code_item, refs, fp, cfi_refs 277 // Fetch dex register size. 278 movzwl CODE_ITEM_REGISTERS_SIZE_OFFSET(\code_item), %ebx 279 // Fetch outs size. 280 movzwq CODE_ITEM_OUTS_SIZE_OFFSET(\code_item), \refs 281 282 // Compute required frame size for dex registers: ((2 * ebx) + refs) 283 leaq (\refs, %rbx, 2), %r11 284 salq $$2, %r11 285 286 // Compute new stack pointer in r10: add 24 for saving the previous frame, 287 // pc, and method being executed. 288 leaq -24(%rsp), %r10 289 subq %r11, %r10 290 // Alignment 291 andq $$-16, %r10 292 293 // Set reference and dex registers. 294 leaq 24(%r10, \refs, 4), \refs 295 leaq (\refs, %rbx, 4), \fp 296 297 // Now setup the stack pointer. 298 movq %rsp, %r11 299 CFI_DEF_CFA_REGISTER(r11) 300 movq %r10, %rsp 301 movq %r11, -8(\refs) 302 CFI_DEFINE_CFA_DEREF(\cfi_refs, -8, (6 + 4 + 1) * 8) 303 304 // Put nulls in reference frame. 305 testl %ebx, %ebx 306 je 2f 307 movq \refs, %r10 3081: 309 movl $$0, (%r10) 310 addq $$4, %r10 311 cmpq %r10, \fp 312 jne 1b 3132: 314 // Save the ArtMethod. 315 movq %rdi, (%rsp) 316.endm 317 318// Puts the next floating point argument into the expected register, 319// fetching values based on a non-range invoke. 320// Uses rax as temporary. 321// 322// TODO: We could simplify a lot of code by loading the G argument into 323// the "inst" register. Given that we enter the handler with "1(rPC)" in 324// the rINST, we can just add rINST<<16 to the args and we don't even 325// need to pass "arg_index" around. 326.macro LOOP_OVER_SHORTY_LOADING_XMMS xmm_reg, inst, shorty, arg_index, finished 3271: // LOOP 328 movb (REG_VAR(shorty)), %al // bl := *shorty 329 addq MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 330 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 331 je VAR(finished) 332 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto FOUND_DOUBLE 333 je 2f 334 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto FOUND_FLOAT 335 je 3f 336 shrq MACRO_LITERAL(4), REG_VAR(inst) 337 addq MACRO_LITERAL(1), REG_VAR(arg_index) 338 // Handle extra argument in arg array taken by a long. 339 cmpb MACRO_LITERAL(74), %al // if (al != 'J') goto LOOP 340 jne 1b 341 shrq MACRO_LITERAL(4), REG_VAR(inst) 342 addq MACRO_LITERAL(1), REG_VAR(arg_index) 343 jmp 1b // goto LOOP 3442: // FOUND_DOUBLE 345 subq MACRO_LITERAL(8), %rsp 346 movq REG_VAR(inst), %rax 347 andq MACRO_LITERAL(0xf), %rax 348 GET_VREG %eax, %rax 349 movl %eax, (%rsp) 350 shrq MACRO_LITERAL(4), REG_VAR(inst) 351 addq MACRO_LITERAL(1), REG_VAR(arg_index) 352 cmpq MACRO_LITERAL(4), REG_VAR(arg_index) 353 je 5f 354 movq REG_VAR(inst), %rax 355 andq MACRO_LITERAL(0xf), %rax 356 shrq MACRO_LITERAL(4), REG_VAR(inst) 357 addq MACRO_LITERAL(1), REG_VAR(arg_index) 358 jmp 6f 3595: 360 movzbl 1(rPC), %eax 361 andq MACRO_LITERAL(0xf), %rax 3626: 363 GET_VREG %eax, %rax 364 movl %eax, 4(%rsp) 365 movsd (%rsp), REG_VAR(xmm_reg) 366 addq MACRO_LITERAL(8), %rsp 367 jmp 4f 3683: // FOUND_FLOAT 369 cmpq MACRO_LITERAL(4), REG_VAR(arg_index) 370 je 7f 371 movq REG_VAR(inst), %rax 372 andq MACRO_LITERAL(0xf), %rax 373 shrq MACRO_LITERAL(4), REG_VAR(inst) 374 addq MACRO_LITERAL(1), REG_VAR(arg_index) 375 jmp 8f 3767: 377 movzbl 1(rPC), %eax 378 andq MACRO_LITERAL(0xf), %rax 3798: 380 GET_VREG_XMMs REG_VAR(xmm_reg), %rax 3814: 382.endm 383 384// Puts the next int/long/object argument in the expected register, 385// fetching values based on a non-range invoke. 386// Uses rax as temporary. 387.macro LOOP_OVER_SHORTY_LOADING_GPRS gpr_reg64, gpr_reg32, inst, shorty, arg_index, finished 3881: // LOOP 389 movb (REG_VAR(shorty)), %al // bl := *shorty 390 addq MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 391 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 392 je VAR(finished) 393 cmpb MACRO_LITERAL(74), %al // if (al == 'J') goto FOUND_LONG 394 je 2f 395 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto SKIP_FLOAT 396 je 3f 397 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto SKIP_DOUBLE 398 je 4f 399 cmpq MACRO_LITERAL(4), REG_VAR(arg_index) 400 je 7f 401 movq REG_VAR(inst), %rax 402 andq MACRO_LITERAL(0xf), %rax 403 shrq MACRO_LITERAL(4), REG_VAR(inst) 404 addq MACRO_LITERAL(1), REG_VAR(arg_index) 405 jmp 8f 4067: 407 movzbl 1(rPC), %eax 408 andq MACRO_LITERAL(0xf), %rax 4098: 410 GET_VREG REG_VAR(gpr_reg32), %rax 411 jmp 5f 4122: // FOUND_LONG 413 subq MACRO_LITERAL(8), %rsp 414 movq REG_VAR(inst), %rax 415 andq MACRO_LITERAL(0xf), %rax 416 GET_VREG %eax, %rax 417 movl %eax, (%rsp) 418 shrq MACRO_LITERAL(4), REG_VAR(inst) 419 addq MACRO_LITERAL(1), REG_VAR(arg_index) 420 cmpq MACRO_LITERAL(4), REG_VAR(arg_index) 421 je 9f 422 movq REG_VAR(inst), %rax 423 andq MACRO_LITERAL(0xf), %rax 424 shrq MACRO_LITERAL(4), REG_VAR(inst) 425 addq MACRO_LITERAL(1), REG_VAR(arg_index) 426 jmp 10f 4279: 428 movzbl 1(rPC), %eax 429 andq MACRO_LITERAL(0xf), %rax 43010: 431 GET_VREG %eax, %rax 432 movl %eax, 4(%rsp) 433 movq (%rsp), REG_VAR(gpr_reg64) 434 addq MACRO_LITERAL(8), %rsp 435 jmp 5f 4363: // SKIP_FLOAT 437 shrq MACRO_LITERAL(4), REG_VAR(inst) 438 addq MACRO_LITERAL(1), REG_VAR(arg_index) 439 jmp 1b 4404: // SKIP_DOUBLE 441 shrq MACRO_LITERAL(4), REG_VAR(inst) 442 addq MACRO_LITERAL(1), REG_VAR(arg_index) 443 cmpq MACRO_LITERAL(4), REG_VAR(arg_index) 444 je 1b 445 shrq MACRO_LITERAL(4), REG_VAR(inst) 446 addq MACRO_LITERAL(1), REG_VAR(arg_index) 447 jmp 1b 4485: 449.endm 450 451// Puts the next floating point argument into the expected register, 452// fetching values based on a range invoke. 453// Uses rax as temporary. 454.macro LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm_reg, shorty, arg_index, stack_index, finished 4551: // LOOP 456 movb (REG_VAR(shorty)), %al // bl := *shorty 457 addq MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 458 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 459 je VAR(finished) 460 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto FOUND_DOUBLE 461 je 2f 462 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto FOUND_FLOAT 463 je 3f 464 addq MACRO_LITERAL(1), REG_VAR(arg_index) 465 addq MACRO_LITERAL(1), REG_VAR(stack_index) 466 // Handle extra argument in arg array taken by a long. 467 cmpb MACRO_LITERAL(74), %al // if (al != 'J') goto LOOP 468 jne 1b 469 addq MACRO_LITERAL(1), REG_VAR(arg_index) 470 addq MACRO_LITERAL(1), REG_VAR(stack_index) 471 jmp 1b // goto LOOP 4722: // FOUND_DOUBLE 473 GET_VREG_XMMd REG_VAR(xmm_reg), REG_VAR(arg_index) 474 addq MACRO_LITERAL(2), REG_VAR(arg_index) 475 addq MACRO_LITERAL(2), REG_VAR(stack_index) 476 jmp 4f 4773: // FOUND_FLOAT 478 GET_VREG_XMMs REG_VAR(xmm_reg), REG_VAR(arg_index) 479 addq MACRO_LITERAL(1), REG_VAR(arg_index) 480 addq MACRO_LITERAL(1), REG_VAR(stack_index) 4814: 482.endm 483 484// Puts the next floating point argument into the expected stack slot, 485// fetching values based on a range invoke. 486// Uses rax as temporary. 487// 488// TODO: We could just copy all the vregs to the stack slots in a simple loop 489// (or REP MOVSD) without looking at the shorty at all. (We could also drop 490// the "stack_index" from the macros for loading registers.) We could also do 491// that conditionally if argument word count > 6; otherwise we know that all 492// args fit into registers. 493.macro LOOP_RANGE_OVER_FPs shorty, arg_index, stack_index, finished 4941: // LOOP 495 movb (REG_VAR(shorty)), %al // bl := *shorty 496 addq MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 497 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 498 je VAR(finished) 499 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto FOUND_DOUBLE 500 je 2f 501 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto FOUND_FLOAT 502 je 3f 503 addq MACRO_LITERAL(1), REG_VAR(arg_index) 504 addq MACRO_LITERAL(1), REG_VAR(stack_index) 505 // Handle extra argument in arg array taken by a long. 506 cmpb MACRO_LITERAL(74), %al // if (al != 'J') goto LOOP 507 jne 1b 508 addq MACRO_LITERAL(1), REG_VAR(arg_index) 509 addq MACRO_LITERAL(1), REG_VAR(stack_index) 510 jmp 1b // goto LOOP 5112: // FOUND_DOUBLE 512 movq (rFP, REG_VAR(arg_index), 4), %rax 513 movq %rax, 8(%rsp, REG_VAR(stack_index), 4) 514 addq MACRO_LITERAL(2), REG_VAR(arg_index) 515 addq MACRO_LITERAL(2), REG_VAR(stack_index) 516 jmp 1b 5173: // FOUND_FLOAT 518 movl (rFP, REG_VAR(arg_index), 4), %eax 519 movl %eax, 8(%rsp, REG_VAR(stack_index), 4) 520 addq MACRO_LITERAL(1), REG_VAR(arg_index) 521 addq MACRO_LITERAL(1), REG_VAR(stack_index) 522 jmp 1b 523.endm 524 525// Puts the next int/long/object argument in the expected register, 526// fetching values based on a range invoke. 527// Uses rax as temporary. 528.macro LOOP_RANGE_OVER_SHORTY_LOADING_GPRS gpr_reg64, gpr_reg32, shorty, arg_index, stack_index, finished 5291: // LOOP 530 movb (REG_VAR(shorty)), %al // bl := *shorty 531 addq MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 532 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 533 je VAR(finished) 534 cmpb MACRO_LITERAL(74), %al // if (al == 'J') goto FOUND_LONG 535 je 2f 536 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto SKIP_FLOAT 537 je 3f 538 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto SKIP_DOUBLE 539 je 4f 540 movl (rFP, REG_VAR(arg_index), 4), REG_VAR(gpr_reg32) 541 addq MACRO_LITERAL(1), REG_VAR(arg_index) 542 addq MACRO_LITERAL(1), REG_VAR(stack_index) 543 jmp 5f 5442: // FOUND_LONG 545 movq (rFP, REG_VAR(arg_index), 4), REG_VAR(gpr_reg64) 546 addq MACRO_LITERAL(2), REG_VAR(arg_index) 547 addq MACRO_LITERAL(2), REG_VAR(stack_index) 548 jmp 5f 5493: // SKIP_FLOAT 550 addq MACRO_LITERAL(1), REG_VAR(arg_index) 551 addq MACRO_LITERAL(1), REG_VAR(stack_index) 552 jmp 1b 5534: // SKIP_DOUBLE 554 addq MACRO_LITERAL(2), REG_VAR(arg_index) 555 addq MACRO_LITERAL(2), REG_VAR(stack_index) 556 jmp 1b 5575: 558.endm 559 560// Puts the next int/long/object argument in the expected stack slot, 561// fetching values based on a range invoke. 562// Uses rax as temporary. 563.macro LOOP_RANGE_OVER_INTs shorty, arg_index, stack_index, finished 5641: // LOOP 565 movb (REG_VAR(shorty)), %al // al := *shorty 566 addq MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 567 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 568 je VAR(finished) 569 cmpb MACRO_LITERAL(74), %al // if (al == 'J') goto FOUND_LONG 570 je 2f 571 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto SKIP_FLOAT 572 je 3f 573 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto SKIP_DOUBLE 574 je 4f 575 movl (rFP, REG_VAR(arg_index), 4), %eax 576 movl %eax, 8(%rsp, REG_VAR(stack_index), 4) 577 addq MACRO_LITERAL(1), REG_VAR(arg_index) 578 addq MACRO_LITERAL(1), REG_VAR(stack_index) 579 jmp 1b 5802: // FOUND_LONG 581 movq (rFP, REG_VAR(arg_index), 4), %rax 582 movq %rax, 8(%rsp, REG_VAR(stack_index), 4) 583 addq MACRO_LITERAL(2), REG_VAR(arg_index) 584 addq MACRO_LITERAL(2), REG_VAR(stack_index) 585 jmp 1b 5863: // SKIP_FLOAT 587 addq MACRO_LITERAL(1), REG_VAR(arg_index) 588 addq MACRO_LITERAL(1), REG_VAR(stack_index) 589 jmp 1b 5904: // SKIP_DOUBLE 591 addq MACRO_LITERAL(2), REG_VAR(arg_index) 592 addq MACRO_LITERAL(2), REG_VAR(stack_index) 593 jmp 1b 594.endm 595 596// Puts the next floating point parameter passed in physical register 597// in the expected dex register array entry. 598// Uses rax as temporary. 599.macro LOOP_OVER_SHORTY_STORING_XMMS xmm_reg, shorty, arg_index, fp, finished 6001: // LOOP 601 movb (REG_VAR(shorty)), %al // al := *shorty 602 addq MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 603 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 604 je VAR(finished) 605 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto FOUND_DOUBLE 606 je 2f 607 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto FOUND_FLOAT 608 je 3f 609 addq MACRO_LITERAL(4), REG_VAR(arg_index) 610 // Handle extra argument in arg array taken by a long. 611 cmpb MACRO_LITERAL(74), %al // if (al != 'J') goto LOOP 612 jne 1b 613 addq MACRO_LITERAL(4), REG_VAR(arg_index) 614 jmp 1b // goto LOOP 6152: // FOUND_DOUBLE 616 movsd REG_VAR(xmm_reg),(REG_VAR(fp), REG_VAR(arg_index), 1) 617 addq MACRO_LITERAL(8), REG_VAR(arg_index) 618 jmp 4f 6193: // FOUND_FLOAT 620 movss REG_VAR(xmm_reg), (REG_VAR(fp), REG_VAR(arg_index), 1) 621 addq MACRO_LITERAL(4), REG_VAR(arg_index) 6224: 623.endm 624 625// Puts the next int/long/object parameter passed in physical register 626// in the expected dex register array entry, and in case of object in the 627// expected reference array entry. 628// Uses rax as temporary. 629.macro LOOP_OVER_SHORTY_STORING_GPRS gpr_reg64, gpr_reg32, shorty, arg_index, regs, refs, finished 6301: // LOOP 631 movb (REG_VAR(shorty)), %al // bl := *shorty 632 addq MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 633 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 634 je VAR(finished) 635 cmpb MACRO_LITERAL(74), %al // if (al == 'J') goto FOUND_LONG 636 je 2f 637 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto SKIP_FLOAT 638 je 3f 639 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto SKIP_DOUBLE 640 je 4f 641 movl REG_VAR(gpr_reg32), (REG_VAR(regs), REG_VAR(arg_index), 1) 642 cmpb MACRO_LITERAL(76), %al // if (al != 'L') goto NOT_REFERENCE 643 jne 6f 644 movl REG_VAR(gpr_reg32), (REG_VAR(refs), REG_VAR(arg_index), 1) 6456: // NOT_REFERENCE 646 addq MACRO_LITERAL(4), REG_VAR(arg_index) 647 jmp 5f 6482: // FOUND_LONG 649 movq REG_VAR(gpr_reg64), (REG_VAR(regs), REG_VAR(arg_index), 1) 650 addq MACRO_LITERAL(8), REG_VAR(arg_index) 651 jmp 5f 6523: // SKIP_FLOAT 653 addq MACRO_LITERAL(4), REG_VAR(arg_index) 654 jmp 1b 6554: // SKIP_DOUBLE 656 addq MACRO_LITERAL(8), REG_VAR(arg_index) 657 jmp 1b 6585: 659.endm 660 661// Puts the next floating point parameter passed in stack 662// in the expected dex register array entry. 663// Uses rax as temporary. 664// 665// TODO: Or we could just spill regs to the reserved slots in the caller's 666// frame and copy all regs in a simple loop. This time, however, we would 667// need to look at the shorty anyway to look for the references. 668// (The trade-off is different for passing arguments and receiving them.) 669.macro LOOP_OVER_FPs shorty, arg_index, regs, stack_ptr, finished 6701: // LOOP 671 movb (REG_VAR(shorty)), %al // bl := *shorty 672 addq MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 673 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 674 je VAR(finished) 675 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto FOUND_DOUBLE 676 je 2f 677 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto FOUND_FLOAT 678 je 3f 679 addq MACRO_LITERAL(4), REG_VAR(arg_index) 680 // Handle extra argument in arg array taken by a long. 681 cmpb MACRO_LITERAL(74), %al // if (al != 'J') goto LOOP 682 jne 1b 683 addq MACRO_LITERAL(4), REG_VAR(arg_index) 684 jmp 1b // goto LOOP 6852: // FOUND_DOUBLE 686 movq OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 1), %rax 687 movq %rax, (REG_VAR(regs), REG_VAR(arg_index), 1) 688 addq MACRO_LITERAL(8), REG_VAR(arg_index) 689 jmp 1b 6903: // FOUND_FLOAT 691 movl OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 1), %eax 692 movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 1) 693 addq MACRO_LITERAL(4), REG_VAR(arg_index) 694 jmp 1b 695.endm 696 697// Puts the next int/long/object parameter passed in stack 698// in the expected dex register array entry, and in case of object in the 699// expected reference array entry. 700// Uses rax as temporary. 701.macro LOOP_OVER_INTs shorty, arg_index, regs, refs, stack_ptr, finished 7021: // LOOP 703 movb (REG_VAR(shorty)), %al // bl := *shorty 704 addq MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 705 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 706 je VAR(finished) 707 cmpb MACRO_LITERAL(74), %al // if (al == 'J') goto FOUND_LONG 708 je 2f 709 cmpb MACRO_LITERAL(76), %al // if (al == 'L') goto FOUND_REFERENCE 710 je 6f 711 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto SKIP_FLOAT 712 je 3f 713 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto SKIP_DOUBLE 714 je 4f 715 movl OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 1), %eax 716 movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 1) 717 addq MACRO_LITERAL(4), REG_VAR(arg_index) 718 jmp 1b 7196: // FOUND_REFERENCE 720 movl OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 1), %eax 721 movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 1) 722 movl %eax, (REG_VAR(refs), REG_VAR(arg_index), 1) 723 addq MACRO_LITERAL(4), REG_VAR(arg_index) 724 jmp 1b 7252: // FOUND_LONG 726 movq OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 1), %rax 727 movq %rax, (REG_VAR(regs), REG_VAR(arg_index), 1) 728 addq MACRO_LITERAL(8), REG_VAR(arg_index) 729 jmp 1b 7303: // SKIP_FLOAT 731 addq MACRO_LITERAL(4), REG_VAR(arg_index) 732 jmp 1b 7334: // SKIP_DOUBLE 734 addq MACRO_LITERAL(8), REG_VAR(arg_index) 735 jmp 1b 736.endm 737 738// Increase method hotness and do suspend check before starting executing the method. 739.macro START_EXECUTING_INSTRUCTIONS 740 movq (%rsp), %rdi 741 addw $$1, ART_METHOD_HOTNESS_COUNT_OFFSET(%rdi) 742 jo 2f 743 testl $$(THREAD_SUSPEND_OR_CHECKPOINT_REQUEST), rSELF:THREAD_FLAGS_OFFSET 744 jz 1f 745 EXPORT_PC 746 call SYMBOL(art_quick_test_suspend) 7471: 748 FETCH_INST 749 GOTO_NEXT 7502: 751 movq $$0, %rsi 752 movq rFP, %rdx 753 call nterp_hot_method 754 jmp 1b 755.endm 756 757.macro SPILL_ALL_CALLEE_SAVES 758 PUSH r15 759 PUSH r14 760 PUSH r13 761 PUSH r12 762 PUSH rbp 763 PUSH rbx 764 SETUP_FP_CALLEE_SAVE_FRAME 765.endm 766 767.macro RESTORE_ALL_CALLEE_SAVES 768 RESTORE_FP_CALLEE_SAVE_FRAME 769 POP rbx 770 POP rbp 771 POP r12 772 POP r13 773 POP r14 774 POP r15 775.endm 776 777// Helper to setup the stack after doing a nterp to nterp call. This will setup: 778// - rNEW_FP: the new pointer to dex registers 779// - rNEW_REFS: the new pointer to references 780// - rPC: the new PC pointer to execute 781// - edi: number of arguments 782// - ecx: first dex register 783.macro SETUP_STACK_FOR_INVOKE 784 // We do the same stack overflow check as the compiler. See CanMethodUseNterp 785 // in how we limit the maximum nterp frame size. 786 testq %rax, -STACK_OVERFLOW_RESERVED_BYTES(%rsp) 787 788 // Spill all callee saves to have a consistent stack frame whether we 789 // are called by compiled code or nterp. 790 SPILL_ALL_CALLEE_SAVES 791 792 // Setup the frame. 793 SETUP_STACK_FRAME %rax, rNEW_REFS, rNEW_FP, CFI_NEW_REFS 794 // Make r11 point to the top of the dex register array. 795 leaq (rNEW_FP, %rbx, 4), %r11 796 797 // Fetch instruction information before replacing rPC. 798 movzbl 1(rPC), %edi 799 movzwl 4(rPC), %ecx 800 801 // Set the dex pc pointer. 802 leaq CODE_ITEM_INSNS_OFFSET(%rax), rPC 803 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) 804.endm 805 806// Setup arguments based on a non-range nterp to nterp call, and start executing 807// the method. We expect: 808// - rNEW_FP: the new pointer to dex registers 809// - rNEW_REFS: the new pointer to references 810// - rPC: the new PC pointer to execute 811// - edi: number of arguments 812// - ecx: first dex register 813// - r11: top of dex register array 814// - esi: receiver if non-static. 815.macro SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 816 // Now all temporary registers (except r11 containing top of registers array) 817 // are available, copy the parameters. 818 // /* op vA, vB, {vC...vG} */ 819 movl %edi, %eax 820 shrl $$4, %eax # Number of arguments 821 jz 6f # shl sets the Z flag 822 movq MACRO_LITERAL(-1), %r10 823 cmpl MACRO_LITERAL(2), %eax 824 jl 1f 825 je 2f 826 cmpl MACRO_LITERAL(4), %eax 827 jl 3f 828 je 4f 829 830 // We use a decrementing r10 to store references relative 831 // to rNEW_FP and dex registers relative to r11. 832 // 833 // TODO: We could set up r10 as the number of registers (this can be an additional output from 834 // SETUP_STACK_FOR_INVOKE) and then just decrement it by one before copying each arg to 835 // (rNEW_FP, r10, 4) and (rNEW_REFS, r10, 4). 836 // Maybe even introduce macros NEW_VREG_ADDRESS/NEW_VREG_REF_ADDRESS. 8375: 838 andq MACRO_LITERAL(15), %rdi 839 GET_VREG_OBJECT %edx, %rdi 840 movl %edx, (rNEW_FP, %r10, 4) 841 GET_VREG %edx, %rdi 842 movl %edx, (%r11, %r10, 4) 843 subq MACRO_LITERAL(1), %r10 8444: 845 movl %ecx, %eax 846 shrl MACRO_LITERAL(12), %eax 847 GET_VREG_OBJECT %edx, %rax 848 movl %edx, (rNEW_FP, %r10, 4) 849 GET_VREG %edx, %rax 850 movl %edx, (%r11, %r10, 4) 851 subq MACRO_LITERAL(1), %r10 8523: 853 movl %ecx, %eax 854 shrl MACRO_LITERAL(8), %eax 855 andl MACRO_LITERAL(0xf), %eax 856 GET_VREG_OBJECT %edx, %rax 857 movl %edx, (rNEW_FP, %r10, 4) 858 GET_VREG %edx, %rax 859 movl %edx, (%r11, %r10, 4) 860 subq MACRO_LITERAL(1), %r10 8612: 862 movl %ecx, %eax 863 shrl MACRO_LITERAL(4), %eax 864 andl MACRO_LITERAL(0xf), %eax 865 GET_VREG_OBJECT %edx, %rax 866 movl %edx, (rNEW_FP, %r10, 4) 867 GET_VREG %edx, %rax 868 movl %edx, (%r11, %r10, 4) 869 subq MACRO_LITERAL(1), %r10 8701: 871 .if \is_string_init 872 // Ignore the first argument 873 .elseif \is_static 874 movl %ecx, %eax 875 andq MACRO_LITERAL(0x000f), %rax 876 GET_VREG_OBJECT %edx, %rax 877 movl %edx, (rNEW_FP, %r10, 4) 878 GET_VREG %edx, %rax 879 movl %edx, (%r11, %r10, 4) 880 .else 881 movl %esi, (rNEW_FP, %r10, 4) 882 movl %esi, (%r11, %r10, 4) 883 .endif 884 8856: 886 // Start executing the method. 887 movq rNEW_FP, rFP 888 movq rNEW_REFS, rREFS 889 CFI_DEFINE_CFA_DEREF(CFI_REFS, -8, (6 + 4 + 1) * 8) 890 START_EXECUTING_INSTRUCTIONS 891.endm 892 893// Setup arguments based on a range nterp to nterp call, and start executing 894// the method. 895.macro SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 896 // edi is number of arguments 897 // ecx is first register 898 movq MACRO_LITERAL(-4), %r10 899 .if \is_string_init 900 // Ignore the first argument 901 subl $$1, %edi 902 addl $$1, %ecx 903 .elseif !\is_static 904 subl $$1, %edi 905 addl $$1, %ecx 906 .endif 907 908 testl %edi, %edi 909 je 2f 910 leaq (rREFS, %rcx, 4), %rax # pointer to first argument in reference array 911 leaq (%rax, %rdi, 4), %rax # pointer to last argument in reference array 912 leaq (rFP, %rcx, 4), %rcx # pointer to first argument in register array 913 leaq (%rcx, %rdi, 4), %rdi # pointer to last argument in register array 914 // TODO: Same comment for copying arguments as in SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE. 9151: 916 movl -4(%rax), %edx 917 movl %edx, (rNEW_FP, %r10, 1) 918 movl -4(%rdi), %edx 919 movl %edx, (%r11, %r10, 1) 920 subq MACRO_LITERAL(4), %r10 921 subq MACRO_LITERAL(4), %rax 922 subq MACRO_LITERAL(4), %rdi 923 cmpq %rcx, %rdi 924 jne 1b 925 9262: 927 .if \is_string_init 928 // Ignore first argument 929 .elseif !\is_static 930 movl %esi, (rNEW_FP, %r10, 1) 931 movl %esi, (%r11, %r10, 1) 932 .endif 933 movq rNEW_FP, rFP 934 movq rNEW_REFS, rREFS 935 CFI_DEFINE_CFA_DEREF(CFI_REFS, -8, (6 + 4 + 1) * 8) 936 START_EXECUTING_INSTRUCTIONS 937.endm 938 939.macro GET_SHORTY dest, is_interface, is_polymorphic, is_custom 940 push %rdi 941 push %rsi 942 .if \is_polymorphic 943 movq 16(%rsp), %rdi 944 movq rPC, %rsi 945 call SYMBOL(NterpGetShortyFromInvokePolymorphic) 946 .elseif \is_custom 947 movq 16(%rsp), %rdi 948 movq rPC, %rsi 949 call SYMBOL(NterpGetShortyFromInvokeCustom) 950 .elseif \is_interface 951 movq 16(%rsp), %rdi 952 movzwl 2(rPC), %esi 953 call SYMBOL(NterpGetShortyFromMethodId) 954 .else 955 call SYMBOL(NterpGetShorty) 956 .endif 957 pop %rsi 958 pop %rdi 959 movq %rax, \dest 960.endm 961 962.macro DO_ENTRY_POINT_CHECK call_compiled_code 963 // On entry, the method is %rdi, the instance is %rsi 964 leaq ExecuteNterpImpl(%rip), %rax 965 cmpq %rax, ART_METHOD_QUICK_CODE_OFFSET_64(%rdi) 966 jne VAR(call_compiled_code) 967 968 // TODO: Get code item in a better way and remove below 969 push %rdi 970 push %rsi 971 call SYMBOL(NterpGetCodeItem) 972 pop %rsi 973 pop %rdi 974 // TODO: Get code item in a better way and remove above 975.endm 976 977// Uses r9 and r10 as temporary 978.macro UPDATE_REGISTERS_FOR_STRING_INIT old_value, new_value 979 movq rREFS, %r9 980 movq rFP, %r10 9811: 982 cmpl (%r9), \old_value 983 jne 2f 984 movl \new_value, (%r9) 985 movl \new_value, (%r10) 9862: 987 addq $$4, %r9 988 addq $$4, %r10 989 cmpq %r9, rFP 990 jne 1b 991.endm 992 993.macro COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0 994 .if \is_polymorphic 995 // We always go to compiled code for polymorphic calls. 996 .elseif \is_custom 997 // We always go to compiled code for custom calls. 998 .else 999 DO_ENTRY_POINT_CHECK .Lcall_compiled_code_\suffix 1000 .if \is_string_init 1001 call nterp_to_nterp_string_init_non_range 1002 .elseif \is_static 1003 call nterp_to_nterp_static_non_range 1004 .else 1005 call nterp_to_nterp_instance_non_range 1006 .endif 1007 jmp .Ldone_return_\suffix 1008 .endif 1009 1010.Lcall_compiled_code_\suffix: 1011 GET_SHORTY rINSTq, \is_interface, \is_polymorphic, \is_custom 1012 // From this point: 1013 // - rISNTq contains shorty (in callee-save to switch over return value after call). 1014 // - rdi contains method 1015 // - rsi contains 'this' pointer for instance method. 1016 leaq 1(rINSTq), %r9 // shorty + 1 ; ie skip return arg character 1017 movzwl 4(rPC), %r11d // arguments 1018 .if \is_string_init 1019 shrq MACRO_LITERAL(4), %r11 1020 movq $$1, %r10 // ignore first argument 1021 .elseif \is_static 1022 movq $$0, %r10 // arg_index 1023 .else 1024 shrq MACRO_LITERAL(4), %r11 1025 movq $$1, %r10 // arg_index 1026 .endif 1027 LOOP_OVER_SHORTY_LOADING_XMMS xmm0, r11, r9, r10, .Lxmm_setup_finished_\suffix 1028 LOOP_OVER_SHORTY_LOADING_XMMS xmm1, r11, r9, r10, .Lxmm_setup_finished_\suffix 1029 LOOP_OVER_SHORTY_LOADING_XMMS xmm2, r11, r9, r10, .Lxmm_setup_finished_\suffix 1030 LOOP_OVER_SHORTY_LOADING_XMMS xmm3, r11, r9, r10, .Lxmm_setup_finished_\suffix 1031 LOOP_OVER_SHORTY_LOADING_XMMS xmm4, r11, r9, r10, .Lxmm_setup_finished_\suffix 1032.Lxmm_setup_finished_\suffix: 1033 leaq 1(rINSTq), %r9 // shorty + 1 ; ie skip return arg character 1034 movzwl 4(rPC), %r11d // arguments 1035 .if \is_string_init 1036 movq $$1, %r10 // ignore first argument 1037 shrq MACRO_LITERAL(4), %r11 1038 LOOP_OVER_SHORTY_LOADING_GPRS rsi, esi, r11, r9, r10, .Lgpr_setup_finished_\suffix 1039 .elseif \is_static 1040 movq $$0, %r10 // arg_index 1041 LOOP_OVER_SHORTY_LOADING_GPRS rsi, esi, r11, r9, r10, .Lgpr_setup_finished_\suffix 1042 .else 1043 shrq MACRO_LITERAL(4), %r11 1044 movq $$1, %r10 // arg_index 1045 .endif 1046 LOOP_OVER_SHORTY_LOADING_GPRS rdx, edx, r11, r9, r10, .Lgpr_setup_finished_\suffix 1047 LOOP_OVER_SHORTY_LOADING_GPRS rcx, ecx, r11, r9, r10, .Lgpr_setup_finished_\suffix 1048 LOOP_OVER_SHORTY_LOADING_GPRS r8, r8d, r11, r9, r10, .Lgpr_setup_finished_\suffix 1049 LOOP_OVER_SHORTY_LOADING_GPRS r9, r9d, r11, r9, r10, .Lgpr_setup_finished_\suffix 1050.Lgpr_setup_finished_\suffix: 1051 .if \is_polymorphic 1052 call SYMBOL(art_quick_invoke_polymorphic) 1053 .elseif \is_custom 1054 call SYMBOL(art_quick_invoke_custom) 1055 .else 1056 .if \is_interface 1057 movzwl 2(rPC), %eax 1058 .endif 1059 call *ART_METHOD_QUICK_CODE_OFFSET_64(%rdi) // Call the method. 1060 .endif 1061 cmpb LITERAL(68), (rINSTq) // Test if result type char == 'D'. 1062 je .Lreturn_double_\suffix 1063 cmpb LITERAL(70), (rINSTq) // Test if result type char == 'F'. 1064 jne .Ldone_return_\suffix 1065.Lreturn_float_\suffix: 1066 movd %xmm0, %eax 1067 jmp .Ldone_return_\suffix 1068.Lreturn_double_\suffix: 1069 movq %xmm0, %rax 1070.Ldone_return_\suffix: 1071 /* resume execution of caller */ 1072 .if \is_string_init 1073 movzwl 4(rPC), %r11d // arguments 1074 andq $$0xf, %r11 1075 GET_VREG %esi, %r11 1076 UPDATE_REGISTERS_FOR_STRING_INIT %esi, %eax 1077 .endif 1078 1079 .if \is_polymorphic 1080 ADVANCE_PC_FETCH_AND_GOTO_NEXT 4 1081 .else 1082 ADVANCE_PC_FETCH_AND_GOTO_NEXT 3 1083 .endif 1084.endm 1085 1086.macro COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0 1087 .if \is_polymorphic 1088 // We always go to compiled code for polymorphic calls. 1089 .elseif \is_custom 1090 // We always go to compiled code for custom calls. 1091 .else 1092 DO_ENTRY_POINT_CHECK .Lcall_compiled_code_range_\suffix 1093 .if \is_string_init 1094 call nterp_to_nterp_string_init_range 1095 .elseif \is_static 1096 call nterp_to_nterp_static_range 1097 .else 1098 call nterp_to_nterp_instance_range 1099 .endif 1100 jmp .Ldone_return_range_\suffix 1101 .endif 1102 1103.Lcall_compiled_code_range_\suffix: 1104 GET_SHORTY rINSTq, \is_interface, \is_polymorphic, \is_custom 1105 // From this point: 1106 // - rINSTq contains shorty (in callee-save to switch over return value after call). 1107 // - rdi contains method 1108 // - rsi contains 'this' pointer for instance method. 1109 leaq 1(rINSTq), %r9 // shorty + 1 ; ie skip return arg character 1110 movzwl 4(rPC), %r10d // arg start index 1111 .if \is_string_init 1112 addq $$1, %r10 // arg start index 1113 movq $$1, %rbp // index in stack 1114 .elseif \is_static 1115 movq $$0, %rbp // index in stack 1116 .else 1117 addq $$1, %r10 // arg start index 1118 movq $$1, %rbp // index in stack 1119 .endif 1120 LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm0, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix 1121 LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm1, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix 1122 LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm2, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix 1123 LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm3, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix 1124 LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm4, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix 1125 LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm5, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix 1126 LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm6, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix 1127 LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm7, r9, r10, rbp, .Lxmm_setup_finished_range_\suffix 1128 LOOP_RANGE_OVER_FPs r9, r10, rbp, .Lxmm_setup_finished_range_\suffix 1129.Lxmm_setup_finished_range_\suffix: 1130 leaq 1(%rbx), %r11 // shorty + 1 ; ie skip return arg character 1131 movzwl 4(rPC), %r10d // arg start index 1132 .if \is_string_init 1133 addq $$1, %r10 // arg start index 1134 movq $$1, %rbp // index in stack 1135 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS rsi, esi, r11, r10, rbp, .Lgpr_setup_finished_\suffix 1136 .elseif \is_static 1137 movq $$0, %rbp // index in stack 1138 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS rsi, esi, r11, r10, rbp, .Lgpr_setup_finished_\suffix 1139 .else 1140 addq $$1, %r10 // arg start index 1141 movq $$1, %rbp // index in stack 1142 .endif 1143 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS rdx, edx, r11, r10, rbp, .Lgpr_setup_finished_range_\suffix 1144 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS rcx, ecx, r11, r10, rbp, .Lgpr_setup_finished_range_\suffix 1145 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r8, r8d, r11, r10, rbp, .Lgpr_setup_finished_range_\suffix 1146 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r9, r9d, r11, r10, rbp, .Lgpr_setup_finished_range_\suffix 1147 LOOP_RANGE_OVER_INTs r11, r10, rbp, .Lgpr_setup_finished_range_\suffix 1148 1149.Lgpr_setup_finished_range_\suffix: 1150 .if \is_polymorphic 1151 call SYMBOL(art_quick_invoke_polymorphic) 1152 .elseif \is_custom 1153 call SYMBOL(art_quick_invoke_custom) 1154 .else 1155 .if \is_interface 1156 movzwl 2(rPC), %eax 1157 .endif 1158 call *ART_METHOD_QUICK_CODE_OFFSET_64(%rdi) // Call the method. 1159 .endif 1160 cmpb LITERAL(68), (%rbx) // Test if result type char == 'D'. 1161 je .Lreturn_range_double_\suffix 1162 cmpb LITERAL(70), (%rbx) // Test if result type char == 'F'. 1163 je .Lreturn_range_float_\suffix 1164 /* resume execution of caller */ 1165.Ldone_return_range_\suffix: 1166 .if \is_string_init 1167 movzwl 4(rPC), %r11d // arguments 1168 GET_VREG %esi, %r11 1169 UPDATE_REGISTERS_FOR_STRING_INIT %esi, %eax 1170 .endif 1171 1172 .if \is_polymorphic 1173 ADVANCE_PC_FETCH_AND_GOTO_NEXT 4 1174 .else 1175 ADVANCE_PC_FETCH_AND_GOTO_NEXT 3 1176 .endif 1177.Lreturn_range_double_\suffix: 1178 movq %xmm0, %rax 1179 jmp .Ldone_return_range_\suffix 1180.Lreturn_range_float_\suffix: 1181 movd %xmm0, %eax 1182 jmp .Ldone_return_range_\suffix 1183.endm 1184 1185// Fetch some information from the thread cache. 1186// Uses rax, rdx, rcx as temporaries. 1187.macro FETCH_FROM_THREAD_CACHE dest_reg, slow_path 1188 movq rSELF:THREAD_SELF_OFFSET, %rax 1189 movq rPC, %rdx 1190 salq MACRO_LITERAL(THREAD_INTERPRETER_CACHE_SIZE_SHIFT), %rdx 1191 andq MACRO_LITERAL(THREAD_INTERPRETER_CACHE_SIZE_MASK), %rdx 1192 cmpq THREAD_INTERPRETER_CACHE_OFFSET(%rax, %rdx, 1), rPC 1193 jne \slow_path 1194 movq __SIZEOF_POINTER__+THREAD_INTERPRETER_CACHE_OFFSET(%rax, %rdx, 1), \dest_reg 1195.endm 1196 1197// Helper for static field get. 1198.macro OP_SGET load="movl", wide="0" 1199 // Fast-path which gets the field from thread-local cache. 1200 FETCH_FROM_THREAD_CACHE %rax, 2f 12011: 1202 movl ART_FIELD_OFFSET_OFFSET(%rax), %edx 1203 movl ART_FIELD_DECLARING_CLASS_OFFSET(%rax), %eax 1204 cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1205 jne 3f 12064: 1207 .if \wide 1208 movq (%eax,%edx,1), %rax 1209 SET_WIDE_VREG %rax, rINSTq # fp[A] <- value 1210 .else 1211 \load (%eax, %edx, 1), %eax 1212 SET_VREG %eax, rINSTq # fp[A] <- value 1213 .endif 1214 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 12152: 1216 movq rSELF:THREAD_SELF_OFFSET, %rdi 1217 movq 0(%rsp), %rsi 1218 movq rPC, %rdx 1219 EXPORT_PC 1220 call nterp_get_static_field 1221 // Clear the marker that we put for volatile fields. The x86 memory 1222 // model doesn't require a barrier. 1223 andq $$-2, %rax 1224 jmp 1b 12253: 1226 call art_quick_read_barrier_mark_reg00 1227 jmp 4b 1228.endm 1229 1230// Helper for static field put. 1231.macro OP_SPUT rINST_reg="rINST", store="movl", wide="0": 1232 // Fast-path which gets the field from thread-local cache. 1233 FETCH_FROM_THREAD_CACHE %rax, 2f 12341: 1235 movl ART_FIELD_OFFSET_OFFSET(%rax), %edx 1236 movl ART_FIELD_DECLARING_CLASS_OFFSET(%rax), %eax 1237 cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1238 jne 3f 12394: 1240 .if \wide 1241 GET_WIDE_VREG rINSTq, rINSTq # rINST <- v[A] 1242 .else 1243 GET_VREG rINST, rINSTq # rINST <- v[A] 1244 .endif 1245 \store \rINST_reg, (%rax,%rdx,1) 1246 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 12472: 1248 movq rSELF:THREAD_SELF_OFFSET, %rdi 1249 movq 0(%rsp), %rsi 1250 movq rPC, %rdx 1251 EXPORT_PC 1252 call nterp_get_static_field 1253 testq MACRO_LITERAL(1), %rax 1254 je 1b 1255 // Clear the marker that we put for volatile fields. The x86 memory 1256 // model doesn't require a barrier. 1257 CLEAR_VOLATILE_MARKER %rax 1258 movl ART_FIELD_OFFSET_OFFSET(%rax), %edx 1259 movl ART_FIELD_DECLARING_CLASS_OFFSET(%rax), %eax 1260 cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1261 jne 6f 12625: 1263 .if \wide 1264 GET_WIDE_VREG rINSTq, rINSTq # rINST <- v[A] 1265 .else 1266 GET_VREG rINST, rINSTq # rINST <- v[A] 1267 .endif 1268 \store \rINST_reg, (%rax,%rdx,1) 1269 lock addl $$0, (%rsp) 1270 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 12713: 1272 call art_quick_read_barrier_mark_reg00 1273 jmp 4b 12746: 1275 call art_quick_read_barrier_mark_reg00 1276 jmp 5b 1277.endm 1278 1279 1280.macro OP_IPUT_INTERNAL rINST_reg="rINST", store="movl", wide="0": 1281 movzbq rINSTbl, %rcx # rcx <- BA 1282 sarl $$4, %ecx # ecx <- B 1283 GET_VREG %ecx, %rcx # vB (object we're operating on) 1284 testl %ecx, %ecx # is object null? 1285 je common_errNullObject 1286 andb $$0xf, rINSTbl # rINST <- A 1287 .if \wide 1288 GET_WIDE_VREG rINSTq, rINSTq # rax<- fp[A]/fp[A+1] 1289 .else 1290 GET_VREG rINST, rINSTq # rINST <- v[A] 1291 .endif 1292 \store \rINST_reg, (%rcx,%rax,1) 1293.endm 1294 1295// Helper for instance field put. 1296.macro OP_IPUT rINST_reg="rINST", store="movl", wide="0": 1297 // Fast-path which gets the field from thread-local cache. 1298 FETCH_FROM_THREAD_CACHE %rax, 2f 12991: 1300 OP_IPUT_INTERNAL \rINST_reg, \store, \wide 1301 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 13022: 1303 movq rSELF:THREAD_SELF_OFFSET, %rdi 1304 movq 0(%rsp), %rsi 1305 movq rPC, %rdx 1306 EXPORT_PC 1307 call nterp_get_instance_field_offset 1308 testl %eax, %eax 1309 jns 1b 1310 negl %eax 1311 OP_IPUT_INTERNAL \rINST_reg, \store, \wide 1312 lock addl $$0, (%rsp) 1313 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 1314.endm 1315 1316// Helper for instance field get. 1317.macro OP_IGET load="movl", wide="0" 1318 // Fast-path which gets the field from thread-local cache. 1319 FETCH_FROM_THREAD_CACHE %rax, 2f 13201: 1321 movl rINST, %ecx # rcx <- BA 1322 sarl $$4, %ecx # ecx <- B 1323 GET_VREG %ecx, %rcx # vB (object we're operating on) 1324 testl %ecx, %ecx # is object null? 1325 je common_errNullObject 1326 andb $$0xf,rINSTbl # rINST <- A 1327 .if \wide 1328 movq (%rcx,%rax,1), %rax 1329 SET_WIDE_VREG %rax, rINSTq # fp[A] <- value 1330 .else 1331 \load (%rcx,%rax,1), %eax 1332 SET_VREG %eax, rINSTq # fp[A] <- value 1333 .endif 1334 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 13352: 1336 movq rSELF:THREAD_SELF_OFFSET, %rdi 1337 movq 0(%rsp), %rsi 1338 movq rPC, %rdx 1339 EXPORT_PC 1340 call nterp_get_instance_field_offset 1341 testl %eax, %eax 1342 jns 1b 1343 negl %eax 1344 jmp 1b 1345.endm 1346 1347%def entry(): 1348/* 1349 * ArtMethod entry point. 1350 * 1351 * On entry: 1352 * rdi ArtMethod* callee 1353 * rest method parameters 1354 */ 1355 1356OAT_ENTRY ExecuteNterpImpl, EndExecuteNterpImpl 1357 .cfi_startproc 1358 .cfi_def_cfa rsp, 8 1359 testq %rax, -STACK_OVERFLOW_RESERVED_BYTES(%rsp) 1360 /* Spill callee save regs */ 1361 SPILL_ALL_CALLEE_SAVES 1362 1363 // TODO: Get shorty in a better way and remove below 1364 PUSH rdi 1365 PUSH rsi 1366 PUSH rdx 1367 PUSH rcx 1368 PUSH r8 1369 PUSH r9 1370 1371 // Save xmm registers + alignment. 1372 subq MACRO_LITERAL(8 * 8 + 8), %rsp 1373 CFI_ADJUST_CFA_OFFSET(8 * 8 + 8) 1374 movq %xmm0, 0(%rsp) 1375 movq %xmm1, 8(%rsp) 1376 movq %xmm2, 16(%rsp) 1377 movq %xmm3, 24(%rsp) 1378 movq %xmm4, 32(%rsp) 1379 movq %xmm5, 40(%rsp) 1380 movq %xmm6, 48(%rsp) 1381 movq %xmm7, 56(%rsp) 1382 1383 // Save method in callee-save rbx. 1384 movq %rdi, %rbx 1385 call SYMBOL(NterpGetShorty) 1386 // Save shorty in callee-save rbp. 1387 movq %rax, %rbp 1388 movq %rbx, %rdi 1389 call SYMBOL(NterpGetCodeItem) 1390 movq %rax, rPC 1391 1392 // Restore xmm registers + alignment. 1393 movq 0(%rsp), %xmm0 1394 movq 8(%rsp), %xmm1 1395 movq 16(%rsp), %xmm2 1396 movq 24(%rsp), %xmm3 1397 movq 32(%rsp), %xmm4 1398 movq 40(%rsp), %xmm5 1399 movq 48(%rsp), %xmm6 1400 movq 56(%rsp), %xmm7 1401 addq MACRO_LITERAL(8 * 8 + 8), %rsp 1402 CFI_ADJUST_CFA_OFFSET(-8 * 8 - 8) 1403 1404 POP r9 1405 POP r8 1406 POP rcx 1407 POP rdx 1408 POP rsi 1409 POP rdi 1410 // TODO: Get shorty in a better way and remove above 1411 1412 // Setup the stack for executing the method. 1413 SETUP_STACK_FRAME rPC, rREFS, rFP, CFI_REFS 1414 1415 // Setup the parameters 1416 movzwl CODE_ITEM_INS_SIZE_OFFSET(rPC), %r14d 1417 testl %r14d, %r14d 1418 je .Lxmm_setup_finished 1419 1420 subq %r14, %rbx 1421 salq $$2, %rbx // rbx is now the offset for inputs into the registers array. 1422 1423 testl $$ART_METHOD_IS_STATIC_FLAG, ART_METHOD_ACCESS_FLAGS_OFFSET(%rdi) 1424 1425 // Available: rdi, r10, r14 1426 // Note the leaq below don't change the flags. 1427 leaq 1(%rbp), %r10 // shorty + 1 ; ie skip return arg character 1428 leaq (rFP, %rbx, 1), %rdi 1429 leaq (rREFS, %rbx, 1), %rbx 1430 jne .Lhandle_static_method 1431 movl %esi, (%rdi) 1432 movl %esi, (%rbx) 1433 addq $$4, %rdi 1434 addq $$4, %rbx 1435 addq $$4, %r11 1436 movq $$0, %r14 1437 jmp .Lcontinue_setup_gprs 1438.Lhandle_static_method: 1439 movq $$0, %r14 1440 LOOP_OVER_SHORTY_STORING_GPRS rsi, esi, r10, r14, rdi, rbx, .Lgpr_setup_finished 1441.Lcontinue_setup_gprs: 1442 LOOP_OVER_SHORTY_STORING_GPRS rdx, edx, r10, r14, rdi, rbx, .Lgpr_setup_finished 1443 LOOP_OVER_SHORTY_STORING_GPRS rcx, ecx, r10, r14, rdi, rbx, .Lgpr_setup_finished 1444 LOOP_OVER_SHORTY_STORING_GPRS r8, r8d, r10, r14, rdi, rbx, .Lgpr_setup_finished 1445 LOOP_OVER_SHORTY_STORING_GPRS r9, r9d, r10, r14, rdi, rbx, .Lgpr_setup_finished 1446 LOOP_OVER_INTs r10, r14, rdi, rbx, r11, .Lgpr_setup_finished 1447.Lgpr_setup_finished: 1448 leaq 1(%rbp), %r10 // shorty + 1 ; ie skip return arg character 1449 movq $$0, %r14 // reset counter 1450 LOOP_OVER_SHORTY_STORING_XMMS xmm0, r10, r14, rdi, .Lxmm_setup_finished 1451 LOOP_OVER_SHORTY_STORING_XMMS xmm1, r10, r14, rdi, .Lxmm_setup_finished 1452 LOOP_OVER_SHORTY_STORING_XMMS xmm2, r10, r14, rdi, .Lxmm_setup_finished 1453 LOOP_OVER_SHORTY_STORING_XMMS xmm3, r10, r14, rdi, .Lxmm_setup_finished 1454 LOOP_OVER_SHORTY_STORING_XMMS xmm4, r10, r14, rdi, .Lxmm_setup_finished 1455 LOOP_OVER_SHORTY_STORING_XMMS xmm5, r10, r14, rdi, .Lxmm_setup_finished 1456 LOOP_OVER_SHORTY_STORING_XMMS xmm6, r10, r14, rdi, .Lxmm_setup_finished 1457 LOOP_OVER_SHORTY_STORING_XMMS xmm7, r10, r14, rdi, .Lxmm_setup_finished 1458 LOOP_OVER_FPs r10, r14, rdi, r11, .Lxmm_setup_finished 1459.Lxmm_setup_finished: 1460 // Set the dex pc pointer. 1461 addq $$CODE_ITEM_INSNS_OFFSET, rPC 1462 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) 1463 1464 // Set rIBASE 1465 leaq artNterpAsmInstructionStart(%rip), rIBASE 1466 /* start executing the instruction at rPC */ 1467 START_EXECUTING_INSTRUCTIONS 1468 /* NOTE: no fallthrough */ 1469 // cfi info continues, and covers the whole nterp implementation. 1470 END ExecuteNterpImpl 1471 1472%def opcode_pre(): 1473 1474%def helpers(): 1475 1476%def footer(): 1477/* 1478 * =========================================================================== 1479 * Common subroutines and data 1480 * =========================================================================== 1481 */ 1482 1483 .text 1484 .align 2 1485 1486// Note: mterp also uses the common_* names below for helpers, but that's OK 1487// as the C compiler compiled each interpreter separately. 1488common_errDivideByZero: 1489 EXPORT_PC 1490 call art_quick_throw_div_zero 1491 1492common_errArrayIndex: 1493 EXPORT_PC 1494 movl MIRROR_ARRAY_LENGTH_OFFSET(%edi), %eax 1495 movl %esi, %edi 1496 movl %eax, %esi 1497 call art_quick_throw_array_bounds 1498 1499common_errNullObject: 1500 EXPORT_PC 1501 call art_quick_throw_null_pointer_exception 1502 1503NterpCommonInvokeStatic: 1504 COMMON_INVOKE_NON_RANGE is_static=1, is_interface=0, suffix="invokeStatic" 1505 1506NterpCommonInvokeStaticRange: 1507 COMMON_INVOKE_RANGE is_static=1, is_interface=0, suffix="invokeStatic" 1508 1509NterpCommonInvokeInstance: 1510 COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="invokeInstance" 1511 1512NterpCommonInvokeInstanceRange: 1513 COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="invokeInstance" 1514 1515NterpCommonInvokeInterface: 1516 COMMON_INVOKE_NON_RANGE is_static=0, is_interface=1, suffix="invokeInterface" 1517 1518NterpCommonInvokeInterfaceRange: 1519 COMMON_INVOKE_RANGE is_static=0, is_interface=1, suffix="invokeInterface" 1520 1521NterpCommonInvokePolymorphic: 1522 COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, is_string_init=0, is_polymorphic=1, suffix="invokePolymorphic" 1523 1524NterpCommonInvokePolymorphicRange: 1525 COMMON_INVOKE_RANGE is_static=0, is_interface=0, is_polymorphic=1, suffix="invokePolymorphic" 1526 1527NterpCommonInvokeCustom: 1528 COMMON_INVOKE_NON_RANGE is_static=1, is_interface=0, is_string_init=0, is_polymorphic=0, is_custom=1, suffix="invokeCustom" 1529 1530NterpCommonInvokeCustomRange: 1531 COMMON_INVOKE_RANGE is_static=1, is_interface=0, is_polymorphic=0, is_custom=1, suffix="invokeCustom" 1532 1533NterpHandleStringInit: 1534 COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, is_string_init=1, suffix="stringInit" 1535 1536NterpHandleStringInitRange: 1537 COMMON_INVOKE_RANGE is_static=0, is_interface=0, is_string_init=1, suffix="stringInit" 1538 1539NterpNewInstance: 1540 EXPORT_PC 1541 // Fast-path which gets the class from thread-local cache. 1542 FETCH_FROM_THREAD_CACHE %rdi, 2f 1543 cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1544 jne 3f 15454: 1546 callq *rSELF:THREAD_ALLOC_OBJECT_ENTRYPOINT_OFFSET 15471: 1548 SET_VREG_OBJECT %eax, rINSTq # fp[A] <- value 1549 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 15502: 1551 movq rSELF:THREAD_SELF_OFFSET, %rdi 1552 movq 0(%rsp), %rsi 1553 movq rPC, %rdx 1554 call nterp_get_class_or_allocate_object 1555 jmp 1b 15563: 1557 // 07 is %rdi 1558 call art_quick_read_barrier_mark_reg07 1559 jmp 4b 1560 1561NterpNewArray: 1562 /* new-array vA, vB, class@CCCC */ 1563 EXPORT_PC 1564 // Fast-path which gets the class from thread-local cache. 1565 FETCH_FROM_THREAD_CACHE %rdi, 2f 1566 cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1567 jne 3f 15681: 1569 movzbl rINSTbl,%esi 1570 sarl $$4,%esi # esi<- B 1571 GET_VREG %esi %rsi # esi<- vB (array length) 1572 andb $$0xf,rINSTbl # rINST<- A 1573 callq *rSELF:THREAD_ALLOC_ARRAY_ENTRYPOINT_OFFSET 1574 SET_VREG_OBJECT %eax, rINSTq # fp[A] <- value 1575 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 15762: 1577 movq rSELF:THREAD_SELF_OFFSET, %rdi 1578 movq 0(%rsp), %rsi 1579 movq rPC, %rdx 1580 call nterp_get_class_or_allocate_object 1581 movq %rax, %rdi 1582 jmp 1b 15833: 1584 // 07 is %rdi 1585 call art_quick_read_barrier_mark_reg07 1586 jmp 1b 1587 1588NterpPutObjectInstanceField: 1589 // Fast-path which gets the field from thread-local cache. 1590 FETCH_FROM_THREAD_CACHE %rax, 2f 15911: 1592 movzbq rINSTbl, %rcx # rcx <- BA 1593 sarl $$4, %ecx # ecx <- B 1594 GET_VREG %ecx, %rcx # vB (object we're operating on) 1595 testl %ecx, %ecx # is object null? 1596 je common_errNullObject 1597 andb $$0xf, rINSTbl # rINST <- A 1598 GET_VREG rINST, rINSTq # rINST <- v[A] 1599 movl rINST, (%rcx,%rax,1) 1600 testl rINST, rINST 1601 je 4f 1602 movq rSELF:THREAD_CARD_TABLE_OFFSET, %rax 1603 shrq $$CARD_TABLE_CARD_SHIFT, %rcx 1604 movb %al, (%rax, %rcx, 1) 16054: 1606 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 16072: 1608 EXPORT_PC 1609 movq rSELF:THREAD_SELF_OFFSET, %rdi 1610 movq 0(%rsp), %rsi 1611 movq rPC, %rdx 1612 EXPORT_PC 1613 call nterp_get_instance_field_offset 1614 testl %eax, %eax 1615 jns 1b 1616 negl %eax 1617 movzbq rINSTbl, %rcx # rcx <- BA 1618 sarl $$4, %ecx # ecx <- B 1619 GET_VREG %ecx, %rcx # vB (object we're operating on) 1620 testl %ecx, %ecx # is object null? 1621 je common_errNullObject 1622 andb $$0xf, rINSTbl # rINST <- A 1623 GET_VREG rINST, rINSTq # rINST <- v[A] 1624 movl rINST, (%rcx,%rax,1) 1625 testl rINST, rINST 1626 je 5f 1627 movq rSELF:THREAD_CARD_TABLE_OFFSET, %rax 1628 shrq $$CARD_TABLE_CARD_SHIFT, %rcx 1629 movb %al, (%rcx, %rax, 1) 16305: 1631 lock addl $$0, (%rsp) 1632 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 1633 1634NterpGetObjectInstanceField: 1635 // Fast-path which gets the field from thread-local cache. 1636 FETCH_FROM_THREAD_CACHE %rax, 2f 16371: 1638 movl rINST, %ecx # rcx <- BA 1639 sarl $$4, %ecx # ecx <- B 1640 GET_VREG %ecx, %rcx # vB (object we're operating on) 1641 testl %ecx, %ecx # is object null? 1642 je common_errNullObject 1643 testb $$READ_BARRIER_TEST_VALUE, GRAY_BYTE_OFFSET(%ecx) 1644 movl (%rcx,%rax,1), %eax 1645 jnz 3f 16464: 1647 andb $$0xf,rINSTbl # rINST <- A 1648 SET_VREG_OBJECT %eax, rINSTq # fp[A] <- value 1649 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 16502: 1651 EXPORT_PC 1652 movq rSELF:THREAD_SELF_OFFSET, %rdi 1653 movq 0(%rsp), %rsi 1654 movq rPC, %rdx 1655 EXPORT_PC 1656 call nterp_get_instance_field_offset 1657 testl %eax, %eax 1658 jns 1b 1659 // For volatile fields, we return a negative offset. Remove the sign 1660 // and no need for any barrier thanks to the memory model. 1661 negl %eax 1662 jmp 1b 16633: 1664 // reg00 is eax 1665 call art_quick_read_barrier_mark_reg00 1666 jmp 4b 1667 1668NterpPutObjectStaticField: 1669 // Fast-path which gets the field from thread-local cache. 1670 FETCH_FROM_THREAD_CACHE %rax, 2f 16711: 1672 movl ART_FIELD_OFFSET_OFFSET(%rax), %edx 1673 movl ART_FIELD_DECLARING_CLASS_OFFSET(%rax), %eax 1674 cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1675 jne 3f 16765: 1677 GET_VREG %ecx, rINSTq 1678 movl %ecx, (%eax, %edx, 1) 1679 testl %ecx, %ecx 1680 je 4f 1681 movq rSELF:THREAD_CARD_TABLE_OFFSET, %rcx 1682 shrq $$CARD_TABLE_CARD_SHIFT, %rax 1683 movb %cl, (%rax, %rcx, 1) 16844: 1685 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 16862: 1687 movq rSELF:THREAD_SELF_OFFSET, %rdi 1688 movq 0(%rsp), %rsi 1689 movq rPC, %rdx 1690 EXPORT_PC 1691 call nterp_get_static_field 1692 testq MACRO_LITERAL(1), %rax 1693 je 1b 1694 CLEAR_VOLATILE_MARKER %rax 1695 movl ART_FIELD_OFFSET_OFFSET(%rax), %edx 1696 movl ART_FIELD_DECLARING_CLASS_OFFSET(%rax), %eax 1697 cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1698 jne 7f 16996: 1700 movzbl rINSTbl, %ecx 1701 GET_VREG %ecx, %rcx 1702 movl %ecx, (%eax, %edx, 1) 1703 testl %ecx, %ecx 1704 je 8f 1705 movq rSELF:THREAD_CARD_TABLE_OFFSET, %rcx 1706 shrq $$CARD_TABLE_CARD_SHIFT, %rax 1707 movb %cl, (%rax, %rcx, 1) 17088: 1709 lock addl $$0, (%rsp) 1710 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 17113: 1712 call art_quick_read_barrier_mark_reg00 1713 jmp 5b 17147: 1715 call art_quick_read_barrier_mark_reg00 1716 jmp 6b 1717 1718NterpGetObjectStaticField: 1719 // Fast-path which gets the field from thread-local cache. 1720 FETCH_FROM_THREAD_CACHE %rax, 2f 17211: 1722 movl ART_FIELD_OFFSET_OFFSET(%rax), %edx 1723 movl ART_FIELD_DECLARING_CLASS_OFFSET(%rax), %eax 1724 cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1725 jne 5f 17266: 1727 testb $$READ_BARRIER_TEST_VALUE, GRAY_BYTE_OFFSET(%eax) 1728 movl (%eax, %edx, 1), %eax 1729 jnz 3f 17304: 1731 SET_VREG_OBJECT %eax, rINSTq # fp[A] <- value 1732 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 17332: 1734 movq rSELF:THREAD_SELF_OFFSET, %rdi 1735 movq 0(%rsp), %rsi 1736 movq rPC, %rdx 1737 EXPORT_PC 1738 call nterp_get_static_field 1739 andq $$-2, %rax 1740 jmp 1b 17413: 1742 call art_quick_read_barrier_mark_reg00 1743 jmp 4b 17445: 1745 call art_quick_read_barrier_mark_reg00 1746 jmp 6b 1747 1748NterpGetBooleanStaticField: 1749 OP_SGET load="movsbl", wide=0 1750 1751NterpGetByteStaticField: 1752 OP_SGET load="movsbl", wide=0 1753 1754NterpGetCharStaticField: 1755 OP_SGET load="movzwl", wide=0 1756 1757NterpGetShortStaticField: 1758 OP_SGET load="movswl", wide=0 1759 1760NterpGetWideStaticField: 1761 OP_SGET load="movq", wide=1 1762 1763NterpGetIntStaticField: 1764 OP_SGET load="movl", wide=0 1765 1766NterpPutStaticField: 1767 OP_SPUT rINST_reg=rINST, store="movl", wide=0 1768 1769NterpPutBooleanStaticField: 1770NterpPutByteStaticField: 1771 OP_SPUT rINST_reg=rINSTbl, store="movb", wide=0 1772 1773NterpPutCharStaticField: 1774NterpPutShortStaticField: 1775 OP_SPUT rINST_reg=rINSTw, store="movw", wide=0 1776 1777NterpPutWideStaticField: 1778 OP_SPUT rINST_reg=rINSTq, store="movq", wide=1 1779 1780NterpPutInstanceField: 1781 OP_IPUT rINST_reg=rINST, store="movl", wide=0 1782 1783NterpPutBooleanInstanceField: 1784NterpPutByteInstanceField: 1785 OP_IPUT rINST_reg=rINSTbl, store="movb", wide=0 1786 1787NterpPutCharInstanceField: 1788NterpPutShortInstanceField: 1789 OP_IPUT rINST_reg=rINSTw, store="movw", wide=0 1790 1791NterpPutWideInstanceField: 1792 OP_IPUT rINST_reg=rINSTq, store="movq", wide=1 1793 1794NterpGetBooleanInstanceField: 1795 OP_IGET load="movzbl", wide=0 1796 1797NterpGetByteInstanceField: 1798 OP_IGET load="movsbl", wide=0 1799 1800NterpGetCharInstanceField: 1801 OP_IGET load="movzwl", wide=0 1802 1803NterpGetShortInstanceField: 1804 OP_IGET load="movswl", wide=0 1805 1806NterpGetWideInstanceField: 1807 OP_IGET load="movq", wide=1 1808 1809NterpGetInstanceField: 1810 OP_IGET load="movl", wide=0 1811 1812NterpInstanceOf: 1813 /* instance-of vA, vB, class@CCCC */ 1814 // Fast-path which gets the class from thread-local cache. 1815 EXPORT_PC 1816 FETCH_FROM_THREAD_CACHE %rsi, 2f 1817 cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1818 jne 5f 18191: 1820 movzbl rINSTbl,%edi 1821 sarl $$4,%edi # edi<- B 1822 GET_VREG %edi %rdi # edi<- vB (object) 1823 andb $$0xf,rINSTbl # rINST<- A 1824 testl %edi, %edi 1825 je 3f 1826 call art_quick_instance_of 1827 SET_VREG %eax, rINSTq # fp[A] <- value 18284: 1829 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 18303: 1831 SET_VREG %edi, rINSTq # fp[A] <-0 1832 jmp 4b 18332: 1834 movq rSELF:THREAD_SELF_OFFSET, %rdi 1835 movq 0(%rsp), %rsi 1836 movq rPC, %rdx 1837 call nterp_get_class_or_allocate_object 1838 movq %rax, %rsi 1839 jmp 1b 18405: 1841 // 06 is %rsi 1842 call art_quick_read_barrier_mark_reg06 1843 jmp 1b 1844 1845NterpCheckCast: 1846 // Fast-path which gets the class from thread-local cache. 1847 EXPORT_PC 1848 FETCH_FROM_THREAD_CACHE %rsi, 3f 1849 cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1850 jne 4f 18511: 1852 GET_VREG %edi, rINSTq 1853 testl %edi, %edi 1854 je 2f 1855 call art_quick_check_instance_of 18562: 1857 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 18583: 1859 movq rSELF:THREAD_SELF_OFFSET, %rdi 1860 movq 0(%rsp), %rsi 1861 movq rPC, %rdx 1862 call nterp_get_class_or_allocate_object 1863 movq %rax, %rsi 1864 jmp 1b 18654: 1866 // 06 is %rsi 1867 call art_quick_read_barrier_mark_reg06 1868 jmp 1b 1869 1870NterpHandleHotnessOverflow: 1871 leaq (rPC, rINSTq, 2), %rsi 1872 movq rFP, %rdx 1873 call nterp_hot_method 1874 testq %rax, %rax 1875 jne 1f 1876 leaq (rPC, rINSTq, 2), rPC 1877 FETCH_INST 1878 GOTO_NEXT 18791: 1880 // Drop the current frame. 1881 movq -8(rREFS), %rsp 1882 CFI_DEF_CFA(rsp, CALLEE_SAVES_SIZE) 1883 1884 // Setup the new frame 1885 movq OSR_DATA_FRAME_SIZE(%rax), %rcx 1886 // Given stack size contains all callee saved registers, remove them. 1887 subq $$CALLEE_SAVES_SIZE, %rcx 1888 1889 // Remember CFA. 1890 movq %rsp, %rbp 1891 CFI_DEF_CFA_REGISTER(rbp) 1892 1893 subq %rcx, %rsp 1894 movq %rsp, %rdi // rdi := beginning of stack 1895 leaq OSR_DATA_MEMORY(%rax), %rsi // rsi := memory to copy 1896 rep movsb // while (rcx--) { *rdi++ = *rsi++ } 1897 1898 // Fetch the native PC to jump to and save it in a callee-save register. 1899 movq OSR_DATA_NATIVE_PC(%rax), %rbx 1900 1901 // Free the memory holding OSR Data. 1902 movq %rax, %rdi 1903 call free 1904 1905 // Jump to the compiled code. 1906 jmp *%rbx 1907 1908NterpHandleInvokeInterfaceOnObjectMethodRange: 1909 // First argument is the 'this' pointer. 1910 movzwl 4(rPC), %r11d // arguments 1911 movl (rFP, %r11, 4), %esi 1912 // Note: if esi is null, this will be handled by our SIGSEGV handler. 1913 movl MIRROR_OBJECT_CLASS_OFFSET(%esi), %edx 1914 movq MIRROR_CLASS_VTABLE_OFFSET_64(%edx, %eax, 8), %rdi 1915 jmp NterpCommonInvokeInstanceRange 1916 1917NterpHandleInvokeInterfaceOnObjectMethod: 1918 // First argument is the 'this' pointer. 1919 movzwl 4(rPC), %r11d // arguments 1920 andq MACRO_LITERAL(0xf), %r11 1921 movl (rFP, %r11, 4), %esi 1922 // Note: if esi is null, this will be handled by our SIGSEGV handler. 1923 movl MIRROR_OBJECT_CLASS_OFFSET(%esi), %edx 1924 movq MIRROR_CLASS_VTABLE_OFFSET_64(%edx, %eax, 8), %rdi 1925 jmp NterpCommonInvokeInstance 1926 1927// This is the logical end of ExecuteNterpImpl, where the frame info applies. 1928// EndExecuteNterpImpl includes the methods below as we want the runtime to 1929// see them as part of the Nterp PCs. 1930.cfi_endproc 1931 1932nterp_to_nterp_static_non_range: 1933 .cfi_startproc 1934 .cfi_def_cfa rsp, 8 1935 SETUP_STACK_FOR_INVOKE 1936 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0 1937 .cfi_endproc 1938 1939nterp_to_nterp_string_init_non_range: 1940 .cfi_startproc 1941 .cfi_def_cfa rsp, 8 1942 SETUP_STACK_FOR_INVOKE 1943 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1 1944 .cfi_endproc 1945 1946nterp_to_nterp_instance_non_range: 1947 .cfi_startproc 1948 .cfi_def_cfa rsp, 8 1949 SETUP_STACK_FOR_INVOKE 1950 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 1951 .cfi_endproc 1952 1953nterp_to_nterp_static_range: 1954 .cfi_startproc 1955 .cfi_def_cfa rsp, 8 1956 SETUP_STACK_FOR_INVOKE 1957 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=1 1958 .cfi_endproc 1959 1960nterp_to_nterp_instance_range: 1961 .cfi_startproc 1962 .cfi_def_cfa rsp, 8 1963 SETUP_STACK_FOR_INVOKE 1964 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0 1965 .cfi_endproc 1966 1967nterp_to_nterp_string_init_range: 1968 .cfi_startproc 1969 .cfi_def_cfa rsp, 8 1970 SETUP_STACK_FOR_INVOKE 1971 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1 1972 .cfi_endproc 1973 1974// This is the end of PCs contained by the OatQuickMethodHeader created for the interpreter 1975// entry point. 1976 FUNCTION_TYPE(EndExecuteNterpImpl) 1977 ASM_HIDDEN SYMBOL(EndExecuteNterpImpl) 1978 .global SYMBOL(EndExecuteNterpImpl) 1979SYMBOL(EndExecuteNterpImpl): 1980 1981// Entrypoints into runtime. 1982NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField 1983NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset 1984NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray 1985NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange 1986NTERP_TRAMPOLINE nterp_get_class_or_allocate_object, NterpGetClassOrAllocateObject 1987NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod 1988NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod 1989NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject 1990 1991// gen_mterp.py will inline the following definitions 1992// within [ExecuteNterpImpl, EndExecuteNterpImpl). 1993%def instruction_end(): 1994 1995 FUNCTION_TYPE(artNterpAsmInstructionEnd) 1996 ASM_HIDDEN SYMBOL(artNterpAsmInstructionEnd) 1997 .global SYMBOL(artNterpAsmInstructionEnd) 1998SYMBOL(artNterpAsmInstructionEnd): 1999 // artNterpAsmInstructionEnd is used as landing pad for exception handling. 2000 FETCH_INST 2001 GOTO_NEXT 2002 2003%def instruction_start(): 2004 2005 FUNCTION_TYPE(artNterpAsmInstructionStart) 2006 ASM_HIDDEN SYMBOL(artNterpAsmInstructionStart) 2007 .global SYMBOL(artNterpAsmInstructionStart) 2008SYMBOL(artNterpAsmInstructionStart) = .L_op_nop 2009 .text 2010 2011%def opcode_start(): 2012 ENTRY nterp_${opcode} 2013%def opcode_end(): 2014 END nterp_${opcode} 2015%def helper_start(name): 2016 ENTRY ${name} 2017%def helper_end(name): 2018 END ${name} 2019