1 /*
2 * Copyright (c) 2023 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/compiler/assembler/assembler.h"
19 #include "ecmascript/compiler/argument_accessor.h"
20 #include "ecmascript/compiler/common_stubs.h"
21 #include "ecmascript/compiler/rt_call_signature.h"
22 #include "ecmascript/deoptimizer/deoptimizer.h"
23 #include "ecmascript/ecma_runtime_call_info.h"
24 #include "ecmascript/frames.h"
25 #include "ecmascript/js_function.h"
26 #include "ecmascript/method.h"
27 #include "ecmascript/js_thread.h"
28 #include "ecmascript/message_string.h"
29 #include "ecmascript/runtime_call_id.h"
30
31 namespace panda::ecmascript::aarch64 {
32 using Label = panda::ecmascript::Label;
33 #define __ assembler->
34
35 // * uint64_t OptimizedFastCallEntry(uintptr_t glue, uint32_t actualNumArgs, const JSTaggedType argV[],
36 // uintptr_t prevFp)
37 // * Arguments:
38 // %x0 - glue
39 // %x1 - actualNumArgs
40 // %x2 - argV
41 // %x3 - prevFp
OptimizedFastCallEntry(ExtendedAssembler * assembler)42 void OptimizedFastCall::OptimizedFastCallEntry(ExtendedAssembler *assembler)
43 {
44 __ BindAssemblerStub(RTSTUB_ID(OptimizedFastCallEntry));
45 Register glueReg(X0);
46 Register argc(X1);
47 Register argV(X2);
48 Register prevFpReg(X3);
49 Register sp(SP);
50
51 OptimizedCall::PushJSFunctionEntryFrame (assembler, prevFpReg);
52 __ Mov(Register(X3), argc);
53 __ Mov(Register(X4), argV);
54 Register tmpArgc(X3);
55 Register tmpArgV(X4);
56
57 __ Mov(Register(X20), glueReg);
58 __ Ldr(Register(X1), MemoryOperand(tmpArgV, 0));
59 __ Ldr(Register(X2), MemoryOperand(tmpArgV, FRAME_SLOT_SIZE));
60 __ Add(tmpArgV, tmpArgV, Immediate(DOUBLE_SLOT_SIZE));
61
62 __ CallAssemblerStub(RTSTUB_ID(JSFastCallWithArgV), false);
63 __ Mov(Register(X2), Register(X20));
64 OptimizedCall::PopJSFunctionEntryFrame(assembler, Register(X2));
65 __ Ret();
66 }
67
68 // * uint64_t OptimizedFastCallAndPushUndefined(uintptr_t glue, uint32_t expectedNumArgs, uint32_t actualNumArgs,
69 // uintptr_t codeAddr, uintptr_t argv)
70 // * Arguments wil CC calling convention:
71 // %x0 - glue
72 // %x1 - actualNumArgs
73 // %x2 - func
74 // %x3 - new target
75 // %x4 - this
76 // %x5 - arg0
77 // %x6 - arg1
78 // %x7 - arg2
79 //
80 // * The OptimizedJSFunctionArgsConfig Frame's structure is illustrated as the following:
81 // +--------------------------+
82 // | arg[N-1] |
83 // +--------------------------+
84 // | . . . . |
85 // +--------------------------+
86 // | arg[0] |
87 // +--------------------------+
88 // | argC |
89 // sp ---> +--------------------------+ -----------------
90 // | | ^
91 // | prevFP | |
92 // |--------------------------| OptimizedJSFunctionArgsConfigFrame
93 // | frameType | |
94 // | | V
95 // +--------------------------+ -----------------
OptimizedFastCallAndPushUndefined(ExtendedAssembler * assembler)96 void OptimizedFastCall::OptimizedFastCallAndPushUndefined(ExtendedAssembler *assembler)
97 {
98 __ BindAssemblerStub(RTSTUB_ID(OptimizedFastCallAndPushUndefined));
99 Register glue(X0);
100 Register actualNumArgs(X1);
101 Register jsfunc(X2);
102 Register codeAddr(X3);
103 Register sp(SP);
104 Register currentSp = __ AvailableRegister1();
105 Register op = __ AvailableRegister1();
106 Label call;
107 Label arg4;
108 Label arg5;
109 Label arg6;
110 Label argc;
111 Label checkExpectedArgs;
112
113 // construct frame
114 OptimizedCall::PushOptimizedArgsConfigFrame(assembler);
115
116 __ Mov(__ AvailableRegister3(), Register(X1));
117 __ Add(__ AvailableRegister4(), sp, Immediate(4 * FRAME_SLOT_SIZE)); // 4 skip fp lr type x19
118 Register actualNumArgsReg = __ AvailableRegister3();
119 Register argV = __ AvailableRegister4();
120
121 Register method = __ AvailableRegister1();
122 Register expectedNumArgs = __ AvailableRegister2();
123 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
124 __ Ldr(expectedNumArgs, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
125 __ Lsr(expectedNumArgs, expectedNumArgs, MethodLiteral::NumArgsBits::START_BIT);
126 __ And(expectedNumArgs, expectedNumArgs,
127 LogicalImmediate::Create(
128 MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegXSize));
129 __ Add(expectedNumArgs, expectedNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
130
131 Label arg7;
132 Label arg8;
133 __ Mov(Register(X1), Register(X2)); // func move to argc
134 __ Mov(Register(X2), Register(X4)); // this move to func
135 jsfunc = Register(X1);
136
137 __ Cmp(actualNumArgsReg, Immediate(3)); // 3: 3 args
138 __ B(Condition::NE, &arg4);
139 __ Mov(Register(X3), Immediate(JSTaggedValue::VALUE_UNDEFINED));
140 __ Mov(Register(X4), Immediate(JSTaggedValue::VALUE_UNDEFINED));
141 __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED));
142 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
143 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
144 __ B(&checkExpectedArgs);
145
146 __ Bind(&arg4);
147 {
148 __ Mov(Register(X3), Register(X5));
149 __ Cmp(actualNumArgsReg, Immediate(4)); // 4: 4 args
150 __ B(Condition::NE, &arg5);
151 __ Mov(Register(X4), Immediate(JSTaggedValue::VALUE_UNDEFINED));
152 __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED));
153 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
154 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
155 __ B(&checkExpectedArgs);
156 }
157
158 __ Bind(&arg5);
159 {
160 __ Mov(Register(X4), Register(X6));
161 __ Cmp(actualNumArgsReg, Immediate(5)); // 5: 5 args
162 __ B(Condition::NE, &arg6);
163 __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED));
164 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
165 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
166 __ B(&checkExpectedArgs);
167 }
168
169 __ Bind(&arg6);
170 {
171 __ Mov(Register(X5), Register(X7));
172 __ Cmp(actualNumArgsReg, Immediate(6)); // 6: 6 args
173 __ B(Condition::NE, &arg7);
174 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
175 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
176 __ B(&checkExpectedArgs);
177 }
178
179 __ Bind(&arg7);
180 {
181 __ Ldr(op, MemoryOperand(argV, 0));
182 __ Mov(Register(X6), op);
183 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
184 __ Cmp(actualNumArgsReg, Immediate(7)); // 7: 7 args
185 __ B(Condition::NE, &arg8);
186 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
187 __ B(&checkExpectedArgs);
188 }
189
190 __ Bind(&arg8);
191 {
192 __ Ldr(op, MemoryOperand(argV, 0));
193 __ Mov(Register(X7), op);
194 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
195 __ Cmp(actualNumArgsReg, Immediate(8)); // 8: 8 args
196 __ B(Condition::NE, &argc);
197 __ B(&checkExpectedArgs);
198 }
199
200 __ Bind(&argc);
201 {
202 __ Sub(expectedNumArgs, expectedNumArgs, Immediate(8)); // 8 : register save 8 arg
203 __ Sub(actualNumArgsReg, actualNumArgsReg, Immediate(8)); // 8 : register save 8 arg
204 OptimizedCall::IncreaseStackForArguments(assembler, expectedNumArgs, currentSp);
205 TempRegister1Scope scope1(assembler);
206 TempRegister2Scope scope2(assembler);
207 Register tmp = __ TempRegister1();
208 Register undefinedValue = __ TempRegister2();
209 __ Sub(tmp, expectedNumArgs, actualNumArgsReg);
210 PushUndefinedWithArgc(assembler, glue, tmp, undefinedValue, currentSp, nullptr, nullptr);
211 PushArgsWithArgv(assembler, glue, actualNumArgsReg, argV, undefinedValue, currentSp, nullptr, nullptr);
212 __ B(&call);
213 }
214
215 __ Bind(&checkExpectedArgs);
216 {
217 __ Cmp(expectedNumArgs, Immediate(8)); // 8 : register save 8 arg
218 __ B(Condition::LS, &call);
219 __ Sub(expectedNumArgs, expectedNumArgs, Immediate(8)); // 8 : register save 8 arg
220 OptimizedCall::IncreaseStackForArguments(assembler, expectedNumArgs, currentSp);
221 TempRegister2Scope scope2(assembler);
222 Register undefinedValue = __ TempRegister2();
223 PushUndefinedWithArgc(assembler, glue, expectedNumArgs, undefinedValue, currentSp, nullptr, nullptr);
224 __ B(&call);
225 }
226 __ Bind(&call);
227 TempRegister1Scope scope1(assembler);
228 Register method1 = __ TempRegister1();
229 __ Ldr(method1, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
230 __ Ldr(X11, MemoryOperand(method1, Method::CODE_ENTRY_OFFSET));
231 __ Blr(X11);
232
233 __ Mov(Register(SP), Register(FP));
234 __ RestoreFpAndLr();
235 __ Ret();
236 }
237
238 // * uint64_t JSFastCallWithArgV(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
239 // JSTaggedType this, argV)
240 // * cc calling convention call js function()
241 // * arguments:
242 // %x0 - glue
243 // %x1 - call-target
244 // %x2 - this
245 // %x3 - artual argc
246 // %x4 - argv
JSFastCallWithArgV(ExtendedAssembler * assembler)247 void OptimizedFastCall::JSFastCallWithArgV(ExtendedAssembler *assembler)
248 {
249 __ BindAssemblerStub(RTSTUB_ID(JSFastCallWithArgV));
250 Register sp(SP);
251 Register glue(X0);
252 Register actualNumArgs(X3);
253 Register jsfunc(X1);
254 Register thisObj(X2);
255 Register currentSp = __ AvailableRegister1();
256 Register callsiteSp = __ AvailableRegister2();
257 Label call;
258 __ Mov(callsiteSp, sp);
259 OptimizedCall::PushOptimizedUnfoldArgVFrame(assembler, callsiteSp);
260 TempRegister2Scope scope2(assembler);
261 Register op = __ TempRegister2();
262 Register argC = __ AvailableRegister3();
263 Register argV = __ AvailableRegister4();
264 __ Mov(argC, actualNumArgs);
265 __ Mov(argV, Register(X4));
266
267 __ Cmp(argC, Immediate(0));
268 __ B(Condition::EQ, &call);
269 __ Ldr(op, MemoryOperand(argV, 0));
270 __ Mov(Register(X3), op); // first arg
271 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
272 __ Sub(argC, argC, Immediate(1));
273
274 __ Cmp(argC, Immediate(0));
275 __ B(Condition::EQ, &call);
276 __ Ldr(op, MemoryOperand(argV, 0));
277 __ Mov(Register(X4), op); // second arg
278 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
279 __ Sub(argC, argC, Immediate(1));
280
281 __ Cmp(argC, Immediate(0));
282 __ B(Condition::EQ, &call);
283 __ Ldr(op, MemoryOperand(argV, 0));
284 __ Mov(Register(X5), op); // third arg
285 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
286 __ Sub(argC, argC, Immediate(1));
287
288 __ Cmp(argC, Immediate(0));
289 __ B(Condition::EQ, &call);
290 __ Ldr(op, MemoryOperand(argV, 0));
291 __ Mov(Register(X6), op);
292 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
293 __ Sub(argC, argC, Immediate(1));
294
295 __ Cmp(argC, Immediate(0));
296 __ B(Condition::EQ, &call);
297 __ Ldr(op, MemoryOperand(argV, 0));
298 __ Mov(Register(X7), op);
299 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
300 __ Sub(argC, argC, Immediate(1));
301
302 __ Cmp(argC, Immediate(0));
303 __ B(Condition::EQ, &call);
304 OptimizedCall::IncreaseStackForArguments(assembler, argC, currentSp);
305 PushArgsWithArgv(assembler, glue, argC, argV, op, currentSp, nullptr, nullptr);
306
307 __ Bind(&call);
308 TempRegister1Scope scope1(assembler);
309 Register method = __ TempRegister1();
310 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
311 __ Ldr(X11, MemoryOperand(method, Method::CODE_ENTRY_OFFSET));
312 __ Blr(X11);
313
314 __ Mov(Register(SP), Register(FP));
315 __ RestoreFpAndLr();
316 __ Ret();
317 }
318
319 // * Arguments:
320 // %x0 - glue
321 // %x1 - func
322 // %x2 - this
323 // %x3 - actualNumArgs
324 // %x4 - argv
325 // %x5 - expectedNumArgs
JSFastCallWithArgVAndPushUndefined(ExtendedAssembler * assembler)326 void OptimizedFastCall::JSFastCallWithArgVAndPushUndefined(ExtendedAssembler *assembler)
327 {
328 __ BindAssemblerStub(RTSTUB_ID(JSFastCallWithArgVAndPushUndefined));
329 Register sp(SP);
330 Register glue(X0);
331 Register jsfunc(X1);
332 Register thisObj(X2);
333 Register currentSp = __ AvailableRegister1();
334 Register op = __ AvailableRegister1();
335 Register callsiteSp = __ AvailableRegister2();
336 Label call;
337 Label arg1;
338 Label arg2;
339 Label arg3;
340 Label arg4;
341 Label arg5;
342 Label argc;
343 Label checkExpectedArgs;
344 __ Mov(callsiteSp, sp);
345 OptimizedCall::PushOptimizedUnfoldArgVFrame(assembler, callsiteSp);
346 Register actualNumArgsReg = __ AvailableRegister3();
347 Register argV = __ AvailableRegister4();
348 Register expectedNumArgs = __ AvailableRegister2();
349 __ Mov(actualNumArgsReg, Register(X3));
350 __ Mov(argV, Register(X4));
351 __ Mov(expectedNumArgs, Register(X5));
352
353 __ Cmp(actualNumArgsReg, Immediate(0));
354 __ B(Condition::NE, &arg1);
355 __ Mov(Register(X3), Immediate(JSTaggedValue::VALUE_UNDEFINED));
356 __ Mov(Register(X4), Immediate(JSTaggedValue::VALUE_UNDEFINED));
357 __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED));
358 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
359 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
360 __ B(&checkExpectedArgs);
361
362 __ Bind(&arg1);
363 {
364 __ Ldr(op, MemoryOperand(argV, 0));
365 __ Mov(Register(X3), op);
366 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
367 __ Cmp(actualNumArgsReg, Immediate(1));
368 __ B(Condition::NE, &arg2);
369 __ Mov(Register(X4), Immediate(JSTaggedValue::VALUE_UNDEFINED));
370 __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED));
371 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
372 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
373 __ B(&checkExpectedArgs);
374 }
375
376 __ Bind(&arg2);
377 {
378 __ Ldr(op, MemoryOperand(argV, 0));
379 __ Mov(Register(X4), op);
380 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
381 __ Cmp(actualNumArgsReg, Immediate(2)); // 2: 2 args
382 __ B(Condition::NE, &arg3);
383 __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED));
384 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
385 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
386 __ B(&checkExpectedArgs);
387 }
388
389 __ Bind(&arg3);
390 {
391 __ Ldr(op, MemoryOperand(argV, 0));
392 __ Mov(Register(X5), op);
393 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
394 __ Cmp(actualNumArgsReg, Immediate(3)); // 3: 3 args
395 __ B(Condition::NE, &arg4);
396 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
397 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
398 __ B(&checkExpectedArgs);
399 }
400
401 __ Bind(&arg4);
402 {
403 __ Ldr(op, MemoryOperand(argV, 0));
404 __ Mov(Register(X6), op);
405 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
406 __ Cmp(actualNumArgsReg, Immediate(4)); // 4: 4 args
407 __ B(Condition::NE, &arg5);
408 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
409 __ B(&checkExpectedArgs);
410 }
411
412 __ Bind(&arg5);
413 {
414 __ Ldr(op, MemoryOperand(argV, 0));
415 __ Mov(Register(X7), op);
416 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
417 __ Cmp(actualNumArgsReg, Immediate(5)); // 5: 5 args
418 __ B(Condition::NE, &argc);
419 __ B(&checkExpectedArgs);
420 }
421
422 __ Bind(&argc);
423 {
424 __ Sub(expectedNumArgs, expectedNumArgs, Immediate(5)); // 5 : register save 5 arg
425 __ Sub(actualNumArgsReg, actualNumArgsReg, Immediate(5)); // 5 : register save 5 arg
426 OptimizedCall::IncreaseStackForArguments(assembler, expectedNumArgs, currentSp);
427 TempRegister1Scope scope1(assembler);
428 TempRegister2Scope scope2(assembler);
429 Register tmp = __ TempRegister1();
430 Register undefinedValue = __ TempRegister2();
431 __ Sub(tmp, expectedNumArgs, actualNumArgsReg);
432 PushUndefinedWithArgc(assembler, glue, tmp, undefinedValue, currentSp, nullptr, nullptr);
433 PushArgsWithArgv(assembler, glue, actualNumArgsReg, argV, undefinedValue, currentSp, nullptr, nullptr);
434 __ B(&call);
435 }
436
437 __ Bind(&checkExpectedArgs);
438 {
439 __ Cmp(expectedNumArgs, Immediate(5)); // 5 : register save 5 arg
440 __ B(Condition::LS, &call);
441 __ Sub(expectedNumArgs, expectedNumArgs, Immediate(5)); // 5 : register save 5 arg
442 OptimizedCall::IncreaseStackForArguments(assembler, expectedNumArgs, currentSp);
443 TempRegister2Scope scope2(assembler);
444 Register undefinedValue = __ TempRegister2();
445 PushUndefinedWithArgc(assembler, glue, expectedNumArgs, undefinedValue, currentSp, nullptr, nullptr);
446 __ B(&call);
447 }
448
449 __ Bind(&call);
450 TempRegister1Scope scope1(assembler);
451 Register method = __ TempRegister1();
452 __ Ldr(method, MemoryOperand(X1, JSFunction::METHOD_OFFSET));
453 __ Ldr(X11, MemoryOperand(method, Method::CODE_ENTRY_OFFSET));
454 __ Blr(X11);
455
456 __ Mov(Register(SP), Register(FP));
457 __ RestoreFpAndLr();
458 __ Ret();
459 }
460 #undef __
461 } // panda::ecmascript::aarch64