• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 CallRuntime(uintptr_t glue, uint64_t runtime_id, uint64_t argc, uintptr_t arg0, ...)
36 // * webkit_jscc calling convention call runtime_id's runtime function(c-abi)
37 // * Arguments:
38 //         %x0 - glue
39 //
40 // * Optimized-leaved-frame layout as the following:
41 //         +--------------------------+
42 //         |       argv[N-1]          |
43 //         |--------------------------|
44 //         |       . . . . .          |
45 //         |--------------------------|
46 //         |       argv[0]            |
47 //         +--------------------------+-------------
48 //         |       argc               |            ^
49 //         |--------------------------|            |
50 //         |       RuntimeId          |            |
51 //  sp --> |--------------------------|   OptimizedLeaveFrame
52 //         |       ret-addr           |            |
53 //         |--------------------------|            |
54 //         |       prevFp             |            |
55 //         |--------------------------|            |
56 //         |       frameType          |            v
57 //         +--------------------------+-------------
58 
CallRuntime(ExtendedAssembler * assembler)59 void OptimizedCall::CallRuntime(ExtendedAssembler *assembler)
60 {
61     Register glue(X0);
62     Register fp(FP);
63     Register tmp(X19);
64     Register sp(SP);
65     Register argC(X1);
66     Register argV(X2);
67 
68     __ BindAssemblerStub(RTSTUB_ID(CallRuntime));
69     __ PushFpAndLr();
70 
71     Register frameType(X2);
72     // construct Leave Frame and callee save
73     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::LEAVE_FRAME)));
74     // 2 : 2 means pairs
75     __ Stp(tmp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
76     __ Add(fp, sp, Immediate(2 * FRAME_SLOT_SIZE));  // 16: skip frame type and tmp
77     __ Str(fp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
78 
79     // load runtime trampoline address
80     Register rtfunc(X19);
81     __ Ldr(tmp, MemoryOperand(fp, GetStackArgOffSetToFp(0)));  // 0: the first arg id
82     // 3 : 3 means 2 << 3 = 8
83     __ Add(tmp, glue, Operand(tmp, LSL, 3));
84     __ Ldr(rtfunc, MemoryOperand(tmp, JSThread::GlueData::GetRTStubEntriesOffset(false)));
85     __ Ldr(argC, MemoryOperand(fp, GetStackArgOffSetToFp(1)));  // 1: the second arg id
86     __ Add(argV, fp, Immediate(GetStackArgOffSetToFp(2)));  // 2: the third arg id
87     __ Blr(rtfunc);
88 
89     // callee restore
90     // 0 : 0 restore size
91     __ Ldr(tmp, MemoryOperand(sp, 0));
92 
93     // descontruct frame
94     // 2 :2 means stack frame slot size
95     __ Add(sp, sp, Immediate(2 * FRAME_SLOT_SIZE));
96     __ RestoreFpAndLr();
97     __ Ret();
98 }
99 
IncreaseStackForArguments(ExtendedAssembler * assembler,Register argc,Register currentSp)100 void OptimizedCall::IncreaseStackForArguments(ExtendedAssembler *assembler, Register argc, Register currentSp)
101 {
102     Register sp(SP);
103     __ Mov(currentSp, sp);
104     // add extra aguments, env and numArgs
105     __ Add(argc, argc, Immediate(static_cast<int64_t>(CommonArgIdx::ACTUAL_ARGC)));
106     __ Sub(currentSp, currentSp, Operand(argc, UXTW, FRAME_SLOT_SIZE_LOG2));
107     Label aligned;
108     __ Tst(currentSp, LogicalImmediate::Create(0xf, RegXSize));  // 0xf: 0x1111
109     __ B(Condition::EQ, &aligned);
110     __ Sub(currentSp, currentSp, Immediate(FRAME_SLOT_SIZE));
111     __ Bind(&aligned);
112     __ Mov(sp, currentSp);
113     __ Add(currentSp, currentSp, Operand(argc, UXTW, FRAME_SLOT_SIZE_LOG2));
114 }
115 
116 // * uint64_t JSFunctionEntry(uintptr_t glue, uint32_t actualNumArgs, const JSTaggedType argV[], uintptr_t prevFp,
117 //                            size_t callType)
118 // * Arguments:
119 //        %x0 - glue
120 //        %x1 - actualNumArgs
121 //        %x2 - argV
122 //        %x3 - prevFp
123 //        %x4 - callType
124 //
125 // * The JSFunctionEntry Frame's structure is illustrated as the following:
126 //          +--------------------------+
127 //          |      . . . . . .         |
128 //  sp ---> +--------------------------+ -----------------
129 //          |        prevFP            |                 ^
130 //          |--------------------------|                 |
131 //          |       frameType          |      JSFunctionEntryFrame
132 //          |--------------------------|                 |
133 //          |    preLeaveFrameFp       |                 v
134 //          +--------------------------+ -----------------
135 
JSFunctionEntry(ExtendedAssembler * assembler)136 void OptimizedCall::JSFunctionEntry(ExtendedAssembler *assembler)
137 {
138     __ BindAssemblerStub(RTSTUB_ID(JSFunctionEntry));
139     Register glueReg(X0);
140     Register argV(X2);
141     Register prevFpReg(X3);
142     Register flag(X4);
143     Register sp(SP);
144     Register tmpArgV(X7);
145     Label lJSCallNewWithArgV;
146     Label lPopFrame;
147 
148     PushJSFunctionEntryFrame (assembler, prevFpReg);
149     __ Mov(Register(X6), flag);
150     __ Mov(tmpArgV, argV);
151     __ Mov(Register(X20), glueReg);
152     __ Ldr(Register(X2), MemoryOperand(tmpArgV, 0));
153     __ Ldr(Register(X3), MemoryOperand(tmpArgV, FRAME_SLOT_SIZE));
154     __ Ldr(Register(X4), MemoryOperand(tmpArgV, DOUBLE_SLOT_SIZE));
155     __ Add(tmpArgV, tmpArgV, Immediate(TRIPLE_SLOT_SIZE));
156     __ Mov(Register(X5), tmpArgV);
157     __ Cmp(Register(X6), Immediate(1));
158     __ B(Condition::EQ, &lJSCallNewWithArgV);
159     __ CallAssemblerStub(RTSTUB_ID(JSCallWithArgV), false);
160     __ B(&lPopFrame);
161 
162     __ Bind(&lJSCallNewWithArgV);
163     {
164         __ CallAssemblerStub(RTSTUB_ID(JSCallNewWithArgV), false);
165     }
166 
167     __ Bind(&lPopFrame);
168     __ Mov(Register(X2), Register(X20));
169     PopJSFunctionEntryFrame(assembler, Register(X2));
170     __ Ret();
171 }
172 
173 // * uint64_t OptimizedCallOptimized(uintptr_t glue, uint32_t expectedNumArgs, uint32_t actualNumArgs,
174 //                                   uintptr_t codeAddr, uintptr_t argv, uintptr_t lexEnv)
175 // * Arguments wil CC calling convention:
176 //         %x0 - glue
177 //         %x1 - codeAddr
178 //         %x2 - actualNumArgs
179 //         %x3 - expectedNumArgs
180 //         %x4  - argv
181 //         %x5  - lexEnv
182 //
183 // * The OptimizedJSFunctionArgsConfig Frame's structure is illustrated as the following:
184 //          +--------------------------+
185 //          |         arg[N-1]         |
186 //          +--------------------------+
187 //          |         . . . .          |
188 //          +--------------------------+
189 //          |         arg[0]           |
190 //          +--------------------------+
191 //          |         argC             |
192 //  sp ---> +--------------------------+ -----------------
193 //          |                          |                 ^
194 //          |        prevFP            |                 |
195 //          |--------------------------|    OptimizedJSFunctionArgsConfigFrame
196 //          |       frameType          |                 |
197 //          |                          |                 V
198 //          +--------------------------+ -----------------
199 
OptimizedCallOptimized(ExtendedAssembler * assembler)200 void OptimizedCall::OptimizedCallOptimized(ExtendedAssembler *assembler)
201 {
202     __ BindAssemblerStub(RTSTUB_ID(OptimizedCallOptimized));
203     Register glue(X0);
204     Register expectedNumArgs(X1);
205     Register actualNumArgs(X2);
206     Register codeAddr(X3);
207     Register argV(X4);
208     Register env(X5);
209     Register currentSp(X6);
210     Register sp(SP);
211     Label copyArguments;
212     Label invokeCompiledJSFunction;
213 
214     // construct frame
215     PushOptimizedArgsConfigFrame(assembler);
216     Register argC(X7);
217     __ Cmp(expectedNumArgs, actualNumArgs);
218     __ CMov(argC, expectedNumArgs, actualNumArgs, Condition::HI);
219     IncreaseStackForArguments(assembler, argC, currentSp);
220     {
221         TempRegister1Scope scope1(assembler);
222         TempRegister2Scope scope2(assembler);
223         Register tmp = __ TempRegister1();
224         Register undefinedValue = __ TempRegister2();
225         __ Subs(tmp, expectedNumArgs, actualNumArgs);
226         __ B(Condition::LS, &copyArguments);
227         PushUndefinedWithArgc(assembler, glue, tmp, undefinedValue, currentSp, nullptr, nullptr);
228     }
229     __ Bind(&copyArguments);
230     __ Cbz(actualNumArgs, &invokeCompiledJSFunction);
231     {
232         TempRegister1Scope scope1(assembler);
233         TempRegister2Scope scope2(assembler);
234         Register argc = __ TempRegister1();
235         Register argValue = __ TempRegister2();
236         __ Mov(argc, actualNumArgs);
237         PushArgsWithArgv(assembler, glue, argc, argV, argValue, currentSp, &invokeCompiledJSFunction, nullptr);
238     }
239     __ Bind(&invokeCompiledJSFunction);
240     {
241         __ Mov(Register(X19), expectedNumArgs);
242         __ Str(actualNumArgs, MemoryOperand(sp, FRAME_SLOT_SIZE));
243         __ Str(env, MemoryOperand(sp, 0)); // 0: means zero size
244         __ Blr(codeAddr);
245     }
246 
247     // pop argV argC
248     // 3 : 3 means argC * 8
249     __ Ldr(actualNumArgs, MemoryOperand(sp, FRAME_SLOT_SIZE));
250     PopJSFunctionArgs(assembler, Register(X19), actualNumArgs);
251     // pop prevLeaveFrameFp to restore thread->currentFrame_
252     PopOptimizedArgsConfigFrame(assembler);
253     __ Ret();
254 }
255 
OptimizedCallAsmInterpreter(ExtendedAssembler * assembler)256 void OptimizedCall::OptimizedCallAsmInterpreter(ExtendedAssembler *assembler)
257 {
258     Label target;
259     PushAsmInterpBridgeFrame(assembler);
260     __ Bl(&target);
261     PopAsmInterpBridgeFrame(assembler);
262     __ Ret();
263     __ Bind(&target);
264     {
265         AsmInterpreterCall::JSCallCommonEntry(assembler, JSCallMode::CALL_FROM_AOT);
266     }
267 }
268 
269 // * uint64_t CallBuiltinTrampoline(uintptr_t glue, uintptr_t codeAddress, uint32_t argc, ...)
270 // * webkit_jscc calling convention call runtime_id's runtime function(c-abi)
271 // * Argument:
272 //           %x0: glue
273 //
274 // * Construct Native Leave Frame Layout:
275 //          +--------------------------+
276 //          |       argv[N-1]          |
277 //          +--------------------------+
278 //          |      . . . . . .         |
279 //          +--------------------------+
280 //          |      argv[3]=a0          |
281 //          +--------------------------+
282 //          |      argv[2]=this        |
283 //          +--------------------------+
284 //          |   argv[1]=new-target     |
285 //          +--------------------------+
286 //          |   argv[0]=call-target    |
287 //          +--------------------------+ -----------------
288 //          |       argc               |                 ^
289 //          |--------------------------|                 |
290 //          |       env or thread      |                 |
291 //          |--------------------------|                 |
292 //          |       returnAddr         |    OptimizedBuiltinLeaveFrame
293 //  sp ---> |--------------------------|                 |
294 //          |       callsiteFp         |                 |
295 //          |--------------------------|                 |
296 //          |       frameType          |                 |
297 //          |--------------------------|                 |
298 //          |       align byte         |                 v
299 //          +--------------------------+ -----------------
300 
CallBuiltinTrampoline(ExtendedAssembler * assembler)301 void OptimizedCall::CallBuiltinTrampoline(ExtendedAssembler *assembler)
302 {
303     Register glue(X0);
304     Register sp(SP);
305     Register nativeFuncAddr(X4);
306     Register glueTemp(X2);
307     Register temp(X1);
308     Register zero(Zero);
309 
310     __ Mov(glueTemp, glue);
311     __ Str(glue, MemoryOperand(sp, 0)); // thread (instead of env)
312     __ Add(Register(X0), sp, Immediate(0));
313     AsmInterpreterCall::PushBuiltinFrame(assembler, glueTemp, FrameType::BUILTIN_CALL_LEAVE_FRAME, temp, zero);
314 
315     AsmInterpreterCall::CallNativeInternal(assembler, nativeFuncAddr);
316     __ Ret();
317 }
318 
319 // * uint64_t JSCall(uintptr_t glue, JSTaggedType env, uint32_t argc, JSTaggedType calltarget, JSTaggedType new,
320 //                   JSTaggedType this, arg[0], arg[1], arg[2], ..., arg[N-1])
321 // * webkit_jscc calling convention call js function()
322 //
323 // * OptimizedJSFunctionFrame layout description as the following:
324 //               +--------------------------+
325 //               |        arg[N-1]          |
326 //               +--------------------------+
327 //               |       ...                |
328 //               +--------------------------+
329 //               |       arg[1]             |
330 //               +--------------------------+
331 //               |       arg[0]             |
332 //               +--------------------------+
333 //               |       this               |
334 //               +--------------------------+
335 //               |       new-target         |
336 //               +--------------------------+
337 //               |       call-target        |
338 //               |--------------------------|
339 //               |       argc               |
340 //               |--------------------------|
341 //               |       lexEnv             |
342 //      sp ----> |--------------------------| ---------------
343 //               |       returnAddr         |               ^
344 //               |--------------------------|               |
345 //               |       callsiteFp         |               |
346 //               |--------------------------|   OptimizedJSFunctionFrame
347 //               |       frameType          |               |
348 //               |--------------------------|               |
349 //               |       call-target        |               v
350 //               +--------------------------+ ---------------
351 
GenJSCall(ExtendedAssembler * assembler,bool isNew)352 void OptimizedCall::GenJSCall(ExtendedAssembler *assembler, bool isNew)
353 {
354     Register jsfunc(X1);
355     Register sp(SP);
356     __ Ldr(jsfunc, MemoryOperand(sp, FRAME_SLOT_SIZE * 2)); // 2: skip env and argc
357     JSCallInternal(assembler, jsfunc, isNew);
358 }
359 
JSCallNew(ExtendedAssembler * assembler)360 void OptimizedCall::JSCallNew(ExtendedAssembler *assembler)
361 {
362     __ BindAssemblerStub(RTSTUB_ID(JSCallNew));
363     GenJSCall(assembler, true);
364 }
365 
JSCall(ExtendedAssembler * assembler)366 void OptimizedCall::JSCall(ExtendedAssembler *assembler)
367 {
368     __ BindAssemblerStub(RTSTUB_ID(JSCall));
369     GenJSCall(assembler, false);
370 }
371 
JSCallInternal(ExtendedAssembler * assembler,Register jsfunc,bool isNew)372 void OptimizedCall::JSCallInternal(ExtendedAssembler *assembler, Register jsfunc, bool isNew)
373 {
374     Register sp(SP);
375     Register glue(X0);
376     Register taggedValue(X2);
377     Label nonCallable;
378     Label notJSFunction;
379     JSCallCheck(assembler, jsfunc, taggedValue, &nonCallable, &notJSFunction);
380 
381     Register method(X2);
382     Register callField(X3);
383     Register actualArgC(X4);
384     Label callNativeMethod;
385     Label callOptimizedMethod;
386     Label lCallConstructor;
387     Label lCallBuiltinStub;
388     Label lCallNativeCpp;
389 
390     __ Ldr(Register(X5), MemoryOperand(jsfunc, JSFunction::LEXICAL_ENV_OFFSET));
391     __ Str(Register(X5), MemoryOperand(sp, 0));
392     __ Ldr(Register(X5), MemoryOperand(jsfunc, 0));
393     __ Ldr(Register(X5), MemoryOperand(Register(X5), JSHClass::BIT_FIELD_OFFSET));
394     __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
395     __ Ldr(actualArgC, MemoryOperand(sp, FRAME_SLOT_SIZE));
396     __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
397     __ Tbnz(callField, MethodLiteral::IsNativeBit::START_BIT, &callNativeMethod);
398     if (!isNew) {
399         __ Tbnz(Register(X5), JSHClass::ClassConstructorBit::START_BIT, &lCallConstructor);
400     }
401     __ Tbnz(callField, MethodLiteral::IsAotCodeBit::START_BIT, &callOptimizedMethod);
402     {
403         Register argV(X5);
404         // aot argV = sp + 16
405         __ Add(argV, sp, Immediate(DOUBLE_SLOT_SIZE));
406         // asm interpreter argV = argv + 24
407         __ Add(argV, argV, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() * FRAME_SLOT_SIZE));
408         __ Sub(actualArgC, actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum()));
409         OptimizedCallAsmInterpreter(assembler);
410     }
411 
412     __ Bind(&callNativeMethod);
413     {
414         Register nativeFuncAddr(X4);
415         if (!isNew) {
416             __ Tbz(callField, MethodLiteral::IsFastBuiltinBit::START_BIT, &lCallNativeCpp);
417             // 3 : 3 means call0 call1 call2 call3
418             __ Cmp(actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() + 3));
419             __ B(Condition::LE, &lCallBuiltinStub);
420         } else {
421             __ Tbnz(callField, MethodLiteral::IsFastBuiltinBit::START_BIT, &lCallBuiltinStub);
422         }
423         __ Bind(&lCallNativeCpp);
424         __ Ldr(nativeFuncAddr, MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
425         CallBuiltinTrampoline(assembler);
426     }
427 
428     __ Bind(&lCallBuiltinStub);
429     {
430         TempRegister1Scope scope1(assembler);
431         Register builtinStub = __ TempRegister1();
432         __ Ldr(Register(X5), MemoryOperand(method, Method::EXTRA_LITERAL_INFO_OFFSET));  // get extra literal
433         __ And(Register(X5).W(), Register(X5).W(), LogicalImmediate::Create(0xff, RegWSize));
434         if (!isNew) {
435             __ Cmp(Register(X5).W(), Immediate(kungfu::BuiltinsStubCSigns::BUILTINS_CONSTRUCTOR_STUB_FIRST));
436             __ B(Condition::GE, &lCallNativeCpp);
437         }
438         __ Add(builtinStub, glue, Operand(Register(X5).W(), UXTW, FRAME_SLOT_SIZE_LOG2));
439         __ Ldr(builtinStub, MemoryOperand(builtinStub, JSThread::GlueData::GetBuiltinsStubEntriesOffset(false)));
440 
441         __ Ldr(Register(X1), MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
442         __ Ldr(Register(X2), MemoryOperand(sp, DOUBLE_SLOT_SIZE));  // get jsfunc
443         __ Ldr(Register(X3), MemoryOperand(sp, TRIPLE_SLOT_SIZE));  // get newtarget
444         __ Ldr(Register(X4), MemoryOperand(sp, QUADRUPLE_SLOT_SIZE));  // get this
445         __ Ldr(Register(X5), MemoryOperand(sp, FRAME_SLOT_SIZE));  // get number args
446         __ Sub(Register(X5), Register(X5), Immediate(NUM_MANDATORY_JSFUNC_ARGS));
447         if (!isNew) {
448             Label lTailCall;
449             Register fp(X29);
450             __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE));  // get arg0 arg1
451             __ Cmp(Register(X5), Immediate(3));  // 3: callarg3
452             __ B(Condition::NE, &lTailCall);
453             PushOptimizedFrame(assembler);
454             {
455                 // push arg3 and call
456                 TempRegister2Scope scope2(assembler);
457                 Register arg3 = __ TempRegister2();
458                 __ Ldr(arg3, MemoryOperand(fp, DECUPLE_SLOT_SIZE)); // get arg2
459                 __ Stp(arg3, Register(X8), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
460                 __ Blr(builtinStub);
461                 __ Add(sp, sp, Immediate(DOUBLE_SLOT_SIZE));
462             }
463             PopOptimizedFrame(assembler);
464             __ Ret();
465             __ Bind(&lTailCall);
466             {
467                 __ Br(builtinStub);
468             }
469         } else {
470             __ Add(Register(X6), sp, Immediate(QUINTUPLE_SLOT_SIZE));  // get argV
471             __ Br(builtinStub);
472         }
473     }
474 
475     __ Bind(&callOptimizedMethod);
476     {
477         CallOptimziedMethodInternal(assembler, jsfunc, actualArgC, callField, sp);
478     }
479     Label jsBoundFunction;
480     Label jsProxy;
481     __ Bind(&notJSFunction);
482     {
483         Register bitfield(X2);
484         Register jstype2(X5, W);
485         __ And(jstype2, bitfield.W(), LogicalImmediate::Create(0xff, RegWSize));
486         __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_BOUND_FUNCTION)));
487         __ B(Condition::EQ, &jsBoundFunction);
488         __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_PROXY)));
489         __ B(Condition::EQ, &jsProxy);
490         __ Ret();
491     }
492 
493     __ Bind(&jsBoundFunction);
494     {
495         JSBoundFunctionCallInternal(assembler, glue, actualArgC, jsfunc, RTSTUB_ID(JSCall));
496     }
497     __ Bind(&jsProxy);
498     {
499         JSProxyCallInternal(assembler, sp, jsfunc);
500     }
501     __ Bind(&nonCallable);
502     {
503         ThrowNonCallableInternal(assembler, sp);
504     }
505     __ Bind(&lCallConstructor);
506     {
507         Register frameType(X6);
508         __ PushFpAndLr();
509         __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
510         // 2 : 2 means pair
511         __ Stp(Register(Zero), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
512         __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
513         Register argC(X5);
514         Register runtimeId(X6);
515         __ Mov(argC, Immediate(0));
516         __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowCallConstructorException)));
517         // 2 : 2 means pair
518         __ Stp(runtimeId, argC, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
519         __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
520         // 4 : 4 means stack slot
521         __ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
522         __ RestoreFpAndLr();
523         __ Ret();
524     }
525 }
526 
ConstructorJSCall(ExtendedAssembler * assembler)527 void OptimizedCall::ConstructorJSCall([[maybe_unused]]ExtendedAssembler *assembler)
528 {
529     __ BindAssemblerStub(RTSTUB_ID(ConstructorJSCall));
530     Register jsfunc(X1);
531     Register sp(SP);
532     __ Ldr(jsfunc, MemoryOperand(sp, FRAME_SLOT_SIZE * 2)); // 2: skip env and argc
533     ConstructorJSCallInternal(assembler, jsfunc);
534 }
535 
ConstructorJSCallInternal(ExtendedAssembler * assembler,Register jsfunc)536 void OptimizedCall::ConstructorJSCallInternal(ExtendedAssembler *assembler, Register jsfunc)
537 {
538     Register sp(SP);
539     Register glue(X0);
540     Register taggedValue(X2);
541     Label nonCallable;
542     Label notJSFunction;
543     JSCallCheck(assembler, jsfunc, taggedValue, &nonCallable, &notJSFunction);
544 
545     Register method(X2);
546     Register callField(X3);
547     Register actualArgC(X4);
548     Label callNativeMethod;
549     Label callOptimizedMethod;
550     __ Ldr(Register(X5), MemoryOperand(jsfunc, JSFunction::LEXICAL_ENV_OFFSET));
551     __ Str(Register(X5), MemoryOperand(sp, 0));
552     __ Ldr(Register(X5), MemoryOperand(jsfunc, JSFunction::HCLASS_OFFSET));
553     __ Ldr(Register(X5), MemoryOperand(Register(X5), JSHClass::BIT_FIELD_OFFSET));
554     __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
555     __ Ldr(actualArgC, MemoryOperand(sp, FRAME_SLOT_SIZE));
556     __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
557     __ Tbnz(callField, MethodLiteral::IsNativeBit::START_BIT, &callNativeMethod);
558     __ Tbnz(callField, MethodLiteral::IsAotCodeBit::START_BIT, &callOptimizedMethod);
559     {
560         Register argV(X5);
561         // aot argV = sp + 16
562         __ Add(argV, sp, Immediate(DOUBLE_SLOT_SIZE));
563         // asm interpreter argV = argv + 24
564         __ Add(argV, argV, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() * FRAME_SLOT_SIZE));
565         OptimizedCallAsmInterpreter(assembler);
566     }
567 
568     __ Bind(&callNativeMethod);
569     {
570         Register nativeFuncAddr(X4);
571         __ Ldr(nativeFuncAddr, MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
572         CallBuiltinTrampoline(assembler);
573     }
574 
575     __ Bind(&callOptimizedMethod);
576     {
577         CallOptimziedMethodInternal(assembler, jsfunc, actualArgC, callField, sp);
578     }
579     Label jsBoundFunction;
580     Label jsProxy;
581     __ Bind(&notJSFunction);
582     {
583         Register bitfield(X2);
584         Register jstype2(X5, W);
585         __ And(jstype2, bitfield.W(), LogicalImmediate::Create(0xff, RegWSize));
586         __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_BOUND_FUNCTION)));
587         __ B(Condition::EQ, &jsBoundFunction);
588         __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_PROXY)));
589         __ B(Condition::EQ, &jsProxy);
590         __ Ret();
591     }
592 
593     __ Bind(&jsBoundFunction);
594     {
595         JSBoundFunctionCallInternal(assembler, glue, actualArgC, jsfunc, RTSTUB_ID(ConstructorJSCall));
596     }
597     __ Bind(&jsProxy);
598     {
599         JSProxyCallInternal(assembler, sp, jsfunc);
600     }
601     __ Bind(&nonCallable);
602     {
603         ThrowNonCallableInternal(assembler, sp);
604     }
605 }
606 
JSCallCheck(ExtendedAssembler * assembler,Register jsfunc,Register taggedValue,Label * nonCallable,Label * notJSFunction)607 void OptimizedCall::JSCallCheck(ExtendedAssembler *assembler, Register jsfunc, Register taggedValue,
608                                 Label *nonCallable, Label *notJSFunction)
609 {
610     __ Mov(taggedValue, JSTaggedValue::TAG_MARK);
611     __ Cmp(jsfunc, taggedValue);
612     __ B(Condition::HS, nonCallable);
613     __ Cbz(jsfunc, nonCallable);
614     __ Mov(taggedValue, JSTaggedValue::TAG_SPECIAL);
615     __ And(taggedValue, jsfunc, taggedValue);
616     __ Cbnz(taggedValue, nonCallable);
617 
618     Register jshclass(X2);
619     __ Ldr(jshclass, MemoryOperand(jsfunc, JSFunction::HCLASS_OFFSET));
620     Register bitfield(X2);
621     __ Ldr(bitfield, MemoryOperand(jshclass, JSHClass::BIT_FIELD_OFFSET));
622     __ Tbz(bitfield, JSHClass::CallableBit::START_BIT, nonCallable);
623 
624     Register jstype(X3, W);
625     __ And(jstype, bitfield, LogicalImmediate::Create(0xFF, RegWSize));
626     // 4 : 4 means JSType::JS_FUNCTION_FIRST
627     __ Sub(jstype, jstype, Immediate(static_cast<int>(JSType::JS_FUNCTION_FIRST)));
628     // 9 : 9 means JSType::JS_FUNCTION_LAST - JSType::JS_FUNCTION_FIRST + 1
629     __ Cmp(jstype, Immediate(static_cast<int>(JSType::JS_FUNCTION_LAST)
630             - static_cast<int>(JSType::JS_FUNCTION_FIRST) + 1));
631     __ B(Condition::HS, notJSFunction);
632 }
633 
ThrowNonCallableInternal(ExtendedAssembler * assembler,Register sp)634 void OptimizedCall::ThrowNonCallableInternal(ExtendedAssembler *assembler, Register sp)
635 {
636     Register frameType(X6);
637     Register taggedMessageId(X5);
638     __ PushFpAndLr();
639     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
640     __ Mov(taggedMessageId,
641         Immediate(JSTaggedValue(GET_MESSAGE_STRING_ID(NonCallable)).GetRawData()));
642     // 2 : 2 means pair
643     __ Stp(taggedMessageId, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
644     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
645     Register argC(X5);
646     Register runtimeId(X6);
647     __ Mov(argC, Immediate(1));
648     __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowTypeError)));
649     // 2 : 2 means pair
650     __ Stp(runtimeId, argC, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
651     __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
652     __ Mov(Register(X0), Immediate(JSTaggedValue::VALUE_EXCEPTION));
653     // 4 : 4 means stack slot
654     __ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
655     __ RestoreFpAndLr();
656     __ Ret();
657 }
658 
CallOptimziedMethodInternal(ExtendedAssembler * assembler,Register jsfunc,Register actualArgC,Register callField,Register sp)659 void OptimizedCall::CallOptimziedMethodInternal(ExtendedAssembler *assembler, Register jsfunc, Register actualArgC,
660                                                 Register callField, Register sp)
661 {
662     Register expectedNumArgs(X1, W);
663     Register arg2(X2);
664     Register codeAddress(X3);
665     Register argV(X4);
666     Register env(X5);
667     Register method(X6);
668     Label directCallCodeEntry;
669     const int64_t argoffsetSlot = static_cast<int64_t>(CommonArgIdx::FUNC) - 1;
670     __ Mov(Register(X5), jsfunc);
671     __ Mov(arg2, actualArgC);
672     __ Lsr(callField, callField, MethodLiteral::NumArgsBits::START_BIT);
673     __ And(callField.W(), callField.W(),
674         LogicalImmediate::Create(
675             MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegWSize));
676     __ Add(expectedNumArgs, callField.W(), Immediate(NUM_MANDATORY_JSFUNC_ARGS));
677     __ Cmp(arg2.W(), expectedNumArgs);
678     __ Add(argV, sp, Immediate(argoffsetSlot * FRAME_SLOT_SIZE));  // skip env and numArgs
679     __ Ldr(method, MemoryOperand(Register(X5), JSFunctionBase::METHOD_OFFSET)); // get method
680     __ Ldr(codeAddress, MemoryOperand(method, Method::CODE_ENTRY_OFFSET)); // get codeAddress
681     __ Ldr(env, MemoryOperand(sp, 0));
682     __ B(Condition::HS, &directCallCodeEntry);
683     __ CallAssemblerStub(RTSTUB_ID(OptimizedCallOptimized), true);
684     __ Bind(&directCallCodeEntry);
685     __ Br(codeAddress);
686 }
687 
JSBoundFunctionCallInternal(ExtendedAssembler * assembler,Register glue,Register actualArgC,Register jsfunc,int stubId)688 void OptimizedCall::JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Register glue,
689                                                 Register actualArgC, Register jsfunc, int stubId)
690 {
691     // construct frame
692     PushOptimizedArgsConfigFrame(assembler);
693     Register basefp(X29);
694     Register fp = __ AvailableRegister1();
695     Register env(X5);
696 
697     Register argV(X6);
698     __ Add(argV, basefp, Immediate(GetStackArgOffSetToFp(0))); // 0: first index id
699     __ Ldr(actualArgC, MemoryOperand(argV, FRAME_SLOT_SIZE));
700     __ Ldr(env, MemoryOperand(argV, 0));
701 
702     Register boundLength(X2);
703     Register realArgC(X7, W);
704     Label copyBoundArgument;
705     Label pushCallTarget;
706     // get bound arguments
707     __ Ldr(boundLength, MemoryOperand(jsfunc, JSBoundFunction::BOUND_ARGUMENTS_OFFSET));
708     //  get bound length
709     __ Ldr(boundLength, MemoryOperand(boundLength, TaggedArray::LENGTH_OFFSET));
710     __ Add(realArgC, boundLength.W(), actualArgC.W());
711     __ Mov(Register(X19), realArgC);
712     IncreaseStackForArguments(assembler, realArgC, fp);
713     __ Sub(actualArgC.W(), actualArgC.W(), Immediate(NUM_MANDATORY_JSFUNC_ARGS));
714     __ Cmp(actualArgC.W(), Immediate(0));
715     __ B(Condition::EQ, &copyBoundArgument);
716     {
717         TempRegister1Scope scope1(assembler);
718         Register tmp = __ TempRegister1();
719         const int64_t argoffsetSlot = static_cast<int64_t>(CommonArgIdx::FUNC) - 1;
720         __ Add(argV, argV, Immediate((NUM_MANDATORY_JSFUNC_ARGS + argoffsetSlot) *FRAME_SLOT_SIZE));
721         PushArgsWithArgv(assembler, glue, actualArgC, argV, tmp, fp, nullptr, nullptr);
722     }
723     __ Bind(&copyBoundArgument);
724     {
725         Register boundArgs(X4);
726         __ Ldr(boundArgs, MemoryOperand(jsfunc, JSBoundFunction::BOUND_ARGUMENTS_OFFSET));
727         __ Add(boundArgs, boundArgs, Immediate(TaggedArray::DATA_OFFSET));
728         __ Cmp(boundLength.W(), Immediate(0));
729         __ B(Condition::EQ, &pushCallTarget);
730         {
731             TempRegister1Scope scope1(assembler);
732             Register tmp = __ TempRegister1();
733             PushArgsWithArgv(assembler, glue, boundLength, boundArgs, tmp, fp, nullptr, nullptr);
734         }
735     }
736     __ Bind(&pushCallTarget);
737     {
738         Register thisObj(X4);
739         Register newTarget(X6);
740         Register boundTarget(X7);
741         __ Ldr(thisObj, MemoryOperand(jsfunc, JSBoundFunction::BOUND_THIS_OFFSET));
742         __ Mov(newTarget, Immediate(JSTaggedValue::VALUE_UNDEFINED));
743         // 2 : 2 means pair
744         __ Stp(newTarget, thisObj, MemoryOperand(fp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
745         __ Ldr(boundTarget, MemoryOperand(jsfunc, JSBoundFunction::BOUND_TARGET_OFFSET));
746         // 2 : 2 means pair
747         __ Stp(Register(X19), boundTarget, MemoryOperand(fp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
748         __ Str(env, MemoryOperand(fp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
749     }
750     __ CallAssemblerStub(stubId, false);
751 
752     PopJSFunctionArgs(assembler, Register(X19), Register(X19));
753     PopOptimizedArgsConfigFrame(assembler);
754     __ Ret();
755 }
756 
JSProxyCallInternal(ExtendedAssembler * assembler,Register sp,Register jsfunc)757 void OptimizedCall::JSProxyCallInternal(ExtendedAssembler *assembler, Register sp, Register jsfunc)
758 {
759     // input: x1(calltarget)
760     // output: glue:x0 argc:x1 calltarget:x2 argv:x3
761     __ Mov(Register(X2), jsfunc);
762     __ Ldr(Register(X1), MemoryOperand(sp, FRAME_SLOT_SIZE)); // 8: skip env
763     __ Add(X3, sp, Immediate(FRAME_SLOT_SIZE * 2)); // 2: get argv
764 
765     Register proxyCallInternalId(X9);
766     Register baseAddress(X8);
767     Register codeAddress(X10);
768     __ Mov(baseAddress, Immediate(JSThread::GlueData::GetCOStubEntriesOffset(false)));
769     __ Mov(proxyCallInternalId, Immediate(CommonStubCSigns::JsProxyCallInternal));
770     __ Add(codeAddress, X0, baseAddress);
771     __ Ldr(codeAddress, MemoryOperand(codeAddress, proxyCallInternalId, UXTW, FRAME_SLOT_SIZE_LOG2));
772     __ Br(codeAddress);
773 }
774 
775 // * uint64_t JSProxyCallInternalWithArgV(uintptr_t glue, uint32_t argc, JSTaggedType calltarget, uintptr_t argv[])
776 // * c++ calling convention call js function
777 // * Arguments:
778 //        %x0 - glue
779 //        %x1 - argc
780 //        %x2 - calltarget
781 //        %x3 - argV[] = { calltarget, newtarget, thisObj, arg[0], arg[1], ..., arg[N-1])
782 
JSProxyCallInternalWithArgV(ExtendedAssembler * assembler)783 void OptimizedCall::JSProxyCallInternalWithArgV(ExtendedAssembler *assembler)
784 {
785     __ BindAssemblerStub(RTSTUB_ID(JSProxyCallInternalWithArgV));
786     Register jsfunc(X1);
787     Register argv(X3);
788     __ Mov(jsfunc, Register(X2));
789     __ Str(jsfunc, MemoryOperand(argv, 0));
790     JSCallInternal(assembler, jsfunc);
791 }
792 
793 // * uint64_t CallRuntimeWithArgv(uintptr_t glue, uint64_t runtime_id, uint64_t argc, uintptr_t argv)
794 // * cc calling convention call runtime_id's runtion function(c-abi)
795 // * Arguments:
796 //         %x0 - glue
797 //         %x1 - runtime_id
798 //         %x2 - argc
799 //         %x3 - argv
800 //
801 // * Optimized-leaved-frame-with-argv layout as the following:
802 //         +--------------------------+
803 //         |       argv[]             |
804 //         +--------------------------+-------------
805 //         |       argc               |            ^
806 //         |--------------------------|            |
807 //         |       RuntimeId          |   OptimizedWithArgvLeaveFrame
808 //  sp --> |--------------------------|            |
809 //         |       returnAddr         |            |
810 //         |--------------------------|            |
811 //         |       callsiteFp         |            |
812 //         |--------------------------|            |
813 //         |       frameType          |            v
814 //         +--------------------------+-------------
815 
CallRuntimeWithArgv(ExtendedAssembler * assembler)816 void OptimizedCall::CallRuntimeWithArgv(ExtendedAssembler *assembler)
817 {
818     __ BindAssemblerStub(RTSTUB_ID(CallRuntimeWithArgv));
819     Register glue(X0);
820     Register runtimeId(X1);
821     Register argc(X2);
822     Register argv(X3);
823     Register sp(SP);
824     // 2 : 2 means pair
825     __ Stp(argc, argv, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
826     __ Str(runtimeId, MemoryOperand(sp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
827     __ PushFpAndLr();
828     Register fp(X29);
829     __ Str(fp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
830     // construct leave frame
831     Register frameType(X9);
832     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::LEAVE_FRAME_WITH_ARGV)));
833     __ Str(frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
834     __ Add(Register(FP), sp, Immediate(FRAME_SLOT_SIZE));
835 
836      // load runtime trampoline address
837     Register tmp(X9);
838     Register rtfunc(X9);
839     // 3 : 3 means 2 << 3 = 8
840     __ Add(tmp, glue, Operand(runtimeId, LSL, 3));
841     __ Ldr(rtfunc, MemoryOperand(tmp, JSThread::GlueData::GetRTStubEntriesOffset(false)));
842     __ Mov(X1, argc);
843     __ Mov(X2, argv);
844     __ Blr(rtfunc);
845     __ Add(sp, sp, Immediate(FRAME_SLOT_SIZE));
846     __ RestoreFpAndLr();
847     __ Add(sp, sp, Immediate(3 * FRAME_SLOT_SIZE)); // 3 : 3 means pair
848     __ Ret();
849 }
850 
PushMandatoryJSArgs(ExtendedAssembler * assembler,Register jsfunc,Register thisObj,Register newTarget,Register currentSp)851 void OptimizedCall::PushMandatoryJSArgs(ExtendedAssembler *assembler, Register jsfunc,
852                                         Register thisObj, Register newTarget, Register currentSp)
853 {
854     __ Str(thisObj, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
855     __ Str(newTarget, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
856     __ Str(jsfunc, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
857 }
858 
PopJSFunctionArgs(ExtendedAssembler * assembler,Register expectedNumArgs,Register actualNumArgs)859 void OptimizedCall::PopJSFunctionArgs(ExtendedAssembler *assembler, Register expectedNumArgs, Register actualNumArgs)
860 {
861     Register sp(SP);
862     Register fp(X6);
863     Label aligned;
864     const int64_t argoffsetSlot = static_cast<int64_t>(CommonArgIdx::FUNC) - 1;
865     if (expectedNumArgs != actualNumArgs) {
866         TempRegister1Scope scop1(assembler);
867         Register tmp = __ TempRegister1();
868         __ Cmp(expectedNumArgs, actualNumArgs);
869         __ CMov(tmp, expectedNumArgs, actualNumArgs, Condition::HI);
870         __ Add(sp, sp, Operand(tmp, UXTW, FRAME_SLOT_SIZE_LOG2));
871     } else {
872         __ Add(sp, sp, Operand(expectedNumArgs, UXTW, FRAME_SLOT_SIZE_LOG2));
873     }
874     __ Add(sp, sp, Immediate(argoffsetSlot * FRAME_SLOT_SIZE));
875     __ Mov(fp, sp);
876     __ Tst(fp, LogicalImmediate::Create(0xf, RegXSize));  // 0xf: 0x1111
877     __ B(Condition::EQ, &aligned);
878     __ Add(sp, sp, Immediate(FRAME_SLOT_SIZE));
879     __ Bind(&aligned);
880 }
881 
PushJSFunctionEntryFrame(ExtendedAssembler * assembler,Register prevFp)882 void OptimizedCall::PushJSFunctionEntryFrame (ExtendedAssembler *assembler, Register prevFp)
883 {
884     Register fp(X29);
885     Register sp(SP);
886     TempRegister2Scope temp2Scope(assembler);
887     __ PushFpAndLr();
888     Register frameType = __ TempRegister2();
889     // construct frame
890     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_ENTRY_FRAME)));
891     // 2 : 2 means pairs
892     __ Stp(prevFp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
893     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
894     __ CalleeSave();
895 }
896 
PopJSFunctionEntryFrame(ExtendedAssembler * assembler,Register glue)897 void OptimizedCall::PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue)
898 {
899     Register fp(X29);
900     Register sp(SP);
901     Register prevFp(X1);
902     __ CalleeRestore();
903 
904     // 2: prevFp and frameType
905     __ Ldp(prevFp, Register(Zero), MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
906     // restore return address
907     __ RestoreFpAndLr();
908     __ Str(prevFp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
909 }
910 
PushOptimizedArgsConfigFrame(ExtendedAssembler * assembler)911 void OptimizedCall::PushOptimizedArgsConfigFrame(ExtendedAssembler *assembler)
912 {
913     Register sp(SP);
914     TempRegister2Scope temp2Scope(assembler);
915     Register frameType = __ TempRegister2();
916     __ PushFpAndLr();
917     // construct frame
918     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
919     // 2 : 2 means pairs. X19 means calleesave and 16bytes align
920     __ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
921     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
922 }
923 
PopOptimizedArgsConfigFrame(ExtendedAssembler * assembler)924 void OptimizedCall::PopOptimizedArgsConfigFrame(ExtendedAssembler *assembler)
925 {
926     TempRegister2Scope temp2Scope(assembler);
927     Register sp(SP);
928     Register frameType = __ TempRegister2();
929     // 2 : 2 means pop call site sp and type
930     __ Ldp(Register(X19), frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
931     __ RestoreFpAndLr();
932 }
933 
PushOptimizedFrame(ExtendedAssembler * assembler)934 void OptimizedCall::PushOptimizedFrame(ExtendedAssembler *assembler)
935 {
936     Register sp(SP);
937     TempRegister2Scope temp2Scope(assembler);
938     Register frameType = __ TempRegister2();
939     __ PushFpAndLr();
940     // construct frame
941     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_FRAME)));
942     // 2 : 2 means pairs. X19 means calleesave and 16bytes align
943     __ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
944     __ Add(Register(FP), sp, Immediate(FRAME_SLOT_SIZE));
945 }
946 
PopOptimizedFrame(ExtendedAssembler * assembler)947 void OptimizedCall::PopOptimizedFrame(ExtendedAssembler *assembler)
948 {
949     TempRegister2Scope temp2Scope(assembler);
950     Register sp(SP);
951     Register frameType = __ TempRegister2();
952     // 2 : 2 means pop call site sp and type
953     __ Ldp(Register(X19), frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
954     __ RestoreFpAndLr();
955 }
956 
957 // * uint64_t PushOptimizedUnfoldArgVFrame(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
958 //                                         JSTaggedType new, JSTaggedType this, JSTaggedType argV[])
959 // * cc calling convention call js function()
960 // * arguments:
961 //              %x0 - glue
962 //              %x1 - argc
963 //              %x2 - call-target
964 //              %x3 - new-target
965 //              %x4 - this
966 //              %x5 - argv
967 //
968 // * OptimizedUnfoldArgVFrame layout description as the following:
969 //      sp ----> |--------------------------| ---------------
970 //               |       returnAddr         |               ^
971 //  currentFp--> |--------------------------|               |
972 //               |       prevFp             |               |
973 //               |--------------------------|   OptimizedUnfoldArgVFrame
974 //               |       frameType          |               |
975 //               |--------------------------|               |
976 //               |       currentFp          |               v
977 //               +--------------------------+ ---------------
978 
PushOptimizedUnfoldArgVFrame(ExtendedAssembler * assembler,Register callSiteSp)979 void OptimizedCall::PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp)
980 {
981     Register sp(SP);
982     TempRegister2Scope temp2Scope(assembler);
983     Register frameType = __ TempRegister2();
984     __ PushFpAndLr();
985     // construct frame
986     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)));
987     // 2 : 2 means pairs
988     __ Stp(callSiteSp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
989     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
990 }
991 
PopOptimizedUnfoldArgVFrame(ExtendedAssembler * assembler)992 void OptimizedCall::PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler)
993 {
994     Register sp(SP);
995     // 2 : 2 means pop call site sp and type
996     __ Add(sp, sp, Immediate(2 * FRAME_SLOT_SIZE));
997     __ RestoreFpAndLr();
998 }
999 
1000 // * uint64_t JSCallWithArgV(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1001 //                          JSTaggedType new, JSTaggedType this, argV)
1002 // * cc calling convention call js function()
1003 // * arguments:
1004 //              %x0 - glue
1005 //              %x1 - argc
1006 //              %x2 - call-target
1007 //              %x3 - new-target
1008 //              %x4 - this
1009 //              %x5 - argV[]
1010 //
1011 // * OptimizedJSFunctionFrame layout description as the following:
1012 //               +--------------------------+
1013 //               |        arg[N-1]          |
1014 //               +--------------------------+
1015 //               |        . . . . .         |
1016 //               +--------------------------+
1017 //               |        arg[0]            |
1018 //               +--------------------------+
1019 //               |       this               |
1020 //               +--------------------------+
1021 //               |       new-target         |
1022 //               +--------------------------+
1023 //               |       call-target        |
1024 //               |--------------------------|
1025 //               |       argc               |
1026 //      sp ----> |--------------------------| ---------------
1027 //               |       returnAddr         |               ^
1028 //               |--------------------------|               |
1029 //               |       callsiteFp         |               |
1030 //               |--------------------------|  OptimizedJSFunctionFrame
1031 //               |       frameType          |               |
1032 //               |--------------------------|               |
1033 //               |       call-target        |               v
1034 //               +--------------------------+ ---------------
1035 
GenJSCallWithArgV(ExtendedAssembler * assembler,bool isNew)1036 void OptimizedCall::GenJSCallWithArgV(ExtendedAssembler *assembler, bool isNew)
1037 {
1038     Register sp(SP);
1039     Register glue(X0);
1040     Register actualNumArgs(X1);
1041     Register jsfunc(X2);
1042     Register newTarget(X3);
1043     Register thisObj(X4);
1044     Register argV(X5);
1045     Register env(X6);
1046     Register currentSp = __ AvailableRegister1();
1047     Register callsiteSp = __ AvailableRegister2();
1048     Label pushCallThis;
1049 
1050     __ Mov(callsiteSp, sp);
1051     PushOptimizedUnfoldArgVFrame(assembler, callsiteSp);
1052     Register argC(X7);
1053     __ Add(actualNumArgs, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1054     __ Mov(argC, actualNumArgs);
1055     IncreaseStackForArguments(assembler, argC, currentSp);
1056     {
1057         TempRegister1Scope scope1(assembler);
1058         TempRegister2Scope scope2(assembler);
1059         Register tmp = __ TempRegister1();
1060         Register op = __ TempRegister2();
1061         __ Sub(tmp, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1062         PushArgsWithArgv(assembler, glue, tmp, argV, op, currentSp, &pushCallThis, nullptr);
1063     }
1064     __ Bind(&pushCallThis);
1065     PushMandatoryJSArgs(assembler, jsfunc, thisObj, newTarget, currentSp);
1066     __ Str(actualNumArgs, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1067     __ Ldr(env, MemoryOperand(jsfunc, JSFunction::LEXICAL_ENV_OFFSET));
1068     __ Str(env, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1069 
1070     if (isNew) {
1071         __ CallAssemblerStub(RTSTUB_ID(JSCallNew), false);
1072     } else {
1073         __ CallAssemblerStub(RTSTUB_ID(JSCall), false);
1074     }
1075 
1076     __ Ldr(actualNumArgs, MemoryOperand(sp, FRAME_SLOT_SIZE));
1077     PopJSFunctionArgs(assembler, actualNumArgs, actualNumArgs);
1078     PopOptimizedUnfoldArgVFrame(assembler);
1079     __ Ret();
1080 }
1081 
JSCallNewWithArgV(ExtendedAssembler * assembler)1082 void OptimizedCall::JSCallNewWithArgV(ExtendedAssembler *assembler)
1083 {
1084     __ BindAssemblerStub(RTSTUB_ID(JSCallNewWithArgV));
1085     GenJSCallWithArgV(assembler, true);
1086 }
1087 
JSCallWithArgV(ExtendedAssembler * assembler)1088 void OptimizedCall::JSCallWithArgV(ExtendedAssembler *assembler)
1089 {
1090     __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgV));
1091     GenJSCallWithArgV(assembler, false);
1092 }
1093 
ConstructorJSCallWithArgV(ExtendedAssembler * assembler)1094 void OptimizedCall::ConstructorJSCallWithArgV([[maybe_unused]]ExtendedAssembler *assembler)
1095 {
1096     __ BindAssemblerStub(RTSTUB_ID(ConstructorJSCallWithArgV));
1097     Register sp(SP);
1098     Register glue(X0);
1099     Register actualNumArgs(X1);
1100     Register jsfunc(X2);
1101     Register newTarget(X3);
1102     Register thisObj(X4);
1103     Register argV(X5);
1104     Register env(X6);
1105     Register currentSp = __ AvailableRegister1();
1106     Register callsiteSp = __ AvailableRegister2();
1107     Label pushCallThis;
1108 
1109     __ Mov(callsiteSp, sp);
1110     PushOptimizedUnfoldArgVFrame(assembler, callsiteSp);
1111     Register argC(X7);
1112     __ Add(actualNumArgs, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1113     __ Mov(argC, actualNumArgs);
1114     IncreaseStackForArguments(assembler, argC, currentSp);
1115     {
1116         TempRegister1Scope scope1(assembler);
1117         TempRegister2Scope scope2(assembler);
1118         Register tmp = __ TempRegister1();
1119         Register op = __ TempRegister2();
1120         __ Sub(tmp, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1121         PushArgsWithArgv(assembler, glue, tmp, argV, op, currentSp, &pushCallThis, nullptr);
1122     }
1123     __ Bind(&pushCallThis);
1124     PushMandatoryJSArgs(assembler, jsfunc, thisObj, newTarget, currentSp);
1125     __ Str(actualNumArgs, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1126     __ Ldr(env, MemoryOperand(jsfunc, JSFunction::LEXICAL_ENV_OFFSET));
1127     __ Str(env, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1128 
1129     __ CallAssemblerStub(RTSTUB_ID(ConstructorJSCall), false);
1130 
1131     __ Ldr(actualNumArgs, MemoryOperand(sp, FRAME_SLOT_SIZE));
1132     PopJSFunctionArgs(assembler, actualNumArgs, actualNumArgs);
1133     PopOptimizedUnfoldArgVFrame(assembler);
1134     __ Ret();
1135 }
1136 
DeoptEnterAsmInterp(ExtendedAssembler * assembler)1137 void OptimizedCall::DeoptEnterAsmInterp(ExtendedAssembler *assembler)
1138 {
1139     // rdi
1140     Register glueRegister = __ GlueRegister();
1141     Register context(X2);
1142     Register opRegister(X9);
1143     Register outputCount(X10);
1144     Register frameStateBase(X11);
1145     Register currentSlotRegister(X12);
1146     Register sp(SP);
1147 
1148     __ PushFpAndLr();
1149 
1150     __ Mov(currentSlotRegister, sp);
1151     __ Ldr(outputCount, MemoryOperand(context, AsmStackContext::GetOutputCountOffset(false)));
1152     __ Add(frameStateBase, context, Immediate(AsmStackContext::GetSize(false)));
1153 
1154     Label stackOverflow;
1155     // update fp
1156     __ Str(currentSlotRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFpOffset(false)));
1157     PushArgsWithArgv(assembler, glueRegister, outputCount, frameStateBase, opRegister,
1158                      currentSlotRegister, nullptr, &stackOverflow);
1159 
1160     Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
1161     Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
1162     {
1163         // X19, fp, x20, x21,      x22,     x23,  x24
1164         // glue sp   pc  constpool  profile  acc   hotness
1165         __ Ldr(callTargetRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFunctionOffset(false)));
1166         __ Ldr(Register(X20), MemoryOperand(frameStateBase, AsmInterpretedFrame::GetPcOffset(false)));
1167         __ Ldr(Register(X23), MemoryOperand(frameStateBase, AsmInterpretedFrame::GetAccOffset(false)));
1168         __ Ldr(methodRegister, MemoryOperand(callTargetRegister, JSFunctionBase::METHOD_OFFSET));
1169 
1170         __ Add(opRegister, currentSlotRegister, Immediate(AsmInterpretedFrame::GetSize(false)));
1171 
1172         __ Align16(currentSlotRegister);
1173         __ Mov(Register(SP), currentSlotRegister);
1174         AsmInterpreterCall::DispatchCall(assembler, Register(X20), opRegister, Register(X23));
1175     }
1176     __ Bind(&stackOverflow);
1177     {
1178         Register temp(X1);
1179         AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(
1180             assembler, glueRegister, sp, temp);
1181     }
1182 }
1183 
DeoptHandlerAsm(ExtendedAssembler * assembler)1184 void OptimizedCall::DeoptHandlerAsm(ExtendedAssembler *assembler)
1185 {
1186     __ BindAssemblerStub(RTSTUB_ID(DeoptHandlerAsm));
1187     __ PushFpAndLr();
1188     Register sp(SP);
1189     Register fp(FP);
1190     Register frameType(X2);
1191     Register glueReg(X0);
1192 
1193     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_FRAME)));
1194     __ Stp(glueReg, frameType, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1195     __ Add(fp, sp, Immediate(DOUBLE_SLOT_SIZE));
1196     __ CalleeSave();
1197 
1198     Register deoptType(X1);
1199     Register align(X3);
1200     Register argC(X3);
1201     Register runtimeId(X2);
1202     __ Stp(deoptType, align, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1203     __ Mov(argC, Immediate(1));
1204     __ Mov(runtimeId, Immediate(RTSTUB_ID(DeoptHandler)));
1205     __ Stp(runtimeId, argC, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1206     __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1207     __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE)); // 2: skip runtimeId, argc, deoptType, align
1208 
1209     __ CalleeRestore();
1210     Register context(X2);
1211     __ Mov(context, Register(X0));
1212     __ Ldr(glueReg, MemoryOperand(sp, 0));
1213 
1214     Register ret(X0);
1215     Label stackOverflow;
1216     __ Cmp(ret, Immediate(JSTaggedValue::VALUE_EXCEPTION));
1217     __ B(Condition::EQ, &stackOverflow);
1218 
1219     Label target;
1220     Register temp(X1);
1221     __ Ldr(fp, MemoryOperand(context, AsmStackContext::GetCallerFpOffset(false)));
1222     __ Ldr(temp, MemoryOperand(context, AsmStackContext::GetCallFrameTopOffset(false)));
1223     __ Mov(sp, temp);
1224     __ Ldr(Register(X30), MemoryOperand(context, AsmStackContext::GetReturnAddressOffset(false)));
1225 
1226     PushAsmInterpBridgeFrame(assembler);
1227     __ Bl(&target);
1228     PopAsmInterpBridgeFrame(assembler);
1229     __ Ret();
1230     __ Bind(&target);
1231     DeoptEnterAsmInterp(assembler);
1232 
1233     __ Bind(&stackOverflow);
1234     {
1235         __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowStackOverflowException)));
1236         // 2 : 2 means pair
1237         __ Stp(runtimeId, Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1238         __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1239         __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE)); // 2: skip runtimeId&argc glue&type
1240         __ RestoreFpAndLr();
1241         __ Ret();
1242     }
1243 }
1244 #undef __
1245 }  // panda::ecmascript::aarch64