1%def header(): 2/* 3 * Copyright (C) 2021 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/asm_support_x86.S" 24 25/** 26 * x86 ABI general notes: 27 * 28 * Caller save set: 29 * eax, ebx, edx, ecx, st(0)-st(7) 30 * Callee save set: 31 * esi, edi, ebp 32 * Return regs: 33 * 32-bit in eax 34 * 64-bit in edx:eax (low-order 32 in eax) 35 * fp on top of fp stack st(0) 36 * 37 * Stack must be 16-byte aligned to support SSE in native code. 38 */ 39 40#define ARG3 %ebx 41#define ARG2 %edx 42#define ARG1 %ecx 43#define ARG0 %eax 44 45/* 46 * single-purpose registers, given names for clarity 47 */ 48#define rSELF %fs 49#define rPC %esi 50#define CFI_DEX 6 // DWARF register number of the register holding dex-pc (esi). 51#define CFI_TMP 0 // DWARF register number of the first argument register (eax). 52#define rFP %edi 53#define rINST %ebx 54#define rINSTw %bx 55#define rINSTbh %bh 56#define rINSTbl %bl 57#define rIBASE %edx 58#define rREFS %ebp 59#define CFI_REFS 5 // DWARF register number of the reference array (ebp). 60 61// Temporary registers while setting up a frame. 62#define rNEW_FP %ecx 63#define rNEW_REFS %eax 64#define CFI_NEW_REFS 0 65 66#define LOCAL0 4 67#define LOCAL1 8 68#define LOCAL2 12 69 70/* 71 * Get/set the 32-bit value from a Dalvik register. 72 */ 73#define VREG_ADDRESS(_vreg) (rFP,_vreg,4) 74#define VREG_HIGH_ADDRESS(_vreg) 4(rFP,_vreg,4) 75#define VREG_REF_ADDRESS(_vreg) (rREFS,_vreg,4) 76#define VREG_REF_HIGH_ADDRESS(_vreg) 4(rREFS,_vreg,4) 77 78.macro GET_VREG _reg _vreg 79 movl VREG_ADDRESS(\_vreg), \_reg 80.endm 81 82.macro GET_VREG_OBJECT _reg _vreg 83 movl VREG_REF_ADDRESS(\_vreg), \_reg 84.endm 85 86/* Read wide value to xmm. */ 87.macro GET_WIDE_FP_VREG _reg _vreg 88 movq VREG_ADDRESS(\_vreg), \_reg 89.endm 90 91.macro SET_VREG _reg _vreg 92 movl \_reg, VREG_ADDRESS(\_vreg) 93 movl MACRO_LITERAL(0), VREG_REF_ADDRESS(\_vreg) 94.endm 95 96/* Write wide value from xmm. xmm is clobbered. */ 97.macro SET_WIDE_FP_VREG _reg _vreg 98 movq \_reg, VREG_ADDRESS(\_vreg) 99 pxor \_reg, \_reg 100 movq \_reg, VREG_REF_ADDRESS(\_vreg) 101.endm 102 103.macro SET_VREG_OBJECT _reg _vreg 104 movl \_reg, VREG_ADDRESS(\_vreg) 105 movl \_reg, VREG_REF_ADDRESS(\_vreg) 106.endm 107 108.macro GET_VREG_HIGH _reg _vreg 109 movl VREG_HIGH_ADDRESS(\_vreg), \_reg 110.endm 111 112.macro SET_VREG_HIGH _reg _vreg 113 movl \_reg, VREG_HIGH_ADDRESS(\_vreg) 114 movl MACRO_LITERAL(0), VREG_REF_HIGH_ADDRESS(\_vreg) 115.endm 116 117.macro CLEAR_REF _vreg 118 movl MACRO_LITERAL(0), VREG_REF_ADDRESS(\_vreg) 119.endm 120 121.macro CLEAR_WIDE_REF _vreg 122 movl MACRO_LITERAL(0), VREG_REF_ADDRESS(\_vreg) 123 movl MACRO_LITERAL(0), VREG_REF_HIGH_ADDRESS(\_vreg) 124.endm 125 126.macro GET_VREG_XMMs _xmmreg _vreg 127 movss VREG_ADDRESS(\_vreg), \_xmmreg 128.endm 129.macro GET_VREG_XMMd _xmmreg _vreg 130 movsd VREG_ADDRESS(\_vreg), \_xmmreg 131.endm 132.macro SET_VREG_XMMs _xmmreg _vreg 133 movss \_xmmreg, VREG_ADDRESS(\_vreg) 134.endm 135.macro SET_VREG_XMMd _xmmreg _vreg 136 movsd \_xmmreg, VREG_ADDRESS(\_vreg) 137.endm 138 139// Includes the return address implicitly pushed on stack by 'call'. 140#define CALLEE_SAVES_SIZE (3 * 4 + 1 * 4) 141 142#define PARAMETERS_SAVES_SIZE (4 * 4) 143 144// +4 for the ArtMethod of the caller. 145#define OFFSET_TO_FIRST_ARGUMENT_IN_STACK (CALLEE_SAVES_SIZE + PARAMETERS_SAVES_SIZE + 4) 146 147/* 148 * Refresh rINST. 149 * At enter to handler rINST does not contain the opcode number. 150 * However some utilities require the full value, so this macro 151 * restores the opcode number. 152 */ 153.macro REFRESH_INST _opnum 154 movb rINSTbl, rINSTbh 155 movb $$\_opnum, rINSTbl 156.endm 157 158/* 159 * Fetch the next instruction from rPC into rINSTw. Does not advance rPC. 160 */ 161.macro FETCH_INST 162 movzwl (rPC), rINST 163.endm 164 165.macro FETCH_INST_CLEAR_OPCODE 166 movzbl 1(rPC), rINST 167.endm 168 169/* 170 * Remove opcode from rINST, compute the address of handler and jump to it. 171 */ 172.macro GOTO_NEXT 173 movzx rINSTbl,%ecx 174 movzbl rINSTbh,rINST 175 shll MACRO_LITERAL(${handler_size_bits}), %ecx 176 addl rIBASE, %ecx 177 jmp *%ecx 178.endm 179 180/* 181 * Advance rPC by instruction count. 182 */ 183.macro ADVANCE_PC _count 184 leal 2*\_count(rPC), rPC 185.endm 186 187/* 188 * Advance rPC by instruction count, fetch instruction and jump to handler. 189 */ 190.macro ADVANCE_PC_FETCH_AND_GOTO_NEXT _count 191 ADVANCE_PC \_count 192 FETCH_INST 193 GOTO_NEXT 194.endm 195 196.macro NTERP_DEF_CFA cfi_reg 197 CFI_DEF_CFA_BREG_PLUS_UCONST \cfi_reg, -4, CALLEE_SAVES_SIZE + PARAMETERS_SAVES_SIZE 198.endm 199 200.macro RESTORE_IBASE 201 call 0f 2020: 203 popl rIBASE 204 addl MACRO_LITERAL(SYMBOL(artNterpAsmInstructionStart) - 0b), rIBASE 205.endm 206 207.macro SPILL_ALL_CORE_PARAMETERS 208 PUSH_ARG eax 209 PUSH_ARG ecx 210 PUSH_ARG edx 211 PUSH_ARG ebx 212.endm 213 214.macro RESTORE_ALL_CORE_PARAMETERS 215 POP_ARG ebx 216 POP_ARG edx 217 POP_ARG ecx 218 POP_ARG eax 219.endm 220 221.macro DROP_PARAMETERS_SAVES 222 addl $$(PARAMETERS_SAVES_SIZE), %esp 223.endm 224 225.macro SAVE_WIDE_RETURN 226 movl %edx, LOCAL2(%esp) 227.endm 228 229.macro LOAD_WIDE_RETURN reg 230 movl LOCAL2(%esp), \reg 231.endm 232 233// An assembly entry that has a OatQuickMethodHeader prefix. 234.macro OAT_ENTRY name, end 235 FUNCTION_TYPE(\name) 236 ASM_HIDDEN SYMBOL(\name) 237 .global SYMBOL(\name) 238 .balign 16 239 // Padding of 3 * 4 bytes to get 16 bytes alignment of code entry. 240 .long 0 241 .long 0 242 .long 0 243 // OatQuickMethodHeader. Note that the top two bits must be clear. 244 .long (SYMBOL(\end) - SYMBOL(\name)) 245SYMBOL(\name): 246.endm 247 248.macro ENTRY name 249 .text 250 ASM_HIDDEN SYMBOL(\name) 251 .global SYMBOL(\name) 252 FUNCTION_TYPE(\name) 253SYMBOL(\name): 254.endm 255 256.macro END name 257 SIZE(\name) 258.endm 259 260// Macro for defining entrypoints into runtime. We don't need to save registers 261// (we're not holding references there), but there is no 262// kDontSave runtime method. So just use the kSaveRefsOnly runtime method. 263.macro NTERP_TRAMPOLINE name, helper 264DEFINE_FUNCTION \name 265 movd %ebx, %xmm0 266 SETUP_SAVE_REFS_ONLY_FRAME ebx 267 movd %xmm0, %ebx 268 PUSH_ARG ebx 269 PUSH_ARG edx 270 PUSH_ARG ecx 271 PUSH_ARG eax 272 call \helper 273 addl MACRO_LITERAL(16), %esp 274 CFI_ADJUST_CFA_OFFSET(-16) 275 RESTORE_IBASE 276 FETCH_INST_CLEAR_OPCODE 277 RESTORE_SAVE_REFS_ONLY_FRAME 278 cmpl LITERAL(0), %fs:THREAD_EXCEPTION_OFFSET 279 jne nterp_deliver_pending_exception 280 ret 281END_FUNCTION \name 282.endm 283 284.macro CLEAR_VOLATILE_MARKER reg 285 andl MACRO_LITERAL(-2), \reg 286.endm 287 288.macro EXPORT_PC 289 movl rPC, -8(rREFS) 290.endm 291 292.macro FETCH_PC 293 movl -8(rREFS), rPC 294.endm 295 296 297.macro BRANCH 298 leal (rPC, rINST, 2), rPC 299 // Update method counter and do a suspend check if the branch is negative or zero. 300 testl rINST, rINST 301 jle 3f 3022: 303 FETCH_INST 304 GOTO_NEXT 3053: 306 movl (%esp), %eax 307 movzwl ART_METHOD_HOTNESS_COUNT_OFFSET(%eax), %ecx 308#if (NTERP_HOTNESS_VALUE != 0) 309#error Expected 0 for hotness value 310#endif 311 // If the counter is at zero, handle this in the runtime. 312 testw %cx, %cx 313 je NterpHandleHotnessOverflow 314 // Update counter. 315 addl $$-1, %ecx 316 movw %cx, ART_METHOD_HOTNESS_COUNT_OFFSET(%eax) 317 DO_SUSPEND_CHECK continue_label=2b 318.endm 319 320// Expects: 321// - edx, and eax to be available. 322// Outputs: 323// - \registers contains the dex registers size 324// - \outs contains the outs size 325// - if load_ins is 1, \ins contains the ins 326// - \code_item is replaced with a pointer to the instructions 327.macro FETCH_CODE_ITEM_INFO code_item, registers, outs, ins, load_ins 328 testl MACRO_LITERAL(1), \code_item 329 je 5f 330 andl $$-2, \code_item // Remove the extra bit that marks it's a compact dex file. 331 movzwl COMPACT_CODE_ITEM_FIELDS_OFFSET(\code_item), %edx 332 movl %edx, \registers 333 sarl $$COMPACT_CODE_ITEM_REGISTERS_SIZE_SHIFT, \registers 334 andl $$0xf, \registers 335 movl %edx, \outs 336 sarl $$COMPACT_CODE_ITEM_OUTS_SIZE_SHIFT, \outs 337 andl $$0xf, \outs 338 .if \load_ins 339 movl %edx, \ins 340 sarl $$COMPACT_CODE_ITEM_INS_SIZE_SHIFT, \ins 341 andl $$0xf, \ins 342 .else 343 movl %edx, %eax 344 sarl $$COMPACT_CODE_ITEM_INS_SIZE_SHIFT, %eax 345 andl $$0xf, %eax 346 addl %eax, \registers 347 .endif 348 testw $$COMPACT_CODE_ITEM_REGISTERS_INS_OUTS_FLAGS, COMPACT_CODE_ITEM_FLAGS_OFFSET(\code_item) 349 je 4f 350 movl \code_item, %eax 351 testw $$COMPACT_CODE_ITEM_INSNS_FLAG, COMPACT_CODE_ITEM_FLAGS_OFFSET(\code_item) 352 je 1f 353 subl $$4, %eax 3541: 355 testw $$COMPACT_CODE_ITEM_REGISTERS_FLAG, COMPACT_CODE_ITEM_FLAGS_OFFSET(\code_item) 356 je 2f 357 subl $$2, %eax 358 movzwl (%eax), %edx 359 addl %edx, \registers 3602: 361 testw $$COMPACT_CODE_ITEM_INS_FLAG, COMPACT_CODE_ITEM_FLAGS_OFFSET(\code_item) 362 je 3f 363 subl $$2, %eax 364 movzwl (%eax), %edx 365 .if \load_ins 366 addl %edx, \ins 367 .else 368 addl %edx, \registers 369 .endif 3703: 371 testw $$COMPACT_CODE_ITEM_OUTS_FLAG, COMPACT_CODE_ITEM_FLAGS_OFFSET(\code_item) 372 je 4f 373 subl $$2, %eax 374 movzwl (%eax), %edx 375 addl %edx, \outs 3764: 377 .if \load_ins 378 addl \ins, \registers 379 .endif 380 addl $$COMPACT_CODE_ITEM_INSNS_OFFSET, \code_item 381 jmp 6f 3825: 383 // Fetch dex register size. 384 movzwl CODE_ITEM_REGISTERS_SIZE_OFFSET(\code_item), \registers 385 // Fetch outs size. 386 movzwl CODE_ITEM_OUTS_SIZE_OFFSET(\code_item), \outs 387 .if \load_ins 388 movzwl CODE_ITEM_INS_SIZE_OFFSET(\code_item), \ins 389 .endif 390 addl $$CODE_ITEM_INSNS_OFFSET, \code_item 3916: 392.endm 393 394// Setup the stack to start executing the method. Expects: 395// - eax, edx, and ebx to be available. 396// 397// Inputs 398// - code_item: where the code item is 399// - refs: register where the pointer to dex references will be 400// - fp: register where the pointer to dex values will be 401// - cfi_refs: CFI register number of refs 402// - load_ins: whether to store the 'ins' value of the code item in esi 403// 404// Outputs 405// - ebx contains the dex registers size 406// - edx contains the old stack pointer. 407// - \code_item is replace with a pointer to the instructions 408// - if load_ins is 1, esi contains the ins 409.macro SETUP_STACK_FRAME code_item, refs, fp, cfi_refs, load_ins 410 FETCH_CODE_ITEM_INFO \code_item, %ebx, \refs, %esi, \load_ins 411 412 movl $$3, %eax 413 cmpl $$2, \refs 414 cmovle %eax, \refs 415 416 // Compute required frame size for dex registers: ((2 * ebx) + refs) 417 leal (\refs, %ebx, 2), %edx 418 sall $$2, %edx 419 420 // Compute new stack pointer in fp: add 12 for saving the previous frame, 421 // pc, and method being executed. 422 leal -12(%esp), \fp 423 subl %edx, \fp 424 // Alignment 425 andl $$-16, \fp 426 427 // Now setup the stack pointer. 428 movl %esp, %edx 429 CFI_DEF_CFA_REGISTER(edx) 430 movl \fp, %esp 431 432 leal 12(%esp, \refs, 4), \refs 433 leal (\refs, %ebx, 4), \fp 434 435 // Save old stack pointer. 436 movl %edx, -4(\refs) 437 NTERP_DEF_CFA \cfi_refs 438 439 // Save ArtMethod. 440 movl 12(%edx), %eax 441 movl %eax, (%esp) 442 443 // Put nulls in reference frame. 444 testl %ebx, %ebx 445 je 2f 446 movl \refs, %eax 4471: 448 movl $$0, (%eax) 449 addl $$4, %eax 450 cmpl %eax, \fp 451 jne 1b 4522: 453.endm 454 455// Puts the next floating point argument into the expected register, 456// fetching values based on a non-range invoke. 457// Uses eax as temporary. 458// 459// TODO: We could simplify a lot of code by loading the G argument into 460// the "inst" register. Given that we enter the handler with "1(rPC)" in 461// the rINST, we can just add rINST<<16 to the args and we don't even 462// need to pass "arg_index" around. 463.macro LOOP_OVER_SHORTY_LOADING_XMMS xmm_reg, inst, shorty, arg_index, finished 4641: // LOOP 465 movb (REG_VAR(shorty)), %al // al := *shorty 466 addl MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 467 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 468 je VAR(finished) 469 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto FOUND_DOUBLE 470 je 2f 471 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto FOUND_FLOAT 472 je 3f 473 shrl MACRO_LITERAL(4), REG_VAR(inst) 474 addl MACRO_LITERAL(1), REG_VAR(arg_index) 475 // Handle extra argument in arg array taken by a long. 476 cmpb MACRO_LITERAL(74), %al // if (al != 'J') goto LOOP 477 jne 1b 478 shrl MACRO_LITERAL(4), REG_VAR(inst) 479 addl MACRO_LITERAL(1), REG_VAR(arg_index) 480 jmp 1b // goto LOOP 4812: // FOUND_DOUBLE 482 subl MACRO_LITERAL(8), %esp 483 movl REG_VAR(inst), %eax 484 andl MACRO_LITERAL(0xf), %eax 485 GET_VREG %eax, %eax 486 movl %eax, (%esp) 487 shrl MACRO_LITERAL(4), REG_VAR(inst) 488 addl MACRO_LITERAL(1), REG_VAR(arg_index) 489 cmpl MACRO_LITERAL(4), REG_VAR(arg_index) 490 je 5f 491 movl REG_VAR(inst), %eax 492 andl MACRO_LITERAL(0xf), %eax 493 shrl MACRO_LITERAL(4), REG_VAR(inst) 494 addl MACRO_LITERAL(1), REG_VAR(arg_index) 495 jmp 6f 4965: 497 movzbl 1(rPC), %eax 498 andl MACRO_LITERAL(0xf), %eax 4996: 500 GET_VREG %eax, %eax 501 movl %eax, 4(%esp) 502 movq (%esp), REG_VAR(xmm_reg) 503 addl MACRO_LITERAL(8), %esp 504 jmp 4f 5053: // FOUND_FLOAT 506 cmpl MACRO_LITERAL(4), REG_VAR(arg_index) 507 je 7f 508 movl REG_VAR(inst), %eax 509 andl MACRO_LITERAL(0xf), %eax 510 shrl MACRO_LITERAL(4), REG_VAR(inst) 511 addl MACRO_LITERAL(1), REG_VAR(arg_index) 512 jmp 8f 5137: 514 movzbl 1(rPC), %eax 515 andl MACRO_LITERAL(0xf), %eax 5168: 517 GET_VREG_XMMs REG_VAR(xmm_reg), %eax 5184: 519.endm 520 521// Puts the next int/long/object argument in the expected register, 522// fetching values based on a non-range invoke. 523// Uses eax as temporary. 524.macro LOOP_OVER_SHORTY_LOADING_GPRS gpr_reg, gpr_long_reg, inst, shorty, arg_index, finished, if_long, is_ebx 5251: // LOOP 526 movb (REG_VAR(shorty)), %al // al := *shorty 527 addl MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 528 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 529 je VAR(finished) 530 cmpb MACRO_LITERAL(74), %al // if (al == 'J') goto FOUND_LONG 531 je 2f 532 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto SKIP_FLOAT 533 je 3f 534 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto SKIP_DOUBLE 535 je 4f 536 cmpl MACRO_LITERAL(4), REG_VAR(arg_index) 537 je 7f 538 movl REG_VAR(inst), %eax 539 andl MACRO_LITERAL(0xf), %eax 540 shrl MACRO_LITERAL(4), REG_VAR(inst) 541 addl MACRO_LITERAL(1), REG_VAR(arg_index) 542 jmp 8f 5437: 544 // Fetch PC 545 movl LOCAL1(%esp), %eax 546 movl -8(%eax), %eax 547 movzbl 1(%eax), %eax 548 andl MACRO_LITERAL(0xf), %eax 5498: 550 GET_VREG REG_VAR(gpr_reg), %eax 551 jmp 5f 5522: // FOUND_LONG 553 .if \is_ebx 554 // Put back shorty and exit 555 subl MACRO_LITERAL(1), REG_VAR(shorty) 556 jmp 5f 557 .else 558 movl REG_VAR(inst), %eax 559 andl MACRO_LITERAL(0xf), %eax 560 GET_VREG REG_VAR(gpr_reg), %eax 561 shrl MACRO_LITERAL(4), REG_VAR(inst) 562 addl MACRO_LITERAL(1), REG_VAR(arg_index) 563 cmpl MACRO_LITERAL(4), REG_VAR(arg_index) 564 je 9f 565 movl REG_VAR(inst), %eax 566 andl MACRO_LITERAL(0xf), %eax 567 shrl MACRO_LITERAL(4), REG_VAR(inst) 568 addl MACRO_LITERAL(1), REG_VAR(arg_index) 569 jmp 10f 5709: 571 // Fetch PC 572 movl LOCAL1(%esp), %eax 573 movl -8(%eax), %eax 574 movzbl 1(%eax), %eax 575 andl MACRO_LITERAL(0xf), %eax 57610: 577 GET_VREG REG_VAR(gpr_long_reg), %eax 578 jmp \if_long 579 .endif 5803: // SKIP_FLOAT 581 shrl MACRO_LITERAL(4), REG_VAR(inst) 582 addl MACRO_LITERAL(1), REG_VAR(arg_index) 583 jmp 1b 5844: // SKIP_DOUBLE 585 shrl MACRO_LITERAL(8), REG_VAR(inst) 586 addl MACRO_LITERAL(2), REG_VAR(arg_index) 587 jmp 1b 5885: 589.endm 590 591// Puts the next int/long/object argument in the expected stack slot, 592// fetching values based on a non-range invoke. 593// Uses eax as temporary. 594.macro LOOP_OVER_SHORTY_LOADING_INTS stack_offset, shorty, inst, arg_index, finished, is_string_init 5951: // LOOP 596 movb (REG_VAR(shorty)), %al // al := *shorty 597 addl MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 598 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 599 je VAR(finished) 600 cmpb MACRO_LITERAL(74), %al // if (al == 'J') goto FOUND_LONG 601 je 2f 602 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto SKIP_FLOAT 603 je 3f 604 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto SKIP_DOUBLE 605 je 4f 606 .if \is_string_init 607 cmpl MACRO_LITERAL(3), REG_VAR(arg_index) 608 .else 609 cmpl MACRO_LITERAL(4), REG_VAR(arg_index) 610 .endif 611 je 7f 612 movl REG_VAR(inst), %eax 613 andl MACRO_LITERAL(0xf), %eax 614 shrl MACRO_LITERAL(4), REG_VAR(inst) 615 jmp 8f 6167: 617 // Fetch PC. 618 movl (LOCAL1 + \stack_offset)(%esp), %eax 619 movl -8(%eax), %eax 620 movzbl 1(%eax), %eax 621 andl MACRO_LITERAL(0xf), %eax 6228: 623 GET_VREG %eax, %eax 624 // Add 4 for the ArtMethod. 625 movl %eax, (4 + \stack_offset)(%esp, REG_VAR(arg_index), 4) 626 addl MACRO_LITERAL(1), REG_VAR(arg_index) 627 jmp 1b 6282: // FOUND_LONG 629 movl REG_VAR(inst), %eax 630 andl MACRO_LITERAL(0xf), %eax 631 GET_VREG %eax, %eax 632 // Add 4 for the ArtMethod. 633 movl %eax, (4 + \stack_offset)(%esp, REG_VAR(arg_index), 4) 634 shrl MACRO_LITERAL(4), REG_VAR(inst) 635 addl MACRO_LITERAL(1), REG_VAR(arg_index) 636 .if \is_string_init 637 cmpl MACRO_LITERAL(3), REG_VAR(arg_index) 638 .else 639 cmpl MACRO_LITERAL(4), REG_VAR(arg_index) 640 .endif 641 je 9f 642 movl REG_VAR(inst), %eax 643 andl MACRO_LITERAL(0xf), %eax 644 shrl MACRO_LITERAL(4), REG_VAR(inst) 645 jmp 10f 6469: 647 // Fetch PC. 648 movl (LOCAL1 + \stack_offset)(%esp), %eax 649 movl -8(%eax), %eax 650 movzbl 1(%eax), %eax 651 andl MACRO_LITERAL(0xf), %eax 65210: 653 GET_VREG %eax, %eax 654 // +4 for the ArtMethod. 655 movl %eax, (4 + \stack_offset)(%esp, REG_VAR(arg_index), 4) 656 addl MACRO_LITERAL(1), REG_VAR(arg_index) 657 jmp 1b 6583: // SKIP_FLOAT 659 shrl MACRO_LITERAL(4), REG_VAR(inst) 660 addl MACRO_LITERAL(1), REG_VAR(arg_index) 661 jmp 1b 6624: // SKIP_DOUBLE 663 shrl MACRO_LITERAL(8), REG_VAR(inst) 664 addl MACRO_LITERAL(2), REG_VAR(arg_index) 665 jmp 1b 666.endm 667 668// Puts the next floating point argument into the expected register, 669// fetching values based on a range invoke. 670// Uses eax as temporary. 671.macro LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm_reg, shorty, arg_index, stack_index, finished 6721: // LOOP 673 movb (REG_VAR(shorty)), %al // al := *shorty 674 addl MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 675 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 676 je VAR(finished) 677 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto FOUND_DOUBLE 678 je 2f 679 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto FOUND_FLOAT 680 je 3f 681 addl MACRO_LITERAL(1), REG_VAR(arg_index) 682 addl MACRO_LITERAL(1), REG_VAR(stack_index) 683 // Handle extra argument in arg array taken by a long. 684 cmpb MACRO_LITERAL(74), %al // if (al != 'J') goto LOOP 685 jne 1b 686 addl MACRO_LITERAL(1), REG_VAR(arg_index) 687 addl MACRO_LITERAL(1), REG_VAR(stack_index) 688 jmp 1b // goto LOOP 6892: // FOUND_DOUBLE 690 GET_VREG_XMMd REG_VAR(xmm_reg), REG_VAR(arg_index) 691 addl MACRO_LITERAL(2), REG_VAR(arg_index) 692 addl MACRO_LITERAL(2), REG_VAR(stack_index) 693 jmp 4f 6943: // FOUND_FLOAT 695 GET_VREG_XMMs REG_VAR(xmm_reg), REG_VAR(arg_index) 696 addl MACRO_LITERAL(1), REG_VAR(arg_index) 697 add MACRO_LITERAL(1), REG_VAR(stack_index) 6984: 699.endm 700 701// Puts the next floating point argument into the expected stack slot, 702// fetching values based on a range invoke. 703// Uses eax as temporary. 704// 705// TODO: We could just copy all the vregs to the stack slots in a simple loop 706// (or REP MOVSD) without looking at the shorty at all. (We could also drop 707// the "stack_index" from the macros for loading registers.) We could also do 708// that conditionally if argument word count > 3; otherwise we know that all 709// args fit into registers. 710.macro LOOP_RANGE_OVER_FPs shorty, arg_index, stack_index, finished 7111: // LOOP 712 movb (REG_VAR(shorty)), %al // bl := *shorty 713 addl MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 714 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 715 je VAR(finished) 716 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto FOUND_DOUBLE 717 je 2f 718 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto FOUND_FLOAT 719 je 3f 720 addl MACRO_LITERAL(1), REG_VAR(arg_index) 721 addl MACRO_LITERAL(1), REG_VAR(stack_index) 722 // Handle extra argument in arg array taken by a long. 723 cmpb MACRO_LITERAL(74), %al // if (al != 'J') goto LOOP 724 jne 1b 725 addl MACRO_LITERAL(1), REG_VAR(arg_index) 726 addl MACRO_LITERAL(1), REG_VAR(stack_index) 727 jmp 1b // goto LOOP 7282: // FOUND_DOUBLE 729 movq (rFP, REG_VAR(arg_index), 4), %xmm4 730 movq %xmm4, 4(%esp, REG_VAR(stack_index), 4) 731 addl MACRO_LITERAL(2), REG_VAR(arg_index) 732 addl MACRO_LITERAL(2), REG_VAR(stack_index) 733 jmp 1b 7343: // FOUND_FLOAT 735 movl (rFP, REG_VAR(arg_index), 4), %eax 736 movl %eax, 4(%esp, REG_VAR(stack_index), 4) 737 addl MACRO_LITERAL(1), REG_VAR(arg_index) 738 addl MACRO_LITERAL(1), REG_VAR(stack_index) 739 jmp 1b 740.endm 741 742// Puts the next int/long/object argument in the expected register, 743// fetching values based on a range invoke. 744// Uses eax as temporary. 745.macro LOOP_RANGE_OVER_SHORTY_LOADING_GPRS gpr_reg, gpr_long_reg, shorty, arg_index, stack_index, finished, if_long, is_ebx 7461: // LOOP 747 movb (REG_VAR(shorty)), %al // al := *shorty 748 addl MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 749 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 750 je VAR(finished) 751 cmpb MACRO_LITERAL(74), %al // if (al == 'J') goto FOUND_LONG 752 je 2f 753 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto SKIP_FLOAT 754 je 3f 755 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto SKIP_DOUBLE 756 je 4f 757 movl (rFP, REG_VAR(arg_index), 4), REG_VAR(gpr_reg) 758 addl MACRO_LITERAL(1), REG_VAR(arg_index) 759 addl MACRO_LITERAL(1), REG_VAR(stack_index) 760 jmp 5f 7612: // FOUND_LONG 762 .if \is_ebx 763 // Put back shorty and exit 764 subl MACRO_LITERAL(1), REG_VAR(shorty) 765 .else 766 movl (rFP, REG_VAR(arg_index), 4), REG_VAR(gpr_reg) 767 movl 4(rFP, REG_VAR(arg_index), 4), REG_VAR(gpr_long_reg) 768 addl MACRO_LITERAL(2), REG_VAR(arg_index) 769 addl MACRO_LITERAL(2), REG_VAR(stack_index) 770 .endif 771 jmp \if_long 7723: // SKIP_FLOAT 773 addl MACRO_LITERAL(1), REG_VAR(arg_index) 774 addl MACRO_LITERAL(1), REG_VAR(stack_index) 775 jmp 1b 7764: // SKIP_DOUBLE 777 addl MACRO_LITERAL(2), REG_VAR(arg_index) 778 addl MACRO_LITERAL(2), REG_VAR(stack_index) 779 jmp 1b 7805: 781.endm 782 783// Puts the next int/long/object argument in the expected stack slot, 784// fetching values based on a range invoke. 785// Uses eax as temporary. 786.macro LOOP_RANGE_OVER_INTs offset, shorty, arg_index, stack_index, finished 7871: // LOOP 788 movb (REG_VAR(shorty)), %al // al := *shorty 789 addl MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 790 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 791 je VAR(finished) 792 cmpb MACRO_LITERAL(74), %al // if (al == 'J') goto FOUND_LONG 793 je 2f 794 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto SKIP_FLOAT 795 je 3f 796 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto SKIP_DOUBLE 797 je 4f 798 movl (rFP, REG_VAR(arg_index), 4), %eax 799 // Add 4 for the ArtMethod. 800 movl %eax, (4 + \offset)(%esp, REG_VAR(stack_index), 4) 8013: // SKIP_FLOAT 802 addl MACRO_LITERAL(1), REG_VAR(arg_index) 803 addl MACRO_LITERAL(1), REG_VAR(stack_index) 804 jmp 1b 8052: // FOUND_LONG 806 movl (rFP, REG_VAR(arg_index), 4), %eax 807 // Add 4 for the ArtMethod. 808 movl %eax, (4 + \offset)(%esp, REG_VAR(stack_index), 4) 809 movl 4(rFP, REG_VAR(arg_index), 4), %eax 810 // Add 4 for the ArtMethod and 4 for other half. 811 movl %eax, (4 + 4 + \offset)(%esp, REG_VAR(stack_index), 4) 8124: // SKIP_DOUBLE 813 addl MACRO_LITERAL(2), REG_VAR(arg_index) 814 addl MACRO_LITERAL(2), REG_VAR(stack_index) 815 jmp 1b 816.endm 817 818// Puts the next floating point parameter passed in physical register 819// in the expected dex register array entry. 820// Uses eax as temporary. 821.macro LOOP_OVER_SHORTY_STORING_XMMS xmm_reg, shorty, arg_index, fp, finished 8221: // LOOP 823 movb (REG_VAR(shorty)), %al // al := *shorty 824 addl MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 825 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 826 je VAR(finished) 827 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto FOUND_DOUBLE 828 je 2f 829 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto FOUND_FLOAT 830 je 3f 831 addl MACRO_LITERAL(1), REG_VAR(arg_index) 832 // Handle extra argument in arg array taken by a long. 833 cmpb MACRO_LITERAL(74), %al // if (al != 'J') goto LOOP 834 jne 1b 835 addl MACRO_LITERAL(1), REG_VAR(arg_index) 836 jmp 1b // goto LOOP 8372: // FOUND_DOUBLE 838 movq REG_VAR(xmm_reg),(REG_VAR(fp), REG_VAR(arg_index), 4) 839 addl MACRO_LITERAL(2), REG_VAR(arg_index) 840 jmp 4f 8413: // FOUND_FLOAT 842 movss REG_VAR(xmm_reg), (REG_VAR(fp), REG_VAR(arg_index), 4) 843 addl MACRO_LITERAL(1), REG_VAR(arg_index) 8444: 845.endm 846 847// Puts the next int/long/object parameter passed in physical register 848// in the expected dex register array entry, and in case of object in the 849// expected reference array entry. 850// Uses eax as temporary. 851.macro LOOP_OVER_SHORTY_STORING_GPRS offset, offset_long, stack_ptr, shorty, arg_index, regs, refs, finished, if_long, is_ebx 8521: // LOOP 853 movb (REG_VAR(shorty)), %al // al := *shorty 854 addl MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 855 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 856 je VAR(finished) 857 cmpb MACRO_LITERAL(74), %al // if (al == 'J') goto FOUND_LONG 858 je 2f 859 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto SKIP_FLOAT 860 je 3f 861 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto SKIP_DOUBLE 862 je 4f 863 cmpb MACRO_LITERAL(76), %al // if (al != 'L') goto NOT_REFERENCE 864 jne 6f 865 movl \offset(REG_VAR(stack_ptr)), %eax 866 movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 4) 867 movl %eax, (REG_VAR(refs), REG_VAR(arg_index), 4) 868 addl MACRO_LITERAL(1), REG_VAR(arg_index) 869 jmp 5f 8702: // FOUND_LONG 871 .if \is_ebx 872 // Put back shorty and jump to \if_long 873 subl MACRO_LITERAL(1), REG_VAR(shorty) 874 .else 875 movl \offset(REG_VAR(stack_ptr)), %eax 876 movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 4) 877 movl \offset_long(REG_VAR(stack_ptr)), %eax 878 movl %eax, 4(REG_VAR(regs), REG_VAR(arg_index), 4) 879 addl MACRO_LITERAL(2), REG_VAR(arg_index) 880 .endif 881 jmp \if_long 8823: // SKIP_FLOAT 883 addl MACRO_LITERAL(1), REG_VAR(arg_index) 884 jmp 1b 8854: // SKIP_DOUBLE 886 addl MACRO_LITERAL(2), REG_VAR(arg_index) 887 jmp 1b 8886: // NOT_REFERENCE 889 movl \offset(REG_VAR(stack_ptr)), %eax 890 movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 4) 891 addl MACRO_LITERAL(1), REG_VAR(arg_index) 8925: 893.endm 894 895// Puts the next floating point parameter passed in stack 896// in the expected dex register array entry. 897// Uses eax as temporary. 898// 899// TODO: Or we could just spill regs to the reserved slots in the caller's 900// frame and copy all regs in a simple loop. This time, however, we would 901// need to look at the shorty anyway to look for the references. 902// (The trade-off is different for passing arguments and receiving them.) 903.macro LOOP_OVER_FPs shorty, arg_index, regs, stack_ptr, finished 9041: // LOOP 905 movb (REG_VAR(shorty)), %al // al := *shorty 906 addl MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 907 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 908 je VAR(finished) 909 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto FOUND_DOUBLE 910 je 2f 911 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto FOUND_FLOAT 912 je 3f 913 addl MACRO_LITERAL(1), REG_VAR(arg_index) 914 // Handle extra argument in arg array taken by a long. 915 cmpb MACRO_LITERAL(74), %al // if (al != 'J') goto LOOP 916 jne 1b 917 addl MACRO_LITERAL(1), REG_VAR(arg_index) 918 jmp 1b // goto LOOP 9192: // FOUND_DOUBLE 920 movq OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 4), %xmm4 921 movq %xmm4, (REG_VAR(regs), REG_VAR(arg_index), 4) 922 addl MACRO_LITERAL(2), REG_VAR(arg_index) 923 jmp 1b 9243: // FOUND_FLOAT 925 movl OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 4), %eax 926 movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 4) 927 addl MACRO_LITERAL(1), REG_VAR(arg_index) 928 jmp 1b 929.endm 930 931// Puts the next int/long/object parameter passed in stack 932// in the expected dex register array entry, and in case of object in the 933// expected reference array entry. 934// Uses eax as temporary. 935.macro LOOP_OVER_INTs shorty, arg_index, regs, refs, stack_ptr, finished 9361: // LOOP 937 movb (REG_VAR(shorty)), %al // al := *shorty 938 addl MACRO_LITERAL(1), REG_VAR(shorty) // shorty++ 939 cmpb MACRO_LITERAL(0), %al // if (al == '\0') goto finished 940 je VAR(finished) 941 cmpb MACRO_LITERAL(74), %al // if (al == 'J') goto FOUND_LONG 942 je 2f 943 cmpb MACRO_LITERAL(76), %al // if (al == 'L') goto FOUND_REFERENCE 944 je 6f 945 cmpb MACRO_LITERAL(70), %al // if (al == 'F') goto SKIP_FLOAT 946 je 3f 947 cmpb MACRO_LITERAL(68), %al // if (al == 'D') goto SKIP_DOUBLE 948 je 4f 949 movl OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 4), %eax 950 movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 4) 951 addl MACRO_LITERAL(1), REG_VAR(arg_index) 952 jmp 1b 9536: // FOUND_REFERENCE 954 movl OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 4), %eax 955 movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 4) 956 movl %eax, (REG_VAR(refs), REG_VAR(arg_index), 4) 9573: // SKIP_FLOAT 958 addl MACRO_LITERAL(1), REG_VAR(arg_index) 959 jmp 1b 9602: // FOUND_LONG 961 movl OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_index), 4), %eax 962 movl %eax, (REG_VAR(regs), REG_VAR(arg_index), 4) 963 movl (OFFSET_TO_FIRST_ARGUMENT_IN_STACK+4)(REG_VAR(stack_ptr), REG_VAR(arg_index), 4), %eax 964 movl %eax, 4(REG_VAR(regs), REG_VAR(arg_index), 4) 9654: // SKIP_DOUBLE 966 addl MACRO_LITERAL(2), REG_VAR(arg_index) 967 jmp 1b 968.endm 969 970// Increase method hotness and do suspend check before starting executing the method. 971.macro START_EXECUTING_INSTRUCTIONS 972 movl (%esp), %eax 973 movzwl ART_METHOD_HOTNESS_COUNT_OFFSET(%eax), %ecx 974#if (NTERP_HOTNESS_VALUE != 0) 975#error Expected 0 for hotness value 976#endif 977 // If the counter is at zero, handle this in the runtime. 978 testl %ecx, %ecx 979 je 3f 980 // Update counter. 981 addl $$-1, %ecx 982 movw %cx, ART_METHOD_HOTNESS_COUNT_OFFSET(%eax) 9831: 984 testl $$(THREAD_SUSPEND_OR_CHECKPOINT_REQUEST), rSELF:THREAD_FLAGS_OFFSET 985 jz 2f 986 EXPORT_PC 987 call SYMBOL(art_quick_test_suspend) 988 RESTORE_IBASE 9892: 990 FETCH_INST 991 GOTO_NEXT 9923: 993 CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot=4f, if_not_hot=1b 9944: 995 movl $$0, ARG1 996 movl rFP, ARG2 997 call nterp_hot_method 998 jmp 2b 999.endm 1000 1001.macro SPILL_ALL_CALLEE_SAVES 1002 PUSH edi 1003 PUSH esi 1004 PUSH ebp 1005.endm 1006 1007.macro RESTORE_ALL_CALLEE_SAVES 1008 POP ebp 1009 POP esi 1010 POP edi 1011.endm 1012 1013.macro GET_SHORTY dest, is_interface, is_polymorphic, is_custom 1014 // Save eax (ArtMethod), ecx (potential this). 1015 push %eax 1016 push %ecx 1017 .if \is_polymorphic 1018 push rPC 1019 push 12(%esp) 1020 call SYMBOL(NterpGetShortyFromInvokePolymorphic) 1021 addl MACRO_LITERAL(8), %esp 1022 .elseif \is_custom 1023 push rPC 1024 push 12(%esp) 1025 call SYMBOL(NterpGetShortyFromInvokeCustom) 1026 addl MACRO_LITERAL(8), %esp 1027 .elseif \is_interface 1028 subl MACRO_LITERAL(16), %esp 1029 // Save interface method. 1030 movss %xmm7, (%esp) 1031 movzwl 2(rPC), %eax 1032 pushl %eax 1033 // Caller is at 8 (saved ArtMethod + ecx) + 16 + 4 (second argument) 1034 pushl 28(%esp) 1035 call SYMBOL(NterpGetShortyFromMethodId) 1036 // Restore interface method. 1037 movss 8(%esp), %xmm7 1038 addl MACRO_LITERAL(24), %esp 1039 .else 1040 subl MACRO_LITERAL(4), %esp // Alignment 1041 push %eax 1042 call SYMBOL(NterpGetShorty) 1043 addl MACRO_LITERAL(8), %esp 1044 .endif 1045 movl %eax, \dest 1046 pop %ecx 1047 pop %eax 1048.endm 1049 1050.macro GET_SHORTY_SLOW_PATH dest, is_interface 1051 // Save all registers that can hold arguments in the fast path. 1052 pushl %eax 1053 pushl %ecx 1054 pushl %edx 1055 subl MACRO_LITERAL(4), %esp 1056 movss %xmm0, (%esp) 1057 .if \is_interface 1058 // Alignment. 1059 subl MACRO_LITERAL(8), %esp 1060 movzwl 2(rPC), %eax 1061 pushl %eax 1062 // Caller is at 16 (parameters) + 8 (alignment) + 4 (second argument). 1063 pushl 28(%esp) 1064 call SYMBOL(NterpGetShortyFromMethodId) 1065 movl %eax, \dest 1066 movss 16(%esp), %xmm0 1067 addl MACRO_LITERAL(20), %esp 1068 .else 1069 // Alignment. 1070 subl MACRO_LITERAL(12), %esp 1071 pushl %eax 1072 call SYMBOL(NterpGetShorty) 1073 movl %eax, \dest 1074 movss 16(%esp), %xmm0 1075 addl MACRO_LITERAL(20), %esp 1076 .endif 1077 popl %edx 1078 popl %ecx 1079 popl %eax 1080.endm 1081 1082// Uses ecx and edx as temporary 1083.macro UPDATE_REGISTERS_FOR_STRING_INIT old_value, new_value 1084 movl rREFS, %edx 1085 movl rFP, %ecx 10861: 1087 cmpl (%edx), \old_value 1088 jne 2f 1089 movl \new_value, (%edx) 1090 movl \new_value, (%ecx) 10912: 1092 addl $$4, %edx 1093 addl $$4, %ecx 1094 cmpl %edx, rFP 1095 jne 1b 1096.endm 1097 1098.macro DO_CALL is_polymorphic, is_custom 1099 .if \is_polymorphic 1100 call SYMBOL(art_quick_invoke_polymorphic) 1101 .elseif \is_custom 1102 call SYMBOL(art_quick_invoke_custom) 1103 .else 1104 call *ART_METHOD_QUICK_CODE_OFFSET_32(%eax) 1105 .endif 1106.endm 1107 1108.macro COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0 1109 .if \is_polymorphic 1110 // No fast path for polymorphic calls. 1111 .elseif \is_custom 1112 // No fast path for custom calls. 1113 .elseif \is_string_init 1114 // No fast path for string.init. 1115 .else 1116 testl $$ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG, ART_METHOD_ACCESS_FLAGS_OFFSET(%eax) 1117 je .Lfast_path_with_few_args_\suffix 1118 movzbl 1(rPC), %edx 1119 movl %edx, %ebx 1120 shrl MACRO_LITERAL(4), %ebx # Number of arguments 1121 .if \is_static 1122 jz .Linvoke_fast_path_\suffix # shl sets the Z flag 1123 .else 1124 cmpl MACRO_LITERAL(1), %ebx 1125 je .Linvoke_fast_path_\suffix 1126 .endif 1127 movzwl 4(rPC), %esi 1128 cmpl MACRO_LITERAL(2), %ebx 1129 .if \is_static 1130 jl .Lone_arg_fast_path_\suffix 1131 .endif 1132 je .Ltwo_args_fast_path_\suffix 1133 cmpl MACRO_LITERAL(4), %ebx 1134 jl .Lthree_args_fast_path_\suffix 1135 je .Lfour_args_fast_path_\suffix 1136 1137 andl MACRO_LITERAL(0xf), %edx 1138 GET_VREG %edx, %edx 1139 movl %edx, (4 + 4 * 4)(%esp) 1140.Lfour_args_fast_path_\suffix: 1141 movl %esi, %edx 1142 shrl MACRO_LITERAL(12), %edx 1143 GET_VREG %edx, %edx 1144 movl %edx, (4 + 3 * 4)(%esp) 1145.Lthree_args_fast_path_\suffix: 1146 movl %esi, %ebx 1147 shrl MACRO_LITERAL(8), %ebx 1148 andl MACRO_LITERAL(0xf), %ebx 1149 GET_VREG %ebx, %ebx 1150.Ltwo_args_fast_path_\suffix: 1151 movl %esi, %edx 1152 shrl MACRO_LITERAL(4), %edx 1153 andl MACRO_LITERAL(0xf), %edx 1154 GET_VREG %edx, %edx 1155.Lone_arg_fast_path_\suffix: 1156 .if \is_static 1157 andl MACRO_LITERAL(0xf), %esi 1158 GET_VREG %ecx, %esi 1159 .else 1160 // First argument already in %ecx. 1161 .endif 1162.Linvoke_fast_path_\suffix: 1163 // Fetch PC before calling for proper stack unwinding. 1164 FETCH_PC 1165 call *ART_METHOD_QUICK_CODE_OFFSET_32(%eax) // Call the method. 1166 // In case of a long return, save the high half into LOCAL0 1167 SAVE_WIDE_RETURN 1168 RESTORE_IBASE 1169 ADVANCE_PC_FETCH_AND_GOTO_NEXT 3 1170 1171.Lfast_path_with_few_args_\suffix: 1172 // Fast path when we have zero or one argument (modulo 'this'). If there 1173 // is one argument, we can put it in both floating point and core register. 1174 movzbl 1(rPC), %edx 1175 shrl MACRO_LITERAL(4), %edx # Number of arguments 1176 .if \is_static 1177 cmpl MACRO_LITERAL(1), %edx 1178 jl .Linvoke_with_few_args_\suffix 1179 jne .Lget_shorty_\suffix 1180 movzwl 4(rPC), %ecx 1181 andl MACRO_LITERAL(0xf), %ecx // dex register of first argument 1182 GET_VREG %ecx, %ecx 1183 movd %ecx, %xmm0 1184 .else 1185 cmpl MACRO_LITERAL(2), %edx 1186 jl .Linvoke_with_few_args_\suffix 1187 jne .Lget_shorty_\suffix 1188 movzwl 4(rPC), %edx 1189 shrl MACRO_LITERAL(4), %edx 1190 andl MACRO_LITERAL(0xf), %edx // dex register of second argument 1191 GET_VREG %edx, %edx 1192 movd %edx, %xmm0 1193 .endif 1194.Linvoke_with_few_args_\suffix: 1195 // Check if the next instruction is move-result or move-result-wide. 1196 // If it is, we fetch the shorty and jump to the regular invocation. 1197 movzwl 6(rPC), %ebx 1198 andl MACRO_LITERAL(0xfe), %ebx 1199 cmpl MACRO_LITERAL(0x0a), %ebx 1200 je .Lget_shorty_and_invoke_\suffix 1201 call *ART_METHOD_QUICK_CODE_OFFSET_32(%eax) // Call the method. 1202 RESTORE_IBASE 1203 ADVANCE_PC_FETCH_AND_GOTO_NEXT 3 1204.Lget_shorty_and_invoke_\suffix: 1205 GET_SHORTY_SLOW_PATH %esi, \is_interface 1206 jmp .Lgpr_setup_finished_\suffix 1207 .endif 1208 1209.Lget_shorty_\suffix: 1210 GET_SHORTY %ebx, \is_interface, \is_polymorphic, \is_custom 1211 movl %eax, LOCAL0(%esp) 1212 movl %ebp, LOCAL1(%esp) 1213 movl %ebx, LOCAL2(%esp) 1214 // From this point: 1215 // - ebx contains shorty (in callee-save to switch over return value after call). 1216 // - eax, edx, and ebp are available 1217 // - ecx contains 'this' pointer for instance method. 1218 // TODO: ebp/rREFS is used for stack unwinding, can we find a way to preserve it? 1219 leal 1(%ebx), %edx // shorty + 1 ; ie skip return arg character 1220 movzwl 4(rPC), %ebx // arguments 1221 .if \is_string_init 1222 shrl MACRO_LITERAL(4), %ebx 1223 movl $$1, %ebp // ignore first argument 1224 .elseif \is_static 1225 movl $$0, %ebp // arg_index 1226 .else 1227 shrl MACRO_LITERAL(4), %ebx 1228 movl $$1, %ebp // arg_index 1229 .endif 1230 LOOP_OVER_SHORTY_LOADING_XMMS xmm0, ebx, edx, ebp, .Lxmm_setup_finished_\suffix 1231 LOOP_OVER_SHORTY_LOADING_XMMS xmm1, ebx, edx, ebp, .Lxmm_setup_finished_\suffix 1232 LOOP_OVER_SHORTY_LOADING_XMMS xmm2, ebx, edx, ebp, .Lxmm_setup_finished_\suffix 1233 LOOP_OVER_SHORTY_LOADING_XMMS xmm3, ebx, edx, ebp, .Lxmm_setup_finished_\suffix 1234 // We know this can only be a float. 1235 movb (%edx), %al // al := *shorty 1236 cmpb MACRO_LITERAL(70), %al // if (al != 'F') goto finished 1237 jne .Lxmm_setup_finished_\suffix 1238 movzbl 1(rPC), %eax 1239 andl MACRO_LITERAL(0xf), %eax 1240 GET_VREG %eax, %eax 1241 // Add four for the ArtMethod. 1242 movl %eax, 4(%esp, %ebp, 4) 1243 // We know there is no more argument, jump to the call. 1244 jmp .Lrestore_saved_values_\suffix 1245.Lxmm_setup_finished_\suffix: 1246 // Reload rREFS for fetching the PC. 1247 movl LOCAL1(%esp), %ebp 1248 // Reload shorty 1249 movl LOCAL2(%esp), %ebx 1250 FETCH_PC 1251 leal 1(%ebx), %ebx // shorty + 1 ; ie skip return arg character 1252 movzwl 4(rPC), %esi // arguments 1253 .if \is_string_init 1254 movl $$0, %ebp // arg_index 1255 shrl MACRO_LITERAL(4), %esi 1256 LOOP_OVER_SHORTY_LOADING_GPRS ecx, edx, esi, ebx, ebp, .Lrestore_saved_values_\suffix, .Lif_long_ebx_\suffix, is_ebx=0 1257 .elseif \is_static 1258 movl $$0, %ebp // arg_index 1259 LOOP_OVER_SHORTY_LOADING_GPRS ecx, edx, esi, ebx, ebp, .Lrestore_saved_values_\suffix, .Lif_long_ebx_\suffix, is_ebx=0 1260 .else 1261 shrl MACRO_LITERAL(4), %esi 1262 movl $$1, %ebp // arg_index 1263 .endif 1264 // For long argument, store second half in eax to not overwrite the shorty. 1265 LOOP_OVER_SHORTY_LOADING_GPRS edx, eax, esi, ebx, ebp, .Lrestore_saved_values_\suffix, .Lif_long_\suffix, is_ebx=0 1266.Lif_long_ebx_\suffix: 1267 // Store in eax to not overwrite the shorty. 1268 LOOP_OVER_SHORTY_LOADING_GPRS eax, eax, esi, ebx, ebp, .Lrestore_saved_values_\suffix, .Lif_long_\suffix, is_ebx=1 1269.Lif_long_\suffix: 1270 // Save shorty, as LOOP_OVER_SHORTY_LOADING_INTS might overwrite the LOCAL2 slot for a long argument. 1271 pushl LOCAL2(%esp) 1272 pushl %eax 1273 LOOP_OVER_SHORTY_LOADING_INTS 8, ebx, esi, ebp, .Lrestore_ebx_\suffix, \is_string_init 1274.Lrestore_ebx_\suffix: 1275 popl %ebx 1276 popl %esi 1277 movl LOCAL0(%esp), %eax 1278 movl LOCAL1(%esp), %ebp 1279 jmp .Lgpr_setup_finished_\suffix 1280.Lrestore_saved_values_\suffix: 1281 movl LOCAL0(%esp), %eax 1282 movl LOCAL1(%esp), %ebp 1283 movl LOCAL2(%esp), %esi 1284.Lgpr_setup_finished_\suffix: 1285 // Look at the shorty now, as we'll want %esi to have the PC for proper stack unwinding 1286 // and we're running out of callee-save registers. 1287 cmpb LITERAL(68), (%esi) // Test if result type char == 'D'. 1288 je .Linvoke_double_\suffix 1289 cmpb LITERAL(70), (%esi) // Test if result type char == 'F'. 1290 je .Linvoke_float_\suffix 1291 FETCH_PC 1292 DO_CALL \is_polymorphic, \is_custom 1293 SAVE_WIDE_RETURN 1294.Ldone_return_\suffix: 1295 /* resume execution of caller */ 1296 .if \is_string_init 1297 movzwl 4(rPC), %ecx // arguments 1298 andl $$0xf, %ecx 1299 GET_VREG rINST, %ecx 1300 UPDATE_REGISTERS_FOR_STRING_INIT rINST, %eax 1301 .endif 1302 RESTORE_IBASE 1303 1304 .if \is_polymorphic 1305 ADVANCE_PC_FETCH_AND_GOTO_NEXT 4 1306 .else 1307 ADVANCE_PC_FETCH_AND_GOTO_NEXT 3 1308 .endif 1309 1310.Linvoke_double_\suffix: 1311 FETCH_PC 1312 DO_CALL \is_polymorphic, \is_custom 1313 movq %xmm0, LOCAL1(%esp) 1314 movl LOCAL1(%esp), %eax 1315 jmp .Ldone_return_\suffix 1316.Linvoke_float_\suffix: 1317 FETCH_PC 1318 DO_CALL \is_polymorphic, \is_custom 1319 movd %xmm0, %eax 1320 jmp .Ldone_return_\suffix 1321.endm 1322 1323.macro COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0 1324 .if \is_polymorphic 1325 // No fast path for polymorphic calls. 1326 .elseif \is_custom 1327 // No fast path for custom calls. 1328 .elseif \is_string_init 1329 // No fast path for string.init. 1330 .else 1331 testl $$ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG, ART_METHOD_ACCESS_FLAGS_OFFSET(%eax) 1332 je .Lfast_path_with_few_args_range_\suffix 1333 movzbl 1(rPC), %edx // number of arguments 1334 .if \is_static 1335 testl %edx, %edx 1336 je .Linvoke_fast_path_range_\suffix 1337 .else 1338 cmpl MACRO_LITERAL(1), %edx 1339 je .Linvoke_fast_path_range_\suffix 1340 .endif 1341 movzwl 4(rPC), %ebx // dex register of first argument 1342 leal (rFP, %ebx, 4), %esi // location of first dex register value 1343 cmpl MACRO_LITERAL(2), %edx 1344 .if \is_static 1345 jl .Lone_arg_fast_path_range_\suffix 1346 .endif 1347 je .Ltwo_args_fast_path_range_\suffix 1348 cmp MACRO_LITERAL(4), %edx 1349 jl .Lthree_args_fast_path_range_\suffix 1350 1351.Lloop_over_fast_path_range_\suffix: 1352 subl MACRO_LITERAL(1), %edx 1353 movl (%esi, %edx, 4), %ebx 1354 movl %ebx, 4(%esp, %edx, 4) // Add 4 for the ArtMethod 1355 cmpl MACRO_LITERAL(3), %edx 1356 jne .Lloop_over_fast_path_range_\suffix 1357 1358.Lthree_args_fast_path_range_\suffix: 1359 movl 8(%esi), %ebx 1360.Ltwo_args_fast_path_range_\suffix: 1361 movl 4(%esi), %edx 1362.Lone_arg_fast_path_range_\suffix: 1363 .if \is_static 1364 movl 0(%esi), %ecx 1365 .else 1366 // First argument already in %ecx. 1367 .endif 1368.Linvoke_fast_path_range_\suffix: 1369 FETCH_PC 1370 call *ART_METHOD_QUICK_CODE_OFFSET_32(%eax) // Call the method. 1371 SAVE_WIDE_RETURN 1372 RESTORE_IBASE 1373 ADVANCE_PC_FETCH_AND_GOTO_NEXT 3 1374 1375.Lfast_path_with_few_args_range_\suffix: 1376 // Fast path when we have zero or one argument (modulo 'this'). If there 1377 // is one argument, we can put it in both floating point and core register. 1378 movzbl 1(rPC), %ebx # Number of arguments 1379 .if \is_static 1380 cmpl MACRO_LITERAL(1), %ebx 1381 jl .Linvoke_with_few_args_range_\suffix 1382 jne .Lget_shorty_range_\suffix 1383 movzwl 4(rPC), %ebx // Dex register of first argument 1384 GET_VREG %ecx, %ebx 1385 movd %ecx, %xmm0 1386 .else 1387 cmpl MACRO_LITERAL(2), %ebx 1388 jl .Linvoke_with_few_args_range_\suffix 1389 jne .Lget_shorty_range_\suffix 1390 movzwl 4(rPC), %ebx 1391 addl MACRO_LITERAL(1), %ebx // dex register of second argument 1392 GET_VREG %edx, %ebx 1393 movd %edx, %xmm0 1394 .endif 1395.Linvoke_with_few_args_range_\suffix: 1396 // Check if the next instruction is move-result or move-result-wide. 1397 // If it is, we fetch the shorty and jump to the regular invocation. 1398 movzwl 6(rPC), %ebx 1399 and MACRO_LITERAL(0xfe), %ebx 1400 cmpl MACRO_LITERAL(0x0a), %ebx 1401 je .Lget_shorty_and_invoke_range_\suffix 1402 call *ART_METHOD_QUICK_CODE_OFFSET_32(%eax) // Call the method. 1403 RESTORE_IBASE 1404 ADVANCE_PC_FETCH_AND_GOTO_NEXT 3 1405.Lget_shorty_and_invoke_range_\suffix: 1406 GET_SHORTY_SLOW_PATH %esi, \is_interface 1407 jmp .Lgpr_setup_finished_range_\suffix 1408 .endif 1409 1410.Lget_shorty_range_\suffix: 1411 GET_SHORTY %ebx, \is_interface, \is_polymorphic, \is_custom 1412 movl %eax, LOCAL0(%esp) 1413 movl %ebp, LOCAL1(%esp) 1414 movl %ebx, LOCAL2(%esp) 1415 // From this point: 1416 // - ebx contains shorty (in callee-save to switch over return value after call). 1417 // - eax, edx, ebx, and ebp are available. 1418 // - ecx contains 'this' pointer for instance method. 1419 // TODO: ebp/rREFS is used for stack unwinding, can we find a way to preserve it? 1420 leal 1(%ebx), %edx // shorty + 1 ; ie skip return arg character 1421 movzwl 4(rPC), %ebx // arg start index 1422 .if \is_string_init 1423 addl $$1, %ebx // arg start index 1424 movl $$0, %ebp // index in stack 1425 .elseif \is_static 1426 movl $$0, %ebp // index in stack 1427 .else 1428 addl $$1, %ebx // arg start index 1429 movl $$1, %ebp // index in stack 1430 .endif 1431 LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm0, edx, ebx, ebp, .Lxmm_setup_finished_range_\suffix 1432 LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm1, edx, ebx, ebp, .Lxmm_setup_finished_range_\suffix 1433 LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm2, edx, ebx, ebp, .Lxmm_setup_finished_range_\suffix 1434 LOOP_RANGE_OVER_SHORTY_LOADING_XMMS xmm3, edx, ebx, ebp, .Lxmm_setup_finished_range_\suffix 1435 LOOP_RANGE_OVER_FPs edx, ebx, ebp, .Lxmm_setup_finished_range_\suffix 1436.Lxmm_setup_finished_range_\suffix: 1437 // Reload rREFS for fetching the PC. 1438 movl LOCAL1(%esp), %ebp 1439 // Reload shorty 1440 movl LOCAL2(%esp), %ebx 1441 FETCH_PC 1442 leal 1(%ebx), %ebx // shorty + 1 ; ie skip return arg character 1443 // From this point: 1444 // - ebx contains shorty 1445 // - eax and ebp are available. 1446 // - ecx contains 'this' pointer for instance method. 1447 movzwl 4(rPC), %ebp // arg start index 1448 // rPC (esi) is now available 1449 .if \is_string_init 1450 addl $$1, %ebp // arg start index 1451 movl $$0, %esi // index in stack 1452 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS ecx, edx, ebx, ebp, esi, .Lrestore_saved_values_range_\suffix, .Lif_long_ebx_range_\suffix, is_ebx=0 1453 .elseif \is_static 1454 movl $$0, %esi // index in stack 1455 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS ecx, edx, ebx, ebp, esi, .Lrestore_saved_values_range_\suffix, .Lif_long_ebx_range_\suffix, is_ebx=0 1456 .else 1457 addl $$1, %ebp // arg start index 1458 movl $$1, %esi // index in stack 1459 .endif 1460 // For long argument, store second half in eax to not overwrite the shorty. 1461 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS edx, eax, ebx, ebp, esi, .Lrestore_saved_values_range_\suffix, .Lif_long_range_\suffix, is_ebx=0 1462.Lif_long_ebx_range_\suffix: 1463 // Store in eax to not overwrite the shorty. 1464 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS eax, eax, ebx, ebp, esi, .Lrestore_saved_values_range_\suffix, .Lif_long_range_\suffix, is_ebx=1 1465.Lif_long_range_\suffix: 1466 // Save shorty, as LOOP_RANGE_OVER_SHORTY_LOADING_INTS might overwrite the LOCAL2 slot for a long argument. 1467 pushl LOCAL2(%esp) 1468 pushl %eax 1469 LOOP_RANGE_OVER_INTs 8, ebx, ebp, esi, .Lrestore_ebx_range_\suffix 1470.Lrestore_ebx_range_\suffix: 1471 popl %ebx 1472 popl %esi 1473 movl LOCAL0(%esp), %eax 1474 movl LOCAL1(%esp), %ebp 1475 jmp .Lgpr_setup_finished_range_\suffix 1476 1477.Lrestore_saved_values_range_\suffix: 1478 movl LOCAL0(%esp), %eax 1479 movl LOCAL1(%esp), %ebp 1480 // Save shorty in callee-save register 1481 movl LOCAL2(%esp), %esi 1482 1483.Lgpr_setup_finished_range_\suffix: 1484 cmpb LITERAL(68), (%esi) // Test if result type char == 'D'. 1485 je .Lreturn_range_double_\suffix 1486 cmpb LITERAL(70), (%esi) // Test if result type char == 'F'. 1487 je .Lreturn_range_float_\suffix 1488 1489 FETCH_PC 1490 DO_CALL \is_polymorphic, \is_custom 1491 SAVE_WIDE_RETURN 1492.Ldone_return_range_\suffix: 1493 /* resume execution of caller */ 1494 .if \is_string_init 1495 movzwl 4(rPC), %ecx // arguments 1496 GET_VREG rINST, %ecx 1497 UPDATE_REGISTERS_FOR_STRING_INIT rINST, %eax 1498 .endif 1499 RESTORE_IBASE 1500 .if \is_polymorphic 1501 ADVANCE_PC_FETCH_AND_GOTO_NEXT 4 1502 .else 1503 ADVANCE_PC_FETCH_AND_GOTO_NEXT 3 1504 .endif 1505.Lreturn_range_double_\suffix: 1506 FETCH_PC 1507 DO_CALL \is_polymorphic, \is_custom 1508 movq %xmm0, LOCAL1(%esp) 1509 movl LOCAL1(%esp), %eax 1510 jmp .Ldone_return_range_\suffix 1511.Lreturn_range_float_\suffix: 1512 FETCH_PC 1513 DO_CALL \is_polymorphic, \is_custom 1514 movd %xmm0, %eax 1515 jmp .Ldone_return_range_\suffix 1516.endm 1517 1518// Helper for static field get. 1519.macro OP_SGET load="movl", wide="0" 1520 // Fast-path which gets the field from thread-local cache. 1521% fetch_from_thread_cache("%eax", miss_label="2f") 15221: 1523 movl ART_FIELD_OFFSET_OFFSET(%eax), %ecx 1524 movl ART_FIELD_DECLARING_CLASS_OFFSET(%eax), %eax 1525 cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1526 jne 3f 15274: 1528 .if \wide 1529 addl %ecx, %eax 1530 \load (%eax), %ecx 1531 SET_VREG %ecx, rINST # fp[A] <- value 1532 \load 4(%eax), %ecx 1533 SET_VREG_HIGH %ecx, rINST 1534 .else 1535 \load (%eax, %ecx, 1), %eax 1536 SET_VREG %eax, rINST # fp[A] <- value 1537 .endif 1538 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 15392: 1540 EXPORT_PC 1541 movl rSELF:THREAD_SELF_OFFSET, ARG0 1542 movl 0(%esp), ARG1 1543 movl rPC, ARG2 1544 movl $$0, ARG3 1545 call nterp_get_static_field 1546 .if !\wide 1547 CLEAR_VOLATILE_MARKER %eax 1548 jmp 1b 1549 .else 1550 testl MACRO_LITERAL(1), %eax 1551 je 1b 1552 CLEAR_VOLATILE_MARKER %eax 1553 movl ART_FIELD_OFFSET_OFFSET(%eax), %ecx 1554 movl ART_FIELD_DECLARING_CLASS_OFFSET(%eax), %eax 1555 cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1556 jne 5f 15576: 1558 movsd (%eax, %ecx, 1), %xmm0 1559 SET_WIDE_FP_VREG %xmm0, rINST 1560 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 15615: 1562 call art_quick_read_barrier_mark_reg00 1563 jmp 6b 1564 .endif 15653: 1566 call art_quick_read_barrier_mark_reg00 1567 jmp 4b 1568.endm 1569 1570// Helper for static field put. 1571.macro OP_SPUT rINST_reg="rINST", store="movl", wide="0": 1572 // Fast-path which gets the field from thread-local cache. 1573% fetch_from_thread_cache("%eax", miss_label="2f") 15741: 1575 movl ART_FIELD_OFFSET_OFFSET(%eax), %ecx 1576 movl ART_FIELD_DECLARING_CLASS_OFFSET(%eax), %eax 1577 cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1578 jne 3f 15794: 1580 .if \wide 1581 addl %ecx, %eax 1582 GET_VREG %ecx, rINST # rINST <- v[A] 1583 movl %ecx, (%eax) 1584 GET_VREG_HIGH %ecx, rINST 1585 movl %ecx, 4(%eax) 1586 .else 1587 GET_VREG rINST, rINST # rINST <- v[A] 1588 \store \rINST_reg, (%eax,%ecx,1) 1589 .endif 1590 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 15912: 1592 EXPORT_PC 1593 movl rSELF:THREAD_SELF_OFFSET, ARG0 1594 movl 0(%esp), ARG1 1595 movl rPC, ARG2 1596 movl $$0, ARG3 1597 call nterp_get_static_field 1598 testl MACRO_LITERAL(1), %eax 1599 je 1b 1600 // Clear the marker that we put for volatile fields. 1601 CLEAR_VOLATILE_MARKER %eax 1602 movl ART_FIELD_OFFSET_OFFSET(%eax), %ecx 1603 movl ART_FIELD_DECLARING_CLASS_OFFSET(%eax), %eax 1604 cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1605 jne 6f 16065: 1607 .if \wide 1608 addl %ecx, %eax 1609 GET_WIDE_FP_VREG %xmm0, rINST 1610 movsd %xmm0, (%eax) 1611 .else 1612 GET_VREG rINST, rINST # rINST <- v[A] 1613 \store \rINST_reg, (%eax,%ecx,1) 1614 .endif 1615 lock addl $$0, (%esp) 1616 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 16173: 1618 call art_quick_read_barrier_mark_reg00 1619 jmp 4b 16206: 1621 call art_quick_read_barrier_mark_reg00 1622 jmp 5b 1623.endm 1624 1625 1626.macro OP_IPUT_INTERNAL rINST_reg="rINST", store="movl", wide="0", volatile="0": 1627 movzbl rINSTbl, %ecx # ecx <- BA 1628 sarl $$4, %ecx # ecx <- B 1629 GET_VREG %ecx, %ecx # vB (object we're operating on) 1630 testl %ecx, %ecx # is object null? 1631 je common_errNullObject 1632 andb $$0xf, rINSTbl # rINST <- A 1633 .if \wide 1634 addl %ecx, %eax 1635 GET_WIDE_FP_VREG %xmm0, rINST 1636 movsd %xmm0, (%eax) 1637 .else 1638 GET_VREG rINST, rINST # rINST <- v[A] 1639 \store \rINST_reg, (%ecx,%eax,1) 1640 .endif 1641.endm 1642 1643// Helper for instance field put. 1644.macro OP_IPUT rINST_reg="rINST", store="movl", wide="0": 1645 // Fast-path which gets the field from thread-local cache. 1646% fetch_from_thread_cache("%eax", miss_label="2f") 16471: 1648 OP_IPUT_INTERNAL \rINST_reg, \store, \wide, volatile=0 1649 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 16502: 1651 EXPORT_PC 1652 movl rSELF:THREAD_SELF_OFFSET, ARG0 1653 movl 0(%esp), ARG1 1654 movl rPC, ARG2 1655 movl $$0, ARG3 1656 call nterp_get_instance_field_offset 1657 testl %eax, %eax 1658 jns 1b 1659 negl %eax 1660 OP_IPUT_INTERNAL \rINST_reg, \store, \wide, volatile=1 1661 lock addl $$0, (%esp) 1662 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 1663.endm 1664 1665// Helper for instance field get. 1666.macro OP_IGET load="movl", wide="0" 1667 // Fast-path which gets the field from thread-local cache. 1668% fetch_from_thread_cache("%eax", miss_label="2f") 16691: 1670 movl rINST, %ecx # ecx <- BA 1671 sarl $$4, %ecx # ecx <- B 1672 GET_VREG %ecx, %ecx # vB (object we're operating on) 1673 testl %ecx, %ecx # is object null? 1674 je common_errNullObject 1675 andb $$0xf,rINSTbl # rINST <- A 1676 .if \wide 1677 addl %ecx, %eax 1678 \load (%eax), %ecx 1679 SET_VREG %ecx, rINST 1680 \load 4(%eax), %ecx 1681 SET_VREG_HIGH %ecx, rINST 1682 .else 1683 \load (%ecx,%eax,1), %eax 1684 SET_VREG %eax, rINST # fp[A] <- value 1685 .endif 1686 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 16872: 1688 EXPORT_PC 1689 movl rSELF:THREAD_SELF_OFFSET, ARG0 1690 movl 0(%esp), ARG1 1691 movl rPC, ARG2 1692 movl $$0, ARG3 1693 call nterp_get_instance_field_offset 1694 testl %eax, %eax 1695 jns 1b 1696 negl %eax 1697 .if !\wide 1698 jmp 1b 1699 .else 1700 movl rINST, %ecx # ecx <- BA 1701 sarl $$4, %ecx # ecx <- B 1702 GET_VREG %ecx, %ecx # vB (object we're operating on) 1703 testl %ecx, %ecx # is object null? 1704 je common_errNullObject 1705 andb $$0xf,rINSTbl # rINST <- A 1706 movsd (%eax, %ecx, 1), %xmm0 1707 SET_WIDE_FP_VREG %xmm0, rINST 1708 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 1709 .endif 1710.endm 1711 1712// Store a reference parameter into our dex register frame. 1713// Uses xmm4 as temporary. 1714.macro SETUP_REFERENCE_PARAMETER_IN_GPR offset, stack_ptr, regs, refs, ins, arg_offset, finished 1715 movss \offset(REG_VAR(stack_ptr)), %xmm4 1716 movss %xmm4, (REG_VAR(regs), REG_VAR(arg_offset)) 1717 movss %xmm4, (REG_VAR(refs), REG_VAR(arg_offset)) 1718 addl MACRO_LITERAL(4), REG_VAR(arg_offset) 1719 subl MACRO_LITERAL(1), REG_VAR(ins) 1720 je \finished 1721.endm 1722 1723// Store a reference parameter into our dex register frame. 1724// Uses xmm4 as temporary. 1725.macro SETUP_REFERENCE_PARAMETERS_IN_STACK stack_ptr, regs, refs, ins, arg_offset 17261: 1727 movss OFFSET_TO_FIRST_ARGUMENT_IN_STACK(REG_VAR(stack_ptr), REG_VAR(arg_offset)), %xmm4 1728 movss %xmm4, (REG_VAR(regs), REG_VAR(arg_offset)) 1729 movss %xmm4, (REG_VAR(refs), REG_VAR(arg_offset)) 1730 addl MACRO_LITERAL(4), REG_VAR(arg_offset) 1731 subl MACRO_LITERAL(1), REG_VAR(ins) 1732 jne 1b 1733.endm 1734 1735.macro DO_SUSPEND_CHECK continue_label 1736 testl $$(THREAD_SUSPEND_OR_CHECKPOINT_REQUEST), rSELF:THREAD_FLAGS_OFFSET 1737 jz \continue_label 1738 jmp NterpCallSuspendAndGotoNext 1739.endm 1740 1741.macro CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot, if_not_hot 1742 testl $$ART_METHOD_IS_MEMORY_SHARED_FLAG, ART_METHOD_ACCESS_FLAGS_OFFSET(%eax) 1743 jz \if_hot 1744 movzwl rSELF:THREAD_SHARED_METHOD_HOTNESS_OFFSET, %ecx 1745 testl %ecx, %ecx 1746 je \if_hot 1747 addl $$-1, %ecx 1748 movw %cx, rSELF:THREAD_SHARED_METHOD_HOTNESS_OFFSET 1749 jmp \if_not_hot 1750.endm 1751 1752 1753%def entry(): 1754/* 1755 * ArtMethod entry point. 1756 * 1757 * On entry: 1758 * eax ArtMethod* callee 1759 * rest method parameters 1760 */ 1761 1762OAT_ENTRY ExecuteNterpWithClinitImpl, EndExecuteNterpWithClinitImpl 1763 push %esi 1764 // For simplicity, we don't do a read barrier here, but instead rely 1765 // on art_quick_resolution_trampoline to always have a suspend point before 1766 // calling back here. 1767 movl ART_METHOD_DECLARING_CLASS_OFFSET(%eax), %esi 1768 cmpb $$(MIRROR_CLASS_IS_VISIBLY_INITIALIZED_VALUE), MIRROR_CLASS_IS_VISIBLY_INITIALIZED_OFFSET(%esi) 1769 jae .Lcontinue_execute_nterp 1770 cmpb $$(MIRROR_CLASS_IS_INITIALIZING_VALUE), MIRROR_CLASS_IS_VISIBLY_INITIALIZED_OFFSET(%esi) 1771 jb .Linvoke_trampoline 1772 movl MIRROR_CLASS_CLINIT_THREAD_ID_OFFSET(%esi), %esi 1773 cmpl %esi, rSELF:THREAD_TID_OFFSET 1774 je .Lcontinue_execute_nterp 1775.Linvoke_trampoline: 1776 pop %esi 1777 jmp art_quick_resolution_trampoline 1778.Lcontinue_execute_nterp: 1779 pop %esi 1780 jmp ExecuteNterpImpl 1781EndExecuteNterpWithClinitImpl: 1782 1783OAT_ENTRY ExecuteNterpImpl, EndExecuteNterpImpl 1784 .cfi_startproc 1785 .cfi_def_cfa esp, 4 1786 testl %eax, -STACK_OVERFLOW_RESERVED_BYTES(%esp) 1787 // Spill callee save regs 1788 SPILL_ALL_CALLEE_SAVES 1789 1790 // Make argument registers available. 1791 SPILL_ALL_CORE_PARAMETERS 1792 1793 // Fetch code item. 1794 movl ART_METHOD_DATA_OFFSET_32(%eax), %ecx 1795 1796 // Setup the stack for executing the method. 1797 SETUP_STACK_FRAME %ecx, rREFS, rFP, CFI_REFS, load_ins=1 1798 1799 // Save the PC 1800 movl %ecx, -8(rREFS) 1801 1802 // Setup the parameters 1803 testl %esi, %esi 1804 je .Lxmm_setup_finished 1805 1806 subl %esi, %ebx 1807 sall $$2, %ebx // ebx is now the offset for inputs into the registers array. 1808 1809 // Reload ArtMethod. 1810 movl (%esp), %eax 1811 testl $$ART_METHOD_NTERP_ENTRY_POINT_FAST_PATH_FLAG, ART_METHOD_ACCESS_FLAGS_OFFSET(%eax) 1812 je .Lsetup_slow_path 1813 leal (rREFS, %ebx, 1), %ecx 1814 leal (rFP, %ebx, 1), %ebx 1815 movl $$0, %eax 1816 1817 // edx is the old stack pointer 1818 SETUP_REFERENCE_PARAMETER_IN_GPR 8, edx, ebx, ecx, esi, eax, .Lxmm_setup_finished 1819 SETUP_REFERENCE_PARAMETER_IN_GPR 4, edx, ebx, ecx, esi, eax, .Lxmm_setup_finished 1820 SETUP_REFERENCE_PARAMETER_IN_GPR 0, edx, ebx, ecx, esi, eax, .Lxmm_setup_finished 1821 SETUP_REFERENCE_PARAMETERS_IN_STACK edx, ebx, ecx, esi, eax 1822 jmp .Lxmm_setup_finished 1823 1824.Lsetup_slow_path: 1825 // If the method is not static and there is one argument ('this'), we don't need to fetch the 1826 // shorty. 1827 testl $$ART_METHOD_IS_STATIC_FLAG, ART_METHOD_ACCESS_FLAGS_OFFSET(%eax) 1828 jne .Lsetup_with_shorty 1829 1830 // Record 'this'. 1831 movl 8(%edx), %eax 1832 movl %eax, (rFP, %ebx) 1833 movl %eax, (rREFS, %ebx) 1834 1835 cmpl $$1, %esi 1836 je .Lxmm_setup_finished 1837 1838.Lsetup_with_shorty: 1839 // Save xmm registers. Core registers have already been saved. 1840 subl MACRO_LITERAL(4 * 8), %esp 1841 movq %xmm0, 0(%esp) 1842 movq %xmm1, 8(%esp) 1843 movq %xmm2, 16(%esp) 1844 movq %xmm3, 24(%esp) 1845 subl MACRO_LITERAL(12), %esp 1846 pushl (4 * 8 + 12)(%esp) 1847 call SYMBOL(NterpGetShorty) 1848 addl MACRO_LITERAL(16), %esp 1849 1850 // Restore xmm registers 1851 movq 0(%esp), %xmm0 1852 movq 8(%esp), %xmm1 1853 movq 16(%esp), %xmm2 1854 movq 24(%esp), %xmm3 1855 addl MACRO_LITERAL(4 * 8), %esp 1856 1857 // Reload the old stack pointer. 1858 movl -4(rREFS), %edx 1859 // TODO: Get shorty in a better way and remove above 1860 1861 movl $$0, %esi 1862 movl (%esp), %ecx 1863 testl $$ART_METHOD_IS_STATIC_FLAG, ART_METHOD_ACCESS_FLAGS_OFFSET(%ecx) 1864 1865 // Note the leal and movl below don't change the flags. 1866 leal (rFP, %ebx, 1), %ecx 1867 leal (rREFS, %ebx, 1), %ebx 1868 // Save rFP (%edi), we're using it as temporary below. 1869 movl rFP, LOCAL1(%esp) 1870 leal 1(%eax), %edi // shorty + 1 ; ie skip return arg character 1871 // Save shorty + 1 1872 movl %edi, LOCAL2(%esp) 1873 jne .Lhandle_static_method 1874 addl $$4, %ecx 1875 addl $$4, %ebx 1876 addl $$4, %edx 1877 LOOP_OVER_SHORTY_STORING_GPRS 0, -4, edx, edi, esi, ecx, ebx, .Lgpr_setup_finished, .Lif_long, is_ebx=0 1878 LOOP_OVER_SHORTY_STORING_GPRS -4, 0, edx, edi, esi, ecx, ebx, .Lgpr_setup_finished, .Lif_long, is_ebx=1 1879 jmp .Lif_long 1880.Lhandle_static_method: 1881 LOOP_OVER_SHORTY_STORING_GPRS 8, 4, edx, edi, esi, ecx, ebx, .Lgpr_setup_finished, .Lif_long_ebx, is_ebx=0 1882 LOOP_OVER_SHORTY_STORING_GPRS 4, 0, edx, edi, esi, ecx, ebx, .Lgpr_setup_finished, .Lif_long, is_ebx=0 1883.Lif_long_ebx: 1884 LOOP_OVER_SHORTY_STORING_GPRS 0, 0, edx, edi, esi, ecx, ebx, .Lgpr_setup_finished, .Lif_long, is_ebx=1 1885.Lif_long: 1886 LOOP_OVER_INTs edi, esi, ecx, ebx, edx, .Lgpr_setup_finished 1887.Lgpr_setup_finished: 1888 // Restore shorty + 1 1889 movl LOCAL2(%esp), %edi 1890 movl $$0, %esi // reset counter 1891 LOOP_OVER_SHORTY_STORING_XMMS xmm0, edi, esi, ecx, .Lrestore_fp 1892 LOOP_OVER_SHORTY_STORING_XMMS xmm1, edi, esi, ecx, .Lrestore_fp 1893 LOOP_OVER_SHORTY_STORING_XMMS xmm2, edi, esi, ecx, .Lrestore_fp 1894 LOOP_OVER_SHORTY_STORING_XMMS xmm3, edi, esi, ecx, .Lrestore_fp 1895 LOOP_OVER_FPs edi, esi, ecx, edx, .Lrestore_fp 1896.Lrestore_fp: 1897 movl LOCAL1(%esp), rFP 1898.Lxmm_setup_finished: 1899 FETCH_PC 1900 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) 1901 // Set rIBASE 1902 RESTORE_IBASE 1903 /* start executing the instruction at rPC */ 1904 START_EXECUTING_INSTRUCTIONS 1905 /* NOTE: no fallthrough */ 1906 // cfi info continues, and covers the whole nterp implementation. 1907 END ExecuteNterpImpl 1908 1909%def opcode_pre(): 1910 1911%def fetch_from_thread_cache(dest_reg, miss_label): 1912 // Fetch some information from the thread cache. 1913 // Uses eax, and ecx as temporaries. 1914 movl rSELF:THREAD_SELF_OFFSET, %eax 1915 movl rPC, %ecx 1916 sall MACRO_LITERAL(THREAD_INTERPRETER_CACHE_SIZE_SHIFT), %ecx 1917 andl MACRO_LITERAL(THREAD_INTERPRETER_CACHE_SIZE_MASK), %ecx 1918 cmpl THREAD_INTERPRETER_CACHE_OFFSET(%eax, %ecx, 1), rPC 1919 jne ${miss_label} 1920 movl __SIZEOF_POINTER__+THREAD_INTERPRETER_CACHE_OFFSET(%eax, %ecx, 1), ${dest_reg} 1921 1922%def footer(): 1923/* 1924 * =========================================================================== 1925 * Common subroutines and data 1926 * =========================================================================== 1927 */ 1928 1929 .text 1930 .align 2 1931 1932// Enclose all code below in a symbol (which gets printed in backtraces). 1933ENTRY nterp_helper 1934 1935// Note: mterp also uses the common_* names below for helpers, but that's OK 1936// as the assembler compiled each interpreter separately. 1937common_errDivideByZero: 1938 EXPORT_PC 1939 call art_quick_throw_div_zero 1940 1941// Expect array in eax, index in ecx. 1942common_errArrayIndex: 1943 EXPORT_PC 1944 movl MIRROR_ARRAY_LENGTH_OFFSET(%eax), %edx 1945 movl %ecx, %eax 1946 movl %edx, %ecx 1947 call art_quick_throw_array_bounds 1948 1949common_errNullObject: 1950 EXPORT_PC 1951 call art_quick_throw_null_pointer_exception 1952 1953NterpCommonInvokeStatic: 1954 COMMON_INVOKE_NON_RANGE is_static=1, is_interface=0, suffix="invokeStatic" 1955 1956NterpCommonInvokeStaticRange: 1957 COMMON_INVOKE_RANGE is_static=1, is_interface=0, suffix="invokeStatic" 1958 1959NterpCommonInvokeInstance: 1960 COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="invokeInstance" 1961 1962NterpCommonInvokeInstanceRange: 1963 COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="invokeInstance" 1964 1965NterpCommonInvokeInterface: 1966 COMMON_INVOKE_NON_RANGE is_static=0, is_interface=1, suffix="invokeInterface" 1967 1968NterpCommonInvokeInterfaceRange: 1969 COMMON_INVOKE_RANGE is_static=0, is_interface=1, suffix="invokeInterface" 1970 1971NterpCommonInvokePolymorphic: 1972 COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, is_polymorphic=1, suffix="invokePolymorphic" 1973 1974NterpCommonInvokePolymorphicRange: 1975 COMMON_INVOKE_RANGE is_static=0, is_interface=0, is_polymorphic=1, suffix="invokePolymorphic" 1976 1977NterpCommonInvokeCustom: 1978 COMMON_INVOKE_NON_RANGE is_static=1, is_interface=0, is_polymorphic=0, is_custom=1, suffix="invokeCustom" 1979 1980NterpCommonInvokeCustomRange: 1981 COMMON_INVOKE_RANGE is_static=1, is_interface=0, is_polymorphic=0, is_custom=1, suffix="invokeCustom" 1982 1983NterpHandleStringInit: 1984 COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, is_string_init=1, suffix="stringInit" 1985 1986NterpHandleStringInitRange: 1987 COMMON_INVOKE_RANGE is_static=0, is_interface=0, is_string_init=1, suffix="stringInit" 1988 1989NterpNewInstance: 1990 EXPORT_PC 1991 // Fast-path which gets the class from thread-local cache. 1992% fetch_from_thread_cache("%eax", miss_label="2f") 1993 cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 1994 jne 3f 19954: 1996 call *rSELF:THREAD_ALLOC_OBJECT_ENTRYPOINT_OFFSET 1997 RESTORE_IBASE 1998 FETCH_INST_CLEAR_OPCODE 19991: 2000 SET_VREG_OBJECT %eax, rINST # fp[A] <- value 2001 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 20022: 2003 movl rSELF:THREAD_SELF_OFFSET, ARG0 2004 movl 0(%esp), ARG1 2005 movl rPC, ARG2 2006 call nterp_allocate_object 2007 jmp 1b 20083: 2009 // 00 is %eax 2010 call art_quick_read_barrier_mark_reg00 2011 jmp 4b 2012 2013NterpNewArray: 2014 /* new-array vA, vB, class@CCCC */ 2015 EXPORT_PC 2016 // Fast-path which gets the class from thread-local cache. 2017% fetch_from_thread_cache("%eax", miss_label="2f") 2018 cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 2019 jne 3f 20201: 2021 movzbl rINSTbl, %ecx 2022 sarl $$4, %ecx # ecx<- B 2023 GET_VREG %ecx %ecx # ecx<- vB (array length) 2024 call *rSELF:THREAD_ALLOC_ARRAY_ENTRYPOINT_OFFSET 2025 RESTORE_IBASE 2026 FETCH_INST_CLEAR_OPCODE 2027 andb $$0xf, rINSTbl # rINST<- A 2028 SET_VREG_OBJECT %eax, rINST # fp[A] <- value 2029 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 20302: 2031 movl rSELF:THREAD_SELF_OFFSET, ARG0 2032 movl 0(%esp), ARG1 2033 movl rPC, ARG2 2034 call nterp_get_class 2035 jmp 1b 20363: 2037 // 00 is %eax 2038 call art_quick_read_barrier_mark_reg00 2039 jmp 1b 2040 2041NterpPutObjectInstanceField: 2042 // Fast-path which gets the field from thread-local cache. 2043% fetch_from_thread_cache("%eax", miss_label="2f") 20441: 2045 movl rINST, %ecx # ecx <- BA 2046 andl $$0xf, %ecx # ecx <- A 2047 GET_VREG %ecx, %ecx # ecx <- v[A] 2048 sarl $$4, rINST 2049 GET_VREG rINST, rINST # vB (object we're operating on) 2050 testl rINST, rINST # is object null? 2051 je common_errNullObject 2052 movl %ecx, (rINST, %eax, 1) 2053 testl %ecx, %ecx 2054 je 4f 2055 movl rSELF:THREAD_CARD_TABLE_OFFSET, %eax 2056 shrl $$CARD_TABLE_CARD_SHIFT, rINST 2057 movb %al, (%eax, rINST, 1) 20584: 2059 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 20602: 2061 EXPORT_PC 2062 // Fetch the value, needed by nterp_get_instance_field_offset. 2063 movl rINST, %ecx # ecx <- BA 2064 andl $$0xf, %ecx # ecx <- A 2065 GET_VREG ARG3, %ecx # ecx <- v[A] 2066 movl rSELF:THREAD_SELF_OFFSET, ARG0 2067 movl 0(%esp), ARG1 2068 movl rPC, ARG2 2069 call nterp_get_instance_field_offset 2070 testl %eax, %eax 2071 jns 1b 2072 negl %eax 2073 // Reload the value as it may have moved. 2074 movl rINST, %ecx # ecx <- BA 2075 andl $$0xf, %ecx # ecx <- A 2076 GET_VREG %ecx, %ecx # ecx <- v[A] 2077 sarl $$4, rINST 2078 GET_VREG rINST, rINST # vB (object we're operating on) 2079 testl rINST, rINST # is object null? 2080 je common_errNullObject 2081 movl %ecx, (rINST, %eax, 1) 2082 testl %ecx, %ecx 2083 je 5f 2084 movl rSELF:THREAD_CARD_TABLE_OFFSET, %eax 2085 shrl $$CARD_TABLE_CARD_SHIFT, rINST 2086 movb %al, (%eax, rINST, 1) 20875: 2088 lock addl $$0, (%esp) 2089 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 2090 2091NterpGetObjectInstanceField: 2092 // Fast-path which gets the field from thread-local cache. 2093% fetch_from_thread_cache("%eax", miss_label="2f") 20941: 2095 movl rINST, %ecx # ecx <- BA 2096 sarl $$4, %ecx # ecx <- B 2097 GET_VREG %ecx, %ecx # vB (object we're operating on) 2098 testl %ecx, %ecx # is object null? 2099 je common_errNullObject 2100 testb $$READ_BARRIER_TEST_VALUE, GRAY_BYTE_OFFSET(%ecx) 2101 movl (%ecx,%eax,1), %eax 2102 jnz 3f 21034: 2104 andb $$0xf,rINSTbl # rINST <- A 2105 SET_VREG_OBJECT %eax, rINST # fp[A] <- value 2106 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 21072: 2108 EXPORT_PC 2109 movl rSELF:THREAD_SELF_OFFSET, ARG0 2110 movl 0(%esp), ARG1 2111 movl rPC, ARG2 2112 movl $$0, ARG3 2113 call nterp_get_instance_field_offset 2114 testl %eax, %eax 2115 jns 1b 2116 // For volatile fields, we return a negative offset. Remove the sign 2117 // and no need for any barrier thanks to the memory model. 2118 negl %eax 2119 jmp 1b 21203: 2121 // reg00 is eax 2122 call art_quick_read_barrier_mark_reg00 2123 jmp 4b 2124 2125NterpPutObjectStaticField: 2126 GET_VREG rINST, rINST 2127 // Fast-path which gets the field from thread-local cache. 2128% fetch_from_thread_cache("%eax", miss_label="2f") 21291: 2130 movl ART_FIELD_OFFSET_OFFSET(%eax), %ecx 2131 movl ART_FIELD_DECLARING_CLASS_OFFSET(%eax), %eax 2132 cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 2133 jne 3f 21345: 2135 movl rINST, (%eax, %ecx, 1) 2136 testl rINST, rINST 2137 je 4f 2138 movl rSELF:THREAD_CARD_TABLE_OFFSET, %ecx 2139 shrl $$CARD_TABLE_CARD_SHIFT, %eax 2140 movb %cl, (%ecx, %eax, 1) 21414: 2142 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 21432: 2144 EXPORT_PC 2145 movl rSELF:THREAD_SELF_OFFSET, ARG0 2146 movl 0(%esp), ARG1 2147 movl rPC, ARG2 2148 movl rINST, ARG3 2149 call nterp_get_static_field 2150 // Reload the value as it may have moved. 2151 GET_VREG rINST, rINST 2152 testl MACRO_LITERAL(1), %eax 2153 je 1b 2154 CLEAR_VOLATILE_MARKER %eax 2155 movl ART_FIELD_OFFSET_OFFSET(%eax), %ecx 2156 movl ART_FIELD_DECLARING_CLASS_OFFSET(%eax), %eax 2157 cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 2158 jne 7f 21596: 2160 movl rINST, (%eax, %ecx, 1) 2161 testl rINST, rINST 2162 je 8f 2163 movl rSELF:THREAD_CARD_TABLE_OFFSET, %ecx 2164 shrl $$CARD_TABLE_CARD_SHIFT, %eax 2165 movb %cl, (%ecx, %eax, 1) 21668: 2167 lock addl $$0, (%esp) 2168 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 21693: 2170 call art_quick_read_barrier_mark_reg00 2171 jmp 5b 21727: 2173 call art_quick_read_barrier_mark_reg00 2174 jmp 6b 2175 2176NterpGetObjectStaticField: 2177 // Fast-path which gets the field from thread-local cache. 2178% fetch_from_thread_cache("%eax", miss_label="2f") 21791: 2180 movl ART_FIELD_OFFSET_OFFSET(%eax), %ecx 2181 movl ART_FIELD_DECLARING_CLASS_OFFSET(%eax), %eax 2182 cmpl $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET 2183 jne 5f 21846: 2185 testb $$READ_BARRIER_TEST_VALUE, GRAY_BYTE_OFFSET(%eax) 2186 movl (%eax, %ecx, 1), %eax 2187 jnz 3f 21884: 2189 SET_VREG_OBJECT %eax, rINST # fp[A] <- value 2190 ADVANCE_PC_FETCH_AND_GOTO_NEXT 2 21912: 2192 EXPORT_PC 2193 movl rSELF:THREAD_SELF_OFFSET, ARG0 2194 movl 0(%esp), ARG1 2195 movl rPC, ARG2 2196 movl $$0, ARG3 2197 call nterp_get_static_field 2198 CLEAR_VOLATILE_MARKER %eax 2199 jmp 1b 22003: 2201 call art_quick_read_barrier_mark_reg00 2202 jmp 4b 22035: 2204 call art_quick_read_barrier_mark_reg00 2205 jmp 6b 2206 2207NterpGetBooleanStaticField: 2208 OP_SGET load="movzbl", wide=0 2209 2210NterpGetByteStaticField: 2211 OP_SGET load="movsbl", wide=0 2212 2213NterpGetCharStaticField: 2214 OP_SGET load="movzwl", wide=0 2215 2216NterpGetShortStaticField: 2217 OP_SGET load="movswl", wide=0 2218 2219NterpGetWideStaticField: 2220 OP_SGET load="movl", wide=1 2221 2222NterpGetIntStaticField: 2223 OP_SGET load="movl", wide=0 2224 2225NterpPutStaticField: 2226 OP_SPUT rINST_reg=rINST, store="movl", wide=0 2227 2228NterpPutBooleanStaticField: 2229NterpPutByteStaticField: 2230 OP_SPUT rINST_reg=rINSTbl, store="movb", wide=0 2231 2232NterpPutCharStaticField: 2233NterpPutShortStaticField: 2234 OP_SPUT rINST_reg=rINSTw, store="movw", wide=0 2235 2236NterpPutWideStaticField: 2237 OP_SPUT rINST_reg=rINST, store="movl", wide=1 2238 2239NterpPutInstanceField: 2240 OP_IPUT rINST_reg=rINST, store="movl", wide=0 2241 2242NterpPutBooleanInstanceField: 2243NterpPutByteInstanceField: 2244 OP_IPUT rINST_reg=rINSTbl, store="movb", wide=0 2245 2246NterpPutCharInstanceField: 2247NterpPutShortInstanceField: 2248 OP_IPUT rINST_reg=rINSTw, store="movw", wide=0 2249 2250NterpPutWideInstanceField: 2251 OP_IPUT rINST_reg=rINST, store="movl", wide=1 2252 2253NterpGetBooleanInstanceField: 2254 OP_IGET load="movzbl", wide=0 2255 2256NterpGetByteInstanceField: 2257 OP_IGET load="movsbl", wide=0 2258 2259NterpGetCharInstanceField: 2260 OP_IGET load="movzwl", wide=0 2261 2262NterpGetShortInstanceField: 2263 OP_IGET load="movswl", wide=0 2264 2265NterpGetWideInstanceField: 2266 OP_IGET load="movl", wide=1 2267 2268NterpGetInstanceField: 2269 OP_IGET load="movl", wide=0 2270 2271NterpCallSuspendAndGotoNext: 2272 EXPORT_PC 2273 // Save branch offset. 2274 movl rINST, LOCAL0(%esp) 2275 call SYMBOL(art_quick_test_suspend) 2276 RESTORE_IBASE 2277 movl LOCAL0(%esp), rINST 2278 FETCH_INST 2279 GOTO_NEXT 2280 2281NterpHandleHotnessOverflow: 2282 CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot=1f, if_not_hot=4f 22831: 2284 movl rPC, %ecx 2285 movl rFP, ARG2 2286 // Save next PC. 2287 movl %ecx, LOCAL0(%esp) 2288 call nterp_hot_method 2289 testl %eax, %eax 2290 jne 3f 2291 // Fetch next PC. 2292 mov LOCAL0(%esp), rPC 22932: 2294 FETCH_INST 2295 GOTO_NEXT 22963: 2297 // Drop the current frame. 2298 movl -4(rREFS), %esp 2299 CFI_DEF_CFA(esp, PARAMETERS_SAVES_SIZE+CALLEE_SAVES_SIZE) 2300 DROP_PARAMETERS_SAVES 2301 CFI_DEF_CFA(esp, CALLEE_SAVES_SIZE) 2302 2303 // Setup the new frame 2304 movl OSR_DATA_FRAME_SIZE(%eax), %ecx 2305 // Given stack size contains all callee saved registers, remove them. 2306 subl $$CALLEE_SAVES_SIZE, %ecx 2307 2308 // Remember CFA. 2309 movl %esp, %ebp 2310 CFI_DEF_CFA_REGISTER(ebp) 2311 2312 subl %ecx, %esp 2313 movl %esp, %edi // edi := beginning of stack 2314 leal OSR_DATA_MEMORY(%eax), %esi // esi := memory to copy 2315 rep movsb // while (ecx--) { *edi++ = *esi++ } 2316 2317 // Fetch the native PC to jump to and save it in stack. 2318 pushl OSR_DATA_NATIVE_PC(%eax) 2319 CFI_ADJUST_CFA_OFFSET(4) 2320 2321 subl MACRO_LITERAL(8), %esp 2322 CFI_ADJUST_CFA_OFFSET(8) 2323 pushl %eax 2324 CFI_ADJUST_CFA_OFFSET(4) 2325 // Free the memory holding OSR Data. 2326 call SYMBOL(NterpFree) 2327 addl MACRO_LITERAL(12), %esp 2328 CFI_ADJUST_CFA_OFFSET(-12) 2329 2330 // Jump to the compiled code. 2331 ret 23324: 2333 DO_SUSPEND_CHECK continue_label=2b 2334 2335 2336NterpHandleInvokeInterfaceOnObjectMethodRange: 2337 shrl $$16, %eax 2338 movl MIRROR_CLASS_VTABLE_OFFSET_32(%edx, %eax, 4), %eax 2339 jmp NterpCommonInvokeInstanceRange 2340 2341NterpHandleInvokeInterfaceOnObjectMethod: 2342 shrl $$16, %eax 2343 movl MIRROR_CLASS_VTABLE_OFFSET_32(%edx, %eax, 4), %eax 2344 jmp NterpCommonInvokeInstance 2345 2346// This is the logical end of ExecuteNterpImpl, where the frame info applies. 2347// EndExecuteNterpImpl includes the methods below as we want the runtime to 2348// see them as part of the Nterp PCs. 2349.cfi_endproc 2350 2351END nterp_helper 2352 2353// This is the end of PCs contained by the OatQuickMethodHeader created for the interpreter 2354// entry point. 2355 FUNCTION_TYPE(EndExecuteNterpImpl) 2356 ASM_HIDDEN SYMBOL(EndExecuteNterpImpl) 2357 .global SYMBOL(EndExecuteNterpImpl) 2358SYMBOL(EndExecuteNterpImpl): 2359 2360// Entrypoints into runtime. 2361NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField 2362NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset 2363NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray 2364NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange 2365NTERP_TRAMPOLINE nterp_get_class, NterpGetClass 2366NTERP_TRAMPOLINE nterp_allocate_object, NterpAllocateObject 2367NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod 2368NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod 2369NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject 2370 2371DEFINE_FUNCTION nterp_deliver_pending_exception 2372 DELIVER_PENDING_EXCEPTION 2373END_FUNCTION nterp_deliver_pending_exception 2374 2375// gen_mterp.py will inline the following definitions 2376// within [ExecuteNterpImpl, EndExecuteNterpImpl). 2377%def instruction_end(): 2378 2379 FUNCTION_TYPE(artNterpAsmInstructionEnd) 2380 ASM_HIDDEN SYMBOL(artNterpAsmInstructionEnd) 2381 .global SYMBOL(artNterpAsmInstructionEnd) 2382SYMBOL(artNterpAsmInstructionEnd): 2383 // artNterpAsmInstructionEnd is used as landing pad for exception handling. 2384 RESTORE_IBASE 2385 FETCH_INST 2386 GOTO_NEXT 2387 2388%def instruction_start(): 2389 2390 FUNCTION_TYPE(artNterpAsmInstructionStart) 2391 ASM_HIDDEN SYMBOL(artNterpAsmInstructionStart) 2392 .global SYMBOL(artNterpAsmInstructionStart) 2393SYMBOL(artNterpAsmInstructionStart) = .L_op_nop 2394 .text 2395 2396%def opcode_name_prefix(): 2397% return "nterp_" 2398%def opcode_start(): 2399 ENTRY nterp_${opcode} 2400%def opcode_end(): 2401 END nterp_${opcode} 2402 // Advance to the end of this handler. Causes error if we are past that point. 2403 .org nterp_${opcode} + NTERP_HANDLER_SIZE // ${opcode} handler is too big! 2404%def opcode_slow_path_start(name): 2405 ENTRY ${name} 2406%def opcode_slow_path_end(name): 2407 END ${name} 2408