• 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/amd64/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
24    // load arguments into %rdi, %rsi, %rdx, %rcx, %r8, %r9
25    movq (0 * 8)(\begin_ptr), %rdi
26    movq (1 * 8)(\begin_ptr), %rsi
27    movq (2 * 8)(\begin_ptr), %rdx
28    movq (3 * 8)(\begin_ptr), %rcx
29    movq (4 * 8)(\begin_ptr), %r8
30    movq (5 * 8)(\begin_ptr), %r9
31.endm
32
33.macro LOAD_FPR_ARGS begin_ptr
34    // load arguments into xmm0-xmm7
35    movq -(1 * 8)(\begin_ptr), %xmm0
36    movq -(2 * 8)(\begin_ptr), %xmm1
37    movq -(3 * 8)(\begin_ptr), %xmm2
38    movq -(4 * 8)(\begin_ptr), %xmm3
39    movq -(5 * 8)(\begin_ptr), %xmm4
40    movq -(6 * 8)(\begin_ptr), %xmm5
41    movq -(7 * 8)(\begin_ptr), %xmm6
42    movq -(8 * 8)(\begin_ptr), %xmm7
43.endm
44
45// The macro works with the stack prepared by 'PrepareArgStack' macro
46// It takes an argument in arg_reg and stores it to the corresponding stack space
47// depends on its type.
48// After the arg gets stored the macro advances the corresponding pointer
49// The macro assumes %r8 contains base address for gpr and fpr args
50.macro PUSH_ARG arg_reg, tag_reg, gpr_ptr, fpr_ptr, stack_ptr, tmp_reg, next_label
51    subl $SHORTY_FIRST_FLOAT, %r11d
52    cmpl $(SHORTY_NUM_FLOAT_TYPES - 1), %r11d
53    jbe 1f
54
55    // it is an integer arg
56
57#ifdef PANDA_USE_32_BIT_POINTER
58    // if arg is a reference, zero out garbage in upper 32 bits
59    cmpl $(SHORTY_REFERENCE - SHORTY_FIRST_FLOAT), %r11d
60    jne 4f
61    shlq $32, \arg_reg
62    shrq $32, \arg_reg
634:
64#endif
65
66    // determine whether there are free gprs
67    movq \gpr_ptr, \tmp_reg
68    subq %r8, \tmp_reg
69    cmpq $48, \tmp_reg
70    jge 2f
71
72    //there are free gprs
73    movq \arg_reg, (\gpr_ptr)
74    addq $8, \gpr_ptr
75    // check if the arg has type 'any'
76    cmpl $(SHORTY_TAGGED - SHORTY_FIRST_FLOAT), %r11d
77    jne \next_label
78    // value of type 'any'
79    // store the tag if there are free gprs
80    cmpq $40, \tmp_reg
81    jge 3f
82    movq \tag_reg, (\gpr_ptr)
83    addq $8, \gpr_ptr
84    jmp \next_label
853:  // store the tag to the stack
86    movq \tag_reg, (\stack_ptr)
87    addq $8, \stack_ptr
88    jmp \next_label
89
901:
91    // it is a float arg
92    // determine whether there are free float regs
93    movq %r8, \tmp_reg
94    subq \fpr_ptr, \tmp_reg
95    cmpq $64, \tmp_reg
96    jge 2f
97
98    // there are free float regs
99    subq $8, \fpr_ptr
100    movq \arg_reg, (\fpr_ptr)
101    jmp \next_label
1022:
103    // there are no free regs. It is a stack arg
104    movq \arg_reg, (\stack_ptr)
105    addq $8, \stack_ptr
106    // check if the arg has type 'any'
107    cmpl $(SHORTY_TAGGED - SHORTY_FIRST_FLOAT), %r11d
108    jne \next_label
109    movq \tag_reg, (\stack_ptr)
110    addq $8, \stack_ptr
111.endm
112
113// The macro reserves stack space for arguments
114// The reserved stack space is divided into 3 part:
115// 1. the part for arguments passed via the stack
116// 2. the part for the arguments passed via GPRs
117// 3. the part for the arguments passed via the float registers
118// These parts are located as follow:
119// +--------------+
120// |  fpreg argN  |
121// +--------------+
122// |      ...     |
123// +--------------+
124// |  fpreg arg0  |
125// +--------------+ <- %r8 (base)
126// |   gpr arg0   |
127// +--------------+
128// |      ...     |
129// +--------------+
130// |   gpr argN   |
131// +--------------+ <- %rsp
132// |  stack arg0  |
133// +--------------+
134// |      ...     |
135// +--------------+
136// |  stack argN  |
137// +--------------+
138// |    callee    |
139// +--------------+
140// |  THREAD_REG  |
141// +--------------+
142// |     %rbp     |
143// +--------------+
144// | INTERPRETER_ |
145// | TO_COMPILED_ |
146// | CODE_BRIDGE  |
147// +--------------+ <- %rbp
148// |    iframe    |
149// +--------------+
150// | return addr  |
151// +--------------+
152// Input:
153// %rax - SHORTY_PTR_REG
154// %r10d - SHORTY_REG
155// %r11d - shorty value
156// Output (as on the picture)
157// %r8 - gpr base pointer. Points to the beginning of GPR and FPR args space.
158// %rsp - Points to the last stack argument.
159.macro PREPARE_ARG_STACK
160    // %rax - SHORTY_PTR_REG, %r10d - SHORTY_REG, %r11d - shorty value, %esi - GPR arg counter,
161    // %edi - float arg counter, %rdx - stack pointer, %r9 - temp
162    movl $1, %esi // Method*
163    xorl %edi, %edi
164    movq %rsp, %rdx
165
16630:
167    NEXT_SHORTY %r11d
168    cmpl $0, %r11d
169    je 40f
170
171    subl $SHORTY_FIRST_FLOAT, %r11d
172    cmpl $(SHORTY_NUM_FLOAT_TYPES - 1), %r11d
173    jbe 10f
174
175    // it is an integer value
176    xorq %r9, %r9
177    cmpl $(SHORTY_TAGGED - SHORTY_FIRST_FLOAT), %r11d
178    sete %r9b
179    addl $1, %r9d
180    addl %r9d, %esi
181
182    cmpl $6, %esi
183    jle 30b // there are free GPRs
184
185    // there is no GPRs. Adjust %esi and reserve space on the stack
186    movq %rsi, %r9
187    subq $6, %r9
188    movl $6, %esi
189    shlq $3, %r9
190    subq %r9, %rdx
191    jmp 30b
192
19310:
194    // it is a float value
195    cmpl $7, %edi
196    ja 20f
197
198    // there are free float registers
199    addl $1, %edi
200    jmp 30b
201
20220:
203    // there is no more GP registers
204    subq $8, %rdx
205    jmp 30b
206
20740:
208    // make %rsp 16 bytes aligned
209    andq $-16, %rdx
210    // reserve stack space for stack arguments
211    movq %rdx, %rsp
212
213    // reserve gpr space (6 regs)
214    leaq -(6 * 8)(%rsp), %r8
215.endm
216
217// void InterpreterToCompiledCodeBridge(const BytecodeInstruction* insn, const Frame *iframe, const Method *method, ManagedThread* thread)
218.global InterpreterToCompiledCodeBridge
219TYPE_FUNCTION(InterpreterToCompiledCodeBridge)
220InterpreterToCompiledCodeBridge:
221    CFI_STARTPROC
222    CFI_DEF_CFA(rsp, 8)
223
224    pushq %rsi // iframe*
225    CFI_ADJUST_CFA_OFFSET(8)
226
227    movq %rsp, %rax
228    CFI_DEF_CFA_REGISTER(rax)
229
230    // According to the current frame kind set the bridge type
231    movb MANAGED_THREAD_FRAME_KIND_OFFSET(%rcx), %r10b
232    testb %r10b, %r10b
233    movq $INTERPRETER_TO_COMPILED_CODE_BRIDGE, %r11
234    movq $BYPASS_BRIDGE, %r10
235    cmovne %r10, %r11
236    pushq %r11
237
238    pushq %rbp
239    CFI_REL_OFFSET(rbp, -(2 * 8))
240
241    movq %rax, %rbp // set frame pointer
242    CFI_DEF_CFA_REGISTER(rbp)
243
244    pushq %THREAD_REG
245    CFI_REL_OFFSET(THREAD_REG, -(3 * 8))
246    pushq %r14
247    CFI_REL_OFFSET(r14, -(4 * 8))
248    pushq %r13
249    CFI_REL_OFFSET(r13, -(5 * 8))
250    pushq %r12
251    CFI_REL_OFFSET(r12, -(6 * 8))
252    pushq %rbx
253    CFI_REL_OFFSET(rbx, -(7 * 8))
254
255    pushq %rcx // thread*
256    subq $16, %rsp // do not delete, used to copy args
257    // %rsp should be 16-byte aligned here
258
259    // setup regs as follow
260    // %rax - SHORTY_PTR_REG, %r10d - SHORTY_REG, %r11d - shorty value, %rbx - insn_ptr,
261    // %r9 - temp (used by PREPARE_ARG_STACK), %r12 - frame.vregs, %r13 - method, %r14 - method.shorty
262    movq %rdi, %rbx // insn*
263    leaq FRAME_VREGS_OFFSET(%rsi), %r12 // frame.vregs
264    movq %rdx, %r13 // method
265    movq METHOD_SHORTY_OFFSET(%rdx), %r14 // method.shorty
266
267    movq %r14, %SHORTY_PTR_REG
268    INIT_SHORTY_REG
269
270    // parameter 'this' of instance methods is not encoded in the shorty
271    // in case of instance method hack SHORTY_REG by replacing the return type by REF
272    // in the another case just skip the return type
273    movl METHOD_ACCESS_FLAGS_OFFSET(%r13), %ecx
274    testl $ACCESS_STATIC, %ecx
275    jne 1f
276
277    // it is an instance method
278    andl $-16, %SHORTY_REG // clear the least significant 4 bits
279    orl $SHORTY_REFERENCE, %SHORTY_REG
280    jmp 2f
281
2821:
283    SKIP_SHORTY
2842:
285    movl %SHORTY_REG, %r15d // save value of the shorty reg
286    PREPARE_ARG_STACK
287
288    // setup regs as follow
289    // %rax - SHORTY_PTR_REG, %r10d - SHORTY_REG, %r11d - shorty value, %rsi - stack arg ptr,
290    // %rdi - float arg ptr, %rbx - insn_ptr, %r12 - frame.vregs, %r8 - arg base ptr
291    // %rdx - gpr arg ptr, %rcx, %r9 - temps, %r14 - method.shorty
292    movq %rsp, %rsi
293    movq %r8, %rdi
294    movq %r8, %rdx
295    leaq 2(%r14), %SHORTY_PTR_REG // since SHORTY_REG contains already read value SHORTY_REG_PTR should be shifted
296    movl %r15d, %SHORTY_REG // restore the value of the shorty reg
297
298    // store method (the first arg)
299    movq %r13, (%rdx)
300    addq $8, %rdx
301    movzbl (%rbx), %ecx
302    addq $1, %rbx // read opcode and advance insn_ptr
303
304    // The file contains code which checks opcode and jumps
305    // to the corresponding handler.
306    // At the end each handler jumps to .Lload_reg_args label.
307    // The file is autogenerated from runtime/templates/bridge_dispatch.S.erb
308    // Handlers are distinguished by format and located in the corresponding files with name:
309    // handle_call_<format>.S
310    // If you get a compilation error that there is no such file it seems
311    // new call format was introduced and you have to implement the corresponding handler.
312#include "bridge_dispatch_amd64.S"
313
314.Lload_reg_args:
315    movq %r8, %rax
316    LOAD_FPR_ARGS %rax
317    LOAD_GPR_ARGS %rax
318
319    // invoke the method
320    // since the first argument is Method* it must be in %rdi
321    movq METHOD_COMPILED_ENTRY_POINT_OFFSET(%rdi), %rax
322    movq -64(%rbp), %THREAD_REG
323    callq *%rax
324
325    // handle the result
326    // setup registers as follow
327    // %rax, %rdx / %xmm0 - result, %r14d - shorty[0] & 0xF, %r12 - frame.acc, %rcx - temp
328    movzbl (%r14), %r14d
329    andl $0xF, %r14d
330
331    cmpl $SHORTY_VOID, %r14d
332    je .Lreturn
333
334    movq (%rbp), %r12 // load iframe from the stack
335    addq $FRAME_ACC_OFFSET, %r12
336
337    // get tag in rdx
338    cmpl $SHORTY_TAGGED, %r14d
339    je 1f // tag already in rdx
340    xorq %rdx, %rdx
341    cmpl $SHORTY_REFERENCE, %r14d
342    sete %dl
3431:  // store tag
344    movq %rdx, FRAME_ACC_MIRROR_OFFSET(%r12)
345
346    movl %r14d, %esi
347    movl %r14d, %edi
348
349    subl $SHORTY_FIRST_FLOAT, %r14d
350    cmpl $(SHORTY_NUM_FLOAT_TYPES - 1), %r14d
351    jbe 1f // float
352
353    subl $(SHORTY_FIRST_32), %esi
354    cmpl $(SHORTY_NUM_MIN32_TYPES - 1), %esi
355    jbe .L64_32 // 64-bit int / ref or 32-bit int
356
357    // less than 32-bit
358    cmpl $SHORTY_I16, %edi
359    je .LI16
360    ja .LU16
361
362    cmpl $SHORTY_I8, %edi
363    je .LI8
364    jne .LU1_U8
365
3661:
367    // store float value into acc
368    movsd %xmm0, (%r12)
369    jmp .Lreturn
370.LU1_U8:
371    movzbl %al, %eax
372    jmp .L64_32
373.LI8:
374    movsbl %al, %eax
375    jmp .L64_32
376.LI16:
377    movswl %ax, %eax
378    jmp .L64_32
379.LU16:
380    movzwl %ax, %eax
381.L64_32:
382    // store integer value into acc
383    movq %rax, (%r12)
384
385.Lreturn:
386    leaq -56(%rbp), %rsp
387    popq %rbx
388    CFI_RESTORE(rbx)
389    popq %r12
390    CFI_RESTORE(r12)
391    popq %r13
392    CFI_RESTORE(r13)
393    popq %r14
394    CFI_RESTORE(r14)
395    popq %THREAD_REG
396    CFI_RESTORE(THREAD_REG)
397    popq %rbp
398    CFI_RESTORE(rbp)
399    CFI_DEF_CFA(rsp, (3 * 8))
400    addq $16, %rsp
401    CFI_ADJUST_CFA_OFFSET(-(2 * 8))
402    retq
403    CFI_ENDPROC
404
405// uint64_t InvokeCompiledCodeWithArguments(const int64_t* args, const Frame *iframe, const Method *method, ManagedThread* thread)
406.global InvokeCompiledCodeWithArgArray
407TYPE_FUNCTION(InvokeCompiledCodeWithArgArray)
408InvokeCompiledCodeWithArgArray:
409    CFI_STARTPROC
410    CFI_DEF_CFA(rsp, 8)
411
412    pushq %rsi // iframe*
413    CFI_ADJUST_CFA_OFFSET(8)
414
415    movq %rsp, %rax
416    CFI_DEF_CFA_REGISTER(rax)
417
418    // According to the current frame kind set the bridge type
419    movb MANAGED_THREAD_FRAME_KIND_OFFSET(%rcx), %r10b
420    testb %r10b, %r10b
421    movq $INTERPRETER_TO_COMPILED_CODE_BRIDGE, %r11
422    movq $BYPASS_BRIDGE, %r10
423    cmovne %r10, %r11
424    pushq %r11
425
426    pushq %rbp
427    CFI_REL_OFFSET(rbp, -(2 * 8))
428
429    movq %rax, %rbp // set frame pointer
430    CFI_DEF_CFA_REGISTER(rbp)
431
432    pushq %THREAD_REG
433    CFI_REL_OFFSET(THREAD_REG, -(3 * 8))
434    pushq %r14
435    CFI_REL_OFFSET(r14, -(4 * 8))
436    pushq %r13
437    CFI_REL_OFFSET(r13, -(5 * 8))
438    pushq %r12
439    CFI_REL_OFFSET(r12, -(6 * 8))
440    pushq %rbx
441    CFI_REL_OFFSET(rbx, -(7 * 8))
442
443    pushq %rcx // thread*
444    subq $16, %rsp // do not delete, used to copy args
445    // %rsp should be 16-byte aligned here
446
447    // store method.shorty_ to %r14
448    movq %rdx, %r13 // method
449    movq METHOD_SHORTY_OFFSET(%rdx), %r14 // method.shorty
450
451    // check args array
452    // it could be null in case the method has no args
453    cmpq $0, %rdi
454    jne 1f
455
456    movq %r13, %rdi
457    jmp .Linvoke_with_args
458
4591:
460    // setup regs as follow
461    // %rax - SHORTY_PTR_REG, %r10d - SHORTY_REG, %r11d - shorty value, %rbx - arg_ptr
462    // %r13 - method, %r14 - method.shorty
463    movq %rdi, %rbx
464    movq %r14, %SHORTY_PTR_REG
465    INIT_SHORTY_REG
466
467    // parameter 'this' of instance methods is not encoded in the shorty
468    // in case of instance method hack SHORTY_REG by replacing the return type by REF
469    // in the another case just skip the return type
470    movl METHOD_ACCESS_FLAGS_OFFSET(%r13), %ecx
471    testl $ACCESS_STATIC, %ecx
472    jne 1f
473
474    // it is an instance method
475    andl $-16, %SHORTY_REG
476    orl $SHORTY_REFERENCE, %SHORTY_REG
477    jmp 2f
478
4791:
480    SKIP_SHORTY
4812:
482    movl %SHORTY_REG, %r15d // save value of the shorty reg
483    PREPARE_ARG_STACK
484
485    // setup regs as follow
486    // %rax - SHORTY_PTR_REG, %r10d - SHORTY_REG, %r11d - shorty value, %rsi - stack arg ptr,
487    // %rdi - float arg ptr, %rbx - arg_ptr, %r8 - arg base ptr, %rdx - gpr arg ptr,
488    // %rcx, %r9 - temps, %r14 - method.shorty, %r13 - method
489    movq %rsp, %rsi
490    movq %r8, %rdi
491    movq %r8, %rdx
492    leaq 2(%r14), %SHORTY_PTR_REG // since SHORTY_REG contains already read value SHORTY_REG_PTR should be shifted
493    movl %r15d, %SHORTY_REG // restore the value of the shorty reg
494
495    // store method (the last arg)
496    movq %r13, (%rdx)
497    addq $8, %rdx
498
499.Lloop_args_push:
500    NEXT_SHORTY %r11d
501    cmpl $0, %r11d
502    je .Lloopend_args_push
503
504    movq (%rbx), %rcx
505    addq $8, %rbx
506    cmpl $SHORTY_TAGGED, %r11d
507    jne 1f
508    // Load the tag
509    movq (%rbx), %r13
510    addq $8, %rbx
511
5121:  PUSH_ARG %rcx, %r13, %rdx, %rdi, %rsi, %r9, .Lloop_args_push
513    jmp .Lloop_args_push
514.Lloopend_args_push:
515    // load arguments into regs
516    movq %r8, %rax
517    LOAD_FPR_ARGS %rax
518    LOAD_GPR_ARGS %rax
519
520.Linvoke_with_args:
521    // invoke the method
522    // since the first argument is Method* it must be in %rdi
523    movq METHOD_COMPILED_ENTRY_POINT_OFFSET(%rdi), %rax
524    movq -64(%rbp), %THREAD_REG
525    callq *%rax
526
527    // handle the result
528    // we should return it in %rax
529    // setup registers as follow
530    // %rax / %xmm0 - result, %r14d - shorty[0] & 0xF
531    movzbl (%r14), %r14d
532    andl $0xF, %r14d
533
534    cmpl $SHORTY_VOID, %r14d
535    je .Lreturn_
536
537    movl %r14d, %esi
538    movl %r14d, %edi
539
540    subl $SHORTY_FIRST_FLOAT, %r14d
541    cmpl $(SHORTY_NUM_FLOAT_TYPES - 1), %r14d
542    jbe 1f
543
544    subl $(SHORTY_FIRST_32), %esi
545    cmpl $(SHORTY_NUM_MIN32_TYPES - 1), %esi
546    jbe .Lreturn_ // 64-bit int / ref or 32-bit int
547
548    // less than 32-bit
549    cmpl $SHORTY_I16, %edi
550    je .LI16_
551    ja .LU16_
552
553    cmpl $SHORTY_I8, %edi
554    je .LI8_
555    jne .LU1_U8_
556
5571:
558    movq %xmm0, %rax
559    jmp .Lreturn_
560.LU1_U8_:
561    movzbl %al, %eax
562    jmp .Lreturn_
563.LI8_:
564    movsbl %al, %eax
565    jmp .Lreturn_
566.LI16_:
567    movswl %ax, %eax
568    jmp .Lreturn_
569.LU16_:
570    movzwl %ax, %eax
571
572.Lreturn_:
573    leaq -56(%rbp), %rsp
574    popq %rbx
575    CFI_RESTORE(rbx)
576    popq %r12
577    CFI_RESTORE(r12)
578    popq %r13
579    CFI_RESTORE(r13)
580    popq %r14
581    CFI_RESTORE(r14)
582    popq %THREAD_REG
583    CFI_RESTORE(THREAD_REG)
584    popq %rbp
585    CFI_RESTORE(rbp)
586    CFI_DEF_CFA(rsp, (3 * 8))
587    addq $16, %rsp
588    CFI_ADJUST_CFA_OFFSET(-(2 * 8))
589    retq
590    CFI_ENDPROC
591
592