• 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, JSFunction::HCLASS_OFFSET));
463     __ And(Register(X5), Register(X5), LogicalImmediate::Create(TaggedObject::GC_STATE_MASK, RegXSize));
464     __ Ldr(Register(X5), MemoryOperand(Register(X5), JSHClass::BIT_FIELD_OFFSET));
465     __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
466     __ Ldr(actualArgC, MemoryOperand(sp, 0));
467     __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
468     __ Tbnz(callField, MethodLiteral::IsNativeBit::START_BIT, &callNativeMethod);
469     if (!isNew) {
470         __ Tbz(Register(X5), JSHClass::IsClassConstructorOrPrototypeBit::START_BIT, &lNotClass);
471         __ Tbnz(Register(X5), JSHClass::ConstructorBit::START_BIT, &lCallConstructor);
472     }
473     __ Bind(&lNotClass);
474     {
475         Register argV(X5);
476         // skip argc and argv
477         __ Add(argV, sp, Immediate(kungfu::ArgumentAccessor::GetExtraArgsNum() * FRAME_SLOT_SIZE));
478         // asm interpreter argV = argv + 24
479         __ Add(argV, argV, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() * FRAME_SLOT_SIZE));
480         __ Sub(actualArgC, actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum()));
481         OptimizedCallAsmInterpreter(assembler);
482     }
483 
484     __ Bind(&callNativeMethod);
485     {
486         Register nativeFuncAddr(X4);
487         if (!isNew) {
488             __ Tbz(callField, MethodLiteral::IsFastBuiltinBit::START_BIT, &lCallNativeCpp);
489             // 3 : 3 means call0 call1 call2 call3
490             __ Cmp(actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() + 3));
491             __ B(Condition::LE, &lCallBuiltinStub);
492         } else {
493             __ Tbnz(callField, MethodLiteral::IsFastBuiltinBit::START_BIT, &lCallBuiltinStub);
494         }
495         __ Bind(&lCallNativeCpp);
496         __ Ldr(nativeFuncAddr, MemoryOperand(jsfunc, JSFunctionBase::CODE_ENTRY_OFFSET));
497         CallBuiltinTrampoline(assembler);
498     }
499 
500     __ Bind(&lCallBuiltinStub);
501     {
502         TempRegister1Scope scope1(assembler);
503         Register builtinStub = __ TempRegister1();
504         __ Ldr(Register(X5), MemoryOperand(method, Method::EXTRA_LITERAL_INFO_OFFSET));  // get extra literal
505         __ And(Register(X5).W(), Register(X5).W(), LogicalImmediate::Create(0xff, RegWSize));
506         if (!isNew) {
507             __ Cmp(Register(X5).W(), Immediate(BUILTINS_STUB_ID(BUILTINS_CONSTRUCTOR_STUB_FIRST)));
508             __ B(Condition::GE, &lCallNativeCpp);
509         }
510         __ Add(builtinStub, glue, Operand(Register(X5).W(), UXTW, FRAME_SLOT_SIZE_LOG2));
511         __ Ldr(builtinStub, MemoryOperand(builtinStub, JSThread::GlueData::GetBuiltinsStubEntriesOffset(false)));
512 
513         __ Ldr(Register(X1), MemoryOperand(jsfunc, JSFunctionBase::CODE_ENTRY_OFFSET));
514         __ Ldr(Register(X2), MemoryOperand(sp, DOUBLE_SLOT_SIZE));  // get jsfunc
515         __ Ldr(Register(X3), MemoryOperand(sp, TRIPLE_SLOT_SIZE));  // get newtarget
516         __ Ldr(Register(X4), MemoryOperand(sp, QUADRUPLE_SLOT_SIZE));  // get this
517         __ Ldr(Register(X5), MemoryOperand(sp, 0));  // get number args
518         __ Sub(Register(X5), Register(X5), Immediate(NUM_MANDATORY_JSFUNC_ARGS));
519         if (!isNew) {
520             Label lCall0;
521             Label lCall1;
522             Label lCall2;
523             Label lCall3;
524             Label lTailCall;
525             Register fp(X29);
526             __ Cmp(Register(X5), Immediate(0));
527             __ B(Condition::EQ, &lCall0);
528             __ Cmp(Register(X5), Immediate(1));
529             __ B(Condition::EQ, &lCall1);
530             __ Cmp(Register(X5), Immediate(2));  // 2: 2 args
531             __ B(Condition::EQ, &lCall2);
532             __ Cmp(Register(X5), Immediate(3));  // 3: 3 args
533             __ B(Condition::EQ, &lCall3);
534 
535             __ Bind(&lCall0);
536             {
537                 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
538                 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
539                 __ Str(Register(X7), MemoryOperand(sp, 0));  // reset arg2's position
540                 __ B(&lTailCall);
541             }
542 
543             __ Bind(&lCall1);
544             {
545                 __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE));
546                 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));  // reset x7
547                 __ Str(Register(X7), MemoryOperand(sp, 0));  // reset arg2's position
548                 __ B(&lTailCall);
549             }
550 
551             __ Bind(&lCall2);
552             {
553                 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
554                 __ Str(Register(X7), MemoryOperand(sp, 0));  // reset arg2's position
555                 __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE));
556                 __ B(&lTailCall);
557             }
558 
559             __ Bind(&lCall3);
560             __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE));  // get arg0 arg1
561             PushAsmBridgeFrame(assembler);
562             {
563                 // push arg2 and call
564                 TempRegister2Scope scope2(assembler);
565                 Register arg2 = __ TempRegister2();
566                 __ Ldr(arg2, MemoryOperand(fp, NONUPLE_SLOT_SIZE));
567                 __ Stp(arg2, Register(X8), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
568                 __ Blr(builtinStub);
569                 __ Add(sp, sp, Immediate(DOUBLE_SLOT_SIZE));
570             }
571             PopAsmBridgeFrame(assembler);
572             __ Ret();
573             __ Bind(&lTailCall);
574             {
575                 __ Br(builtinStub);
576             }
577         } else {
578             Register argv(X6);
579             TempRegister2Scope scope2(assembler);
580             Register temp = __ TempRegister2();
581             CallBuiltinConstructorStub(assembler, builtinStub, argv, glue, temp);
582         }
583     }
584 
585     Label jsBoundFunction;
586     Label jsProxy;
587     __ Bind(&notJSFunction);
588     {
589         Register bitfield(X2);
590         Register jstype2(X5, W);
591         __ And(jstype2, bitfield.W(), LogicalImmediate::Create(0xff, RegWSize));
592         __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_BOUND_FUNCTION)));
593         __ B(Condition::EQ, &jsBoundFunction);
594         __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_PROXY)));
595         __ B(Condition::EQ, &jsProxy);
596         __ Ret();
597     }
598 
599     __ Bind(&jsBoundFunction);
600     {
601         JSBoundFunctionCallInternal(assembler, glue, actualArgC, jsfunc, RTSTUB_ID(JSCall));
602     }
603     __ Bind(&jsProxy);
604     {
605         Register nativeFuncAddr(X4);
606         __ Ldr(method, MemoryOperand(jsfunc, JSProxy::METHOD_OFFSET));
607         __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
608         __ Ldr(actualArgC, MemoryOperand(sp, 0));
609         __ Ldr(nativeFuncAddr, MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
610         CallBuiltinTrampoline(assembler);
611     }
612     __ Bind(&nonCallable);
613     {
614         ThrowNonCallableInternal(assembler, sp);
615     }
616     __ Bind(&lCallConstructor);
617     {
618         Register frameType(X6);
619         __ PushFpAndLr();
620         __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
621         // 2 : 2 means pair
622         __ Stp(Register(Zero), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
623         __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
624         Register argC(X5);
625         Register runtimeId(X6);
626         __ Mov(argC, Immediate(0));
627         __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowCallConstructorException)));
628         // 2 : 2 means pair
629         __ Stp(runtimeId, argC, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
630         __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
631         // 4 : 4 means stack slot
632         __ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
633         __ RestoreFpAndLr();
634         __ Ret();
635     }
636 }
637 
638 // After the callee function of common aot call deopt, use this bridge to deal with this aot call.
639 // calling convention: webkit_jsc
640 // Input structure:
641 // %X0 - glue
642 // stack:
643 // +--------------------------+
644 // |       arg[N-1]           |
645 // +--------------------------+
646 // |       ...                |
647 // +--------------------------+
648 // |       arg[1]             |
649 // +--------------------------+
650 // |       arg[0]             |
651 // +--------------------------+
652 // |       this               |
653 // +--------------------------+
654 // |       new-target         |
655 // +--------------------------+
656 // |       call-target        |
657 // |--------------------------|
658 // |       argv               |
659 // |--------------------------|
660 // |       argc               |
661 // +--------------------------+ <---- sp
AOTCallToAsmInterBridge(ExtendedAssembler * assembler)662 void OptimizedCall::AOTCallToAsmInterBridge(ExtendedAssembler *assembler)
663 {
664     __ BindAssemblerStub(RTSTUB_ID(AOTCallToAsmInterBridge));
665     Register sp(SP);
666     // params of c++ calling convention
667     Register glue(X0);
668     Register jsfunc(X1);
669     Register method(X2);
670     Register callField(X3);
671     Register actualArgC(X4);
672     Register argV(X5);
673 
674     __ Ldr(jsfunc, MemoryOperand(sp, DOUBLE_SLOT_SIZE));
675     __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
676     __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
677     __ Ldr(actualArgC, MemoryOperand(sp, 0));
678     // skip argc
679     __ Add(argV, sp, Immediate(kungfu::ArgumentAccessor::GetExtraArgsNum() * FRAME_SLOT_SIZE));
680     // asm interpreter argV = argv + 24
681     __ Add(argV, argV, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() * FRAME_SLOT_SIZE));
682     __ Sub(actualArgC, actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum()));
683     OptimizedCallAsmInterpreter(assembler);
684 }
685 
686 // After the callee function of fast aot call deopt, use this bridge to deal with this fast aot call.
687 // Notice: no argc and new-target params compared with not-fast aot call because these params are not needed
688 // by bytecode-analysis
689 // Intruduction: use expected argc as actual argc below for these reasons:
690 // 1) when expected argc == actual argc, pass.
691 // 2) when expected argc > actual argc, undefineds have been pushed in OptimizedFastCallAndPushArgv.
692 // 3) when expected argc < actual argc, redundant params are useless according to bytecode-analysis, just abandon them.
693 // calling convention: c++ calling convention
694 // Input structure:
695 // %X0 - glue
696 // %X1 - call-target
697 // %X2 - this
698 // %X3 - arg0
699 // %X4 - arg1
700 // %X5 - arg2
701 // %X6 - arg3
702 // %X7 - arg4
703 // stack:
704 // +--------------------------+
705 // |        arg[N-1]          |
706 // +--------------------------+
707 // |       ...                |
708 // +--------------------------+
709 // |       arg[5]             |
710 // +--------------------------+ <---- sp
FastCallToAsmInterBridge(ExtendedAssembler * assembler)711 void OptimizedCall::FastCallToAsmInterBridge(ExtendedAssembler *assembler)
712 {
713     __ BindAssemblerStub(RTSTUB_ID(FastCallToAsmInterBridge));
714 
715     // Add a bridge frame to protect the stack map, because args will be put on the stack to construct argv on stack
716     // and the AsmInterpBridgeFrame pushed below cannot protect the stack map anymore.
717     PushAsmBridgeFrame(assembler);
718 
719     Register sp(SP);
720     // Input
721     Register glue(X0);
722     Register jsfunc(X1);
723     Register thisReg(X2);
724 
725     Register tempArgc = __ AvailableRegister1();
726     {
727         TempRegister2Scope scope2(assembler);
728         Register tempMethod = __ TempRegister2();
729 
730         __ Ldr(tempMethod, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
731         __ Ldr(tempArgc, MemoryOperand(tempMethod, Method::CALL_FIELD_OFFSET));
732         __ Lsr(tempArgc, tempArgc, MethodLiteral::NumArgsBits::START_BIT);
733         __ And(tempArgc, tempArgc,
734             LogicalImmediate::Create(
735                 MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegXSize));
736     }
737     {
738         TempRegister1Scope scope1(assembler);
739         Register startSp = __ TempRegister1();
740         __ Mov(startSp, sp);
741 
742         Label lCall0;
743         Label lCall1;
744         Label lCall2;
745         Label lCall3;
746         Label lCall4;
747         Label lCall5;
748         Label lPushCommonRegs;
749 
750         __ Cmp(tempArgc, Immediate(0));
751         __ B(Condition::EQ, &lCall0);
752         __ Cmp(tempArgc, Immediate(1));
753         __ B(Condition::EQ, &lCall1);
754         __ Cmp(tempArgc, Immediate(2));  // 2: 2 args
755         __ B(Condition::EQ, &lCall2);
756         __ Cmp(tempArgc, Immediate(3));  // 3: 3 args
757         __ B(Condition::EQ, &lCall3);
758         __ Cmp(tempArgc, Immediate(4));  // 4: 4 args
759         __ B(Condition::EQ, &lCall4);
760         __ Cmp(tempArgc, Immediate(5));  // 5: 5 args
761         __ B(Condition::EQ, &lCall5);
762         // default: more than 5 args
763         {
764             TempRegister2Scope scope2(assembler);
765             Register onStackArgs = __ TempRegister2();
766             Register op1 = __ AvailableRegister2();
767             Register op2 = __ AvailableRegister3();
768 
769             // skip bridge frame, return addr and a callee save
770             __ Add(onStackArgs, sp, Immediate(QUADRUPLE_SLOT_SIZE));
771             __ Sub(tempArgc, tempArgc, Immediate(5));  // 5: the first 5 args are not on stack
772             Register arg4(X7);
773             PushArgsWithArgvInPair(assembler, tempArgc, onStackArgs, arg4, op1, op2, &lCall4);
774         }
775 
776         __ Bind(&lCall0);
777         {
778             __ B(&lPushCommonRegs);
779         }
780 
781         __ Bind(&lCall1);
782         {
783             __ Stp(Register(X3), Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
784             __ B(&lPushCommonRegs);
785         }
786 
787         __ Bind(&lCall2);
788         {
789             __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
790             __ B(&lPushCommonRegs);
791         }
792 
793         __ Bind(&lCall3);
794         {
795             __ Stp(Register(X5), Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
796             __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
797             __ B(&lPushCommonRegs);
798         }
799 
800         __ Bind(&lCall4);
801         {
802             __ Stp(Register(X5), Register(X6), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
803             __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
804             __ B(&lPushCommonRegs);
805         }
806 
807         __ Bind(&lCall5);
808         {
809             __ Stp(Register(X7), Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
810             __ Stp(Register(X5), Register(X6), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
811             __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
812             __ B(&lPushCommonRegs);
813         }
814 
815         __ Bind(&lPushCommonRegs);
816         {
817             Register newTarget(X7);
818             __ Mov(newTarget, Immediate(JSTaggedValue::VALUE_UNDEFINED));
819             __ Stp(newTarget, thisReg, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
820             __ Stp(startSp, jsfunc, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
821             // fall through
822         }
823     }
824 
825     // params of c++ calling convention
826     // glue: X0
827     // jsfunc: X1
828     Register method(X2);
829     Register methodCallField(X3);
830     Register argc(X4);
831     Register argV(X5);
832     // reload and prepare args for JSCallCommonEntry
833     __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
834     __ Ldr(methodCallField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
835     __ Mov(argc, methodCallField);
836     __ Lsr(argc, argc, MethodLiteral::NumArgsBits::START_BIT);
837     __ And(argc, argc,
838         LogicalImmediate::Create(
839             MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegXSize));
840     __ Add(argV, sp, Immediate((kungfu::ArgumentAccessor::GetFixArgsNum() + 1) * FRAME_SLOT_SIZE));  // 1: skip startSp
841 
842     Label target;
843     PushAsmInterpBridgeFrame(assembler);
844     __ Bl(&target);
845     {
846         PopAsmInterpBridgeFrame(assembler);
847         TempRegister1Scope scope1(assembler);
848         Register startSp = __ TempRegister1();
849         __ Ldp(startSp, Register(Zero), MemoryOperand(sp, ExtendedAssembler::PAIR_SLOT_SIZE, POSTINDEX));
850         __ Mov(sp, startSp);
851         PopAsmBridgeFrame(assembler);
852         __ Ret();
853     }
854     __ Bind(&target);
855     {
856         AsmInterpreterCall::JSCallCommonEntry(assembler, JSCallMode::CALL_FROM_AOT,
857                                               FrameTransitionType::OTHER_TO_OTHER);
858     }
859 }
860 
JSCallCheck(ExtendedAssembler * assembler,Register jsfunc,Register taggedValue,Label * nonCallable,Label * notJSFunction)861 void OptimizedCall::JSCallCheck(ExtendedAssembler *assembler, Register jsfunc, Register taggedValue,
862                                 Label *nonCallable, Label *notJSFunction)
863 {
864     __ Mov(taggedValue, JSTaggedValue::TAG_MARK);
865     __ Cmp(jsfunc, taggedValue);
866     __ B(Condition::HS, nonCallable);
867     __ Cbz(jsfunc, nonCallable);
868     __ Mov(taggedValue, JSTaggedValue::TAG_SPECIAL);
869     __ And(taggedValue, jsfunc, taggedValue);
870     __ Cbnz(taggedValue, nonCallable);
871 
872     Register jshclass(X2);
873     Register glue(X0);
874     __ Ldr(jshclass, MemoryOperand(jsfunc, JSFunction::HCLASS_OFFSET));
875     __ And(jshclass, jshclass, LogicalImmediate::Create(TaggedObject::GC_STATE_MASK, RegXSize));
876     Register bitfield(X2);
877     __ Ldr(bitfield, MemoryOperand(jshclass, JSHClass::BIT_FIELD_OFFSET));
878     __ Tbz(bitfield, JSHClass::CallableBit::START_BIT, nonCallable);
879 
880     Register jstype(X3, W);
881     __ And(jstype, bitfield, LogicalImmediate::Create(0xFF, RegWSize));
882     // 4 : 4 means JSType::JS_FUNCTION_FIRST
883     __ Sub(jstype, jstype, Immediate(static_cast<int>(JSType::JS_FUNCTION_FIRST)));
884     // 9 : 9 means JSType::JS_FUNCTION_LAST - JSType::JS_FUNCTION_FIRST + 1
885     __ Cmp(jstype, Immediate(static_cast<int>(JSType::JS_FUNCTION_LAST) -
886         static_cast<int>(JSType::JS_FUNCTION_FIRST) + 1));
887     __ B(Condition::HS, notJSFunction);
888 }
889 
ThrowNonCallableInternal(ExtendedAssembler * assembler,Register sp)890 void OptimizedCall::ThrowNonCallableInternal(ExtendedAssembler *assembler, Register sp)
891 {
892     Register frameType(X6);
893     Register taggedMessageId(X5);
894     __ PushFpAndLr();
895     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
896     __ Mov(taggedMessageId,
897         Immediate(JSTaggedValue(GET_MESSAGE_STRING_ID(NonCallable)).GetRawData()));
898     // 2 : 2 means pair
899     __ Stp(taggedMessageId, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
900     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
901     Register argC(X5);
902     Register runtimeId(X6);
903     __ Mov(argC, Immediate(1));
904     __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowTypeError)));
905     // 2 : 2 means pair
906     __ Stp(runtimeId, argC, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
907     __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
908     __ Mov(Register(X0), Immediate(JSTaggedValue::VALUE_EXCEPTION));
909     // 4 : 4 means stack slot
910     __ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
911     __ RestoreFpAndLr();
912     __ Ret();
913 }
914 
JSBoundFunctionCallInternal(ExtendedAssembler * assembler,Register glue,Register actualArgC,Register jsfunc,int stubId)915 void OptimizedCall::JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Register glue,
916                                                 Register actualArgC, Register jsfunc, int stubId)
917 {
918     // construct frame
919     PushOptimizedArgsConfigFrame(assembler);
920     Register basefp(X29);
921     Register fp = __ AvailableRegister1();
922 
923     Register argV(X5);
924     __ Add(argV, basefp, Immediate(GetStackArgOffSetToFp(0))); // 0: first index id
925     __ Ldr(actualArgC, MemoryOperand(argV, 0));
926 
927     Register boundLength(X2);
928     Register realArgC(X7, W);
929     Label copyBoundArgument;
930     Label pushCallTarget;
931     Label popArgs;
932     Label slowCall;
933     Label aotCall;
934     Label notClass;
935     // get bound arguments
936     __ Ldr(boundLength, MemoryOperand(jsfunc, JSBoundFunction::BOUND_ARGUMENTS_OFFSET));
937     //  get bound length
938     __ Ldr(boundLength, MemoryOperand(boundLength, TaggedArray::LENGTH_OFFSET));
939     __ Add(realArgC, boundLength.W(), actualArgC.W());
940     __ Mov(Register(X19), realArgC);
941     IncreaseStackForArguments(assembler, realArgC, fp, static_cast<int64_t>(CommonArgIdx::ACTUAL_ARGV));
942     __ Sub(actualArgC.W(), actualArgC.W(), Immediate(NUM_MANDATORY_JSFUNC_ARGS));
943     __ Cmp(actualArgC.W(), Immediate(0));
944     __ B(Condition::EQ, &copyBoundArgument);
945     {
946         TempRegister1Scope scope1(assembler);
947         Register tmp = __ TempRegister1();
948         const int64_t argoffsetSlot = static_cast<int64_t>(CommonArgIdx::FUNC) - 1;
949         __ Add(argV, argV, Immediate((NUM_MANDATORY_JSFUNC_ARGS + argoffsetSlot) * FRAME_SLOT_SIZE));
950         PushArgsWithArgv(assembler, glue, actualArgC, argV, tmp, fp, nullptr, nullptr);
951     }
952     __ Bind(&copyBoundArgument);
953     {
954         Register boundArgs(X4);
955         __ Ldr(boundArgs, MemoryOperand(jsfunc, JSBoundFunction::BOUND_ARGUMENTS_OFFSET));
956         __ Add(boundArgs, boundArgs, Immediate(TaggedArray::DATA_OFFSET));
957         __ Cmp(boundLength.W(), Immediate(0));
958         __ B(Condition::EQ, &pushCallTarget);
959         {
960             TempRegister1Scope scope1(assembler);
961             Register tmp = __ TempRegister1();
962             PushArgsWithArgv(assembler, glue, boundLength, boundArgs, tmp, fp, nullptr, nullptr);
963         }
964     }
965     Register boundTarget(X7);
966     Register newTarget(X6);
967     __ Bind(&pushCallTarget);
968     {
969         Register thisObj(X4);
970         __ Ldr(thisObj, MemoryOperand(jsfunc, JSBoundFunction::BOUND_THIS_OFFSET));
971         __ Mov(newTarget, Immediate(JSTaggedValue::VALUE_UNDEFINED));
972         // 2 : 2 means pair
973         __ Stp(newTarget, thisObj, MemoryOperand(fp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
974         __ Ldr(boundTarget, MemoryOperand(jsfunc, JSBoundFunction::BOUND_TARGET_OFFSET));
975         // 2 : 2 means pair
976         __ Stp(argV, boundTarget, MemoryOperand(fp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
977         __ Str(Register(X19), MemoryOperand(fp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
978     }
979     JSCallCheck(assembler, boundTarget, Register(X9), &slowCall, &slowCall);
980     Register hclass = __ AvailableRegister2();
981     __ Ldr(hclass, MemoryOperand(boundTarget, JSFunction::HCLASS_OFFSET));
982     __ And(hclass, hclass, LogicalImmediate::Create(TaggedObject::GC_STATE_MASK, RegXSize));
983     __ Ldr(hclass, MemoryOperand(hclass, JSHClass::BIT_FIELD_OFFSET));
984     __ Tbz(hclass, JSHClass::IsClassConstructorOrPrototypeBit::START_BIT, &notClass);
985     __ Tbnz(hclass, JSHClass::ConstructorBit::START_BIT, &slowCall);
986     __ Bind(&notClass);
987     Register compiledCodeFlag(X9, W);
988     __ Ldrh(compiledCodeFlag, MemoryOperand(boundTarget, JSFunctionBase::BIT_FIELD_OFFSET));
989     __ Tbz(compiledCodeFlag, JSFunctionBase::IsCompiledCodeBit::START_BIT, &slowCall);
990     __ Bind(&aotCall);
991     {
992         // output: glue:x0 argc:x1 calltarget:x2 argv:x3 this:x4 newtarget:x5
993         __ Mov(Register(X1), Register(X19));
994         __ Mov(Register(X2), boundTarget);
995         __ Add(X3, fp, Immediate(5 * FRAME_SLOT_SIZE)); // 5: skip argc and argv func new this
996         __ Mov(Register(X5), Register(X6));
997         Register boundCallInternalId(X9);
998         Register baseAddress(X8);
999         Register codeAddress(X10);
1000         __ Mov(baseAddress, Immediate(JSThread::GlueData::GetCOStubEntriesOffset(false)));
1001         __ Mov(boundCallInternalId, Immediate(CommonStubCSigns::JsBoundCallInternal));
1002         __ Add(codeAddress, X0, baseAddress);
1003         __ Ldr(codeAddress, MemoryOperand(codeAddress, boundCallInternalId, UXTW, FRAME_SLOT_SIZE_LOG2));
1004         __ Blr(codeAddress);
1005         __ B(&popArgs);
1006     }
1007     __ Bind(&slowCall);
1008     {
1009         __ CallAssemblerStub(stubId, false);
1010         __ B(&popArgs);
1011     }
1012 
1013     __ Bind(&popArgs);
1014     PopJSFunctionArgs(assembler, Register(X19), Register(X19));
1015     PopOptimizedArgsConfigFrame(assembler);
1016     __ Ret();
1017 }
1018 
1019 // * uint64_t JSProxyCallInternalWithArgV(uintptr_t glue, JSTaggedType calltarget)
1020 // * c++ calling convention call js function
1021 // * Arguments:
1022 //        %x0 - glue
1023 //        %x1 - calltarget
1024 
JSProxyCallInternalWithArgV(ExtendedAssembler * assembler)1025 void OptimizedCall::JSProxyCallInternalWithArgV(ExtendedAssembler *assembler)
1026 {
1027     __ BindAssemblerStub(RTSTUB_ID(JSProxyCallInternalWithArgV));
1028     Register jsfunc(X1);
1029     Register sp(SP);
1030     __ Str(jsfunc, MemoryOperand(sp, DOUBLE_SLOT_SIZE));
1031     JSCallInternal(assembler, jsfunc);
1032 }
1033 
1034 // * uint64_t CallRuntimeWithArgv(uintptr_t glue, uint64_t runtime_id, uint64_t argc, uintptr_t argv)
1035 // * cc calling convention call runtime_id's runtion function(c-abi)
1036 // * Arguments:
1037 //         %x0 - glue
1038 //         %x1 - runtime_id
1039 //         %x2 - argc
1040 //         %x3 - argv
1041 //
1042 // * Optimized-leaved-frame-with-argv layout as the following:
1043 //         +--------------------------+
1044 //         |       argv[]             |
1045 //         +--------------------------+-------------
1046 //         |       argc               |            ^
1047 //         |--------------------------|            |
1048 //         |       RuntimeId          |   OptimizedWithArgvLeaveFrame
1049 //  sp --> |--------------------------|            |
1050 //         |       returnAddr         |            |
1051 //         |--------------------------|            |
1052 //         |       callsiteFp         |            |
1053 //         |--------------------------|            |
1054 //         |       frameType          |            v
1055 //         +--------------------------+-------------
1056 
CallRuntimeWithArgv(ExtendedAssembler * assembler)1057 void OptimizedCall::CallRuntimeWithArgv(ExtendedAssembler *assembler)
1058 {
1059     __ BindAssemblerStub(RTSTUB_ID(CallRuntimeWithArgv));
1060     Register glue(X0);
1061     Register runtimeId(X1);
1062     Register argc(X2);
1063     Register argv(X3);
1064     Register sp(SP);
1065     // 2 : 2 means pair
1066     __ Stp(argc, argv, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1067     __ Stp(Register(X30), runtimeId, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX)); // 2 : 2 means pair
1068     Register fp(X29);
1069     // construct leave frame
1070     Register frameType(X9);
1071     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::LEAVE_FRAME_WITH_ARGV)));
1072     __ Stp(frameType, Register(X29), MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX)); // 2 : 2 means pair
1073     __ Add(Register(FP), sp, Immediate(FRAME_SLOT_SIZE));
1074     __ Str(fp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
1075 
1076      // load runtime trampoline address
1077     Register tmp(X9);
1078     Register rtfunc(X9);
1079     // 3 : 3 means 2 << 3 = 8
1080     __ Add(tmp, glue, Operand(runtimeId, LSL, 3));
1081     __ Ldr(rtfunc, MemoryOperand(tmp, JSThread::GlueData::GetRTStubEntriesOffset(false)));
1082     __ Mov(X1, argc);
1083     __ Mov(X2, argv);
1084     __ Blr(rtfunc);
1085     __ Ldp(Register(Zero), Register(X29), MemoryOperand(sp, ExtendedAssembler::PAIR_SLOT_SIZE, POSTINDEX));
1086     __ Ldp(Register(X30), Register(Zero), MemoryOperand(sp, ExtendedAssembler::PAIR_SLOT_SIZE, POSTINDEX));
1087     __ Add(sp, sp, Immediate(2 * FRAME_SLOT_SIZE)); // 2 : 2 means pair
1088     __ Ret();
1089 }
1090 
PushMandatoryJSArgs(ExtendedAssembler * assembler,Register jsfunc,Register thisObj,Register newTarget,Register currentSp)1091 void OptimizedCall::PushMandatoryJSArgs(ExtendedAssembler *assembler, Register jsfunc,
1092                                         Register thisObj, Register newTarget, Register currentSp)
1093 {
1094     __ Str(thisObj, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1095     __ Str(newTarget, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1096     __ Str(jsfunc, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1097 }
1098 
PopJSFunctionArgs(ExtendedAssembler * assembler,Register expectedNumArgs,Register actualNumArgs)1099 void OptimizedCall::PopJSFunctionArgs(ExtendedAssembler *assembler, Register expectedNumArgs, Register actualNumArgs)
1100 {
1101     Register sp(SP);
1102     Register fp(X6);
1103     Label aligned;
1104     const int64_t argoffsetSlot = static_cast<int64_t>(CommonArgIdx::FUNC) - 1;
1105     if (expectedNumArgs != actualNumArgs) {
1106         TempRegister1Scope scop1(assembler);
1107         Register tmp = __ TempRegister1();
1108         __ Cmp(expectedNumArgs, actualNumArgs);
1109         __ CMov(tmp, expectedNumArgs, actualNumArgs, Condition::HI);
1110         __ Add(sp, sp, Operand(tmp, UXTW, FRAME_SLOT_SIZE_LOG2));
1111     } else {
1112         __ Add(sp, sp, Operand(expectedNumArgs, UXTW, FRAME_SLOT_SIZE_LOG2));
1113     }
1114     __ Add(sp, sp, Immediate(argoffsetSlot * FRAME_SLOT_SIZE));
1115     __ Mov(fp, sp);
1116     __ Tst(fp, LogicalImmediate::Create(0xf, RegXSize));  // 0xf: 0x1111
1117     __ B(Condition::EQ, &aligned);
1118     __ Add(sp, sp, Immediate(FRAME_SLOT_SIZE));
1119     __ Bind(&aligned);
1120 }
1121 
PushJSFunctionEntryFrame(ExtendedAssembler * assembler,Register prevFp)1122 void OptimizedCall::PushJSFunctionEntryFrame(ExtendedAssembler *assembler, Register prevFp)
1123 {
1124     Register fp(X29);
1125     Register sp(SP);
1126     TempRegister2Scope temp2Scope(assembler);
1127     __ PushFpAndLr();
1128     Register frameType = __ TempRegister2();
1129     // construct frame
1130     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_ENTRY_FRAME)));
1131     // 2 : 2 means pairs
1132     __ Stp(prevFp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1133     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
1134     __ CalleeSave();
1135 }
1136 
PopJSFunctionEntryFrame(ExtendedAssembler * assembler,Register glue)1137 void OptimizedCall::PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue)
1138 {
1139     Register fp(X29);
1140     Register sp(SP);
1141     Register prevFp(X1);
1142     __ CalleeRestore();
1143 
1144     // 2: prevFp and frameType
1145     __ Ldp(prevFp, Register(Zero), MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
1146     // restore return address
1147     __ RestoreFpAndLr();
1148     __ Str(prevFp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
1149 }
1150 
PushOptimizedArgsConfigFrame(ExtendedAssembler * assembler)1151 void OptimizedCall::PushOptimizedArgsConfigFrame(ExtendedAssembler *assembler)
1152 {
1153     Register sp(SP);
1154     TempRegister2Scope temp2Scope(assembler);
1155     Register frameType = __ TempRegister2();
1156     __ PushFpAndLr();
1157     // construct frame
1158     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
1159     // 2 : 2 means pairs. X19 means calleesave and 16bytes align
1160     __ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1161     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
1162 }
1163 
PopOptimizedArgsConfigFrame(ExtendedAssembler * assembler)1164 void OptimizedCall::PopOptimizedArgsConfigFrame(ExtendedAssembler *assembler)
1165 {
1166     TempRegister2Scope temp2Scope(assembler);
1167     Register sp(SP);
1168     Register frameType = __ TempRegister2();
1169     // 2 : 2 means pop call site sp and type
1170     __ Ldp(Register(X19), frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
1171     __ RestoreFpAndLr();
1172 }
1173 
PushAsmBridgeFrame(ExtendedAssembler * assembler)1174 void OptimizedCall::PushAsmBridgeFrame(ExtendedAssembler *assembler)
1175 {
1176     Register sp(SP);
1177     TempRegister2Scope temp2Scope(assembler);
1178     Register frameType = __ TempRegister2();
1179     __ PushFpAndLr();
1180     // construct frame
1181     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::ASM_BRIDGE_FRAME)));
1182     // 2 : 2 means pairs. X19 means calleesave and 16bytes align
1183     __ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1184     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
1185 }
1186 
PopAsmBridgeFrame(ExtendedAssembler * assembler)1187 void OptimizedCall::PopAsmBridgeFrame(ExtendedAssembler *assembler)
1188 {
1189     TempRegister2Scope temp2Scope(assembler);
1190     Register sp(SP);
1191     Register frameType = __ TempRegister2();
1192     // 2 : 2 means pop call site sp and type
1193     __ Ldp(Register(X19), frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
1194     __ RestoreFpAndLr();
1195 }
1196 
1197 // * uint64_t PushOptimizedUnfoldArgVFrame(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1198 //                                         JSTaggedType new, JSTaggedType this, JSTaggedType argV[])
1199 // * cc calling convention call js function()
1200 // * arguments:
1201 //              %x0 - glue
1202 //              %x1 - argc
1203 //              %x2 - call-target
1204 //              %x3 - new-target
1205 //              %x4 - this
1206 //              %x5 - argv
1207 //
1208 // * OptimizedUnfoldArgVFrame layout description as the following:
1209 //      sp ----> |--------------------------| ---------------
1210 //               |       returnAddr         |               ^
1211 //  currentFp--> |--------------------------|               |
1212 //               |       prevFp             |               |
1213 //               |--------------------------|   OptimizedUnfoldArgVFrame
1214 //               |       frameType          |               |
1215 //               |--------------------------|               |
1216 //               |       currentFp          |               v
1217 //               +--------------------------+ ---------------
1218 
PushOptimizedUnfoldArgVFrame(ExtendedAssembler * assembler,Register callSiteSp)1219 void OptimizedCall::PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp)
1220 {
1221     Register sp(SP);
1222     TempRegister2Scope temp2Scope(assembler);
1223     Register frameType = __ TempRegister2();
1224     __ PushFpAndLr();
1225     // construct frame
1226     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)));
1227     // 2 : 2 means pairs
1228     __ Stp(callSiteSp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1229     __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
1230 }
1231 
PopOptimizedUnfoldArgVFrame(ExtendedAssembler * assembler)1232 void OptimizedCall::PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler)
1233 {
1234     Register sp(SP);
1235     // 2 : 2 means pop call site sp and type
1236     __ Add(sp, sp, Immediate(2 * FRAME_SLOT_SIZE));
1237     __ RestoreFpAndLr();
1238 }
1239 
1240 // * uint64_t JSCallWithArgV(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1241 //                          JSTaggedType new, JSTaggedType this, argV)
1242 // * cc calling convention call js function()
1243 // * arguments:
1244 //              %x0 - glue
1245 //              %x1 - argc
1246 //              %x2 - call-target
1247 //              %x3 - new-target
1248 //              %x4 - this
1249 //              %x5 - argV[]
1250 //
1251 // * OptimizedJSFunctionFrame layout description as the following:
1252 //               +--------------------------+
1253 //               |       argn               |
1254 //               |--------------------------|
1255 //               |       argn - 1           |
1256 //               |--------------------------|
1257 //               |       .....              |
1258 //               |--------------------------|
1259 //               |       arg2               |
1260 //               |--------------------------|
1261 //               |       arg1               |
1262 //      sp ----> |--------------------------| ---------------
1263 //               |       returnAddr         |               ^
1264 //               |--------------------------|               |
1265 //               |       callsiteFp         |               |
1266 //               |--------------------------|  OptimizedJSFunctionFrame
1267 //               |       frameType          |               |
1268 //               |--------------------------|               |
1269 //               |       call-target        |               v
1270 //               +--------------------------+ ---------------
1271 
GenJSCallWithArgV(ExtendedAssembler * assembler,int id)1272 void OptimizedCall::GenJSCallWithArgV(ExtendedAssembler *assembler, int id)
1273 {
1274     Register sp(SP);
1275     Register glue(X0);
1276     Register actualNumArgs(X1);
1277     Register jsfunc(X2);
1278     Register newTarget(X3);
1279     Register thisObj(X4);
1280     Register argV(X5);
1281     Register currentSp = __ AvailableRegister1();
1282     Register callsiteSp = __ AvailableRegister2();
1283     Label pushCallThis;
1284 
1285     __ Mov(callsiteSp, sp);
1286     PushOptimizedUnfoldArgVFrame(assembler, callsiteSp);
1287     Register argC(X7);
1288     __ Add(actualNumArgs, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1289     __ Mov(argC, actualNumArgs);
1290     IncreaseStackForArguments(assembler, argC, currentSp, static_cast<int64_t>(CommonArgIdx::ACTUAL_ARGV));
1291     {
1292         TempRegister1Scope scope1(assembler);
1293         TempRegister2Scope scope2(assembler);
1294         Register tmp = __ TempRegister1();
1295         Register op = __ TempRegister2();
1296         __ Sub(tmp, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1297         PushArgsWithArgv(assembler, glue, tmp, argV, op, currentSp, &pushCallThis, nullptr);
1298     }
1299     __ Bind(&pushCallThis);
1300     PushMandatoryJSArgs(assembler, jsfunc, thisObj, newTarget, currentSp);
1301     {
1302         TempRegister1Scope scope1(assembler);
1303         Register tmp = __ TempRegister1();
1304         __ Mov(tmp, currentSp);
1305         __ Str(tmp, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1306         __ Str(actualNumArgs, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1307     }
1308     __ CallAssemblerStub(id, false);
1309     __ Ldr(actualNumArgs, MemoryOperand(sp, 0));
1310     PopJSFunctionArgs(assembler, actualNumArgs, actualNumArgs);
1311     PopOptimizedUnfoldArgVFrame(assembler);
1312     __ Ret();
1313 }
1314 
1315 // * uint64_t JSCallWithArgVAndPushArgv(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1316 //                          JSTaggedType new, JSTaggedType this, argV)
1317 // * cc calling convention call js function()
1318 // * arguments:
1319 //              %x0 - glue
1320 //              %x1 - argc
1321 //              %x2 - call-target
1322 //              %x3 - new-target
1323 //              %x4  - this
1324 //              %x5  - argv
JSCallWithArgVAndPushArgv(ExtendedAssembler * assembler)1325 void OptimizedCall::JSCallWithArgVAndPushArgv(ExtendedAssembler *assembler)
1326 {
1327     __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgVAndPushArgv));
1328     GenJSCallWithArgV(assembler, RTSTUB_ID(OptimizedCallAndPushArgv));
1329 }
1330 
JSCallWithArgV(ExtendedAssembler * assembler)1331 void OptimizedCall::JSCallWithArgV(ExtendedAssembler *assembler)
1332 {
1333     __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgV));
1334     GenJSCallWithArgV(assembler, RTSTUB_ID(CallOptimized));
1335 }
1336 
SuperCallWithArgV(ExtendedAssembler * assembler)1337 void OptimizedCall::SuperCallWithArgV(ExtendedAssembler *assembler)
1338 {
1339     __ BindAssemblerStub(RTSTUB_ID(SuperCallWithArgV));
1340     GenJSCallWithArgV(assembler, RTSTUB_ID(JSCallNew));
1341 }
1342 
CallOptimized(ExtendedAssembler * assembler)1343 void OptimizedCall::CallOptimized(ExtendedAssembler *assembler)
1344 {
1345     __ BindAssemblerStub(RTSTUB_ID(CallOptimized));
1346     Register sp(SP);
1347     Register jsfunc(X7);
1348     Register method(X6);
1349     Register codeAddr(X5);
1350     auto funcSlotOffset = kungfu::ArgumentAccessor::GetExtraArgsNum();
1351     __ Ldr(jsfunc, MemoryOperand(sp, funcSlotOffset * FRAME_SLOT_SIZE));
1352     __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
1353     __ Ldr(codeAddr, MemoryOperand(jsfunc, JSFunction::CODE_ENTRY_OFFSET));
1354     __ Br(codeAddr);
1355 }
1356 
DeoptEnterAsmInterpOrBaseline(ExtendedAssembler * assembler)1357 void OptimizedCall::DeoptEnterAsmInterpOrBaseline(ExtendedAssembler *assembler)
1358 {
1359     // rdi
1360     Register glueRegister = __ GlueRegister();
1361     Register context(X2);
1362     Register opRegister(X9);
1363     Register outputCount(X10);
1364     Register frameStateBase(X11);
1365     Register currentSlotRegister(X12);
1366     Register sp(SP);
1367     Register depth(X20);
1368     Register tmpReg(X21);
1369     Register hasExceptionRegister(X25);
1370     Label loopBegin;
1371     Label stackOverflow;
1372     Label pushArgv;
1373     Label gotoExceptionHandler;
1374 
1375     __ PushFpAndLr();
1376     __ Ldr(hasExceptionRegister, MemoryOperand(context, AsmStackContext::GetHasExceptionOffset(false)));
1377     __ Ldr(depth, MemoryOperand(context, AsmStackContext::GetInlineDepthOffset(false)));
1378     __ Add(context, context, Immediate(AsmStackContext::GetSize(false)));
1379     __ Mov(Register(X23), Immediate(0));
1380     // update fp
1381     __ Mov(currentSlotRegister, sp);
1382     __ Bind(&loopBegin);
1383     __ Ldr(outputCount, MemoryOperand(context, 0));
1384     __ Add(frameStateBase, context, Immediate(FRAME_SLOT_SIZE));
1385     __ Cmp(Register(X23), Immediate(0));
1386     __ B(Condition::EQ, &pushArgv);
1387     __ Mov(tmpReg, currentSlotRegister);
1388     __ Add(tmpReg, tmpReg, Immediate(AsmInterpretedFrame::GetSize(false)));
1389     __ Add(Register(X9), frameStateBase, Immediate(AsmInterpretedFrame::GetBaseOffset(false)));
1390     __ Str(tmpReg, MemoryOperand(Register(X9), InterpretedFrameBase::GetPrevOffset(false)));
1391     __ Align16(currentSlotRegister);
1392 
1393     __ Bind(&pushArgv);
1394     __ Mov(tmpReg, outputCount);
1395     __ Str(currentSlotRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFpOffset(false)));
1396     PushArgsWithArgv(assembler, glueRegister, outputCount, frameStateBase, opRegister,
1397                      currentSlotRegister, nullptr, &stackOverflow);
1398     __ Add(context, context, Immediate(FRAME_SLOT_SIZE)); // skip outputCount
1399     __ Add(context, context, Operand(tmpReg, UXTW, FRAME_SLOT_SIZE_LOG2)); // skip args
1400     __ Add(Register(X23), Register(X23), Immediate(1));
1401     __ Cmp(depth, Register(X23));
1402     __ B(Condition::GE, &loopBegin);
1403 
1404     Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
1405     Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
1406     __ Ldr(callTargetRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFunctionOffset(false)));
1407     // get baseline code
1408     __ Ldr(opRegister, MemoryOperand(callTargetRegister, JSFunction::BASELINECODE_OFFSET));
1409     Label baselineCodeUndefined;
1410     __ Cmp(opRegister, Immediate(JSTaggedValue::VALUE_UNDEFINED));
1411     __ B(Condition::EQ, &baselineCodeUndefined);
1412 
1413     // check is compiling
1414     __ Cmp(opRegister, Immediate(JSTaggedValue::VALUE_HOLE));
1415     __ B(Condition::EQ, &baselineCodeUndefined);
1416     {
1417         // x20 is free and callee save
1418         Register newSpRegister = X20;
1419         // get new sp
1420         __ Add(newSpRegister, currentSlotRegister, Immediate(AsmInterpretedFrame::GetSize(false)));
1421         __ Align16(currentSlotRegister);
1422         __ Mov(sp, currentSlotRegister);
1423 
1424         // save glue, callTarget
1425         __ Stp(glueRegister, callTargetRegister, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1426         // callee save
1427         __ CalleeSave();
1428 
1429         // get bytecode pc
1430         Register bytecodePc = opRegister;
1431         __ Ldr(bytecodePc, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetPcOffset(false)));
1432         // get func
1433         Register func(X1);
1434         func = callTargetRegister;
1435         Register argC(X2);
1436         Register runtimeId(X3);
1437         __ Mov(argC, Immediate(2)); // 2: argc
1438         __ Mov(runtimeId, Immediate(RTSTUB_ID(GetNativePcOfstForBaseline)));
1439         // get native pc offset in baselinecode by bytecodePc in func
1440         __ Stp(func, bytecodePc, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1441         __ Stp(runtimeId, argC, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1442         __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1443 
1444         // 2: skip runtimeId argc func bytecodePc
1445         __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE));
1446 
1447         __ CalleeRestore();
1448         // restore glue, callTarget
1449         __ Ldp(X19, callTargetRegister, MemoryOperand(sp, DOUBLE_SLOT_SIZE, AddrMode::POSTINDEX));
1450         // restore method, fp
1451         __ Ldr(methodRegister, MemoryOperand(callTargetRegister, JSFunctionBase::METHOD_OFFSET));
1452         __ Mov(X21, methodRegister);
1453         __ Mov(Register(FP), newSpRegister);
1454 
1455         // update pc
1456         const int64_t pcOffsetFromSp = -24; // -24: 3 slots, frameType, prevFrame, pc
1457         __ Mov(opRegister, Immediate(BASELINEJIT_PC_FLAG));
1458         __ Stur(opRegister, MemoryOperand(Register(FP), pcOffsetFromSp));
1459 
1460         // jmp to baselinecode
1461         __ Br(X0);
1462     }
1463 
1464     __ Bind(&baselineCodeUndefined);
1465     {
1466         // X19, fp, x20, x21,      x22,     x23,  x24
1467         // glue sp   pc  constpool  profile  acc   hotness
1468         __ Ldr(callTargetRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFunctionOffset(false)));
1469         __ Ldr(Register(X20), MemoryOperand(frameStateBase, AsmInterpretedFrame::GetPcOffset(false)));
1470         __ Ldr(Register(X23), MemoryOperand(frameStateBase, AsmInterpretedFrame::GetAccOffset(false)));
1471         __ Ldr(methodRegister, MemoryOperand(callTargetRegister, JSFunctionBase::METHOD_OFFSET));
1472 
1473         __ Add(opRegister, currentSlotRegister, Immediate(AsmInterpretedFrame::GetSize(false)));
1474 
1475         __ Align16(currentSlotRegister);
1476         __ Mov(Register(SP), currentSlotRegister);
1477 
1478         __ Cmp(hasExceptionRegister, Immediate(0));
1479         __ B(Condition::NE, &gotoExceptionHandler);
1480         AsmInterpreterCall::DispatchCall(assembler, Register(X20), opRegister, Register(X23), false);
1481         __ Bind(&gotoExceptionHandler);
1482         AsmInterpreterCall::DispatchCall(assembler, Register(X20), opRegister, Register(X23), true);
1483     }
1484     __ Bind(&stackOverflow);
1485     {
1486         Register temp(X1);
1487         AsmInterpreterCall::ThrowStackOverflowExceptionAndReturnToAsmInterpBridgeFrame(
1488             assembler, glueRegister, sp, temp);
1489     }
1490 }
1491 
DeoptPushAsmInterpBridgeFrame(ExtendedAssembler * assembler,Register context)1492 void OptimizedCall::DeoptPushAsmInterpBridgeFrame(ExtendedAssembler *assembler, Register context)
1493 {
1494     Register fp(X29);
1495     Register sp(SP);
1496 
1497     [[maybe_unused]] TempRegister1Scope scope1(assembler);
1498     Label processLazyDeopt;
1499     Label exit;
1500     Register frameTypeRegister = __ TempRegister1();
1501 
1502     __ Ldr(frameTypeRegister, MemoryOperand(context, AsmStackContext::GetIsFrameLazyDeoptOffset(false)));
1503     __ Cmp(frameTypeRegister, Immediate(0));
1504     __ B(Condition::NE, &processLazyDeopt);
1505     {
1506         __ Mov(frameTypeRegister, Immediate(static_cast<int64_t>(FrameType::ASM_INTERPRETER_BRIDGE_FRAME)));
1507         __ B(&exit);
1508     }
1509     __ Bind(&processLazyDeopt);
1510     {
1511         __ Mov(frameTypeRegister, (static_cast<uint64_t>(FrameType::ASM_INTERPRETER_BRIDGE_FRAME) |
1512             (1ULL << FrameIterator::LAZY_DEOPT_FLAG_BIT)));
1513     }
1514     __ Bind(&exit);
1515     // 2 : return addr & frame type
1516     __ Stp(frameTypeRegister, Register(X30), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1517     // 2 : prevSp & pc
1518     __ Stp(Register(Zero), Register(FP), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1519     __ Add(fp, sp, Immediate(24));  // 24: skip frame type, prevSp, pc
1520 
1521     if (!assembler->FromInterpreterHandler()) {
1522         __ CalleeSave();
1523     }
1524 }
1525 
DeoptHandlerAsm(ExtendedAssembler * assembler)1526 void OptimizedCall::DeoptHandlerAsm(ExtendedAssembler *assembler)
1527 {
1528     __ BindAssemblerStub(RTSTUB_ID(DeoptHandlerAsm));
1529     __ PushFpAndLr();
1530     Register sp(SP);
1531     Register fp(FP);
1532     Register frameType(X3);
1533     Register glueReg(X0);
1534 
1535     __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::ASM_BRIDGE_FRAME)));
1536     __ Stp(glueReg, frameType, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1537     __ Add(fp, sp, Immediate(DOUBLE_SLOT_SIZE));
1538     __ CalleeSave();
1539 
1540     Register deoptType(X1);
1541     Register maybeAcc(X2);
1542     Register argC(X3);
1543     Register runtimeId(X4);
1544     __ Stp(deoptType, maybeAcc, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1545     __ Mov(argC, Immediate(2)); // 2: argc
1546     __ Mov(runtimeId, Immediate(RTSTUB_ID(DeoptHandler)));
1547     __ Stp(runtimeId, argC, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1548     __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1549     __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE)); // 2: skip runtimeId, argc, depth, shiftLen
1550 
1551     __ CalleeRestore();
1552     Register context(X2);
1553     __ Mov(context, Register(X0));
1554     __ Ldr(glueReg, MemoryOperand(sp, 0));
1555 
1556     Register ret(X0);
1557     Label stackOverflow;
1558     __ Cmp(ret, Immediate(JSTaggedValue::VALUE_EXCEPTION));
1559     __ B(Condition::EQ, &stackOverflow);
1560 
1561     Label target;
1562     Register temp(X1);
1563     __ Ldr(fp, MemoryOperand(context, AsmStackContext::GetCallerFpOffset(false)));
1564     __ Ldr(temp, MemoryOperand(context, AsmStackContext::GetCallFrameTopOffset(false)));
1565     __ Mov(sp, temp);
1566     __ Ldr(Register(X30), MemoryOperand(context, AsmStackContext::GetReturnAddressOffset(false)));
1567 
1568     DeoptPushAsmInterpBridgeFrame(assembler, context);
1569     __ Bl(&target);
1570     PopAsmInterpBridgeFrame(assembler);
1571     __ Ret();
1572     __ Bind(&target);
1573     DeoptEnterAsmInterpOrBaseline(assembler);
1574 
1575     __ Bind(&stackOverflow);
1576     {
1577         __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowStackOverflowException)));
1578         // 2 : 2 means pair
1579         __ Stp(runtimeId, Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1580         __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1581         __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE)); // 2: skip runtimeId&argc glue&type
1582         __ RestoreFpAndLr();
1583         __ Ret();
1584     }
1585 }
1586 #undef __
1587 }  // panda::ecmascript::aarch64
1588