1 /*
2  * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/compiler/trampoline/aarch64/common_call.h"
17 
18 #include "ecmascript/compiler/assembler/assembler.h"
19 #include "ecmascript/compiler/argument_accessor.h"
20 #include "ecmascript/compiler/rt_call_signature.h"
21 #include "ecmascript/deoptimizer/deoptimizer.h"
22 #include "ecmascript/ecma_runtime_call_info.h"
23 #include "ecmascript/frames.h"
24 #include "ecmascript/js_function.h"
25 #include "ecmascript/method.h"
26 #include "ecmascript/js_thread.h"
27 #include "ecmascript/message_string.h"
28 #include "ecmascript/runtime_call_id.h"
29 
30 namespace panda::ecmascript::aarch64 {
31 using Label = panda::ecmascript::Label;
32 #define __ assembler->
33 
34 // * uint64_t CallRuntime(uintptr_t glue, uint64_t runtime_id, uint64_t argc, uintptr_t arg0, ...)
35 // * webkit_jscc calling convention call runtime_id's runtime function(c-abi)
36 // * Arguments:
37 //         %x0 - glue
38 //
39 // * Optimized-leaved-frame layout as the following:
40 //         +--------------------------+
41 //         |       argv[N-1]          |
42 //         |--------------------------|
43 //         |       . . . . .          |
44 //         |--------------------------|
45 //         |       argv[0]            |
46 //         +--------------------------+-------------
47 //         |       argc               |            ^
48 //         |--------------------------|            |
49 //         |       RuntimeId          |            |
50 //  sp --> |--------------------------|   OptimizedLeaveFrame
51 //         |       ret-addr           |            |
52 //         |--------------------------|            |
53 //         |       prevFp             |            |
54 //         |--------------------------|            |
55 //         |       frameType          |            v
56 //         +--------------------------+-------------
57 
CallRuntime(ExtendedAssembler *assembler)58 void OptimizedCall::CallRuntime(ExtendedAssembler *assembler)
59 {
60     Register glue(X0);
61     Register fp(FP);
62     Register tmp(X19);
63     Register sp(SP);
64     Register argC(X1);
65     Register argV(X2);
66 
67     __ BindAssemblerStub(RTSTUB_ID(CallRuntime));
68     __ PushFpAndLr();
69 
70     Register frameType(X2);
71     // construct Leave Frame and callee save
72     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::LEAVE_FRAME)));
73     // 2 : 2 means pairs
74     __ Stp(tmp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
75     __ Add(fp, sp, Immediate(2 * FRAME_SLOT_SIZE));  // 2 : 2 means pairs
76     __ Str(fp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
77 
78     // load runtime trampoline address
79     Register rtfunc(X19);
80     __ Ldr(tmp, MemoryOperand(fp, GetStackArgOffSetToFp(0)));  // 0: the first arg id
81     // 3 : 3 means 2 << 3 = 8
82     __ Add(tmp, glue, Operand(tmp, LSL, 3));
83     __ Ldr(rtfunc, MemoryOperand(tmp, JSThread::GlueData::GetRTStubEntriesOffset(false)));
84     __ Ldr(argC, MemoryOperand(fp, GetStackArgOffSetToFp(1)));  // 1: the second arg id
85     __ Add(argV, fp, Immediate(GetStackArgOffSetToFp(2)));  // 2: the third arg id
86     __ Blr(rtfunc);
87 
88     // callee restore
89     // 0 : 0 restore size
90     __ Ldr(tmp, MemoryOperand(sp, 0));
91 
92     // descontruct frame
93     // 2 :2 means stack frame slot size
94     __ Add(sp, sp, Immediate(2 * FRAME_SLOT_SIZE));
95     __ RestoreFpAndLr();
96     __ Ret();
97 }
98 
IncreaseStackForArguments(ExtendedAssembler *assembler, Register argc, Register currentSp, int64_t numExtraArgs)99 void OptimizedCall::IncreaseStackForArguments(ExtendedAssembler *assembler, Register argc, Register currentSp,
100                                               int64_t numExtraArgs)
101 {
102     Register sp(SP);
103     __ Mov(currentSp, sp);
104     if (numExtraArgs > 0) {
105         // add extra aguments, numArgs
106         __ Add(argc, argc, Immediate(numExtraArgs));
107     }
108     __ Sub(currentSp, currentSp, Operand(argc, UXTW, FRAME_SLOT_SIZE_LOG2));
109     Label aligned;
110     __ Tst(currentSp, LogicalImmediate::Create(0xf, RegXSize));  // 0xf: 0x1111
111     __ B(Condition::EQ, &aligned);
112     __ Sub(currentSp, currentSp, Immediate(FRAME_SLOT_SIZE));
113     __ Bind(&aligned);
114     __ Mov(sp, currentSp);
115     __ Add(currentSp, currentSp, Operand(argc, UXTW, FRAME_SLOT_SIZE_LOG2));
116 }
117 
118 // * uint64_t JSFunctionEntry(uintptr_t glue, uint32_t actualNumArgs, const JSTaggedType argV[], uintptr_t prevFp,
119 //                            size_t callType)
120 // * Arguments:
121 //        %x0 - glue
122 //        %x1 - actualNumArgs
123 //        %x2 - argV
124 //        %x3 - prevFp
125 //        %x4 - needPushArgv
126 //
127 // * The JSFunctionEntry Frame's structure is illustrated as the following:
128 //          +--------------------------+
129 //          |      . . . . . .         |
130 //  sp ---> +--------------------------+ -----------------
131 //          |        prevFP            |                 ^
132 //          |--------------------------|                 |
133 //          |       frameType          |      JSFunctionEntryFrame
134 //          |--------------------------|                 |
135 //          |    preLeaveFrameFp       |                 v
136 //          +--------------------------+ -----------------
137 
JSFunctionEntry(ExtendedAssembler *assembler)138 void OptimizedCall::JSFunctionEntry(ExtendedAssembler *assembler)
139 {
140     __ BindAssemblerStub(RTSTUB_ID(JSFunctionEntry));
141     Register glueReg(X0);
142     Register argV(X2);
143     Register prevFpReg(X3);
144     Register needPushArgv(X4);
145     Register sp(SP);
146     Register tmpArgV(X7);
147     Label lJSCallWithArgVAndPushArgv;
148     Label lPopFrame;
149 
150     PushJSFunctionEntryFrame (assembler, prevFpReg);
151     __ Mov(Register(X6), needPushArgv);
152     __ Mov(tmpArgV, argV);
153     __ Mov(Register(X20), glueReg);
154     __ Ldr(Register(X2), MemoryOperand(tmpArgV, 0));
155     __ Ldr(Register(X3), MemoryOperand(tmpArgV, FRAME_SLOT_SIZE));
156     __ Ldr(Register(X4), MemoryOperand(tmpArgV, DOUBLE_SLOT_SIZE));
157     __ Add(tmpArgV, tmpArgV, Immediate(TRIPLE_SLOT_SIZE));
158     __ Mov(Register(X5), tmpArgV);
159     __ Cmp(Register(X6), Immediate(1));
160     __ B(Condition::EQ, &lJSCallWithArgVAndPushArgv);
161     __ CallAssemblerStub(RTSTUB_ID(JSCallWithArgV), false);
162     __ B(&lPopFrame);
163 
164     __ Bind(&lJSCallWithArgVAndPushArgv);
165     __ CallAssemblerStub(RTSTUB_ID(JSCallWithArgVAndPushArgv), false);
166     __ Bind(&lPopFrame);
167     __ Mov(Register(X2), Register(X20));
168     PopJSFunctionEntryFrame(assembler, Register(X2));
169     __ Ret();
170 }
171 
172 // * uint64_t OptimizedCallAndPushArgv(uintptr_t glue, uint32_t argc, JSTaggedType calltarget, JSTaggedType new,
173 //                   JSTaggedType this, arg[0], arg[1], arg[2], ..., arg[N-1])
174 // * webkit_jscc calling convention call js function()
175 //
176 // * OptimizedJSFunctionFrame layout description as the following:
177 //               +--------------------------+
178 //               |        arg[N-1]          |
179 //               +--------------------------+
180 //               |       ...                |
181 //               +--------------------------+
182 //               |       arg[1]             |
183 //               +--------------------------+
184 //               |       arg[0]             |
185 //               +--------------------------+
186 //               |       this               |
187 //               +--------------------------+
188 //               |       new-target         |
189 //               +--------------------------+
190 //               |       call-target        |
191 //               +--------------------------+
192 //               |       argv               |
193 //               +--------------------------+
194 //               |       argc               |
195 //     sp ---->  |--------------------------| ---------------
196 //               |       returnAddr         |               ^
197 //               |--------------------------|               |
198 //               |       callsiteFp         |               |
199 //               |--------------------------|   OptimizedJSFunctionFrame
200 //               |       frameType          |               |
201 //               |--------------------------|               |
202 //               |       call-target        |               v
203 //               +--------------------------+ ---------------
OptimizedCallAndPushArgv(ExtendedAssembler *assembler)204 void OptimizedCall::OptimizedCallAndPushArgv(ExtendedAssembler *assembler)
205 {
206     __ BindAssemblerStub(RTSTUB_ID(OptimizedCallAndPushArgv));
207     Register sp(SP);
208     Register jsfunc(X7);
209     Register method(X6);
210     Register expectedNumArgs(X1);
211     Register actualNumArgs(X2);
212     Register codeAddr(X3);
213     Register argV(X4);
214 
215     auto funcSlotOffSet = kungfu::ArgumentAccessor::GetExtraArgsNum();
216     __ Ldr(jsfunc, MemoryOperand(sp, funcSlotOffSet * FRAME_SLOT_SIZE));
217     __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
218     __ Ldr(codeAddr, MemoryOperand(jsfunc, JSFunction::CODE_ENTRY_OFFSET));
219     __ Ldr(expectedNumArgs, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
220     __ Lsr(expectedNumArgs, expectedNumArgs, MethodLiteral::NumArgsBits::START_BIT);
221     __ And(expectedNumArgs, expectedNumArgs,
222         LogicalImmediate::Create(
223             MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegXSize));
224     __ Add(expectedNumArgs, expectedNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
225 
226     __ Add(argV, sp, Immediate(funcSlotOffSet * FRAME_SLOT_SIZE));  // skip numArgs and argv
227     __ Ldr(actualNumArgs, MemoryOperand(sp, 0));
228 
229     Register glue(X0);
230     Register currentSp(X5);
231     Label copyArguments;
232     Label invokeCompiledJSFunction;
233 
234     // construct frame
235     PushOptimizedArgsConfigFrame(assembler);
236     Register argC(X7);
237     __ Cmp(expectedNumArgs, actualNumArgs);
238     __ CMov(argC, expectedNumArgs, actualNumArgs, Condition::HI);
239     IncreaseStackForArguments(assembler, argC, currentSp, static_cast<int64_t>(CommonArgIdx::ACTUAL_ARGV));
240     {
241         TempRegister1Scope scope1(assembler);
242         TempRegister2Scope scope2(assembler);
243         Register tmp = __ TempRegister1();
244         Register undefinedValue = __ TempRegister2();
245         __ Subs(tmp, expectedNumArgs, actualNumArgs);
246         __ B(Condition::LS, &copyArguments);
247         PushUndefinedWithArgc(assembler, glue, tmp, undefinedValue, currentSp, nullptr, nullptr);
248     }
249     __ Bind(&copyArguments);
250     __ Cbz(actualNumArgs, &invokeCompiledJSFunction);
251     {
252         TempRegister1Scope scope1(assembler);
253         TempRegister2Scope scope2(assembler);
254         Register argc = __ TempRegister1();
255         Register argValue = __ TempRegister2();
256         __ Mov(argc, actualNumArgs);
257         PushArgsWithArgv(assembler, glue, argc, argV, argValue, currentSp, &invokeCompiledJSFunction, nullptr);
258     }
259     __ Bind(&invokeCompiledJSFunction);
260     {
261         __ Mov(Register(X19), expectedNumArgs);
262         __ Str(currentSp, MemoryOperand(sp, FRAME_SLOT_SIZE));
263         __ Str(actualNumArgs, MemoryOperand(sp, 0)); // argv, argc
264         __ Blr(codeAddr);
265     }
266 
267     // pop argV argC
268     // 3 : 3 means argC * 8
269     __ Ldr(actualNumArgs, MemoryOperand(sp, 0));
270     PopJSFunctionArgs(assembler, Register(X19), actualNumArgs);
271     // pop prevLeaveFrameFp to restore thread->currentFrame_
272     PopOptimizedArgsConfigFrame(assembler);
273     __ Ret();
274 }
275 
OptimizedCallAsmInterpreter(ExtendedAssembler *assembler)276 void OptimizedCall::OptimizedCallAsmInterpreter(ExtendedAssembler *assembler)
277 {
278     Label target;
279     PushAsmInterpBridgeFrame(assembler);
280     __ Bl(&target);
281     PopAsmInterpBridgeFrame(assembler);
282     __ Ret();
283     __ Bind(&target);
284     {
285         AsmInterpreterCall::JSCallCommonEntry(assembler, JSCallMode::CALL_FROM_AOT,
286                                               FrameTransitionType::OTHER_TO_OTHER);
287     }
288 }
289 
290 // * uint64_t CallBuiltinTrampoline(uintptr_t glue, uintptr_t codeAddress, uint32_t argc, ...)
291 // * webkit_jscc calling convention call runtime_id's runtime function(c-abi)
292 // * Argument:
293 //           %x0: glue
294 //
295 // * Construct Native Leave Frame Layout:
296 //          +--------------------------+
297 //          |       argv[N-1]          |
298 //          +--------------------------+
299 //          |      . . . . . .         |
300 //          +--------------------------+
301 //          |      argv[3]=a0          |
302 //          +--------------------------+
303 //          |      argv[2]=this        |
304 //          +--------------------------+
305 //          |   argv[1]=new-target     |
306 //          +--------------------------+
307 //          |   argv[0]=call-target    |
308 //          +--------------------------+ -----------------
309 //          |       argc               |                 ^
310 //          |--------------------------|                 |
311 //          |       thread             |                 |
312 //          |--------------------------|                 |
313 //          |       returnAddr         |    OptimizedBuiltinLeaveFrame
314 //  sp ---> |--------------------------|                 |
315 //          |       callsiteFp         |                 |
316 //          |--------------------------|                 |
317 //          |       frameType          |                 v
318 //          +--------------------------+ -----------------
319 
CallBuiltinTrampoline(ExtendedAssembler *assembler)320 void OptimizedCall::CallBuiltinTrampoline(ExtendedAssembler *assembler)
321 {
322     Register glue(X0);
323     Register sp(SP);
324     Register nativeFuncAddr(X4);
325     Register temp(X1);
326 
327     // remove argv
328     __ Ldr(temp, MemoryOperand(sp, 0));
329     __ Stp(glue, temp, MemoryOperand(sp, 0));   // argc, glue
330     // returnAddr, callsiteFp
331     __ Stp(Register(X29), Register(X30), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
332     __ Mov(temp, sp);
333     __ Str(temp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false))); // rbp
334     __ Mov(Register(X29), temp); // rbp
335     __ Mov(temp, Immediate(static_cast<int32_t>(FrameType::BUILTIN_CALL_LEAVE_FRAME)));
336     __ Stp(Register(Zero), temp, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX)); // frameType, argv
337     __ Add(Register(X0), sp, Immediate(QUADRUPLE_SLOT_SIZE));
338     __ Blr(nativeFuncAddr);
339 
340     __ Mov(sp, Register(FP));
341     __ Ldp(Register(X29), Register(X30), MemoryOperand(sp, DOUBLE_SLOT_SIZE, AddrMode::POSTINDEX));
342     __ Ldr(temp, MemoryOperand(sp, FRAME_SLOT_SIZE)); // argc
343     __ Stp(temp, Register(Zero), MemoryOperand(sp, 0)); // argv, argc
344 
345     __ Ret();
346 }
347 
348 // * uint64_t CallBuiltinConstructorStub(uintptr_t glue, uintptr_t codeAddress, uint32_t argc, ...)
349 // * webkit_jscc calling convention call runtime_id's runtime function(c-abi)
350 //
351 // * Construct Native Leave Frame Layout:
352 //          +--------------------------+
353 //          |       argv[N-1]          |
354 //          +--------------------------+
355 //          |      . . . . . .         |
356 //          +--------------------------+
357 //          |      argv[3]=a0          |
358 //          +--------------------------+
359 //          |      argv[2]=this        |
360 //          +--------------------------+
361 //          |   argv[1]=new-target     |
362 //          +--------------------------+
363 //          |   argv[0]=call-target    |
364 //          +--------------------------+ -----------------
365 //          |       argc               |                 ^
366 //          |--------------------------|                 |
367 //          |       thread             |                 |
368 //          |--------------------------|                 |
369 //          |       returnAddr         |    OptimizedBuiltinLeaveFrame
370 //  sp ---> |--------------------------|                 |
371 //          |       callsiteFp         |                 |
372 //          |--------------------------|                 |
373 //          |       frameType          |                 v
374 //          +--------------------------+ -----------------
375 
CallBuiltinConstructorStub(ExtendedAssembler *assembler, Register builtinStub, Register argv, Register glue, Register temp)376 void OptimizedCall::CallBuiltinConstructorStub(ExtendedAssembler *assembler, Register builtinStub, Register argv,
377                                                Register glue, Register temp)
378 {
379     Register sp(SP);
380 
381     __ Ldr(temp, MemoryOperand(sp, 0));
382     __ Stp(glue, temp, MemoryOperand(sp, 0));   // argc, glue
383     // returnAddr, callsiteFp
384     __ Stp(Register(X29), Register(X30), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
385     __ Mov(temp, sp);
386     __ Mov(Register(X29), temp); // rbp
387     __ Mov(temp, Immediate(static_cast<int32_t>(FrameType::BUILTIN_CALL_LEAVE_FRAME)));
388     __ Stp(Register(Zero), temp, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX)); // frameType, argv
389     __ Add(argv, sp, Immediate(NONUPLE_SLOT_SIZE));
390     __ Blr(builtinStub);
391 
392     __ Mov(sp, Register(FP));
393     __ Ldp(Register(X29), Register(X30), MemoryOperand(sp, DOUBLE_SLOT_SIZE, AddrMode::POSTINDEX));
394     __ Ldr(temp, MemoryOperand(sp, FRAME_SLOT_SIZE)); // argc
395     __ Stp(temp, Register(Zero), MemoryOperand(sp, 0)); // argv, argc
396 
397     __ Ret();
398 }
399 
400 // * uint64_t JSCall(uintptr_t glue, uint32_t argc, JSTaggedType calltarget, JSTaggedType new,
401 //                   JSTaggedType this, arg[0], arg[1], arg[2], ..., arg[N-1])
402 // * webkit_jscc calling convention call js function()
403 //
404 // * OptimizedJSFunctionFrame layout description as the following:
405 //               +--------------------------+
406 //               |        arg[N-1]          |
407 //               +--------------------------+
408 //               |       ...                |
409 //               +--------------------------+
410 //               |       arg[1]             |
411 //               +--------------------------+
412 //               |       arg[0]             |
413 //               +--------------------------+
414 //               |       this               |
415 //               +--------------------------+
416 //               |       new-target         |
417 //               +--------------------------+
418 //               |       call-target        |
419 //               +--------------------------+
420 //               |       argv               |
421 //               |--------------------------|
422 //               |       argc               |
423 //      sp ----> |--------------------------| ---------------
424 //               |       returnAddr         |               ^
425 //               |--------------------------|               |
426 //               |       callsiteFp         |               |
427 //               |--------------------------|   OptimizedJSFunctionFrame
428 //               |       frameType          |               |
429 //               |--------------------------|               |
430 //               |       call-target        |               v
431 //               +--------------------------+ ---------------
432 
GenJSCall(ExtendedAssembler *assembler, bool isNew)433 void OptimizedCall::GenJSCall(ExtendedAssembler *assembler, bool isNew)
434 {
435     Register jsfunc(X1);
436     Register sp(SP);
437     __ Ldr(jsfunc, MemoryOperand(sp, DOUBLE_SLOT_SIZE)); // skip 2: argc, argv
438     JSCallInternal(assembler, jsfunc, isNew);
439 }
440 
JSCallNew(ExtendedAssembler *assembler)441 void OptimizedCall::JSCallNew(ExtendedAssembler *assembler)
442 {
443     __ BindAssemblerStub(RTSTUB_ID(JSCallNew));
444     GenJSCall(assembler, true);
445 }
446 
JSCall(ExtendedAssembler *assembler)447 void OptimizedCall::JSCall(ExtendedAssembler *assembler)
448 {
449     __ BindAssemblerStub(RTSTUB_ID(JSCall));
450     GenJSCall(assembler, false);
451 }
452 
JSCallInternal(ExtendedAssembler *assembler, Register jsfunc, bool isNew)453 void OptimizedCall::JSCallInternal(ExtendedAssembler *assembler, Register jsfunc, bool isNew)
454 {
455     Register sp(SP);
456     Register glue(X0);
457     Register taggedValue(X2);
458     Label nonCallable;
459     Label notJSFunction;
460     JSCallCheck(assembler, jsfunc, taggedValue, &nonCallable, &notJSFunction);
461 
462     Register method(X2);
463     Register callField(X3);
464     Register actualArgC(X4);
465     Label callNativeMethod;
466     Label lCallConstructor;
467     Label lCallBuiltinStub;
468     Label lCallNativeCpp;
469     Label lNotClass;
470 
471     __ Ldr(Register(X5), MemoryOperand(jsfunc, 0));
472     __ Ldr(Register(X5), MemoryOperand(Register(X5), JSHClass::BIT_FIELD_OFFSET));
473     __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
474     __ Ldr(actualArgC, MemoryOperand(sp, 0));
475     __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
476     __ Tbnz(callField, MethodLiteral::IsNativeBit::START_BIT, &callNativeMethod);
477     if (!isNew) {
478         __ Tbz(Register(X5), JSHClass::IsClassConstructorOrPrototypeBit::START_BIT, &lNotClass);
479         __ Tbnz(Register(X5), JSHClass::ConstructorBit::START_BIT, &lCallConstructor);
480     }
481     __ Bind(&lNotClass);
482     {
483         Register argV(X5);
484         // skip argc and argv
485         __ Add(argV, sp, Immediate(kungfu::ArgumentAccessor::GetExtraArgsNum() * FRAME_SLOT_SIZE));
486         // asm interpreter argV = argv + 24
487         __ Add(argV, argV, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() * FRAME_SLOT_SIZE));
488         __ Sub(actualArgC, actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum()));
489         OptimizedCallAsmInterpreter(assembler);
490     }
491 
492     __ Bind(&callNativeMethod);
493     {
494         Register nativeFuncAddr(X4);
495         if (!isNew) {
496             __ Tbz(callField, MethodLiteral::IsFastBuiltinBit::START_BIT, &lCallNativeCpp);
497             // 3 : 3 means call0 call1 call2 call3
498             __ Cmp(actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() + 3));
499             __ B(Condition::LE, &lCallBuiltinStub);
500         } else {
501             __ Tbnz(callField, MethodLiteral::IsFastBuiltinBit::START_BIT, &lCallBuiltinStub);
502         }
503         __ Bind(&lCallNativeCpp);
504         __ Ldr(nativeFuncAddr, MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
505         CallBuiltinTrampoline(assembler);
506     }
507 
508     __ Bind(&lCallBuiltinStub);
509     {
510         TempRegister1Scope scope1(assembler);
511         Register builtinStub = __ TempRegister1();
512         __ Ldr(Register(X5), MemoryOperand(method, Method::EXTRA_LITERAL_INFO_OFFSET));  // get extra literal
513         __ And(Register(X5).W(), Register(X5).W(), LogicalImmediate::Create(0xff, RegWSize));
514         if (!isNew) {
515             __ Cmp(Register(X5).W(), Immediate(kungfu::BuiltinsStubCSigns::BUILTINS_CONSTRUCTOR_STUB_FIRST));
516             __ B(Condition::GE, &lCallNativeCpp);
517         }
518         __ Add(builtinStub, glue, Operand(Register(X5).W(), UXTW, FRAME_SLOT_SIZE_LOG2));
519         __ Ldr(builtinStub, MemoryOperand(builtinStub, JSThread::GlueData::GetBuiltinsStubEntriesOffset(false)));
520 
521         __ Ldr(Register(X1), MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
522         __ Ldr(Register(X2), MemoryOperand(sp, DOUBLE_SLOT_SIZE));  // get jsfunc
523         __ Ldr(Register(X3), MemoryOperand(sp, TRIPLE_SLOT_SIZE));  // get newtarget
524         __ Ldr(Register(X4), MemoryOperand(sp, QUADRUPLE_SLOT_SIZE));  // get this
525         __ Ldr(Register(X5), MemoryOperand(sp, 0));  // get number args
526         __ Sub(Register(X5), Register(X5), Immediate(NUM_MANDATORY_JSFUNC_ARGS));
527         if (!isNew) {
528             Label lCall0;
529             Label lCall1;
530             Label lCall2;
531             Label lCall3;
532             Label lTailCall;
533             Register fp(X29);
534             __ Cmp(Register(X5), Immediate(0));
535             __ B(Condition::EQ, &lCall0);
536             __ Cmp(Register(X5), Immediate(1));
537             __ B(Condition::EQ, &lCall1);
538             __ Cmp(Register(X5), Immediate(2));  // 2: 2 args
539             __ B(Condition::EQ, &lCall2);
540             __ Cmp(Register(X5), Immediate(3));  // 3: 3 args
541             __ B(Condition::EQ, &lCall3);
542 
543             __ Bind(&lCall0);
544             {
545                 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
546                 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
547                 __ Str(Register(X7), MemoryOperand(sp, 0));  // reset arg2's position
548                 __ B(&lTailCall);
549             }
550 
551             __ Bind(&lCall1);
552             {
553                 __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE));
554                 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));  // reset x7
555                 __ Str(Register(X7), MemoryOperand(sp, 0));  // reset arg2's position
556                 __ B(&lTailCall);
557             }
558 
559             __ Bind(&lCall2);
560             {
561                 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
562                 __ Str(Register(X7), MemoryOperand(sp, 0));  // reset arg2's position
563                 __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE));
564                 __ B(&lTailCall);
565             }
566 
567             __ Bind(&lCall3);
568             __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE));  // get arg0 arg1
569             PushAsmBridgeFrame(assembler);
570             {
571                 // push arg2 and call
572                 TempRegister2Scope scope2(assembler);
573                 Register arg2 = __ TempRegister2();
574                 __ Ldr(arg2, MemoryOperand(fp, NONUPLE_SLOT_SIZE));
575                 __ Stp(arg2, Register(X8), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
576                 __ Blr(builtinStub);
577                 __ Add(sp, sp, Immediate(DOUBLE_SLOT_SIZE));
578             }
579             PopAsmBridgeFrame(assembler);
580             __ Ret();
581             __ Bind(&lTailCall);
582             {
583                 __ Br(builtinStub);
584             }
585         } else {
586             Register argv(X6);
587             TempRegister2Scope scope2(assembler);
588             Register temp = __ TempRegister2();
589             CallBuiltinConstructorStub(assembler, builtinStub, argv, glue, temp);
590         }
591     }
592 
593     Label jsBoundFunction;
594     Label jsProxy;
595     __ Bind(&notJSFunction);
596     {
597         Register bitfield(X2);
598         Register jstype2(X5, W);
599         __ And(jstype2, bitfield.W(), LogicalImmediate::Create(0xff, RegWSize));
600         __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_BOUND_FUNCTION)));
601         __ B(Condition::EQ, &jsBoundFunction);
602         __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_PROXY)));
603         __ B(Condition::EQ, &jsProxy);
604         __ Ret();
605     }
606 
607     __ Bind(&jsBoundFunction);
608     {
609         JSBoundFunctionCallInternal(assembler, glue, actualArgC, jsfunc, RTSTUB_ID(JSCall));
610     }
611     __ Bind(&jsProxy);
612     {
613         __ Ldr(method, MemoryOperand(jsfunc, JSProxy::METHOD_OFFSET));
614         __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
615         __ Ldr(actualArgC, MemoryOperand(sp, 0));
616         __ B(&callNativeMethod);
617     }
618     __ Bind(&nonCallable);
619     {
620         ThrowNonCallableInternal(assembler, sp);
621     }
622     __ Bind(&lCallConstructor);
623     {
624         Register frameType(X6);
625         __ PushFpAndLr();
626         __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
627         // 2 : 2 means pair
628         __ Stp(Register(Zero), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
629         __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
630         Register argC(X5);
631         Register runtimeId(X6);
632         __ Mov(argC, Immediate(0));
633         __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowCallConstructorException)));
634         // 2 : 2 means pair
635         __ Stp(runtimeId, argC, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
636         __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
637         // 4 : 4 means stack slot
638         __ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
639         __ RestoreFpAndLr();
640         __ Ret();
641     }
642 }
643 
644 // After the callee function of common aot call deopt, use this bridge to deal with this aot call.
645 // calling convention: webkit_jsc
646 // Input structure:
647 // %X0 - glue
648 // stack:
649 // +--------------------------+
650 // |       arg[N-1]           |
651 // +--------------------------+
652 // |       ...                |
653 // +--------------------------+
654 // |       arg[1]             |
655 // +--------------------------+
656 // |       arg[0]             |
657 // +--------------------------+
658 // |       this               |
659 // +--------------------------+
660 // |       new-target         |
661 // +--------------------------+
662 // |       call-target        |
663 // |--------------------------|
664 // |       argv               |
665 // |--------------------------|
666 // |       argc               |
667 // +--------------------------+ <---- sp
AOTCallToAsmInterBridge(ExtendedAssembler *assembler)668 void OptimizedCall::AOTCallToAsmInterBridge(ExtendedAssembler *assembler)
669 {
670     __ BindAssemblerStub(RTSTUB_ID(AOTCallToAsmInterBridge));
671     Register sp(SP);
672     // params of c++ calling convention
673     Register glue(X0);
674     Register jsfunc(X1);
675     Register method(X2);
676     Register callField(X3);
677     Register actualArgC(X4);
678     Register argV(X5);
679 
680     __ Ldr(jsfunc, MemoryOperand(sp, DOUBLE_SLOT_SIZE));
681     __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
682     __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
683     __ Ldr(actualArgC, MemoryOperand(sp, 0));
684     // skip argc
685     __ Add(argV, sp, Immediate(kungfu::ArgumentAccessor::GetExtraArgsNum() * FRAME_SLOT_SIZE));
686     // asm interpreter argV = argv + 24
687     __ Add(argV, argV, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() * FRAME_SLOT_SIZE));
688     __ Sub(actualArgC, actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum()));
689     OptimizedCallAsmInterpreter(assembler);
690 }
691 
692 // After the callee function of fast aot call deopt, use this bridge to deal with this fast aot call.
693 // Notice: no argc and new-target params compared with not-fast aot call because these params are not needed
694 // by bytecode-analysis
695 // Intruduction: use expected argc as actual argc below for these reasons:
696 // 1) when expected argc == actual argc, pass.
697 // 2) when expected argc > actual argc, undefineds have been pushed in OptimizedFastCallAndPushArgv.
698 // 3) when expected argc < actual argc, redundant params are useless according to bytecode-analysis, just abandon them.
699 // calling convention: c++ calling convention
700 // Input structure:
701 // %X0 - glue
702 // %X1 - call-target
703 // %X2 - this
704 // %X3 - arg0
705 // %X4 - arg1
706 // %X5 - arg2
707 // %X6 - arg3
708 // %X7 - arg4
709 // stack:
710 // +--------------------------+
711 // |        arg[N-1]          |
712 // +--------------------------+
713 // |       ...                |
714 // +--------------------------+
715 // |       arg[5]             |
716 // +--------------------------+ <---- sp
FastCallToAsmInterBridge(ExtendedAssembler *assembler)717 void OptimizedCall::FastCallToAsmInterBridge(ExtendedAssembler *assembler)
718 {
719     __ BindAssemblerStub(RTSTUB_ID(FastCallToAsmInterBridge));
720 
721     // Add a bridge frame to protect the stack map, because args will be put on the stack to construct argv on stack
722     // and the AsmInterpBridgeFrame pushed below cannot protect the stack map anymore.
723     PushAsmBridgeFrame(assembler);
724 
725     Register sp(SP);
726     // Input
727     Register glue(X0);
728     Register jsfunc(X1);
729     Register thisReg(X2);
730 
731     Register tempArgc = __ AvailableRegister1();
732     {
733         TempRegister2Scope scope2(assembler);
734         Register tempMethod = __ TempRegister2();
735 
736         __ Ldr(tempMethod, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
737         __ Ldr(tempArgc, MemoryOperand(tempMethod, Method::CALL_FIELD_OFFSET));
738         __ Lsr(tempArgc, tempArgc, MethodLiteral::NumArgsBits::START_BIT);
739         __ And(tempArgc, tempArgc,
740             LogicalImmediate::Create(
741                 MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegXSize));
742     }
743     {
744         TempRegister1Scope scope1(assembler);
745         Register startSp = __ TempRegister1();
746         __ Mov(startSp, sp);
747 
748         Label lCall0;
749         Label lCall1;
750         Label lCall2;
751         Label lCall3;
752         Label lCall4;
753         Label lCall5;
754         Label lPushCommonRegs;
755 
756         __ Cmp(tempArgc, Immediate(0));
757         __ B(Condition::EQ, &lCall0);
758         __ Cmp(tempArgc, Immediate(1));
759         __ B(Condition::EQ, &lCall1);
760         __ Cmp(tempArgc, Immediate(2));  // 2: 2 args
761         __ B(Condition::EQ, &lCall2);
762         __ Cmp(tempArgc, Immediate(3));  // 3: 3 args
763         __ B(Condition::EQ, &lCall3);
764         __ Cmp(tempArgc, Immediate(4));  // 4: 4 args
765         __ B(Condition::EQ, &lCall4);
766         __ Cmp(tempArgc, Immediate(5));  // 5: 5 args
767         __ B(Condition::EQ, &lCall5);
768         // default: more than 5 args
769         {
770             TempRegister2Scope scope2(assembler);
771             Register onStackArgs = __ TempRegister2();
772             Register op1 = __ AvailableRegister2();
773             Register op2 = __ AvailableRegister3();
774 
775             // skip bridge frame, return addr and a callee save
776             __ Add(onStackArgs, sp, Immediate(QUADRUPLE_SLOT_SIZE));
777             __ Sub(tempArgc, tempArgc, Immediate(5));  // 5: the first 5 args are not on stack
778             Register arg4(X7);
779             PushArgsWithArgvInPair(assembler, tempArgc, onStackArgs, arg4, op1, op2, &lCall4);
780         }
781 
782         __ Bind(&lCall0);
783         {
784             __ B(&lPushCommonRegs);
785         }
786 
787         __ Bind(&lCall1);
788         {
789             __ Stp(Register(X3), Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
790             __ B(&lPushCommonRegs);
791         }
792 
793         __ Bind(&lCall2);
794         {
795             __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
796             __ B(&lPushCommonRegs);
797         }
798 
799         __ Bind(&lCall3);
800         {
801             __ Stp(Register(X5), Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
802             __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
803             __ B(&lPushCommonRegs);
804         }
805 
806         __ Bind(&lCall4);
807         {
808             __ Stp(Register(X5), Register(X6), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
809             __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
810             __ B(&lPushCommonRegs);
811         }
812 
813         __ Bind(&lCall5);
814         {
815             __ Stp(Register(X7), Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
816             __ Stp(Register(X5), Register(X6), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
817             __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
818             __ B(&lPushCommonRegs);
819         }
820 
821         __ Bind(&lPushCommonRegs);
822         {
823             Register newTarget(X7);
824             __ Mov(newTarget, Immediate(JSTaggedValue::VALUE_UNDEFINED));
825             __ Stp(newTarget, thisReg, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
826             __ Stp(startSp, jsfunc, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
827             // fall through
828         }
829     }
830 
831     // params of c++ calling convention
832     // glue: X0
833     // jsfunc: X1
834     Register method(X2);
835     Register methodCallField(X3);
836     Register argc(X4);
837     Register argV(X5);
838     // reload and prepare args for JSCallCommonEntry
839     __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
840     __ Ldr(methodCallField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
841     __ Mov(argc, methodCallField);
842     __ Lsr(argc, argc, MethodLiteral::NumArgsBits::START_BIT);
843     __ And(argc, argc,
844         LogicalImmediate::Create(
845             MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegXSize));
846     __ Add(argV, sp, Immediate((kungfu::ArgumentAccessor::GetFixArgsNum() + 1) * FRAME_SLOT_SIZE));  // 1: skip startSp
847 
848     Label target;
849     PushAsmInterpBridgeFrame(assembler);
850     __ Bl(&target);
851     {
852         PopAsmInterpBridgeFrame(assembler);
853         TempRegister1Scope scope1(assembler);
854         Register startSp = __ TempRegister1();
855         __ Ldp(startSp, Register(Zero), MemoryOperand(sp, ExtendedAssembler::PAIR_SLOT_SIZE, POSTINDEX));
856         __ Mov(sp, startSp);
857         PopAsmBridgeFrame(assembler);
858         __ Ret();
859     }
860     __ Bind(&target);
861     {
862         AsmInterpreterCall::JSCallCommonEntry(assembler, JSCallMode::CALL_FROM_AOT,
863                                               FrameTransitionType::OTHER_TO_OTHER);
864     }
865 }
866 
JSCallCheck(ExtendedAssembler *assembler, Register jsfunc, Register taggedValue, Label *nonCallable, Label *notJSFunction)867 void OptimizedCall::JSCallCheck(ExtendedAssembler *assembler, Register jsfunc, Register taggedValue,
868                                 Label *nonCallable, Label *notJSFunction)
869 {
870     __ Mov(taggedValue, JSTaggedValue::TAG_MARK);
871     __ Cmp(jsfunc, taggedValue);
872     __ B(Condition::HS, nonCallable);
873     __ Cbz(jsfunc, nonCallable);
874     __ Mov(taggedValue, JSTaggedValue::TAG_SPECIAL);
875     __ And(taggedValue, jsfunc, taggedValue);
876     __ Cbnz(taggedValue, nonCallable);
877 
878     Register jshclass(X2);
879     __ Ldr(jshclass, MemoryOperand(jsfunc, JSFunction::HCLASS_OFFSET));
880     Register bitfield(X2);
881     __ Ldr(bitfield, MemoryOperand(jshclass, JSHClass::BIT_FIELD_OFFSET));
882     __ Tbz(bitfield, JSHClass::CallableBit::START_BIT, nonCallable);
883 
884     Register jstype(X3, W);
885     __ And(jstype, bitfield, LogicalImmediate::Create(0xFF, RegWSize));
886     // 4 : 4 means JSType::JS_FUNCTION_FIRST
887     __ Sub(jstype, jstype, Immediate(static_cast<int>(JSType::JS_FUNCTION_FIRST)));
888     // 9 : 9 means JSType::JS_FUNCTION_LAST - JSType::JS_FUNCTION_FIRST + 1
889     __ Cmp(jstype, Immediate(static_cast<int>(JSType::JS_FUNCTION_LAST) -
890         static_cast<int>(JSType::JS_FUNCTION_FIRST) + 1));
891     __ B(Condition::HS, notJSFunction);
892 }
893 
ThrowNonCallableInternal(ExtendedAssembler *assembler, Register sp)894 void OptimizedCall::ThrowNonCallableInternal(ExtendedAssembler *assembler, Register sp)
895 {
896     Register frameType(X6);
897     Register taggedMessageId(X5);
898     __ PushFpAndLr();
899     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
900     __ Mov(taggedMessageId,
901         Immediate(JSTaggedValue(GET_MESSAGE_STRING_ID(NonCallable)).GetRawData()));
902     // 2 : 2 means pair
903     __ Stp(taggedMessageId, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
904     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
905     Register argC(X5);
906     Register runtimeId(X6);
907     __ Mov(argC, Immediate(1));
908     __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowTypeError)));
909     // 2 : 2 means pair
910     __ Stp(runtimeId, argC, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
911     __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
912     __ Mov(Register(X0), Immediate(JSTaggedValue::VALUE_EXCEPTION));
913     // 4 : 4 means stack slot
914     __ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
915     __ RestoreFpAndLr();
916     __ Ret();
917 }
918 
JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Register glue, Register actualArgC, Register jsfunc, int stubId)919 void OptimizedCall::JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Register glue,
920                                                 Register actualArgC, Register jsfunc, int stubId)
921 {
922     // construct frame
923     PushOptimizedArgsConfigFrame(assembler);
924     Register basefp(X29);
925     Register fp = __ AvailableRegister1();
926 
927     Register argV(X5);
928     __ Add(argV, basefp, Immediate(GetStackArgOffSetToFp(0))); // 0: first index id
929     __ Ldr(actualArgC, MemoryOperand(argV, 0));
930 
931     Register boundLength(X2);
932     Register realArgC(X7, W);
933     Label copyBoundArgument;
934     Label pushCallTarget;
935     Label popArgs;
936     Label slowCall;
937     Label aotCall;
938     Label notClass;
939     // get bound arguments
940     __ Ldr(boundLength, MemoryOperand(jsfunc, JSBoundFunction::BOUND_ARGUMENTS_OFFSET));
941     //  get bound length
942     __ Ldr(boundLength, MemoryOperand(boundLength, TaggedArray::LENGTH_OFFSET));
943     __ Add(realArgC, boundLength.W(), actualArgC.W());
944     __ Mov(Register(X19), realArgC);
945     IncreaseStackForArguments(assembler, realArgC, fp, static_cast<int64_t>(CommonArgIdx::ACTUAL_ARGV));
946     __ Sub(actualArgC.W(), actualArgC.W(), Immediate(NUM_MANDATORY_JSFUNC_ARGS));
947     __ Cmp(actualArgC.W(), Immediate(0));
948     __ B(Condition::EQ, &copyBoundArgument);
949     {
950         TempRegister1Scope scope1(assembler);
951         Register tmp = __ TempRegister1();
952         const int64_t argoffsetSlot = static_cast<int64_t>(CommonArgIdx::FUNC) - 1;
953         __ Add(argV, argV, Immediate((NUM_MANDATORY_JSFUNC_ARGS + argoffsetSlot) * FRAME_SLOT_SIZE));
954         PushArgsWithArgv(assembler, glue, actualArgC, argV, tmp, fp, nullptr, nullptr);
955     }
956     __ Bind(&copyBoundArgument);
957     {
958         Register boundArgs(X4);
959         __ Ldr(boundArgs, MemoryOperand(jsfunc, JSBoundFunction::BOUND_ARGUMENTS_OFFSET));
960         __ Add(boundArgs, boundArgs, Immediate(TaggedArray::DATA_OFFSET));
961         __ Cmp(boundLength.W(), Immediate(0));
962         __ B(Condition::EQ, &pushCallTarget);
963         {
964             TempRegister1Scope scope1(assembler);
965             Register tmp = __ TempRegister1();
966             PushArgsWithArgv(assembler, glue, boundLength, boundArgs, tmp, fp, nullptr, nullptr);
967         }
968     }
969     Register boundTarget(X7);
970     Register newTarget(X6);
971     __ Bind(&pushCallTarget);
972     {
973         Register thisObj(X4);
974         __ Ldr(thisObj, MemoryOperand(jsfunc, JSBoundFunction::BOUND_THIS_OFFSET));
975         __ Mov(newTarget, Immediate(JSTaggedValue::VALUE_UNDEFINED));
976         // 2 : 2 means pair
977         __ Stp(newTarget, thisObj, MemoryOperand(fp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
978         __ Ldr(boundTarget, MemoryOperand(jsfunc, JSBoundFunction::BOUND_TARGET_OFFSET));
979         // 2 : 2 means pair
980         __ Stp(argV, boundTarget, MemoryOperand(fp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
981         __ Str(Register(X19), MemoryOperand(fp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
982     }
983     JSCallCheck(assembler, boundTarget, Register(X9), &slowCall, &slowCall);
984     Register hclass = __ AvailableRegister2();
985     __ Ldr(hclass, MemoryOperand(boundTarget, 0));
986     __ Ldr(hclass, MemoryOperand(hclass, JSHClass::BIT_FIELD_OFFSET));
987     __ Tbz(hclass, JSHClass::IsClassConstructorOrPrototypeBit::START_BIT, &notClass);
988     __ Tbnz(hclass, JSHClass::ConstructorBit::START_BIT, &slowCall);
989     __ Bind(&notClass);
990     Register compiledCodeFlag(X9, W);
991     __ Ldrh(compiledCodeFlag, MemoryOperand(boundTarget, JSFunctionBase::BIT_FIELD_OFFSET));
992     __ Tbz(compiledCodeFlag, JSFunctionBase::IsCompiledCodeBit::START_BIT, &slowCall);
993     __ Bind(&aotCall);
994     {
995         // output: glue:x0 argc:x1 calltarget:x2 argv:x3 this:x4 newtarget:x5
996         __ Mov(Register(X1), Register(X19));
997         __ Mov(Register(X2), boundTarget);
998         __ Add(X3, fp, Immediate(5 * FRAME_SLOT_SIZE)); // 5: skip argc and argv func new this
999         __ Mov(Register(X5), Register(X6));
1000         Register boundCallInternalId(X9);
1001         Register baseAddress(X8);
1002         Register codeAddress(X10);
1003         __ Mov(baseAddress, Immediate(JSThread::GlueData::GetCOStubEntriesOffset(false)));
1004         __ Mov(boundCallInternalId, Immediate(CommonStubCSigns::JsBoundCallInternal));
1005         __ Add(codeAddress, X0, baseAddress);
1006         __ Ldr(codeAddress, MemoryOperand(codeAddress, boundCallInternalId, UXTW, FRAME_SLOT_SIZE_LOG2));
1007         __ Blr(codeAddress);
1008         __ B(&popArgs);
1009     }
1010     __ Bind(&slowCall);
1011     {
1012         __ CallAssemblerStub(stubId, false);
1013         __ B(&popArgs);
1014     }
1015 
1016     __ Bind(&popArgs);
1017     PopJSFunctionArgs(assembler, Register(X19), Register(X19));
1018     PopOptimizedArgsConfigFrame(assembler);
1019     __ Ret();
1020 }
1021 
1022 // * uint64_t JSProxyCallInternalWithArgV(uintptr_t glue, JSTaggedType calltarget)
1023 // * c++ calling convention call js function
1024 // * Arguments:
1025 //        %x0 - glue
1026 //        %x1 - calltarget
1027 
JSProxyCallInternalWithArgV(ExtendedAssembler *assembler)1028 void OptimizedCall::JSProxyCallInternalWithArgV(ExtendedAssembler *assembler)
1029 {
1030     __ BindAssemblerStub(RTSTUB_ID(JSProxyCallInternalWithArgV));
1031     Register jsfunc(X1);
1032     Register sp(SP);
1033     __ Str(jsfunc, MemoryOperand(sp, DOUBLE_SLOT_SIZE));
1034     JSCallInternal(assembler, jsfunc);
1035 }
1036 
1037 // * uint64_t CallRuntimeWithArgv(uintptr_t glue, uint64_t runtime_id, uint64_t argc, uintptr_t argv)
1038 // * cc calling convention call runtime_id's runtion function(c-abi)
1039 // * Arguments:
1040 //         %x0 - glue
1041 //         %x1 - runtime_id
1042 //         %x2 - argc
1043 //         %x3 - argv
1044 //
1045 // * Optimized-leaved-frame-with-argv layout as the following:
1046 //         +--------------------------+
1047 //         |       argv[]             |
1048 //         +--------------------------+-------------
1049 //         |       argc               |            ^
1050 //         |--------------------------|            |
1051 //         |       RuntimeId          |   OptimizedWithArgvLeaveFrame
1052 //  sp --> |--------------------------|            |
1053 //         |       returnAddr         |            |
1054 //         |--------------------------|            |
1055 //         |       callsiteFp         |            |
1056 //         |--------------------------|            |
1057 //         |       frameType          |            v
1058 //         +--------------------------+-------------
1059 
CallRuntimeWithArgv(ExtendedAssembler *assembler)1060 void OptimizedCall::CallRuntimeWithArgv(ExtendedAssembler *assembler)
1061 {
1062     __ BindAssemblerStub(RTSTUB_ID(CallRuntimeWithArgv));
1063     Register glue(X0);
1064     Register runtimeId(X1);
1065     Register argc(X2);
1066     Register argv(X3);
1067     Register sp(SP);
1068     // 2 : 2 means pair
1069     __ Stp(argc, argv, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1070     __ Stp(Register(X30), runtimeId, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX)); // 2 : 2 means pair
1071     Register fp(X29);
1072     // construct leave frame
1073     Register frameType(X9);
1074     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::LEAVE_FRAME_WITH_ARGV)));
1075     __ Stp(frameType, Register(X29), MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX)); // 2 : 2 means pair
1076     __ Add(Register(FP), sp, Immediate(FRAME_SLOT_SIZE));
1077     __ Str(fp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
1078 
1079      // load runtime trampoline address
1080     Register tmp(X9);
1081     Register rtfunc(X9);
1082     // 3 : 3 means 2 << 3 = 8
1083     __ Add(tmp, glue, Operand(runtimeId, LSL, 3));
1084     __ Ldr(rtfunc, MemoryOperand(tmp, JSThread::GlueData::GetRTStubEntriesOffset(false)));
1085     __ Mov(X1, argc);
1086     __ Mov(X2, argv);
1087     __ Blr(rtfunc);
1088     __ Ldp(Register(Zero), Register(X29), MemoryOperand(sp, ExtendedAssembler::PAIR_SLOT_SIZE, POSTINDEX));
1089     __ Ldp(Register(X30), Register(Zero), MemoryOperand(sp, ExtendedAssembler::PAIR_SLOT_SIZE, POSTINDEX));
1090     __ Add(sp, sp, Immediate(2 * FRAME_SLOT_SIZE)); // 2 : 2 means pair
1091     __ Ret();
1092 }
1093 
PushMandatoryJSArgs(ExtendedAssembler *assembler, Register jsfunc, Register thisObj, Register newTarget, Register currentSp)1094 void OptimizedCall::PushMandatoryJSArgs(ExtendedAssembler *assembler, Register jsfunc,
1095                                         Register thisObj, Register newTarget, Register currentSp)
1096 {
1097     __ Str(thisObj, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1098     __ Str(newTarget, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1099     __ Str(jsfunc, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1100 }
1101 
PopJSFunctionArgs(ExtendedAssembler *assembler, Register expectedNumArgs, Register actualNumArgs)1102 void OptimizedCall::PopJSFunctionArgs(ExtendedAssembler *assembler, Register expectedNumArgs, Register actualNumArgs)
1103 {
1104     Register sp(SP);
1105     Register fp(X6);
1106     Label aligned;
1107     const int64_t argoffsetSlot = static_cast<int64_t>(CommonArgIdx::FUNC) - 1;
1108     if (expectedNumArgs != actualNumArgs) {
1109         TempRegister1Scope scop1(assembler);
1110         Register tmp = __ TempRegister1();
1111         __ Cmp(expectedNumArgs, actualNumArgs);
1112         __ CMov(tmp, expectedNumArgs, actualNumArgs, Condition::HI);
1113         __ Add(sp, sp, Operand(tmp, UXTW, FRAME_SLOT_SIZE_LOG2));
1114     } else {
1115         __ Add(sp, sp, Operand(expectedNumArgs, UXTW, FRAME_SLOT_SIZE_LOG2));
1116     }
1117     __ Add(sp, sp, Immediate(argoffsetSlot * FRAME_SLOT_SIZE));
1118     __ Mov(fp, sp);
1119     __ Tst(fp, LogicalImmediate::Create(0xf, RegXSize));  // 0xf: 0x1111
1120     __ B(Condition::EQ, &aligned);
1121     __ Add(sp, sp, Immediate(FRAME_SLOT_SIZE));
1122     __ Bind(&aligned);
1123 }
1124 
PushJSFunctionEntryFrame(ExtendedAssembler *assembler, Register prevFp)1125 void OptimizedCall::PushJSFunctionEntryFrame(ExtendedAssembler *assembler, Register prevFp)
1126 {
1127     Register fp(X29);
1128     Register sp(SP);
1129     TempRegister2Scope temp2Scope(assembler);
1130     __ PushFpAndLr();
1131     Register frameType = __ TempRegister2();
1132     // construct frame
1133     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_ENTRY_FRAME)));
1134     // 2 : 2 means pairs
1135     __ Stp(prevFp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1136     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
1137     __ CalleeSave();
1138 }
1139 
PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue)1140 void OptimizedCall::PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue)
1141 {
1142     Register fp(X29);
1143     Register sp(SP);
1144     Register prevFp(X1);
1145     __ CalleeRestore();
1146 
1147     // 2: prevFp and frameType
1148     __ Ldp(prevFp, Register(Zero), MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
1149     // restore return address
1150     __ RestoreFpAndLr();
1151     __ Str(prevFp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
1152 }
1153 
PushOptimizedArgsConfigFrame(ExtendedAssembler *assembler)1154 void OptimizedCall::PushOptimizedArgsConfigFrame(ExtendedAssembler *assembler)
1155 {
1156     Register sp(SP);
1157     TempRegister2Scope temp2Scope(assembler);
1158     Register frameType = __ TempRegister2();
1159     __ PushFpAndLr();
1160     // construct frame
1161     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
1162     // 2 : 2 means pairs. X19 means calleesave and 16bytes align
1163     __ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1164     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
1165 }
1166 
PopOptimizedArgsConfigFrame(ExtendedAssembler *assembler)1167 void OptimizedCall::PopOptimizedArgsConfigFrame(ExtendedAssembler *assembler)
1168 {
1169     TempRegister2Scope temp2Scope(assembler);
1170     Register sp(SP);
1171     Register frameType = __ TempRegister2();
1172     // 2 : 2 means pop call site sp and type
1173     __ Ldp(Register(X19), frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
1174     __ RestoreFpAndLr();
1175 }
1176 
1177 // * uint64_t PushOptimizedUnfoldArgVFrame(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1178 //                                         JSTaggedType new, JSTaggedType this, JSTaggedType argV[])
1179 // * cc calling convention call js function()
1180 // * arguments:
1181 //              %x0 - glue
1182 //              %x1 - argc
1183 //              %x2 - call-target
1184 //              %x3 - new-target
1185 //              %x4 - this
1186 //              %x5 - argv
1187 //
1188 // * OptimizedUnfoldArgVFrame layout description as the following:
1189 //      sp ----> |--------------------------| ---------------
1190 //               |       returnAddr         |               ^
1191 //  currentFp--> |--------------------------|               |
1192 //               |       prevFp             |               |
1193 //               |--------------------------|   OptimizedUnfoldArgVFrame
1194 //               |       frameType          |               |
1195 //               |--------------------------|               |
1196 //               |       currentFp          |               v
1197 //               +--------------------------+ ---------------
1198 
PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp)1199 void OptimizedCall::PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp)
1200 {
1201     Register sp(SP);
1202     TempRegister2Scope temp2Scope(assembler);
1203     Register frameType = __ TempRegister2();
1204     __ PushFpAndLr();
1205     // construct frame
1206     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)));
1207     // 2 : 2 means pairs
1208     __ Stp(callSiteSp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1209     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
1210 }
1211 
PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler)1212 void OptimizedCall::PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler)
1213 {
1214     Register sp(SP);
1215     // 2 : 2 means pop call site sp and type
1216     __ Add(sp, sp, Immediate(2 * FRAME_SLOT_SIZE));
1217     __ RestoreFpAndLr();
1218 }
1219 
1220 // * uint64_t JSCallWithArgV(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1221 //                          JSTaggedType new, JSTaggedType this, argV)
1222 // * cc calling convention call js function()
1223 // * arguments:
1224 //              %x0 - glue
1225 //              %x1 - argc
1226 //              %x2 - call-target
1227 //              %x3 - new-target
1228 //              %x4 - this
1229 //              %x5 - argV[]
1230 //
1231 // * OptimizedJSFunctionFrame layout description as the following:
1232 //               +--------------------------+
1233 //               |       argn               |
1234 //               |--------------------------|
1235 //               |       argn - 1           |
1236 //               |--------------------------|
1237 //               |       .....              |
1238 //               |--------------------------|
1239 //               |       arg2               |
1240 //               |--------------------------|
1241 //               |       arg1               |
1242 //      sp ----> |--------------------------| ---------------
1243 //               |       returnAddr         |               ^
1244 //               |--------------------------|               |
1245 //               |       callsiteFp         |               |
1246 //               |--------------------------|  OptimizedJSFunctionFrame
1247 //               |       frameType          |               |
1248 //               |--------------------------|               |
1249 //               |       call-target        |               v
1250 //               +--------------------------+ ---------------
1251 
GenJSCallWithArgV(ExtendedAssembler *assembler, int id)1252 void OptimizedCall::GenJSCallWithArgV(ExtendedAssembler *assembler, int id)
1253 {
1254     Register sp(SP);
1255     Register glue(X0);
1256     Register actualNumArgs(X1);
1257     Register jsfunc(X2);
1258     Register newTarget(X3);
1259     Register thisObj(X4);
1260     Register argV(X5);
1261     Register currentSp = __ AvailableRegister1();
1262     Register callsiteSp = __ AvailableRegister2();
1263     Label pushCallThis;
1264 
1265     __ Mov(callsiteSp, sp);
1266     PushOptimizedUnfoldArgVFrame(assembler, callsiteSp);
1267     Register argC(X7);
1268     __ Add(actualNumArgs, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1269     __ Mov(argC, actualNumArgs);
1270     IncreaseStackForArguments(assembler, argC, currentSp, static_cast<int64_t>(CommonArgIdx::ACTUAL_ARGV));
1271     {
1272         TempRegister1Scope scope1(assembler);
1273         TempRegister2Scope scope2(assembler);
1274         Register tmp = __ TempRegister1();
1275         Register op = __ TempRegister2();
1276         __ Sub(tmp, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1277         PushArgsWithArgv(assembler, glue, tmp, argV, op, currentSp, &pushCallThis, nullptr);
1278     }
1279     __ Bind(&pushCallThis);
1280     PushMandatoryJSArgs(assembler, jsfunc, thisObj, newTarget, currentSp);
1281     {
1282         TempRegister1Scope scope1(assembler);
1283         Register tmp = __ TempRegister1();
1284         __ Mov(tmp, currentSp);
1285         __ Str(tmp, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1286         __ Str(actualNumArgs, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1287     }
1288     __ CallAssemblerStub(id, false);
1289     __ Ldr(actualNumArgs, MemoryOperand(sp, 0));
1290     PopJSFunctionArgs(assembler, actualNumArgs, actualNumArgs);
1291     PopOptimizedUnfoldArgVFrame(assembler);
1292     __ Ret();
1293 }
1294 
1295 // * uint64_t JSCallWithArgVAndPushArgv(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1296 //                          JSTaggedType new, JSTaggedType this, argV)
1297 // * cc calling convention call js function()
1298 // * arguments:
1299 //              %x0 - glue
1300 //              %x1 - argc
1301 //              %x2 - call-target
1302 //              %x3 - new-target
1303 //              %x4  - this
1304 //              %x5  - argv
JSCallWithArgVAndPushArgv(ExtendedAssembler *assembler)1305 void OptimizedCall::JSCallWithArgVAndPushArgv(ExtendedAssembler *assembler)
1306 {
1307     __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgVAndPushArgv));
1308     GenJSCallWithArgV(assembler, RTSTUB_ID(OptimizedCallAndPushArgv));
1309 }
1310 
JSCallWithArgV(ExtendedAssembler *assembler)1311 void OptimizedCall::JSCallWithArgV(ExtendedAssembler *assembler)
1312 {
1313     __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgV));
1314     GenJSCallWithArgV(assembler, RTSTUB_ID(CallOptimized));
1315 }
1316 
SuperCallWithArgV(ExtendedAssembler *assembler)1317 void OptimizedCall::SuperCallWithArgV(ExtendedAssembler *assembler)
1318 {
1319     __ BindAssemblerStub(RTSTUB_ID(SuperCallWithArgV));
1320     GenJSCallWithArgV(assembler, RTSTUB_ID(JSCallNew));
1321 }
1322 
CallOptimized(ExtendedAssembler *assembler)1323 void OptimizedCall::CallOptimized(ExtendedAssembler *assembler)
1324 {
1325     __ BindAssemblerStub(RTSTUB_ID(CallOptimized));
1326     Register sp(SP);
1327     Register jsfunc(X7);
1328     Register method(X6);
1329     Register codeAddr(X5);
1330     auto funcSlotOffset = kungfu::ArgumentAccessor::GetExtraArgsNum();
1331     __ Ldr(jsfunc, MemoryOperand(sp, funcSlotOffset * FRAME_SLOT_SIZE));
1332     __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
1333     __ Ldr(codeAddr, MemoryOperand(jsfunc, JSFunction::CODE_ENTRY_OFFSET));
1334     __ Br(codeAddr);
1335 }
1336 
DeoptEnterAsmInterp(ExtendedAssembler *assembler)1337 void OptimizedCall::DeoptEnterAsmInterp(ExtendedAssembler *assembler)
1338 {
1339     // rdi
1340     Register glueRegister = __ GlueRegister();
1341     Register context(X2);
1342     Register opRegister(X9);
1343     Register outputCount(X10);
1344     Register frameStateBase(X11);
1345     Register currentSlotRegister(X12);
1346     Register sp(SP);
1347     Register depth(X20);
1348     Register tmpReg(X21);
1349     Label loopBegin;
1350     Label stackOverflow;
1351     Label pushArgv;
1352 
1353     __ PushFpAndLr();
1354 
1355     __ Ldr(depth, MemoryOperand(context, AsmStackContext::GetInlineDepthOffset(false)));
1356     __ Add(context, context, Immediate(AsmStackContext::GetSize(false)));
1357     __ Mov(Register(X23), Immediate(0));
1358     // update fp
1359     __ Mov(currentSlotRegister, sp);
1360     __ Bind(&loopBegin);
1361     __ Ldr(outputCount, MemoryOperand(context, 0));
1362     __ Add(frameStateBase, context, Immediate(FRAME_SLOT_SIZE));
1363     __ Cmp(Register(X23), Immediate(0));
1364     __ B(Condition::EQ, &pushArgv);
1365     __ Mov(tmpReg, currentSlotRegister);
1366     __ Add(tmpReg, tmpReg, Immediate(AsmInterpretedFrame::GetSize(false)));
1367     __ Add(Register(X9), frameStateBase, Immediate(AsmInterpretedFrame::GetBaseOffset(false)));
1368     __ Str(tmpReg, MemoryOperand(Register(X9), InterpretedFrameBase::GetPrevOffset(false)));
1369     __ Align16(currentSlotRegister);
1370 
1371     __ Bind(&pushArgv);
1372     __ Mov(tmpReg, outputCount);
1373     __ Str(currentSlotRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFpOffset(false)));
1374     PushArgsWithArgv(assembler, glueRegister, outputCount, frameStateBase, opRegister,
1375                      currentSlotRegister, nullptr, &stackOverflow);
1376     __ Add(context, context, Immediate(FRAME_SLOT_SIZE)); // skip outputCount
1377     __ Add(context, context, Operand(tmpReg, UXTW, FRAME_SLOT_SIZE_LOG2)); // skip args
1378     __ Add(Register(X23), Register(X23), Immediate(1));
1379     __ Cmp(depth, Register(X23));
1380     __ B(Condition::GE, &loopBegin);
1381 
1382     Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
1383     Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
1384     {
1385         // X19, fp, x20, x21,      x22,     x23,  x24
1386         // glue sp   pc  constpool  profile  acc   hotness
1387         __ Ldr(callTargetRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFunctionOffset(false)));
1388         __ Ldr(Register(X20), MemoryOperand(frameStateBase, AsmInterpretedFrame::GetPcOffset(false)));
1389         __ Ldr(Register(X23), MemoryOperand(frameStateBase, AsmInterpretedFrame::GetAccOffset(false)));
1390         __ Ldr(methodRegister, MemoryOperand(callTargetRegister, JSFunctionBase::METHOD_OFFSET));
1391 
1392         __ Add(opRegister, currentSlotRegister, Immediate(AsmInterpretedFrame::GetSize(false)));
1393 
1394         __ Align16(currentSlotRegister);
1395         __ Mov(Register(SP), currentSlotRegister);
1396         AsmInterpreterCall::DispatchCall(assembler, Register(X20), opRegister, Register(X23));
1397     }
1398     __ Bind(&stackOverflow);
1399     {
1400         Register temp(X1);
1401         AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(
1402             assembler, glueRegister, sp, temp);
1403     }
1404 }
1405 
DeoptHandlerAsm(ExtendedAssembler *assembler)1406 void OptimizedCall::DeoptHandlerAsm(ExtendedAssembler *assembler)
1407 {
1408     __ BindAssemblerStub(RTSTUB_ID(DeoptHandlerAsm));
1409     __ PushFpAndLr();
1410     Register sp(SP);
1411     Register fp(FP);
1412     Register frameType(X3);
1413     Register glueReg(X0);
1414 
1415     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::ASM_BRIDGE_FRAME)));
1416     __ Stp(glueReg, frameType, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1417     __ Add(fp, sp, Immediate(DOUBLE_SLOT_SIZE));
1418     __ CalleeSave();
1419 
1420     Register deoptType(X1);
1421     Register depth(X2);
1422     Register argC(X3);
1423     Register runtimeId(X4);
1424     __ Stp(deoptType, depth, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1425     __ Mov(argC, Immediate(2)); // 2: argc
1426     __ Mov(runtimeId, Immediate(RTSTUB_ID(DeoptHandler)));
1427     __ Stp(runtimeId, argC, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1428     __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1429     __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE)); // 2: skip runtimeId, argc, depth, shiftLen
1430 
1431     __ CalleeRestore();
1432     Register context(X2);
1433     __ Mov(context, Register(X0));
1434     __ Ldr(glueReg, MemoryOperand(sp, 0));
1435 
1436     Register ret(X0);
1437     Label stackOverflow;
1438     __ Cmp(ret, Immediate(JSTaggedValue::VALUE_EXCEPTION));
1439     __ B(Condition::EQ, &stackOverflow);
1440 
1441     Label target;
1442     Register temp(X1);
1443     __ Ldr(fp, MemoryOperand(context, AsmStackContext::GetCallerFpOffset(false)));
1444     __ Ldr(temp, MemoryOperand(context, AsmStackContext::GetCallFrameTopOffset(false)));
1445     __ Mov(sp, temp);
1446     __ Ldr(Register(X30), MemoryOperand(context, AsmStackContext::GetReturnAddressOffset(false)));
1447 
1448     PushAsmInterpBridgeFrame(assembler);
1449     __ Bl(&target);
1450     PopAsmInterpBridgeFrame(assembler);
1451     __ Ret();
1452     __ Bind(&target);
1453     DeoptEnterAsmInterp(assembler);
1454 
1455     __ Bind(&stackOverflow);
1456     {
1457         __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowStackOverflowException)));
1458         // 2 : 2 means pair
1459         __ Stp(runtimeId, Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1460         __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1461         __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE)); // 2: skip runtimeId&argc glue&type
1462         __ RestoreFpAndLr();
1463         __ Ret();
1464     }
1465 }
1466 #undef __
1467 }  // panda::ecmascript::aarch64
1468