• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 "ecmascript/compiler/trampoline/aarch64/common_call.h"
17 
18 #include "ecmascript/runtime_call_id.h"
19 
20 namespace panda::ecmascript::aarch64 {
21 using Label = panda::ecmascript::Label;
22 #define __ assembler->
23 
PushAsmInterpBridgeFrame(ExtendedAssembler * assembler)24 void CommonCall::PushAsmInterpBridgeFrame(ExtendedAssembler *assembler)
25 {
26     Register fp(X29);
27     Register sp(SP);
28 
29     [[maybe_unused]] TempRegister1Scope scope1(assembler);
30     Register frameTypeRegister = __ TempRegister1();
31 
32     __ Mov(frameTypeRegister, Immediate(static_cast<int64_t>(FrameType::ASM_INTERPRETER_BRIDGE_FRAME)));
33     // 2 : return addr & frame type
34     __ Stp(frameTypeRegister, Register(X30), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
35     // 2 : prevSp & pc
36     __ Stp(Register(Zero), Register(FP), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
37     __ Add(fp, sp, Immediate(24));  // 24: skip frame type, prevSp, pc
38 
39     if (!assembler->FromInterpreterHandler()) {
40         __ CalleeSave();
41     }
42 }
43 
PopAsmInterpBridgeFrame(ExtendedAssembler * assembler)44 void CommonCall::PopAsmInterpBridgeFrame(ExtendedAssembler *assembler)
45 {
46     Register sp(SP);
47 
48     if (!assembler->FromInterpreterHandler()) {
49         __ CalleeRestore();
50     }
51     // 2: prevSp & pc
52     __ Ldp(Register(Zero), Register(FP), MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
53     // 2: return addr & frame type
54     __ Ldp(Register(Zero), Register(X30), MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
55 }
56 
57 
PushLeaveFrame(ExtendedAssembler * assembler,Register glue)58 void CommonCall::PushLeaveFrame(ExtendedAssembler *assembler, Register glue)
59 {
60     TempRegister2Scope temp2Scope(assembler);
61     Register frameType = __ TempRegister2();
62     Register currentSp(X6);
63     Register sp(SP);
64 
65     // construct leave frame
66     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::LEAVE_FRAME)));
67     __ PushFpAndLr();
68     // 2 : 2 means pairs
69     __ Stp(Register(X19), frameType, MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
70     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
71     // save to thread currentLeaveFrame_;
72     __ Str(Register(FP), MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
73 }
74 
75 
PopLeaveFrame(ExtendedAssembler * assembler)76 void CommonCall::PopLeaveFrame(ExtendedAssembler *assembler)
77 {
78     Register sp(SP);
79     Register currentSp(X6);
80     TempRegister2Scope temp2Scope(assembler);
81     Register frameType = __ TempRegister2();
82     // 2 : 2 means pairs
83     __ Ldp(Register(X19), frameType, MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
84     __ RestoreFpAndLr();
85 }
86 
PushArgsWithArgv(ExtendedAssembler * assembler,Register glue,Register argc,Register argv,Register op,Register currentSlot,Label * next,Label * stackOverflow)87 void CommonCall::PushArgsWithArgv(ExtendedAssembler *assembler, Register glue, Register argc,
88     Register argv, Register op, Register currentSlot, Label *next, Label *stackOverflow)
89 {
90     Label loopBeginning;
91     if (next != nullptr) {
92         __ Cmp(argc.W(), Immediate(0));
93         __ B(Condition::LS, next);
94     }
95     if (stackOverflow != nullptr) {
96         StackOverflowCheck(assembler, glue, currentSlot, argc, op, stackOverflow);
97     }
98     __ Add(argv, argv, Operand(argc.W(), UXTW, 3));  // 3: argc * 8
99     __ Bind(&loopBeginning);
100     __ Ldr(op, MemoryOperand(argv, -FRAME_SLOT_SIZE, PREINDEX));  // -8: 8 bytes
101     __ Str(op, MemoryOperand(currentSlot, -FRAME_SLOT_SIZE, PREINDEX));  // -8: 8 bytes
102     __ Sub(argc.W(), argc.W(), Immediate(1));
103     __ Cbnz(argc.W(), &loopBeginning);
104 }
105 
PushArgsWithArgvInPair(ExtendedAssembler * assembler,Register argc,Register argv,Register padding,Register op1,Register op2,Label * next)106 void CommonCall::PushArgsWithArgvInPair(ExtendedAssembler *assembler, Register argc,
107     Register argv, Register padding, Register op1, Register op2, Label *next)
108 {
109     Register sp(SP);
110     if (next != nullptr) {
111         __ Cmp(argc.W(), Immediate(0));
112         __ B(Condition::LS, next);
113     }
114 
115     Label copyArgs;
116     __ Tbnz(argc, 0, &copyArgs);
117     {
118         __ Add(argv, argv, Operand(argc.W(), UXTW, 3)); // 3: argc * 8
119         __ Ldr(op1, MemoryOperand(argv, -FRAME_SLOT_SIZE, PREINDEX));
120         __ Stp(op1, Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
121         __ Sub(argc.W(), argc.W(), Immediate(1)); // 1: push the top arg already
122         __ Sub(argv, argv, Operand(argc.W(), UXTW, 3)); // 3: argc * 8
123         __ B(&copyArgs);
124     }
125     __ Bind(&copyArgs);
126     {
127         Label loopBeginning;
128         Label pushPadding;
129         __ Add(argv, argv, Operand(argc.W(), UXTW, 3));  // 3: argc * 8
130 
131         __ Cmp(argc.W(), Immediate(1));  // 1: argc is odd number in copyArgs
132         __ B(Condition::LS, &pushPadding);
133 
134         __ Bind(&loopBeginning);
135         __ Ldp(op1, op2, MemoryOperand(argv, -DOUBLE_SLOT_SIZE, PREINDEX));
136         __ Stp(op1, op2, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
137         __ Sub(argc.W(), argc.W(), Immediate(2));  // 2: pair
138         __ Cmp(argc.W(), Immediate(1));  // 1: argc is odd number in copyArgs
139         __ B(Condition::HI, &loopBeginning);
140 
141         __ Bind(&pushPadding);
142         __ Ldr(op2, MemoryOperand(argv, -FRAME_SLOT_SIZE, PREINDEX));
143         __ Stp(padding, op2, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
144         if (next != nullptr) {
145             __ B(next);
146         }
147     }
148 }
149 
PushUndefinedWithArgc(ExtendedAssembler * assembler,Register glue,Register argc,Register temp,Register currentSlot,Label * next,Label * stackOverflow)150 void CommonCall::PushUndefinedWithArgc(ExtendedAssembler *assembler, Register glue, Register argc, Register temp,
151     Register currentSlot, Label *next, Label *stackOverflow)
152 {
153     if (next != nullptr) {
154         __ Cmp(argc.W(), Immediate(0));
155         __ B(Condition::LE, next);
156     }
157     if (stackOverflow != nullptr) {
158         StackOverflowCheck(assembler, glue, currentSlot, argc, temp, stackOverflow);
159     }
160     Label loopBeginning;
161     __ Mov(temp, Immediate(JSTaggedValue::VALUE_UNDEFINED));
162     __ Bind(&loopBeginning);
163     __ Str(temp, MemoryOperand(currentSlot, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
164     __ Sub(argc.W(), argc.W(), Immediate(1));
165     __ Cbnz(argc.W(), &loopBeginning);
166 }
167 
StackOverflowCheck(ExtendedAssembler * assembler,Register glue,Register currentSlot,Register numArgs,Register op,Label * stackOverflow)168 void CommonCall::StackOverflowCheck(ExtendedAssembler *assembler, Register glue, Register currentSlot,
169     Register numArgs, Register op, Label *stackOverflow)
170 {
171     __ Ldr(op, MemoryOperand(glue, JSThread::GlueData::GetStackLimitOffset(false)));
172     Label skipThrow;
173     __ Sub(op, currentSlot, Operand(op, UXTX, 0));
174     __ Cmp(op, Operand(numArgs, LSL, 3));  // 3: each args occupies 8 bytes
175     __ B(Condition::GT, &skipThrow);
176     __ Ldr(op, MemoryOperand(glue, JSThread::GlueData::GetAllowCrossThreadExecutionOffset(false)));
177     __ Cbz(op, stackOverflow);
178     __ Bind(&skipThrow);
179 }
180 
PushAsmBridgeFrame(ExtendedAssembler * assembler)181 void CommonCall::PushAsmBridgeFrame(ExtendedAssembler *assembler)
182 {
183     Register sp(SP);
184     TempRegister2Scope temp2Scope(assembler);
185     Register frameType = __ TempRegister2();
186     __ PushFpAndLr();
187     // construct frame
188     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::ASM_BRIDGE_FRAME)));
189     // 2 : 2 means pairs. X19 means calleesave and 16bytes align
190     __ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
191     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
192 }
193 
PopAsmBridgeFrame(ExtendedAssembler * assembler)194 void CommonCall::PopAsmBridgeFrame(ExtendedAssembler *assembler)
195 {
196     TempRegister2Scope temp2Scope(assembler);
197     Register sp(SP);
198     Register frameType = __ TempRegister2();
199     // 2 : 2 means pop call site sp and type
200     __ Ldp(Register(X19), frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
201     __ RestoreFpAndLr();
202 }
203 #undef __
204 }  // panda::ecmascript::aarch64