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, ©Args);
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(©Args);
124 }
125 __ Bind(©Args);
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