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