• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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