1/** 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "arch/asm_support.h" 17#include "arch/amd64/shorty.S" 18#include "shorty_values.h" 19 20#define SHORTY_PTR_REG DEFAULT_SHORTY_PTR_REG 21#define SHORTY_REG DEFAULT_SHORTY_REG 22 23.macro LOAD_GPR_ARGS begin_ptr 24 // load arguments into %rdi, %rsi, %rdx, %rcx, %r8, %r9 25 movq (0 * 8)(\begin_ptr), %rdi 26 movq (1 * 8)(\begin_ptr), %rsi 27 movq (2 * 8)(\begin_ptr), %rdx 28 movq (3 * 8)(\begin_ptr), %rcx 29 movq (4 * 8)(\begin_ptr), %r8 30 movq (5 * 8)(\begin_ptr), %r9 31.endm 32 33.macro LOAD_FPR_ARGS begin_ptr 34 // load arguments into xmm0-xmm7 35 movq -(1 * 8)(\begin_ptr), %xmm0 36 movq -(2 * 8)(\begin_ptr), %xmm1 37 movq -(3 * 8)(\begin_ptr), %xmm2 38 movq -(4 * 8)(\begin_ptr), %xmm3 39 movq -(5 * 8)(\begin_ptr), %xmm4 40 movq -(6 * 8)(\begin_ptr), %xmm5 41 movq -(7 * 8)(\begin_ptr), %xmm6 42 movq -(8 * 8)(\begin_ptr), %xmm7 43.endm 44 45// The macro works with the stack prepared by 'PrepareArgStack' macro 46// It takes an argument in arg_reg and stores it to the corresponding stack space 47// depends on its type. 48// After the arg gets stored the macro advances the corresponding pointer 49// The macro assumes %r8 contains base address for gpr and fpr args 50.macro PUSH_ARG arg_reg, tag_reg, gpr_ptr, fpr_ptr, stack_ptr, tmp_reg, next_label 51 subl $SHORTY_FIRST_FLOAT, %r11d 52 cmpl $(SHORTY_NUM_FLOAT_TYPES - 1), %r11d 53 jbe 1f 54 55 // it is an integer arg 56 57#ifdef PANDA_USE_32_BIT_POINTER 58 // if arg is a reference, zero out garbage in upper 32 bits 59 cmpl $(SHORTY_REFERENCE - SHORTY_FIRST_FLOAT), %r11d 60 jne 4f 61 shlq $32, \arg_reg 62 shrq $32, \arg_reg 634: 64#endif 65 66 // determine whether there are free gprs 67 movq \gpr_ptr, \tmp_reg 68 subq %r8, \tmp_reg 69 cmpq $48, \tmp_reg 70 jge 2f 71 72 //there are free gprs 73 movq \arg_reg, (\gpr_ptr) 74 addq $8, \gpr_ptr 75 // check if the arg has type 'any' 76 cmpl $(SHORTY_TAGGED - SHORTY_FIRST_FLOAT), %r11d 77 jne \next_label 78 // value of type 'any' 79 // store the tag if there are free gprs 80 cmpq $40, \tmp_reg 81 jge 3f 82 movq \tag_reg, (\gpr_ptr) 83 addq $8, \gpr_ptr 84 jmp \next_label 853: // store the tag to the stack 86 movq \tag_reg, (\stack_ptr) 87 addq $8, \stack_ptr 88 jmp \next_label 89 901: 91 // it is a float arg 92 // determine whether there are free float regs 93 movq %r8, \tmp_reg 94 subq \fpr_ptr, \tmp_reg 95 cmpq $64, \tmp_reg 96 jge 2f 97 98 // there are free float regs 99 subq $8, \fpr_ptr 100 movq \arg_reg, (\fpr_ptr) 101 jmp \next_label 1022: 103 // there are no free regs. It is a stack arg 104 movq \arg_reg, (\stack_ptr) 105 addq $8, \stack_ptr 106 // check if the arg has type 'any' 107 cmpl $(SHORTY_TAGGED - SHORTY_FIRST_FLOAT), %r11d 108 jne \next_label 109 movq \tag_reg, (\stack_ptr) 110 addq $8, \stack_ptr 111.endm 112 113// The macro reserves stack space for arguments 114// The reserved stack space is divided into 3 part: 115// 1. the part for arguments passed via the stack 116// 2. the part for the arguments passed via GPRs 117// 3. the part for the arguments passed via the float registers 118// These parts are located as follow: 119// +--------------+ 120// | fpreg argN | 121// +--------------+ 122// | ... | 123// +--------------+ 124// | fpreg arg0 | 125// +--------------+ <- %r8 (base) 126// | gpr arg0 | 127// +--------------+ 128// | ... | 129// +--------------+ 130// | gpr argN | 131// +--------------+ <- %rsp 132// | stack arg0 | 133// +--------------+ 134// | ... | 135// +--------------+ 136// | stack argN | 137// +--------------+ 138// | callee | 139// +--------------+ 140// | THREAD_REG | 141// +--------------+ 142// | %rbp | 143// +--------------+ 144// | INTERPRETER_ | 145// | TO_COMPILED_ | 146// | CODE_BRIDGE | 147// +--------------+ <- %rbp 148// | iframe | 149// +--------------+ 150// | return addr | 151// +--------------+ 152// Input: 153// %rax - SHORTY_PTR_REG 154// %r10d - SHORTY_REG 155// %r11d - shorty value 156// Output (as on the picture) 157// %r8 - gpr base pointer. Points to the beginning of GPR and FPR args space. 158// %rsp - Points to the last stack argument. 159.macro PREPARE_ARG_STACK 160 // %rax - SHORTY_PTR_REG, %r10d - SHORTY_REG, %r11d - shorty value, %esi - GPR arg counter, 161 // %edi - float arg counter, %rdx - stack pointer, %r9 - temp 162 movl $1, %esi // Method* 163 xorl %edi, %edi 164 movq %rsp, %rdx 165 16630: 167 NEXT_SHORTY %r11d 168 cmpl $0, %r11d 169 je 40f 170 171 subl $SHORTY_FIRST_FLOAT, %r11d 172 cmpl $(SHORTY_NUM_FLOAT_TYPES - 1), %r11d 173 jbe 10f 174 175 // it is an integer value 176 xorq %r9, %r9 177 cmpl $(SHORTY_TAGGED - SHORTY_FIRST_FLOAT), %r11d 178 sete %r9b 179 addl $1, %r9d 180 addl %r9d, %esi 181 182 cmpl $6, %esi 183 jle 30b // there are free GPRs 184 185 // there is no GPRs. Adjust %esi and reserve space on the stack 186 movq %rsi, %r9 187 subq $6, %r9 188 movl $6, %esi 189 shlq $3, %r9 190 subq %r9, %rdx 191 jmp 30b 192 19310: 194 // it is a float value 195 cmpl $7, %edi 196 ja 20f 197 198 // there are free float registers 199 addl $1, %edi 200 jmp 30b 201 20220: 203 // there is no more GP registers 204 subq $8, %rdx 205 jmp 30b 206 20740: 208 // make %rsp 16 bytes aligned 209 andq $-16, %rdx 210 // reserve stack space for stack arguments 211 movq %rdx, %rsp 212 213 // reserve gpr space (6 regs) 214 leaq -(6 * 8)(%rsp), %r8 215.endm 216 217// void InterpreterToCompiledCodeBridge(const BytecodeInstruction* insn, const Frame *iframe, const Method *method, ManagedThread* thread) 218.global InterpreterToCompiledCodeBridge 219TYPE_FUNCTION(InterpreterToCompiledCodeBridge) 220InterpreterToCompiledCodeBridge: 221 CFI_STARTPROC 222 CFI_DEF_CFA(rsp, 8) 223 224 pushq %rsi // iframe* 225 CFI_ADJUST_CFA_OFFSET(8) 226 227 movq %rsp, %rax 228 CFI_DEF_CFA_REGISTER(rax) 229 230 // According to the current frame kind set the bridge type 231 movb MANAGED_THREAD_FRAME_KIND_OFFSET(%rcx), %r10b 232 testb %r10b, %r10b 233 movq $INTERPRETER_TO_COMPILED_CODE_BRIDGE, %r11 234 movq $BYPASS_BRIDGE, %r10 235 cmovne %r10, %r11 236 pushq %r11 237 238 pushq %rbp 239 CFI_REL_OFFSET(rbp, -(2 * 8)) 240 241 movq %rax, %rbp // set frame pointer 242 CFI_DEF_CFA_REGISTER(rbp) 243 244 pushq %THREAD_REG 245 CFI_REL_OFFSET(THREAD_REG, -(3 * 8)) 246 pushq %r14 247 CFI_REL_OFFSET(r14, -(4 * 8)) 248 pushq %r13 249 CFI_REL_OFFSET(r13, -(5 * 8)) 250 pushq %r12 251 CFI_REL_OFFSET(r12, -(6 * 8)) 252 pushq %rbx 253 CFI_REL_OFFSET(rbx, -(7 * 8)) 254 255 pushq %rcx // thread* 256 subq $16, %rsp // do not delete, used to copy args 257 // %rsp should be 16-byte aligned here 258 259 // setup regs as follow 260 // %rax - SHORTY_PTR_REG, %r10d - SHORTY_REG, %r11d - shorty value, %rbx - insn_ptr, 261 // %r9 - temp (used by PREPARE_ARG_STACK), %r12 - frame.vregs, %r13 - method, %r14 - method.shorty 262 movq %rdi, %rbx // insn* 263 leaq FRAME_VREGS_OFFSET(%rsi), %r12 // frame.vregs 264 movq %rdx, %r13 // method 265 movq METHOD_SHORTY_OFFSET(%rdx), %r14 // method.shorty 266 267 movq %r14, %SHORTY_PTR_REG 268 INIT_SHORTY_REG 269 270 // parameter 'this' of instance methods is not encoded in the shorty 271 // in case of instance method hack SHORTY_REG by replacing the return type by REF 272 // in the another case just skip the return type 273 movl METHOD_ACCESS_FLAGS_OFFSET(%r13), %ecx 274 testl $ACCESS_STATIC, %ecx 275 jne 1f 276 277 // it is an instance method 278 andl $-16, %SHORTY_REG // clear the least significant 4 bits 279 orl $SHORTY_REFERENCE, %SHORTY_REG 280 jmp 2f 281 2821: 283 SKIP_SHORTY 2842: 285 movl %SHORTY_REG, %r15d // save value of the shorty reg 286 PREPARE_ARG_STACK 287 288 // setup regs as follow 289 // %rax - SHORTY_PTR_REG, %r10d - SHORTY_REG, %r11d - shorty value, %rsi - stack arg ptr, 290 // %rdi - float arg ptr, %rbx - insn_ptr, %r12 - frame.vregs, %r8 - arg base ptr 291 // %rdx - gpr arg ptr, %rcx, %r9 - temps, %r14 - method.shorty 292 movq %rsp, %rsi 293 movq %r8, %rdi 294 movq %r8, %rdx 295 leaq 2(%r14), %SHORTY_PTR_REG // since SHORTY_REG contains already read value SHORTY_REG_PTR should be shifted 296 movl %r15d, %SHORTY_REG // restore the value of the shorty reg 297 298 // store method (the first arg) 299 movq %r13, (%rdx) 300 addq $8, %rdx 301 movzbl (%rbx), %ecx 302 addq $1, %rbx // read opcode and advance insn_ptr 303 304 // The file contains code which checks opcode and jumps 305 // to the corresponding handler. 306 // At the end each handler jumps to .Lload_reg_args label. 307 // The file is autogenerated from runtime/templates/bridge_dispatch.S.erb 308 // Handlers are distinguished by format and located in the corresponding files with name: 309 // handle_call_<format>.S 310 // If you get a compilation error that there is no such file it seems 311 // new call format was introduced and you have to implement the corresponding handler. 312#include "bridge_dispatch_amd64.S" 313 314.Lload_reg_args: 315 movq %r8, %rax 316 LOAD_FPR_ARGS %rax 317 LOAD_GPR_ARGS %rax 318 319 // invoke the method 320 // since the first argument is Method* it must be in %rdi 321 movq METHOD_COMPILED_ENTRY_POINT_OFFSET(%rdi), %rax 322 movq -64(%rbp), %THREAD_REG 323 callq *%rax 324 325 // handle the result 326 // setup registers as follow 327 // %rax, %rdx / %xmm0 - result, %r14d - shorty[0] & 0xF, %r12 - frame.acc, %rcx - temp 328 movzbl (%r14), %r14d 329 andl $0xF, %r14d 330 331 cmpl $SHORTY_VOID, %r14d 332 je .Lreturn 333 334 movq (%rbp), %r12 // load iframe from the stack 335 addq $FRAME_ACC_OFFSET, %r12 336 337 // get tag in rdx 338 cmpl $SHORTY_TAGGED, %r14d 339 je 1f // tag already in rdx 340 xorq %rdx, %rdx 341 cmpl $SHORTY_REFERENCE, %r14d 342 sete %dl 3431: // store tag 344 movq %rdx, FRAME_ACC_MIRROR_OFFSET(%r12) 345 346 movl %r14d, %esi 347 movl %r14d, %edi 348 349 subl $SHORTY_FIRST_FLOAT, %r14d 350 cmpl $(SHORTY_NUM_FLOAT_TYPES - 1), %r14d 351 jbe 1f // float 352 353 subl $(SHORTY_FIRST_32), %esi 354 cmpl $(SHORTY_NUM_MIN32_TYPES - 1), %esi 355 jbe .L64_32 // 64-bit int / ref or 32-bit int 356 357 // less than 32-bit 358 cmpl $SHORTY_I16, %edi 359 je .LI16 360 ja .LU16 361 362 cmpl $SHORTY_I8, %edi 363 je .LI8 364 jne .LU1_U8 365 3661: 367 // store float value into acc 368 movsd %xmm0, (%r12) 369 jmp .Lreturn 370.LU1_U8: 371 movzbl %al, %eax 372 jmp .L64_32 373.LI8: 374 movsbl %al, %eax 375 jmp .L64_32 376.LI16: 377 movswl %ax, %eax 378 jmp .L64_32 379.LU16: 380 movzwl %ax, %eax 381.L64_32: 382 // store integer value into acc 383 movq %rax, (%r12) 384 385.Lreturn: 386 leaq -56(%rbp), %rsp 387 popq %rbx 388 CFI_RESTORE(rbx) 389 popq %r12 390 CFI_RESTORE(r12) 391 popq %r13 392 CFI_RESTORE(r13) 393 popq %r14 394 CFI_RESTORE(r14) 395 popq %THREAD_REG 396 CFI_RESTORE(THREAD_REG) 397 popq %rbp 398 CFI_RESTORE(rbp) 399 CFI_DEF_CFA(rsp, (3 * 8)) 400 addq $16, %rsp 401 CFI_ADJUST_CFA_OFFSET(-(2 * 8)) 402 retq 403 CFI_ENDPROC 404 405// uint64_t InvokeCompiledCodeWithArguments(const int64_t* args, const Frame *iframe, const Method *method, ManagedThread* thread) 406.global InvokeCompiledCodeWithArgArray 407TYPE_FUNCTION(InvokeCompiledCodeWithArgArray) 408InvokeCompiledCodeWithArgArray: 409 CFI_STARTPROC 410 CFI_DEF_CFA(rsp, 8) 411 412 pushq %rsi // iframe* 413 CFI_ADJUST_CFA_OFFSET(8) 414 415 movq %rsp, %rax 416 CFI_DEF_CFA_REGISTER(rax) 417 418 // According to the current frame kind set the bridge type 419 movb MANAGED_THREAD_FRAME_KIND_OFFSET(%rcx), %r10b 420 testb %r10b, %r10b 421 movq $INTERPRETER_TO_COMPILED_CODE_BRIDGE, %r11 422 movq $BYPASS_BRIDGE, %r10 423 cmovne %r10, %r11 424 pushq %r11 425 426 pushq %rbp 427 CFI_REL_OFFSET(rbp, -(2 * 8)) 428 429 movq %rax, %rbp // set frame pointer 430 CFI_DEF_CFA_REGISTER(rbp) 431 432 pushq %THREAD_REG 433 CFI_REL_OFFSET(THREAD_REG, -(3 * 8)) 434 pushq %r14 435 CFI_REL_OFFSET(r14, -(4 * 8)) 436 pushq %r13 437 CFI_REL_OFFSET(r13, -(5 * 8)) 438 pushq %r12 439 CFI_REL_OFFSET(r12, -(6 * 8)) 440 pushq %rbx 441 CFI_REL_OFFSET(rbx, -(7 * 8)) 442 443 pushq %rcx // thread* 444 subq $16, %rsp // do not delete, used to copy args 445 // %rsp should be 16-byte aligned here 446 447 // store method.shorty_ to %r14 448 movq %rdx, %r13 // method 449 movq METHOD_SHORTY_OFFSET(%rdx), %r14 // method.shorty 450 451 // check args array 452 // it could be null in case the method has no args 453 cmpq $0, %rdi 454 jne 1f 455 456 movq %r13, %rdi 457 jmp .Linvoke_with_args 458 4591: 460 // setup regs as follow 461 // %rax - SHORTY_PTR_REG, %r10d - SHORTY_REG, %r11d - shorty value, %rbx - arg_ptr 462 // %r13 - method, %r14 - method.shorty 463 movq %rdi, %rbx 464 movq %r14, %SHORTY_PTR_REG 465 INIT_SHORTY_REG 466 467 // parameter 'this' of instance methods is not encoded in the shorty 468 // in case of instance method hack SHORTY_REG by replacing the return type by REF 469 // in the another case just skip the return type 470 movl METHOD_ACCESS_FLAGS_OFFSET(%r13), %ecx 471 testl $ACCESS_STATIC, %ecx 472 jne 1f 473 474 // it is an instance method 475 andl $-16, %SHORTY_REG 476 orl $SHORTY_REFERENCE, %SHORTY_REG 477 jmp 2f 478 4791: 480 SKIP_SHORTY 4812: 482 movl %SHORTY_REG, %r15d // save value of the shorty reg 483 PREPARE_ARG_STACK 484 485 // setup regs as follow 486 // %rax - SHORTY_PTR_REG, %r10d - SHORTY_REG, %r11d - shorty value, %rsi - stack arg ptr, 487 // %rdi - float arg ptr, %rbx - arg_ptr, %r8 - arg base ptr, %rdx - gpr arg ptr, 488 // %rcx, %r9 - temps, %r14 - method.shorty, %r13 - method 489 movq %rsp, %rsi 490 movq %r8, %rdi 491 movq %r8, %rdx 492 leaq 2(%r14), %SHORTY_PTR_REG // since SHORTY_REG contains already read value SHORTY_REG_PTR should be shifted 493 movl %r15d, %SHORTY_REG // restore the value of the shorty reg 494 495 // store method (the last arg) 496 movq %r13, (%rdx) 497 addq $8, %rdx 498 499.Lloop_args_push: 500 NEXT_SHORTY %r11d 501 cmpl $0, %r11d 502 je .Lloopend_args_push 503 504 movq (%rbx), %rcx 505 addq $8, %rbx 506 cmpl $SHORTY_TAGGED, %r11d 507 jne 1f 508 // Load the tag 509 movq (%rbx), %r13 510 addq $8, %rbx 511 5121: PUSH_ARG %rcx, %r13, %rdx, %rdi, %rsi, %r9, .Lloop_args_push 513 jmp .Lloop_args_push 514.Lloopend_args_push: 515 // load arguments into regs 516 movq %r8, %rax 517 LOAD_FPR_ARGS %rax 518 LOAD_GPR_ARGS %rax 519 520.Linvoke_with_args: 521 // invoke the method 522 // since the first argument is Method* it must be in %rdi 523 movq METHOD_COMPILED_ENTRY_POINT_OFFSET(%rdi), %rax 524 movq -64(%rbp), %THREAD_REG 525 callq *%rax 526 527 // handle the result 528 // we should return it in %rax 529 // setup registers as follow 530 // %rax / %xmm0 - result, %r14d - shorty[0] & 0xF 531 movzbl (%r14), %r14d 532 andl $0xF, %r14d 533 534 cmpl $SHORTY_VOID, %r14d 535 je .Lreturn_ 536 537 movl %r14d, %esi 538 movl %r14d, %edi 539 540 subl $SHORTY_FIRST_FLOAT, %r14d 541 cmpl $(SHORTY_NUM_FLOAT_TYPES - 1), %r14d 542 jbe 1f 543 544 subl $(SHORTY_FIRST_32), %esi 545 cmpl $(SHORTY_NUM_MIN32_TYPES - 1), %esi 546 jbe .Lreturn_ // 64-bit int / ref or 32-bit int 547 548 // less than 32-bit 549 cmpl $SHORTY_I16, %edi 550 je .LI16_ 551 ja .LU16_ 552 553 cmpl $SHORTY_I8, %edi 554 je .LI8_ 555 jne .LU1_U8_ 556 5571: 558 movq %xmm0, %rax 559 jmp .Lreturn_ 560.LU1_U8_: 561 movzbl %al, %eax 562 jmp .Lreturn_ 563.LI8_: 564 movsbl %al, %eax 565 jmp .Lreturn_ 566.LI16_: 567 movswl %ax, %eax 568 jmp .Lreturn_ 569.LU16_: 570 movzwl %ax, %eax 571 572.Lreturn_: 573 leaq -56(%rbp), %rsp 574 popq %rbx 575 CFI_RESTORE(rbx) 576 popq %r12 577 CFI_RESTORE(r12) 578 popq %r13 579 CFI_RESTORE(r13) 580 popq %r14 581 CFI_RESTORE(r14) 582 popq %THREAD_REG 583 CFI_RESTORE(THREAD_REG) 584 popq %rbp 585 CFI_RESTORE(rbp) 586 CFI_DEF_CFA(rsp, (3 * 8)) 587 addq $16, %rsp 588 CFI_ADJUST_CFA_OFFSET(-(2 * 8)) 589 retq 590 CFI_ENDPROC 591 592