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