1/** 2 * Copyright (c) 2021-2022 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 sub sp, fp, #36 430 pop {r4 - r10, fp} 431 CFI_RESTORE(fp) 432 CFI_RESTORE(r10) 433 CFI_RESTORE(r9) 434 CFI_RESTORE(r8) 435 CFI_RESTORE(r7) 436 CFI_RESTORE(r6) 437 CFI_RESTORE(r5) 438 CFI_RESTORE(r4) 439 CFI_DEF_CFA(sp,12) 440 add sp, sp, #12 441 CFI_ADJUST_CFA_OFFSET(-12) 442 ldr lr, [sp, #-4] 443 CFI_RESTORE(lr) 444 bx lr 445 CFI_ENDPROC 446 447// InvocationResult InvokeCompiledCodeWithArguments(const int64_t* args, const Frame *iframe, const Method *method, ManagedThread* thread) 448.global InvokeCompiledCodeWithArgArray 449.type InvokeCompiledCodeWithArgArray, %function 450InvokeCompiledCodeWithArgArray: 451 CFI_STARTPROC 452 CFI_DEF_CFA(sp, 0) 453 // Since Invocation result is 128bit structure the areguments are located here: 454 // r0 - pointer to memory where to store the result 455 // r1 - args, r2 - iframe, r3 - method, sp[0] - thread 456 push {r2, 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 ldr THREAD_REG, [fp, #8] 468 469 // According to the current frame kind set the bridge type 470 ldrb r2, [THREAD_REG, #MANAGED_THREAD_FRAME_KIND_OFFSET] 471 cmp r2, #0 472 moveq r2, #INTERPRETER_TO_COMPILED_CODE_BRIDGE 473 movne r2, #BYPASS_BRIDGE 474 str r2, [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, [r3, #METHOD_SHORTY_OFFSET] 481 mov r8, r1 482 mov r6, r3 483 mov ip, r0 484 mov SHORTY_PTR_REG, r7 485 INIT_SHORTY_REG 486 487 bl PrepareArgStack 488 489 // push arguments to the stack 490 // setup regs as follow 491 // r0 - SHORTY_PTR_REG, r1 - SHORTY_REG, r2, r3 - shorty value and temp, 492 // r4 - gpr and fpr base ptr, r5 - gpr arg ptr, r6 - fpr arg ptr, 493 // r7 - stack arg ptr, r8 - args, ip - pointer to memory where to store the result, 494 // lr - method 495 mov SHORTY_PTR_REG, r7 496 INIT_SHORTY_REG 497 mov lr, r6 498 mov r5, r4 499 mov r6, r4 500 mov r7, sp 501 502 // handle the return type 503 NEXT_SHORTY r2 504 cmp r2, #SHORTY_TAGGED 505 // the return type is any 506 // the first arg is the pointer to the result 507 streq ip, [r5, #-4]! 508 509 str lr, [r5, #-4]! // push method to the stack 510 511 // parameter 'this' of instance methods is not encoded in the shorty 512 // in case of instance method hack SHORTY_REG by replacing the return type by REF 513 // in the another case just skip the return type 514 ldr r2, [lr, #METHOD_ACCESS_FLAGS_OFFSET] 515 tst r2, #ACCESS_STATIC 516 lsleq SHORTY_REG, SHORTY_REG, #4 // unshift shorty reg back 517 orreq r1, r1, #SHORTY_REFERENCE 518 519.Lloop_args_push: 520 NEXT_SHORTY r2 521 cmp r2, #0 522 beq .Lloopend_args_push 523 524 // handle the arg 525 PUSH_ARG r8, r5, r6, r7, r2, r3, 10f 52610: add r8, r8, #8 527 b .Lloop_args_push 528.Lloopend_args_push: 529 mov r0, r4 530 LOAD_FPR_ARGS r0, r6 531 LOAD_GPR_ARGS r4, r5 532 533 // setup regs as follow 534 // r7 - method.shorty, r8 - pointer to memory where to store the result 535 ldr r7, [lr, #METHOD_SHORTY_OFFSET] 536 mov r8, ip 537 538 ldr lr, [lr, #METHOD_COMPILED_ENTRY_POINT_OFFSET] 539 blx lr 540 541 // handle the result 542 // setup regs as follow 543 // r0,r1 - result, r2 - *method.shorty & 0xF 544 ldrb r2, [r7] 545 and r2, r2, #0xF 546 cmp r2, #SHORTY_TAGGED 547 beq .Lreturn_ 548 sub r3, r2, #SHORTY_FIRST_FLOAT 549 cmp r3, #(SHORTY_NUM_FLOAT_TYPES - 1) 550 bls .LFLOAT_ 551 552 cmp r2, #SHORTY_REFERENCE 553 cmpne r2, #SHORTY_LAST_INT32 554 bgt .Lstore_result_ // it is a 64bit type 555 // it is a 32bit int 556 mov r1, #0 // zero hight part of int64_t 557 cmp r2, #SHORTY_FIRST_32 558 bge .Lstore_result_ 559 cmp r2, #SHORTY_I16 560 beq .LI16_ 561 bpl .LU16_ 562 cmp r2, #SHORTY_I8 563 beq .LI8_ 564 uxtb r0, r0 565 b .Lstore_result_ 566.LI8_: 567 sxtb r0, r0 568 b .Lstore_result_ 569.LI16_: 570 sxth r0, r0 571 b .Lstore_result_ 572.LU16_: 573 uxth r0, r0 574 b .Lstore_result_ 575.LFLOAT_: 576 cmp r2, #SHORTY_F64 577 vmoveq.f64 r0, r1, d0 578 cmp r2, #SHORTY_F32 579 vmoveq.f32 r0, s0 580 581.Lstore_result_: 582 // store the result r0,r1 into memory [r8] 583 stm r8!, {r0, r1} 584 // store tag 585 cmp r2, #SHORTY_REFERENCE 586 moveq r0, #1 587 movne r0, #0 588 mov r1, #0 589 stm r8, {r0, r1} 590 591.Lreturn_: 592 sub sp, fp, #32 593 pop {r4 - r8, THREAD_REG, fp} 594 CFI_DEF_CFA(sp, 12) 595 CFI_RESTORE(fp) 596 CFI_RESTORE(THREAD_REG) 597 CFI_RESTORE(r8) 598 CFI_RESTORE(r7) 599 CFI_RESTORE(r6) 600 CFI_RESTORE(r5) 601 CFI_RESTORE(r4) 602 add sp, sp, #12 603 CFI_ADJUST_CFA_OFFSET(-12) 604 ldr lr, [sp, #-4] 605 CFI_RESTORE(lr) 606 bx lr 607 CFI_ENDPROC 608 609