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