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/asm_constants.h" 18#include "arch/arm/shorty.S" 19#include "shorty_values.h" 20 21// uint32_t EtsNapiCalcStackArgsSpaceSize (Method *method, bool is_critical) 22.extern EtsNapiCalcStackArgsSpaceSize 23// void EtsNapiBeginCritical (Method *method, uintptr_t args, uintptr_t stack_args, uintptr_t out_args) 24.extern EtsNapiBeginCritical 25// void EtsNapiBegin (Method *method, uintptr_t args, uintptr_t stack_args, uintptr_t out_args) 26.extern EtsNapiBegin 27// void EtsNapiEnd (Method *method) 28.extern EtsNapiEnd 29// ObjectHeader *EtsNapiObjEnd (Method *method, Reference *ref) 30.extern EtsNapiObjEnd 31// bool IsEtsMethodFastNative (Method *method) 32.extern IsEtsMethodFastNative 33 34// The entrypoint for EtsNapi critical method. 35// there are two nuances: 36// 1. Each panda method accepts Method* in the first argument. 37// We have to drop this argument and shift others back 38// 2. We have to convert double arguments and the return value to floats 39// Panda runtime operates only with doubles. 40// The function handles all the cases above. 41.global EtsNapiCriticalNativeEntryPoint 42.type EtsNapiCriticalNativeEntryPoint, %function 43EtsNapiCriticalNativeEntryPoint: 44 CFI_STARTPROC 45 CFI_DEF_CFA(sp,0) 46 47 push {fp, lr} 48 CFI_ADJUST_CFA_OFFSET(8) 49 CFI_REL_OFFSET(lr, 4) 50 CFI_REL_OFFSET(fp, 0) 51 52 mov fp, sp 53 CFI_DEF_CFA_REGISTER(fp) 54 sub sp, sp, #8 55 str r0, [sp, #4] 56 mov lr, #CFRAME_KIND_NATIVE 57 str lr, [sp] 58 59 push {r4, r7} 60 CFI_REL_OFFSET(r7, -12) 61 CFI_REL_OFFSET(r4, -16) 62 63 // Skip locals 64 sub sp, sp, #(CFRAME_LOCALS_COUNT * 4) 65 66 // save argument to the stack 67 vpush {d0 - d7} 68 push {r0 - r3} 69 70 mov r4, r0 // save method to r4 to survive the call 71 72 // Update current frame in the thread 73 blx GetCurrentManagedThread 74 str fp, [r0, #MANAGED_THREAD_FRAME_OFFSET] 75 ldrb r7, [r0, #MANAGED_THREAD_FRAME_KIND_OFFSET] 76 mov r1, #1 77 strb r1, [r0, #MANAGED_THREAD_FRAME_KIND_OFFSET] 78 mov THREAD_REG, r0 79 mov r0, r4 80 81 // Check num args. If all args could be settle in regs 82 // don't calculate stack size 83 ldr r0, [r4, #METHOD_NUM_ARGS_OFFSET] 84 cmp r0, #2 // max 2 long argument 85 // reserve space for GPR and FPR args 86 mov r0, #80 87 ble .Lprepare_stack_critical 88 89 mov r0, r4 90 mov r1, #1 91 blx EtsNapiCalcStackArgsSpaceSize 92 93.Lprepare_stack_critical: 94 mov r1, sp 95 add r2, fp, #8 96 sub sp, sp, r0 97 mov r3, sp 98 mov r0, r4 99 // necessary for stack alignment 100 sub sp, sp, #4 101 push {THREAD_REG} 102 blx EtsNapiBeginCritical 103 add sp, sp, #8 104 105 // load the argument 106 pop {r0 - r3} 107 vpop {d0 - d7} 108 109 // call the method 110 ldr lr, [r4, #METHOD_NATIVE_POINTER_OFFSET] 111 cmp lr, #0 112 beq .Ldone 113 blx lr 114 115.Ldone: 116 // return 117 // signal handler of the sampling profiler use stack space below sp, 118 // so change it carefully only after registers restoration 119 sub sp, fp, #16 120 121 mov r2, r7 122 123 pop {r7} 124 CFI_RESTORE(r7) 125 ldr r4, [sp], #12 126 CFI_RESTORE(r4) 127 pop {fp} 128 CFI_DEF_CFA(sp, 4) 129 CFI_RESTORE(fp) 130 CFI_REMEMBER_STATE 131 132 strb r2, [THREAD_REG, #MANAGED_THREAD_FRAME_KIND_OFFSET] 133 134 // check native exception 135 ldr r3, [THREAD_REG, #MANAGED_THREAD_EXCEPTION_OFFSET] 136 cmp r3, #0 137 beq 1f 138 139 // check frame is compiled 140 cmp r2, #0 141 beq 1f 142 143 // check prev fame is true CFRAME and not BYPASS 144 ldr r3, [fp, #(SLOT_SIZE * COMP_METHOD_OFFSET)] 145 cmp r3, #BYPASS_BRIDGE 146 beq 1f 147 148 add lr, fp, #-CALLER_REG0_OFFSET 149 ldm lr, {r0-r3} 150 151 ldr lr, [fp, #(-CFRAME_FLAGS_SLOT * 4)] 152 tst lr, #CFRAME_HAS_FLOAT_REGS_FLAG_MASK 153 beq 6f 154 155 add lr, fp, #-CALLER_VREG0_OFFSET 156 vldm lr, {d0-d7} 157 1586: 159 pop {lr} 160 CFI_ADJUST_CFA_OFFSET(-4) 161 CFI_RESTORE(lr) 162 163 b ThrowNativeExceptionBridge 164 CFI_RESTORE_STATE 165 1661: 167 pop {lr} 168 CFI_ADJUST_CFA_OFFSET(-4) 169 CFI_RESTORE(lr) 170 bx lr 171 CFI_ENDPROC 172 173// | | 174// | Prev Frame | 175// | | 176// +------------------------+ 177// | ... | 178// | stack args | 179// | ... |-11 180// +---+---+----------------+ 181// | | | LR |-10 182// | | | FP | -9 183// | | | Method * | -8 184// | | | FLAGS | -7 185// | | +----------------+ 186// | | | ... | -6 187// | | | locals | 188// | | | ... | -1 189// | | c +--------+-------+ 190// | | f | | d15.1 | 0 191// | | r | | d15.0 | 1 192// | | a | | d14.1 | 2 193// | | m | | d14.0 | 3 194// | | e | | d13.1 | 4 195// | | | | d13.0 | 5 196// | | | | d12.1 | 6 197// | | | | d12.0 | 7 198// | | | | d11.1 | 8 199// | | | | d11.0 | 9 200// | | | | d10.1 | 10 201// | N | | | d10.0 | 11 202// | a | | callee | d9.1 | 12 203// | p | | saved | d9.0 | 13 204// | i | | | d8.1 | 14 205// | | | | d8.0 | 15 206// | f | | +-------+ 207// | r | | | r10 | 16 208// | a | | | r9 | 17 209// | m | | | r8 | 18 210// | e | | | r7 | 19 211// | | | | r6 | 20 212// | | | | r5 | 21 213// | | | | r4 | 22 214// | | | | align | 23 215// | +---+--------+-------+ 216// | | | d7.1 | 24 217// | | | d7.0 | 25 218// | | | d6.1 | 26 219// | | | d6.0 | 27 220// | | | d5.1 | 28 221// | | | d5.0 | 29 222// | | | d4.1 | 30 223// | | | d4.0 | 31 224// | | | d3.1 | 32 225// | | | d3.0 | 33 226// | | | d2.1 | 34 227// | | args | d2.0 | 35 228// | | | d1.1 | 36 229// | | | d1.0 | 37 230// | | | d0.1 | 38 231// | | | d0.0 | 39 232// | | +-------+ 233// | | | r3 | 40 234// | | | r2 | 41 235// | | | r1 | 42 236// | | | r0 | 43 237// | +-------+----+-------+ 238// | | | Napi d7.1 | 44 239// | | | Napi d7.0 | 45 240// | | | Napi d6.1 | 46 241// | | | Napi d6.0 | 47 242// | | | Napi d5.1 | 48 243// | | | Napi d5.0 | 49 244// | | | Napi d4.1 | 50 245// | | | Napi d4.0 | 51 246// | | | Napi d3.1 | 52 247// | | | Napi d3.0 | 53 248// | | | Napi d2.1 | 54 249// | | Napi | Napi d2.0 | 55 250// | | args | Napi d1.1 | 56 251// | | | Napi d1.0 | 57 252// | | | Napi d0.1 | 58 253// | | | Napi d0.0 | 59 254// | | +------------+ 255// | | | Napi r3 | 60 256// | | | Napi r2 | 61 257// | | | Napi r1 | 62 258// | | | Napi r0 | 63 259// | | +------------+ 260// | | | stack_argN | 64 261// | | | ... | 262// | | | stack_arg1 | 64+(N-1) 263// | | | stack_arg0 | 64+(N-0) 264// +---+-------+------------+ 265// | | 266 267// The entrypoint for EtsNapi method 268// Each panda method accepts *Method in the first argument 269// The goal of this function is just drop this argument and shift other arguments back 270.global EtsNapiEntryPoint 271.type EtsNapiEntryPoint, %function 272EtsNapiEntryPoint: 273 CFI_STARTPROC 274 CFI_DEF_CFA(sp, 0) 275 276 push {fp, lr} 277 CFI_ADJUST_CFA_OFFSET(8) 278 CFI_REL_OFFSET(lr, 4) 279 CFI_REL_OFFSET(fp, 0) 280 281 mov fp, sp 282 CFI_DEF_CFA_REGISTER(fp) 283 sub sp, sp, #8 284 str r0, [sp, #4] 285 mov lr, #CFRAME_KIND_NATIVE 286 str lr, [sp] 287 288 // Skip locals 289 sub sp, sp, #(CFRAME_LOCALS_COUNT * 4) 290 291 // save all the callee saved registers to the stack 292 // stack walker will read them during stack unwinding 293 vpush {d8 - d15} 294 CFI_REL_OFFSET(d15, -((CFRAME_LOCALS_COUNT + 2 + 2) * 4)) 295 CFI_REL_OFFSET(d14, -((CFRAME_LOCALS_COUNT + 2 + 4) * 4)) 296 CFI_REL_OFFSET(d13, -((CFRAME_LOCALS_COUNT + 2 + 6) * 4)) 297 CFI_REL_OFFSET(d12, -((CFRAME_LOCALS_COUNT + 2 + 8) * 4)) 298 CFI_REL_OFFSET(d11, -((CFRAME_LOCALS_COUNT + 2 + 10) * 4)) 299 CFI_REL_OFFSET(d10, -((CFRAME_LOCALS_COUNT + 2 + 12) * 4)) 300 CFI_REL_OFFSET(d9, -((CFRAME_LOCALS_COUNT + 2 + 14) * 4)) 301 CFI_REL_OFFSET(d8, -((CFRAME_LOCALS_COUNT + 2 + 16) * 4)) 302 push {r4 - r10} 303 CFI_REL_OFFSET(r10, -((CFRAME_LOCALS_COUNT + 18 + 1) * 4)) // Thread pointer 304 CFI_REL_OFFSET(r9, -((CFRAME_LOCALS_COUNT + 18 + 2) * 4)) // Shorty return value 305 CFI_REL_OFFSET(r8, -((CFRAME_LOCALS_COUNT + 18 + 3) * 4)) // IsFastNative state 306 CFI_REL_OFFSET(r7, -((CFRAME_LOCALS_COUNT + 18 + 4) * 4)) 307 CFI_REL_OFFSET(r6, -((CFRAME_LOCALS_COUNT + 18 + 5) * 4)) 308 CFI_REL_OFFSET(r5, -((CFRAME_LOCALS_COUNT + 18 + 6) * 4)) 309 CFI_REL_OFFSET(r4, -((CFRAME_LOCALS_COUNT + 18 + 7) * 4)) // Method ptr 310 311 // align to 8 312 sub sp, sp, #4 313 314 // save arguments to the stack 315 vpush {d0 - d7} 316 push {r0 - r3} 317 318 mov r4, r0 // save method to r4 to survive the call 319 320 // save shorty return value to r9 321 ldr r9, [r4, #METHOD_SHORTY_OFFSET] 322 ldr r9, [r9] 323 324 // save IsFastNative state to r8 325 mov r0, r4 326 blx IsEtsMethodFastNative 327 mov r8, r0 328 329 // Update current frame in the thread 330 blx GetCurrentManagedThread 331 str fp, [r0, #MANAGED_THREAD_FRAME_OFFSET] 332 ldrb r7, [r0, #MANAGED_THREAD_FRAME_KIND_OFFSET] 333 mov r1, #1 334 strb r1, [r0, #MANAGED_THREAD_FRAME_KIND_OFFSET] 335 mov THREAD_REG, r0 336 mov r0, r4 337 338 // Check num args. If all args could be settle in regs 339 // don't calculate stack size 340 ldr r0, [r4, #METHOD_NUM_ARGS_OFFSET] 341 cmp r0, #1 // max one long argument 342 // reserve space for GPR and FPR args 343 mov r0, #80 344 ble .Lprepare_stack 345 346 mov r0, r4 347 mov r1, #0 348 blx EtsNapiCalcStackArgsSpaceSize 349 350.Lprepare_stack: 351 mov r1, sp 352 add r2, fp, #8 353 sub sp, sp, r0 354 mov r3, sp 355 mov r0, r4 356 // necessary for stack alignment 357 sub sp, sp, #4 358 push {THREAD_REG} 359 blx EtsNapiBegin 360 add sp, sp, #8 361 362 // load the arguments 363 mov r5, r0 364 ldmia r5!, {r0 - r3} 365 fldmiax r5!, {d0 - d7} 366 367 // call the method 368 ldr lr, [r4, #METHOD_NATIVE_POINTER_OFFSET] 369 cmp lr, #0 370 beq .Lend 371 blx lr 372 373 // handle the result 374 and r9, r9, #0xF 375 cmp r9, #SHORTY_REFERENCE 376 bne 4f 377 // it is a reference. 378 mov r3, r8 379 mov r2, THREAD_REG 380 mov r1, r0 381 mov r0, r4 382 blx EtsNapiObjEnd 383 b .Lreturn 384 3854: sub r3, r9, #SHORTY_FIRST_FLOAT 386 cmp r3, #(SHORTY_NUM_FLOAT_TYPES - 1) 387 bls 3f 388 b 1f 389 3903: vmov r5, r6, d0 391 mov r0, r4 392 mov r1, THREAD_REG 393 mov r2, r8 394 blx EtsNapiEnd 395 vmov d0, r5, r6 396 b .Lreturn 397 3981: mov r5, r0 399 mov r6, r1 400 mov r0, r4 401 mov r1, THREAD_REG 402 mov r2, r8 403 blx EtsNapiEnd 404 mov r0, r5 405 mov r1, r6 406 b .Lreturn 407 408.Lend: 409 mov r0, r4 410 mov r1, THREAD_REG 411 mov r2, r8 412 bl EtsNapiEnd 413 b .Lreturn 414 415.Lreturn: 416 // Restore callee registers, since GC may change its values while moving objects. 417 sub sp, fp, #(CFRAME_ARM_HARD_CALLEE_REGS_OFFSET - 4) 418 419 mov r2, r7 420 421 ldm sp, {r4 - r10} 422 CFI_RESTORE(r10) 423 CFI_RESTORE(r9) 424 CFI_RESTORE(r8) 425 CFI_RESTORE(r7) 426 CFI_RESTORE(r6) 427 CFI_RESTORE(r5) 428 CFI_RESTORE(r4) 429 mov sp, fp 430 CFI_DEF_CFA(sp, 8) 431 pop {fp} 432 CFI_ADJUST_CFA_OFFSET(-4) 433 CFI_RESTORE(fp) 434 CFI_REMEMBER_STATE 435 436 strb r2, [THREAD_REG, #MANAGED_THREAD_FRAME_KIND_OFFSET] 437 438 // check native exception 439 ldr r3, [THREAD_REG, #MANAGED_THREAD_EXCEPTION_OFFSET] 440 cmp r3, #0 441 beq 5f 442 443 // check frame is compiled 444 cmp r2, #0 445 beq 5f 446 447 // check prev frame is true CFRAME and not BYPASS 448 ldr r3, [fp, #(SLOT_SIZE * COMP_METHOD_OFFSET)] 449 cmp r3, #BYPASS_BRIDGE 450 beq 5f 451 452 add lr, fp, #-CALLER_REG0_OFFSET 453 ldm lr, {r0-r3} 454 455 ldr lr, [fp, #(-CFRAME_FLAGS_SLOT * 4)] 456 tst lr, #CFRAME_HAS_FLOAT_REGS_FLAG_MASK 457 beq 7f 458 459 add lr, fp, #-CALLER_VREG0_OFFSET 460 vldm lr, {d0-d7} 461 4627: 463 pop {lr} 464 CFI_ADJUST_CFA_OFFSET(-4) 465 CFI_RESTORE(lr) 466 467 b ThrowNativeExceptionBridge 468 CFI_RESTORE_STATE 469 4705: 471 pop {lr} 472 CFI_ADJUST_CFA_OFFSET(-4) 473 CFI_RESTORE(lr) 474 bx lr 475 CFI_ENDPROC 476 477