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