• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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