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/arm/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, end_ptr 24 // load arguments into r0-r4 while begin_ptr != end_ptr 25 ldr r0, [\begin_ptr, #-4]! 26 cmp \begin_ptr, \end_ptr 27 beq 1f 28 ldr r1, [\begin_ptr, #-4]! 29 cmp \begin_ptr, \end_ptr 30 beq 1f 31 ldr r2, [\begin_ptr, #-4]! 32 cmp \begin_ptr, \end_ptr 33 beq 1f 34 ldr r3, [\begin_ptr, #-4]! 351: // end 36.endm 37 38.macro LOAD_FPR_ARGS begin_ptr, end_ptr 39 // load arguments into d0-d7 while \begin_ptr != \end_ptr 40 cmp \begin_ptr, \end_ptr 41 beq 1f 42 vldmia \begin_ptr!, {d0} 43 cmp \begin_ptr, \end_ptr 44 beq 1f 45 vldmia \begin_ptr!, {d1} 46 cmp \begin_ptr, \end_ptr 47 beq 1f 48 vldmia \begin_ptr!, {d2} 49 cmp \begin_ptr, \end_ptr 50 beq 1f 51 vldmia \begin_ptr!, {d3} 52 cmp \begin_ptr, \end_ptr 53 beq 1f 54 vldmia \begin_ptr!, {d4} 55 cmp \begin_ptr, \end_ptr 56 beq 1f 57 vldmia \begin_ptr!, {d5} 58 cmp \begin_ptr, \end_ptr 59 beq 1f 60 vldmia \begin_ptr!, {d6} 61 cmp \begin_ptr, \end_ptr 62 beq 1f 63 vldmia \begin_ptr!, {d7} 641: 65.endm 66 67// The macro works with the stack prepared by 'PrepareArgStack' procedure 68// It takes an argument in arg_reg and stores it to the corresponding stack space 69// depends on its type. 70// After the arg gets storeg the macro advances the corresponding pointer 71// The macro assumes x9 contains base address for gpr and fpr args 72 73.macro PUSH_ARG arg_ptr, gpr_ptr, fpr_ptr, stack_ptr, tmp1, tmp2, next_label 74 cmp r2, #SHORTY_TAGGED 75 beq 4f 76 77 cmp r2, #SHORTY_REFERENCE 78 cmpne r2, #SHORTY_LAST_INT32 79 bhi 1f 80 // it is a 32bit int or reference 81 ldr \tmp1, [\arg_ptr] 82 // determine whether there are free gprs 83 sub \tmp2, r4, \gpr_ptr 84 cmp \tmp2, #16 85 strlt \tmp1, [\gpr_ptr, #-4]! 86 strge \tmp1, [\stack_ptr], #4 87 b \next_label 88 891: cmp r2, #SHORTY_F32 90 beq 21f 91 cmp r2, #SHORTY_F64 92 beq 22f 93 // it is a 64bit int 94 // align 95 bic \gpr_ptr, \gpr_ptr, #7 96 // determine whether there are free gprs 97 sub \tmp1, r4, \gpr_ptr 98 cmp \tmp1, #16 99 ldm \arg_ptr, {\tmp1, \tmp2} 100 sub \gpr_ptr, \gpr_ptr, #8 101 // store tmp1 and tmp2 in the reverse order 102 // in this order they will be read from the stack 103 str \tmp2, [\gpr_ptr] 104 str \tmp1, [\gpr_ptr, #4] 105 blt \next_label 106 bge 3f 107 10821: // it is a float 109 // determine whether there are free fp regs 110 sub \tmp1, \fpr_ptr, r4 111 cmp \tmp1, #64 112 ldr \tmp1, [\arg_ptr] 113 stmlt \fpr_ptr!, {\tmp1} 114 stmge \stack_ptr!, {\tmp1} 115 b \next_label 116 11722: // it is a double 118 // determine whether there are free fp regs 119 add \fpr_ptr, \fpr_ptr, #7 120 bic \fpr_ptr, \fpr_ptr, #7 121 sub \tmp1, \fpr_ptr, r4 122 cmp \tmp1, #64 123 ldm \arg_ptr, {\tmp1, \tmp2} 124 stmlt \fpr_ptr!, {\tmp1, \tmp2} 125 blt \next_label 126 1273: // it is a 8 byte stack arg 128 // align sp 129 add \stack_ptr, \stack_ptr, #7 130 bic \stack_ptr, \stack_ptr, #7 131 stm \stack_ptr!, {\tmp1, \tmp2} 132 b \next_label 133 1344: // it is value of type 'any' 135 // in the code below we cannot overwrite 136 // tmp2 because it is the same register 137 // as arg_ptr 138 // align gpr_ptr to 8byte boundary 139 bic \gpr_ptr, \gpr_ptr, #7 140 // determine whether there are free gprs 141 // at least for the first int64_t 142 sub \tmp1, r4, \gpr_ptr 143 cmp \tmp1, #16 144 ldr \tmp1, [\arg_ptr], #4 145 sub \gpr_ptr, \gpr_ptr, #8 146 blt 5f 147 // there are no free gprs 148 // store value to the stack 149 // align sp 150 add \stack_ptr, \stack_ptr, #7 151 bic \stack_ptr, \stack_ptr, #7 152 str \tmp1, [\stack_ptr], #4 153 ldr \tmp1, [\arg_ptr], #4 154 str \tmp1, [\stack_ptr], #4 155 b 6f 1565: // there are free grps 157 // store value in the reverse order 158 // in this order they will be read from the stack 159 str \tmp1, [\gpr_ptr, #4] 160 ldr \tmp1, [\arg_ptr], #4 161 str \tmp1, [\gpr_ptr] 1626: // copy tag to the stack 163 ldm \arg_ptr, {\tmp1, \tmp2} 164 stm \stack_ptr!, {\tmp1, \tmp2} 165.endm 166 167// The procedure reserves stack space for the arguments 168// The reserved stack space is divided into 3 part: 169// 1. the part for arguments passed via the stack 170// 2. the part for the arguments passed via GPRs 171// 3. the part for the arguments passed via the float registers 172// These parts are located as follow: 173// +--------------+ 174// | gpr argN | 175// +--------------+ 176// | ... | 177// +--------------+ 178// | gpr arg0 | 179// +--------------+ <- r4 (base) 180// | fpreg arg0 | 181// +--------------+ 182// | ... | 183// +--------------+ 184// | fpreg argN | 185// +--------------+ <- sp 186// | stack arg0 | 187// +--------------+ 188// | ... | 189// +--------------+ 190// | stack argN | 191// +--------------+ 192// | r4 | 193// +--------------+ 194// | ... | 195// +--------------+ 196// | r11 | 197// +--------------+ 198// | fp | 199// +--------------+ 200// | INTERPRETER_ | 201// | TO_COMPILED_ | 202// | CODE_BRIDGE | 203// +--------------+ 204// | iframe | 205// +--------------+ <- fp 206// | lr | 207// +--------------+ 208// Input: 209// r0 - SHORTY_PTR_REG 210// r1 - SHORTY_REG 211// r2 - shorty value (no initialization needed) 212// r6 - method 213// Output (as on the picture) 214// r4 - gpr base pointer. Points to the beginning of GPR and FPR args space. 215// sp - Points to the last stack argument. 216PrepareArgStack: 217 // r0 - SHORTY_PTR_REG, r2 - SHORTY_REG, r2 - shorty value, r3 - gpr args counter, 218 // r4 - fpr args counter 219 mov r3, #1 // Method* 220 mov r4, #0 221 222 NEXT_SHORTY r2 223 // handle return type 224 cmp r2, #SHORTY_TAGGED 225 addeq r3, r3, #1 // reserve space for the pointer to the memory where the result will be stored 226 227 // parameter 'this' of instance methods is not encoded in the shorty 228 ldr r2, [r6, #METHOD_ACCESS_FLAGS_OFFSET] 229 tst r2, #ACCESS_STATIC 230 // it is an instance method 231 addeq r3, r3, #1 // reserve space for 'this' 232 233.Lloop_shorty: 234 NEXT_SHORTY r2 235 cmp r2, #0 236 beq .Lexit 237 238 cmp r2, #SHORTY_REFERENCE 239 cmpne r2, #SHORTY_LAST_INT32 240 bhi 1f 241 // it is a 32bit value or reference 242 cmp r3, #4 243 addlt r3, r3, #1 244 subge sp, sp, #4 245 b .Lloop_shorty 246 2471: sub r2, r2, #SHORTY_FIRST_FLOAT 248 cmp r2, #(SHORTY_NUM_FLOAT_TYPES - 1) 249 bls 2f 250 // it is a 64bit integer or 'any' 251 // align 252 add r3, r3, #1 253 bic r3, r3, #1 254 cmp r3, #4 255 addlt r3, r3, #2 256 // align sp 257 bicge sp, sp, #7 258 subge sp, sp, #8 259 cmp r2, #(SHORTY_TAGGED - SHORTY_FIRST_FLOAT) 260 bne .Lloop_shorty 261 // it is 'any' 262 // reserve space for the tag 263 // align sp 264 bic sp, sp, #7 265 sub sp, sp, #8 266 b .Lloop_shorty 267 2682: // it is a float 269 // align 270 cmp r4, #8 271 addlt r4, r4, #1 272 // align sp 273 bicge sp, sp, #7 274 subge sp, sp, #8 275 b .Lloop_shorty 276 277.Lexit: 278 bic sp, sp, #7 // align sp 279 sub r4, sp, r4, lsl #3 280 mov pc, lr 281 282// void InterpreterToCompiledCodeBridge(const BytecodeInstruction* insn, const Frame *iframe, const Method *method, ManagedThread* thread) 283.global InterpreterToCompiledCodeBridge 284.type InterpreterToCompiledCodeBridge, %function 285InterpreterToCompiledCodeBridge: 286 CFI_STARTPROC 287 CFI_DEF_CFA(sp, 0) 288 push {r1, lr} 289 CFI_ADJUST_CFA_OFFSET(8) 290 CFI_REL_OFFSET(lr, 4) 291 sub sp, sp, #8 292 CFI_ADJUST_CFA_OFFSET(8) 293 294 // According to the current frame kind set the bridge type 295 ldrb ip, [r3, #MANAGED_THREAD_FRAME_KIND_OFFSET] 296 cmp ip, #0 297 moveq ip, #INTERPRETER_TO_COMPILED_CODE_BRIDGE 298 movne ip, #BYPASS_BRIDGE 299 300 str fp, [sp] 301 CFI_REL_OFFSET(fp, 0) 302 str ip, [sp, #4] 303 add fp, sp, #8 304 CFI_DEF_CFA(fp, 8) 305 push {r4 - r10} 306 sub sp, sp, #4 307 // sp should be 8 byte aligned 308 309 // save regs to survive call of PrepareArgStack 310 // r6 - method, r7 - method.shorty, r8 - insn_ptr, r9 - iframe 311 // ip - thread 312 mov r8, r0 313 mov r9, r1 314 ldr r7, [r2, #METHOD_SHORTY_OFFSET] 315 mov r6, r2 316 mov ip, r3 317 mov SHORTY_PTR_REG, r7 318 INIT_SHORTY_REG 319 320 bl PrepareArgStack 321 322 // setup regs as follow 323 // r0 - SHORTY_PTR_REG, r1 - SHORTY_REG, r2, r3 - shorty value and temp, 324 // r4 - gpr and fpr base ptr, r5 - gpr arg ptr, r6 - fpr arg ptr, 325 // r7 - stack arg ptr, r8 - insn ptr, r9 - iframe, r10 - insn, 326 // ip - thread, lr - method 327 mov SHORTY_PTR_REG, r7 328 INIT_SHORTY_REG 329 mov lr, r6 330 mov r5, r4 331 mov r6, r4 332 mov r7, sp 333 334 // handle the return type 335 NEXT_SHORTY r2 336 cmp r2, #SHORTY_TAGGED 337 // the return type is any 338 // the first arg is the pointer to the caller frame's acc 339 addeq r2, r9, #FRAME_ACC_OFFSET 340 streq r2, [r5, #-4]! 341 342 str lr, [r5, #-4]! // push method to the stack 343 344 // parameter 'this' of instance methods is not encoded in the shorty 345 // in case of instance method hack SHORTY_REG by replacing the return type by REF 346 // in the another case just skip the return type 347 ldr r2, [lr, #METHOD_ACCESS_FLAGS_OFFSET] 348 tst r2, #ACCESS_STATIC 349 // it is an instance method 350 lsleq SHORTY_REG, SHORTY_REG, #4 // unshift shorty reg back 351 orreq r1, r1, #SHORTY_REFERENCE 352 353 ldrb r10, [r8], #1 // read opcode and advance insn_ptr 354 355 // set r9 - frame.vregs 356 add r9, r9, #FRAME_VREGS_OFFSET 357 358 // The file contains code which checks opcode and jumps 359 // to the corresponding handler. 360 // At the end each handler jumps to .Linvoke_from_bridge label. 361 // The file is autogenerated from runtime/templates/bridge_dispatch.S.erb 362 // Handlers are distinguished by format and located in the corresponding files with name: 363 // handle_call_<format>.S 364 // If you get a compilation error that there is no such file it seems 365 // new call format was introduced and you have to implement the corresponding handler. 366#include "bridge_dispatch_armhf.S" 367 368.Linvoke_from_bridge: 369 mov r0, r4 370 LOAD_FPR_ARGS r0, r6 371 LOAD_GPR_ARGS r4, r5 372 373 // move thread into THREAD_REG 374 mov THREAD_REG, ip 375 376 ldr r4, [lr, #METHOD_SHORTY_OFFSET] // load Method.shorty_ into r4 to survive the call 377 ldr lr, [lr, #METHOD_COMPILED_ENTRY_POINT_OFFSET] 378 blx lr 379 380 // handle the result 381 // setup registers as follow 382 // r0, r1 or d0 - result, r2 - shorty[0] & 0xF, r3 - frame.acc, r4- temp 383 ldrb r2, [r4] 384 and r2, r2, #0xF 385 386 cmp r2, #SHORTY_VOID 387 cmpne r2, #SHORTY_TAGGED 388 beq .Lreturn 389 ldr r3, [fp] 390 add r3, r3, #FRAME_ACC_OFFSET 391 // store tag 392 cmp r2, #SHORTY_REFERENCE 393 moveq r4, #1 394 movne r4, #0 395 str r4, [r3, #FRAME_ACC_MIRROR_OFFSET] 396 cmpne r2, #SHORTY_LAST_INT32 397 // it is a float or 64bit value(i64, u64, f32, f64) 398 bhi .L64 399 cmp r2, #SHORTY_FIRST_32 400 bge .L32 401 cmp r2, #SHORTY_I16 402 beq .LI16 403 bpl .LU16 404 cmp r2, #SHORTY_I8 405 beq .LI8 406 uxtb r0, r0 407 b .L32 408.LI8: 409 sxtb r0, r0 410 b .L32 411.LI16: 412 sxth r0, r0 413 b .L32 414.LU16: 415 uxth r0, r0 416.L32: 417 // it is a 32bit value or reference 418 str r0, [r3] 419 b .Lreturn 420 421.L64: 422 cmp r2, #SHORTY_F64 423 vmoveq.f64 r0, r1, d0 424 cmp r2, #SHORTY_F32 425 vmoveq.f32 r0, s0 426 stm r3, {r0, r1} 427 428.Lreturn: 429 // Signal handler of the sampling profiler use stack space below sp, 430 // so change it carefully only after registers restoration 431 sub sp, fp, #36 432 pop {r4 - r10, fp} 433 CFI_RESTORE(fp) 434 CFI_RESTORE(r10) 435 CFI_RESTORE(r9) 436 CFI_RESTORE(r8) 437 CFI_RESTORE(r7) 438 CFI_RESTORE(r6) 439 CFI_RESTORE(r5) 440 CFI_RESTORE(r4) 441 CFI_DEF_CFA(sp,12) 442 ldr lr, [sp, #8] 443 CFI_RESTORE(lr) 444 add sp, sp, #12 445 CFI_ADJUST_CFA_OFFSET(-12) 446 bx lr 447 CFI_ENDPROC 448 449// uint64_t InvokeCompiledCodeWithArguments(const int64_t* args, const Frame *iframe, const Method *method, ManagedThread* thread) 450.global InvokeCompiledCodeWithArgArray 451.type InvokeCompiledCodeWithArgArray, %function 452InvokeCompiledCodeWithArgArray: 453 CFI_STARTPROC 454 CFI_DEF_CFA(sp, 0) 455 // r0 - args, r1 - iframe, r2 - method, r3 - thread 456 push {r1, lr} 457 CFI_ADJUST_CFA_OFFSET(8) 458 CFI_REL_OFFSET(lr, 4) 459 sub sp, sp, #12 460 CFI_ADJUST_CFA_OFFSET(12) 461 462 stm sp, {THREAD_REG, fp} 463 CFI_REL_OFFSET(fp, 4) 464 CFI_REL_OFFSET(THREAD_REG, 0) 465 add fp, sp, #12 466 CFI_DEF_CFA(fp, 8) 467 mov THREAD_REG, r3 468 469 // According to the current frame kind set the bridge type 470 ldrb r1, [THREAD_REG, #MANAGED_THREAD_FRAME_KIND_OFFSET] 471 cmp r1, #0 472 moveq r1, #INTERPRETER_TO_COMPILED_CODE_BRIDGE 473 movne r1, #BYPASS_BRIDGE 474 str r1, [sp, #8] 475 push {r4 - r8} 476 // sp should be 8 bytes aligned 477 478 // save regs to survive call of PrepareArgStack 479 // r6 - method, r7 - method.shorty, r8 - args, ip - pointer to memory where to store the result 480 ldr r7, [r2, #METHOD_SHORTY_OFFSET] 481 mov r8, r0 482 mov r6, r2 483 mov SHORTY_PTR_REG, r7 484 INIT_SHORTY_REG 485 486 bl PrepareArgStack 487 488 // push arguments to the stack 489 // setup regs as follow 490 // r0 - SHORTY_PTR_REG, r1 - SHORTY_REG, r2, r3 - shorty value and temp, 491 // r4 - gpr and fpr base ptr, r5 - gpr arg ptr, r6 - fpr arg ptr, 492 // r7 - stack arg ptr, r8 - args, ip - pointer to memory where to store the result, 493 // lr - method 494 mov SHORTY_PTR_REG, r7 495 INIT_SHORTY_REG 496 mov lr, r6 497 mov r5, r4 498 mov r6, r4 499 mov r7, sp 500 501 // handle the return type 502 NEXT_SHORTY r2 503 504 str lr, [r5, #-4]! // push method to the stack 505 506 // parameter 'this' of instance methods is not encoded in the shorty 507 // in case of instance method hack SHORTY_REG by replacing the return type by REF 508 // in the another case just skip the return type 509 ldr r2, [lr, #METHOD_ACCESS_FLAGS_OFFSET] 510 tst r2, #ACCESS_STATIC 511 lsleq SHORTY_REG, SHORTY_REG, #4 // unshift shorty reg back 512 orreq r1, r1, #SHORTY_REFERENCE 513 514.Lloop_args_push: 515 NEXT_SHORTY r2 516 cmp r2, #0 517 beq .Lloopend_args_push 518 519 // handle the arg 520 PUSH_ARG r8, r5, r6, r7, r2, r3, 10f 52110: add r8, r8, #8 522 b .Lloop_args_push 523.Lloopend_args_push: 524 mov r0, r4 525 LOAD_FPR_ARGS r0, r6 526 LOAD_GPR_ARGS r4, r5 527 528 // setup regs as follow 529 // r7 - method.shorty, r8 - pointer to memory where to store the result 530 ldr r7, [lr, #METHOD_SHORTY_OFFSET] 531 mov r8, ip 532 533 ldr lr, [lr, #METHOD_COMPILED_ENTRY_POINT_OFFSET] 534 blx lr 535 536 // handle the result 537 // setup regs as follow 538 // r0,r1 - result, r2 - *method.shorty & 0xF 539 ldrb r2, [r7] 540 and r2, r2, #0xF 541 sub r3, r2, #SHORTY_FIRST_FLOAT 542 cmp r3, #(SHORTY_NUM_FLOAT_TYPES - 1) 543 bls .LFLOAT_ 544 545 cmp r2, #SHORTY_REFERENCE 546 cmpne r2, #SHORTY_LAST_INT32 547 bgt .Lreturn_ // it is a 64bit type 548 // it is a 32bit int 549 mov r1, #0 // zero hight part of int64_t 550 cmp r2, #SHORTY_FIRST_32 551 bge .Lreturn_ 552 cmp r2, #SHORTY_I16 553 beq .LI16_ 554 bpl .LU16_ 555 cmp r2, #SHORTY_I8 556 beq .LI8_ 557 uxtb r0, r0 558 b .Lreturn_ 559.LI8_: 560 sxtb r0, r0 561 b .Lreturn_ 562.LI16_: 563 sxth r0, r0 564 b .Lreturn_ 565.LU16_: 566 uxth r0, r0 567 b .Lreturn_ 568.LFLOAT_: 569 cmp r2, #SHORTY_F64 570 vmoveq.f64 r0, r1, d0 571 cmp r2, #SHORTY_F32 572 vmoveq.f32 r0, s0 573 574.Lreturn_: 575 // Signal handler of the sampling profiler use stack space below sp, 576 // so change it carefully only after registers restoration 577 sub sp, fp, #32 578 pop {r4 - r8, THREAD_REG, fp} 579 CFI_DEF_CFA(sp, 12) 580 CFI_RESTORE(fp) 581 CFI_RESTORE(THREAD_REG) 582 CFI_RESTORE(r8) 583 CFI_RESTORE(r7) 584 CFI_RESTORE(r6) 585 CFI_RESTORE(r5) 586 CFI_RESTORE(r4) 587 ldr lr, [sp, #8] 588 CFI_RESTORE(lr) 589 add sp, sp, #12 590 CFI_ADJUST_CFA_OFFSET(-12) 591 bx lr 592 CFI_ENDPROC 593 594