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