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 PUSH_ARG arg_ptr, stack_ptr, tmp1, tmp2, next_label 24 cmp r2, #SHORTY_TAGGED 25 beq 2f 26 27 sub r2, r2, #SHORTY_FIRST_64 28 cmp r2, #(SHORTY_NUM_64BIT_TYPES - 1) 29 bls 1f 30 // it is a 32bit value 31 ldr \tmp1, [\arg_ptr] 32 str \tmp1, [\stack_ptr], #4 33 b \next_label 341: // it is a 64bit value 35 ldm \arg_ptr, {\tmp1, \tmp2} 36 add \stack_ptr, \stack_ptr, #7 // round the address up to 8 byte boundary 37 bic \stack_ptr, \stack_ptr, #7 38 stm \stack_ptr!, {\tmp1, \tmp2} 39 b \next_label 40 412: // the arg has type 'any' 42 add \stack_ptr, \stack_ptr, #7 // round the address up to 8 byte boundary 43 bic \stack_ptr, \stack_ptr, #7 44 // copy value 45 ldr \tmp2, [\arg_ptr], #4 46 str \tmp2, [\stack_ptr], #4 47 ldr \tmp2, [\arg_ptr], #4 48 str \tmp2, [\stack_ptr], #4 49 // copy tag 50 ldm \arg_ptr, {\tmp1, \tmp2} 51 stm \stack_ptr, {\tmp1, \tmp2} 52 b \next_label 53.endm 54 55.macro LOAD_ARGS begin_ptr, end_ptr 56 ldr r0, [\begin_ptr], #4 57 cmp \begin_ptr, \end_ptr 58 beq 1f 59 ldr r1, [\begin_ptr], #4 60 cmp \begin_ptr, \end_ptr 61 beq 1f 62 ldr r2, [\begin_ptr], #4 63 cmp \begin_ptr, \end_ptr 64 beq 1f 65 ldr r3, [\begin_ptr], #4 661: 67 bic sp, sp, #7 // round downd sp to 8byte boundary 68.endm 69 70// The procedure reserves stack space for the arguments 71// Input: 72// r0 - SHORTY_PTR_REG 73// r1 - SHORTY_REG 74// r2 - shorty value (no initialization needed) 75// r7 - method 76// The procedure musn't use other registers 77PrepareArgStack: 78 // check result type 79 NEXT_SHORTY r2 80 cmp r2, #SHORTY_TAGGED 81 subeq sp, sp, #4 // r0 contains a pointer to the space to which the result will be stored 82 83 sub sp, sp, #4 // space for Method 84 85 // parameter 'this' of instance methods is not encoded in the shorty 86 ldr r2, [r7, #METHOD_ACCESS_FLAGS_OFFSET] 87 tst r2, #ACCESS_STATIC 88 subeq sp, sp, #4 // it is an instance method 89 90.Lloop_shorty: 91 NEXT_SHORTY r2 92 cmp r2, #0 93 beq .Lexit 94 95 cmp r2, #SHORTY_TAGGED 96 beq 1f 97 98 sub r2, r2, #SHORTY_FIRST_64 99 cmp r2, #(SHORTY_NUM_64BIT_TYPES - 1) 100 // it is a 32bit value 101 subhi sp, sp, #4 102 // it is a 64bit value 103 // align arg slot 104 bicls sp, sp, #7 105 subls sp, sp, #8 106 b .Lloop_shorty 107 1081: // argument has type 'any' 109 bic sp, sp, #7 110 sub sp, sp, #16 111 b .Lloop_shorty 112.Lexit: 113 bic sp, sp, #7 // round downd sp to 8byte boundary 114 mov pc, lr 115 116// void InterpreterToCompiledCodeBridge(const BytecodeInstruction* insn, const Frame *iframe, const Method *method, ManagedThread* thread) 117.global InterpreterToCompiledCodeBridge 118.type InterpreterToCompiledCodeBridge, %function 119InterpreterToCompiledCodeBridge: 120 CFI_STARTPROC 121 CFI_DEF_CFA(sp, 0) 122 push {r1, lr} 123 CFI_ADJUST_CFA_OFFSET(8) 124 CFI_REL_OFFSET(lr, 4) 125 126 sub sp, sp, #12 127 CFI_ADJUST_CFA_OFFSET(12) 128 129 stm sp, {THREAD_REG, fp} 130 CFI_REL_OFFSET(fp, 4) 131 CFI_REL_OFFSET(THREAD_REG, 0) 132 add fp, sp, #12 133 CFI_ADJUST_CFA_OFFSET(-12) 134 CFI_DEF_CFA_REGISTER(fp) 135 136 mov THREAD_REG, r3 137 138 // According to the current frame kind set the bridge type 139 ldrb r3, [THREAD_REG, #MANAGED_THREAD_FRAME_KIND_OFFSET] 140 cmp r3, #0 141 moveq r3, #INTERPRETER_TO_COMPILED_CODE_BRIDGE 142 movne r3, #BYPASS_BRIDGE 143 144 str r3, [sp, #8] 145 push {r4, r5, r6, r7, r8, r9} 146 CFI_REL_OFFSET(r9, -((3 + 1) * 4)) 147 CFI_REL_OFFSET(r8, -((3 + 2) * 4)) 148 CFI_REL_OFFSET(r7, -((3 + 3) * 4)) 149 CFI_REL_OFFSET(r6, -((3 + 4) * 4)) 150 CFI_REL_OFFSET(r5, -((3 + 5) * 4)) 151 CFI_REL_OFFSET(r4, -((3 + 6) * 4)) 152 CFI_REL_OFFSET(r3, -((3 + 7) * 4)) 153 sub sp, sp, #4 154 // sp should be 8 byte aligned 155 156 // save regs to survive call of PrepareArgStack 157 // r4 - insn_ptr, r5 - iframe, r6 - method.shorty, r7 - method 158 mov r4, r0 159 mov r5, r1 160 ldr r6, [r2, #METHOD_SHORTY_OFFSET] 161 mov r7, r2 162 mov SHORTY_PTR_REG, r6 163 INIT_SHORTY_REG 164 165 bl PrepareArgStack 166 167 // setup regs as follow 168 // r0 - SHORTY_PTR_REG, r1 - SHORTY_REG, r2 - shorty value, r3 - insn, r4 - insn_ptr, 169 // r5 - iframe, r6, r7 and r9 - temps, r8 - pointer to stack, lr - method 170 mov SHORTY_PTR_REG, r6 171 INIT_SHORTY_REG 172 mov r8, sp 173 mov lr, r7 174 175 // handle the return type 176 NEXT_SHORTY r2 177 cmp r2, #SHORTY_TAGGED 178 // the return type is any 179 // the first arg is the pointer to the caller frame's acc 180 addeq r2, r5, #FRAME_ACC_OFFSET 181 streq r2, [r8], #4 182 183 str lr, [r8], #4 // push method to the stack 184 185 // parameter 'this' of instance methods is not encoded in the shorty 186 // in case of instance method hack SHORTY_REG by replacing the return type by REF 187 // in the another case just skip the return type 188 ldr r2, [lr, #METHOD_ACCESS_FLAGS_OFFSET] 189 tst r2, #ACCESS_STATIC 190 // it is an instance method 191 lsleq SHORTY_REG, SHORTY_REG, #4 // unshift shorty reg 192 orreq SHORTY_REG, SHORTY_REG, #SHORTY_REFERENCE 193 194 // setup r5 as follow 195 // r5 - iframe.vregs 196 add r5, r5, #FRAME_VREGS_OFFSET 197 ldrb r6, [r4], #1 // read opcode and advance insn_ptr 198 199 // The file contains code which checks opcode and jumps 200 // to the corresponding handler. 201 // At the end each handler jumps to .Linvoke_from_bridge label. 202 // The file is autogenerated from runtime/templates/bridge_dispatch.S.erb 203 // Handlers are distinguished by format and located in the corresponding files with name: 204 // handle_call_<format>.S 205 // If you get a compilation error that there is no such file it seems 206 // new call format was introduced and you have to implement the corresponding handler. 207#include "bridge_dispatch_arm.S" 208 209.Linvoke_from_bridge: 210 LOAD_ARGS sp, r8 211 212 ldr r4, [lr, #METHOD_SHORTY_OFFSET] // load Method.shorty_ into r4 to survive the call 213 ldr lr, [lr, #METHOD_COMPILED_ENTRY_POINT_OFFSET] 214 blx lr 215 216 // handle the result 217 // setup registers as follow 218 // r0, r1 - result, r2 - shorty[0] & 0xF, r3 - frame.acc, r4- temp 219 ldrb r2, [r4] 220 and r2, r2, #0xF 221 222 cmp r2, #SHORTY_VOID 223 cmpne r2, #SHORTY_TAGGED 224 beq .Lreturn 225 ldr r3, [fp] 226 add r3, r3, #FRAME_ACC_OFFSET 227 // store tag 228 cmp r2, #SHORTY_REFERENCE 229 moveq r4, #1 230 movne r4, #0 231 str r4, [r3, #FRAME_ACC_MIRROR_OFFSET] 232 streq r0, [r3] 233 beq .Lreturn 234 cmp r2, #SHORTY_FIRST_64 235 // u64, i64, f64 236 stmge r3, {r0, r1} 237 bge .Lreturn 238 cmp r2, #SHORTY_FIRST_32 239 bge .L32 240 cmp r2, #SHORTY_I16 241 beq .LI16 242 bpl .LU16 243 cmp r2, #SHORTY_I8 244 beq .LI8 245 uxtb r0, r0 246 b .L32 247.LI8: 248 sxtb r0, r0 249 b .L32 250.LI16: 251 sxth r0, r0 252 b .L32 253.LU16: 254 uxth r0, r0 255.L32: 256 str r0, [r3] 257.Lreturn: 258 // Signal handler of the sampling profiler use stack space below sp, 259 // so change it carefully only after registers restoration 260 sub sp, fp, #36 261 pop {r4, r5, r6, r7, r8, r9, THREAD_REG, fp} 262 CFI_RESTORE(r4) 263 CFI_RESTORE(r5) 264 CFI_RESTORE(r6) 265 CFI_RESTORE(r7) 266 CFI_RESTORE(r8) 267 CFI_RESTORE(r9) 268 CFI_RESTORE(THREAD_REG) 269 CFI_RESTORE(fp) 270 CFI_DEF_CFA(sp, 12) 271 ldr lr, [sp, #8] 272 CFI_RESTORE(lr) 273 add sp, sp, #12 274 CFI_ADJUST_CFA_OFFSET(-12) 275 bx lr 276 CFI_ENDPROC 277 278// uint64_t InvokeCompiledCodeWithArguments(const int64_t* args, const Frame *iframe, const Method *method, ManagedThread* thread) 279.global InvokeCompiledCodeWithArgArray 280.type InvokeCompiledCodeWithArgArray, %function 281InvokeCompiledCodeWithArgArray: 282 // r0 - args, r1 - iframe, r2 - method, r3 - thread 283 CFI_STARTPROC 284 CFI_DEF_CFA(sp, 0) 285 286 push {r1, lr} 287 CFI_ADJUST_CFA_OFFSET(8) 288 CFI_REL_OFFSET(lr, 4) 289 290 sub sp, sp, #12 291 CFI_ADJUST_CFA_OFFSET(12) 292 293 stm sp, {THREAD_REG, fp} 294 CFI_REL_OFFSET(fp, 4) 295 CFI_REL_OFFSET(THREAD_REG, 0) 296 297 add fp, sp, #12 298 CFI_DEF_CFA_REGISTER(fp) 299 CFI_ADJUST_CFA_OFFSET(-12) 300 301 mov THREAD_REG, r3 302 303 // According to the current frame kind set the bridge type 304 ldrb r1, [THREAD_REG, #MANAGED_THREAD_FRAME_KIND_OFFSET] 305 cmp r1, #0 306 moveq r1, #INTERPRETER_TO_COMPILED_CODE_BRIDGE 307 movne r1, #BYPASS_BRIDGE 308 str r1, [sp, #8] 309 push {r4, r5, r6, r7, r8} 310 CFI_REL_OFFSET(r8, -(4 * 4)) 311 CFI_REL_OFFSET(r7, -(5 * 4)) 312 CFI_REL_OFFSET(r6, -(6 * 4)) 313 CFI_REL_OFFSET(r5, -(7 * 4)) 314 CFI_REL_OFFSET(r4, -(8 * 4)) 315 316 // sp should be 8 bytes aligned 317 318 // setup regs as follow 319 // r4 - args, r6 - method.shorty, r7 - method 320 mov r4, r0 321 mov r7, r2 322 ldr r6, [r2, #METHOD_SHORTY_OFFSET] 323 mov SHORTY_PTR_REG, r6 324 INIT_SHORTY_REG 325 326 bl PrepareArgStack 327 328 // push arguments to the stack 329 // setup regs as follow 330 // r0 - SHORTY_PTR_REG, r1 - SHORTY_REG, r2 - shorty value, r3 - the pointer to the stack, 331 // r4 - args, r5 and r6 - temps, lr - method 332 mov SHORTY_PTR_REG, r6 333 INIT_SHORTY_REG 334 mov r3, sp 335 mov lr, r7 336 337 // handle the return type 338 NEXT_SHORTY r2 339 340 str lr, [r3], #4 341 342 // parameter 'this' of instance methods is not encoded in the shorty 343 // in case of instance method hack SHORTY_REG by replacing the return type by REF 344 // in the another case just skip the return type 345 ldr r2, [lr, #METHOD_ACCESS_FLAGS_OFFSET] 346 tst r2, #ACCESS_STATIC 347 // it is an instance method 348 lsleq SHORTY_REG, SHORTY_REG, #4 // unshift shorty reg 349 orreq SHORTY_REG, SHORTY_REG, #SHORTY_REFERENCE 350 351.Lloop_args_push: 352 NEXT_SHORTY r2 353 cmp r2, #0 354 beq .Lloopend_args_push 355 356 // handle the arg 357 mov r5, r4 358 add r4, r4, #8 359 PUSH_ARG r5, r3, r5, r6, .Lloop_args_push 360.Lloopend_args_push: 361 LOAD_ARGS sp, r3 362 // load shorty into r6 again 363 ldr r6, [lr, #METHOD_SHORTY_OFFSET] 364 365 ldr lr, [lr, #METHOD_COMPILED_ENTRY_POINT_OFFSET] 366 blx lr 367 368 // handle the result 369 // setup regs as follow 370 // r0,r1 - result, r2 - method.shorty[0] & 0xF 371 ldrb r2, [r6] 372 and r2, r2, #0xF 373 sub r3, r2, #SHORTY_FIRST_64 374 cmp r3, #(SHORTY_NUM_64BIT_TYPES - 1) 375 bls .Lreturn_ // the result type is a 64bit type 376 // the result type is a 32bit type 377 mov r1, #0 // set high 32 bits of 64bit value to 0 378 cmp r2, #SHORTY_FIRST_32 379 bge .Lreturn_ 380 cmp r2, #SHORTY_I16 381 beq .LI16_ 382 bpl .LU16_ 383 cmp r2, #SHORTY_I8 384 beq .LI8_ 385 uxtb r0, r0 386 b .Lreturn_ 387.LI8_: 388 sxtb r0, r0 389 b .Lreturn_ 390.LI16_: 391 sxth r0, r0 392 b .Lreturn_ 393.LU16_: 394 uxth r0, r0 395 396.Lreturn_: 397 // Signal handler of the sampling profiler use stack space below sp, 398 // so change it carefully only after registers restoration 399 sub sp, fp, #32 400 pop {r4, r5, r6, r7, r8, THREAD_REG, fp} 401 CFI_RESTORE(fp) 402 CFI_RESTORE(THREAD_REG) 403 CFI_RESTORE(r8) 404 CFI_RESTORE(r7) 405 CFI_RESTORE(r6) 406 CFI_RESTORE(r5) 407 CFI_RESTORE(r4) 408 CFI_DEF_CFA(sp, 12) 409 ldr lr, [sp, #8] 410 CFI_RESTORE(lr) 411 add sp, sp, #12 412 CFI_ADJUST_CFA_OFFSET(-12) 413 bx lr 414 CFI_ENDPROC 415 416