/** * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "arch/asm_support.h" .extern InvokeInterpreter .global DeoptimizeAfterCFrame .type DeoptimizeAfterCFrame, %function DeoptimizeAfterCFrame: CFI_STARTPROC // Parameters: // r0 - thread // r1 - pc of the entry // r2 - pointer to interpreter Frame // r3 - pointer to cframe origin // r4(slot0) - last restored interpreter Frame // Morph CFrame into C2I bridge frame // FROM TO // lr lr // fp <---- COMPILED_CODE_TO_INTERPRETER_BRIDGE // method fp <---- CFI_DEF_CFA(r3, (2 * 4)) CFI_REL_OFFSET(lr, 4) CFI_REL_OFFSET(fp, 0) CFI_REL_OFFSET(THREAD_REG, -((CFRAME_CALLEE_REGS_START_SLOT + 0) * 4)) CFI_REL_OFFSET(r9, -((CFRAME_CALLEE_REGS_START_SLOT + 1) * 4)) CFI_REL_OFFSET(r8, -((CFRAME_CALLEE_REGS_START_SLOT + 2) * 4)) CFI_REL_OFFSET(r7, -((CFRAME_CALLEE_REGS_START_SLOT + 3) * 4)) CFI_REL_OFFSET(r6, -((CFRAME_CALLEE_REGS_START_SLOT + 4) * 4)) CFI_REL_OFFSET(r5, -((CFRAME_CALLEE_REGS_START_SLOT + 5) * 4)) CFI_REL_OFFSET(r4, -((CFRAME_CALLEE_REGS_START_SLOT + 6) * 4)) ldr r4, [sp] sub sp, r3, #((CFRAME_CALLEE_REGS_START_SLOT * 4) + CALLEE_SAVED_SIZE) ldr r5, [r3], #-4 CFI_ADJUST_CFA_OFFSET(4) mov r6, #COMPILED_CODE_TO_INTERPRETER_BRIDGE stm r3, {r5, r6} CFI_REL_OFFSET(fp, 0) mov fp, r3 CFI_DEF_CFA_REGISTER(fp) // Set IFrame's prev_frame to this C2I bridge frame str r3, [r4, #FRAME_PREV_FRAME_OFFSET] BOUNDARY_FRAME_SLOT = ((CFRAME_HEADER_SIZE - 3) + 1) // Copy callee saved registers from cframe into boundary frame. sub r12, r3, #((CFRAME_CALLEE_REGS_START_SLOT - 1) * 4 - 4) sub r11, r3, #((BOUNDARY_FRAME_SLOT - 1) * 4) // Scalar ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(r10, -((BOUNDARY_FRAME_SLOT + 0) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(r9, -((BOUNDARY_FRAME_SLOT + 1) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(r8, -((BOUNDARY_FRAME_SLOT + 2) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(r7, -((BOUNDARY_FRAME_SLOT + 3) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(r6, -((BOUNDARY_FRAME_SLOT + 4) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(r5, -((BOUNDARY_FRAME_SLOT + 5) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(r4, -((BOUNDARY_FRAME_SLOT + 6) * 4)) // Vector (use 32-bit) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s31, -((BOUNDARY_FRAME_SLOT + 7) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s30, -((BOUNDARY_FRAME_SLOT + 8) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s29, -((BOUNDARY_FRAME_SLOT + 9) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s28, -((BOUNDARY_FRAME_SLOT + 10) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s27, -((BOUNDARY_FRAME_SLOT + 11) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s26, -((BOUNDARY_FRAME_SLOT + 12) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s25, -((BOUNDARY_FRAME_SLOT + 13) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s24, -((BOUNDARY_FRAME_SLOT + 14) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s23, -((BOUNDARY_FRAME_SLOT + 15) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s22, -((BOUNDARY_FRAME_SLOT + 16) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s21, -((BOUNDARY_FRAME_SLOT + 17) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s20, -((BOUNDARY_FRAME_SLOT + 18) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s19, -((BOUNDARY_FRAME_SLOT + 19) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s18, -((BOUNDARY_FRAME_SLOT + 20) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s17, -((BOUNDARY_FRAME_SLOT + 21) * 4)) ldr r10, [r12, #-4]! str r10, [r11, #-4]! CFI_REL_OFFSET(s16, -((BOUNDARY_FRAME_SLOT + 22) * 4)) // Save used registers str r3, [sp, #-4]! str r2, [sp, #-4]! str r1, [sp, #-4]! str r0, [sp, #-4]! mov r3, r4 // Arguments are already lay in registers, because signature of DeoptimizeAfterCFrame is similar to InvokeInterpreter blx InvokeInterpreter // r0, r1 - return values // Restore used registers, but not r0, r1 which holds result of the invoked method and should be survive to the end // So we use r4 instead of r0 for restoring THREAD_REG ldr r4, [sp], #4 add sp, sp, #4 ldrd r2, r3, [sp], #8 // Restore stack pointer so that it points to COMPILED_CODE_TO_INTERPRETER_BRIDGE sub sp, r3, #4 // Restore callee saved registers sub r3, r3, #((BOUNDARY_FRAME_SLOT - 1) * 4) ldr r10, [r3, #-4]! ldrd r8, r9, [r3, #-8]! CFI_RESTORE(r9) CFI_RESTORE(r8) ldrd r6, r7, [r3, #-8]! CFI_RESTORE(r7) CFI_RESTORE(r6) // THREAD_REG is r10, but we can't remove `ldr r10, [r3, #-4]!` because we can change number of the THREAD_REG // !NOTE fix this code if THREAD_REG will be change to r4 or r5 mov THREAD_REG, r4 CFI_RESTORE(THREAD_REG) ldrd r4, r5, [r3, #-8]! CFI_RESTORE(r5) CFI_RESTORE(r4) #ifndef PANDA_TARGET_ARM32_ABI_SOFT vldr d15, [r3, #-8] CFI_RESTORE(d15) vldr d14, [r3, #-16] CFI_RESTORE(d14) vldr d13, [r3, #-24] CFI_RESTORE(d13) vldr d12, [r3, #-32] CFI_RESTORE(d12) vldr d11, [r3, #-40] CFI_RESTORE(d11) vldr d10, [r3, #-48] CFI_RESTORE(d10) vldr d9, [r3, #-56] CFI_RESTORE(d9) vldr d8, [r3, #-64] CFI_RESTORE(d8) vmov.f64 d0, r0, r1 #endif ldr fp, [sp, #4] CFI_RESTORE(fp) CFI_DEF_CFA(sp, (4 * 4)) ldr lr, [sp, #12] CFI_RESTORE(lr) add sp, sp, #16 CFI_ADJUST_CFA_OFFSET(-(4 * 4)) bx lr CFI_ENDPROC .global DeoptimizeAfterIFrame .type DeoptimizeAfterIFrame, %function DeoptimizeAfterIFrame: CFI_STARTPROC // Parameters: // r0 - thread // r1 - pc of the entry // r2 - pointer to interpreter Frame // r3 - pointer to cframe origin // r4(slot0) - last restored interpreter Frame // load num_inlined_methods from stack CFI_DEF_CFA(r3, (2 * 4)) CFI_REL_OFFSET(lr, 4) CFI_REL_OFFSET(fp, 0) CFI_REL_OFFSET(r10, -((CFRAME_CALLEE_REGS_START_SLOT + 0) * 4)) CFI_REL_OFFSET(r9, -((CFRAME_CALLEE_REGS_START_SLOT + 1) * 4)) CFI_REL_OFFSET(r8, -((CFRAME_CALLEE_REGS_START_SLOT + 2) * 4)) CFI_REL_OFFSET(r7, -((CFRAME_CALLEE_REGS_START_SLOT + 3) * 4)) CFI_REL_OFFSET(r6, -((CFRAME_CALLEE_REGS_START_SLOT + 4) * 4)) CFI_REL_OFFSET(r5, -((CFRAME_CALLEE_REGS_START_SLOT + 5) * 4)) CFI_REL_OFFSET(r4, -((CFRAME_CALLEE_REGS_START_SLOT + 6) * 4)) ldr r4, [sp] // Restore fp by pointer to the I2C boundary frame // Restore return address, so after interperter finish its work it returns to the I2C bridge mov fp, r3 CFI_DEF_CFA_REGISTER(fp) // Restore stack pointer to the beginning of the cframe mov sp, fp // save num_inlined_methods to new stack str r4, [sp, #-4]! // Restore callee saved registers sub r3, r3, #((CFRAME_CALLEE_REGS_START_SLOT * 4) - 4) ldr r10, [r3, #-4]! CFI_RESTORE(r10) ldrd r8, r9, [r3, #-8]! CFI_RESTORE(r9) CFI_RESTORE(r8) ldrd r6, r7, [r3, #-8]! CFI_RESTORE(r7) CFI_RESTORE(r6) ldrd r4, r5, [r3, #-8]! CFI_RESTORE(r5) CFI_RESTORE(r4) #ifndef PANDA_TARGET_ARM32_ABI_SOFT vldr d15, [r3, #-8] CFI_RESTORE(d15) vldr d14, [r3, #-16] CFI_RESTORE(d14) vldr d13, [r3, #-24] CFI_RESTORE(d13) vldr d12, [r3, #-32] CFI_RESTORE(d12) vldr d11, [r3, #-40] CFI_RESTORE(d11) vldr d10, [r3, #-48] CFI_RESTORE(d10) vldr d9, [r3, #-56] CFI_RESTORE(d9) vldr d8, [r3, #-64] CFI_RESTORE(d8) #endif // load num_inlined_methods from new stack ldr r3, [sp], #4 bl InvokeInterpreter #ifndef PANDA_TARGET_ARM32_ABI_SOFT // InvokeInterpreter returns int64 value, but result can be double, so we copy value to vector register vmov.f64 d0, r0, r1 #endif pop {fp, lr} CFI_RESTORE(lr) CFI_RESTORE(fp) CFI_DEF_CFA(sp, 0) bx lr CFI_ENDPROC .global DropCompiledFrameAndReturn .type DropCompiledFrameAndReturn, %function DropCompiledFrameAndReturn: CFI_STARTPROC // r0 - pointer to cframe origin CFI_DEF_CFA(r0, (2 * 4)) CFI_REL_OFFSET(lr, 4) CFI_REL_OFFSET(fp, 0) CFI_REL_OFFSET(r10, -((CFRAME_CALLEE_REGS_START_SLOT + 0) * 4)) CFI_REL_OFFSET(r9, -((CFRAME_CALLEE_REGS_START_SLOT + 1) * 4)) CFI_REL_OFFSET(r8, -((CFRAME_CALLEE_REGS_START_SLOT + 2) * 4)) CFI_REL_OFFSET(r7, -((CFRAME_CALLEE_REGS_START_SLOT + 3) * 4)) CFI_REL_OFFSET(r6, -((CFRAME_CALLEE_REGS_START_SLOT + 4) * 4)) CFI_REL_OFFSET(r5, -((CFRAME_CALLEE_REGS_START_SLOT + 5) * 4)) CFI_REL_OFFSET(r4, -((CFRAME_CALLEE_REGS_START_SLOT + 6) * 4)) mov fp, r0 CFI_DEF_CFA_REGISTER(fp) // Restore callee saved registers from dropped CFrame sub r0, r0, #((CFRAME_CALLEE_REGS_START_SLOT * 4) - 4) ldr r10, [r0, #-4]! CFI_RESTORE(r10) ldrd r8, r9, [r0, #-8]! CFI_RESTORE(r9) CFI_RESTORE(r8) ldrd r6, r7, [r0, #-8]! CFI_RESTORE(r7) CFI_RESTORE(r6) ldrd r4, r5, [r0, #-8]! CFI_RESTORE(r5) CFI_RESTORE(r4) #ifndef PANDA_TARGET_ARM32_ABI_SOFT vldr d15, [r0, #-8] CFI_RESTORE(d15) vldr d14, [r0, #-16] CFI_RESTORE(d14) vldr d13, [r0, #-24] CFI_RESTORE(d13) vldr d12, [r0, #-32] CFI_RESTORE(d12) vldr d11, [r0, #-40] CFI_RESTORE(d11) vldr d10, [r0, #-48] CFI_RESTORE(d10) vldr d9, [r0, #-56] CFI_RESTORE(d9) vldr d8, [r0, #-64] CFI_RESTORE(d8) #endif // We need to clear return value, since it will be written to the IFrame's accumulator. Without this, it holds // garbage and StackWalker verification might fail. mov r0, #0 mov r1, #0 mov sp, fp pop {fp, lr} CFI_RESTORE(lr) CFI_RESTORE(fp) CFI_DEF_CFA(sp, 0) bx lr CFI_ENDPROC