• 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(BUILTINS_STUB_ID(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 
PushAsmBridgeFrame(ExtendedAssembler * assembler)818 void OptimizedCall::PushAsmBridgeFrame(ExtendedAssembler *assembler)
819 {
820     __ Pushq(rbp);
821     __ Pushq(static_cast<int32_t>(FrameType::ASM_BRIDGE_FRAME));
822     __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
823 }
824 
PopAsmBridgeFrame(ExtendedAssembler * assembler)825 void OptimizedCall::PopAsmBridgeFrame(ExtendedAssembler *assembler)
826 {
827     __ Addq(FRAME_SLOT_SIZE, rsp);  // skip type
828     __ Popq(rbp);
829 }
830 
JSCallCheck(ExtendedAssembler * assembler,Register jsFuncReg,Label * lNonCallable,Label * lNotJSFunction,Label * lJSFunctionCall)831 void OptimizedCall::JSCallCheck(ExtendedAssembler *assembler, Register jsFuncReg,
832                                 Label *lNonCallable, Label *lNotJSFunction, Label *lJSFunctionCall)
833 {
834     __ Movabs(JSTaggedValue::TAG_INT, rdx); // IsTaggedInt
835     __ And(jsFuncReg, rdx);
836     __ Cmp(0x0, rdx);
837     __ Jne(lNonCallable);
838     __ Cmp(0x0, jsFuncReg); // IsHole
839     __ Je(lNonCallable);
840     __ Movabs(JSTaggedValue::TAG_SPECIAL, rdx);
841     __ And(jsFuncReg, rdx);  // IsSpecial
842     __ Cmp(0x0, rdx);
843     __ Jne(lNonCallable);
844 
845     __ Movq(jsFuncReg, rsi); // save jsFunc
846     __ Movq(Operand(jsFuncReg, JSFunction::HCLASS_OFFSET), rax); // get jsHclass
847     Register maskRegister = rdx;
848     __ Movabs(TaggedObject::GC_STATE_MASK, maskRegister);
849     __ And(maskRegister, rax);
850     Register jsHclassReg = rax;
851     __ Movl(Operand(jsHclassReg, JSHClass::BIT_FIELD_OFFSET), rax);
852     __ Btl(JSHClass::CallableBit::START_BIT, rax); // IsCallable
853     __ Jnb(lNonCallable);
854 
855     __ Cmpb(static_cast<int32_t>(JSType::JS_FUNCTION_FIRST), rax);
856     __ Jb(lNotJSFunction);
857     __ Cmpb(static_cast<int32_t>(JSType::JS_FUNCTION_LAST), rax);
858     __ Jbe(lJSFunctionCall); // objecttype in (0x04 ~ 0x0c)
859 }
860 
ThrowNonCallableInternal(ExtendedAssembler * assembler,Register glueReg)861 void OptimizedCall::ThrowNonCallableInternal(ExtendedAssembler *assembler, Register glueReg)
862 {
863     __ Pushq(rbp);
864     __ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)); // set frame type
865     __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
866     __ Movq(MessageString::Message_NonCallable, rax);
867     __ Movabs(JSTaggedValue::TAG_INT, r10);
868     __ Orq(r10, rax);
869     __ Pushq(rax); // message id
870     __ Pushq(1); // argc
871     __ Pushq(RTSTUB_ID(ThrowTypeError)); // runtime id
872     __ Movq(glueReg, rax); // glue
873     __ Movq(kungfu::RuntimeStubCSigns::ID_CallRuntime, r10);
874     __ Movq(Operand(rax, r10, Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)), r10);
875     __ Callq(r10); // call CallRuntime
876     __ Movabs(JSTaggedValue::VALUE_EXCEPTION, rax); // return exception
877     __ Addq(4 * FRAME_SLOT_SIZE, rsp); // 4: sp + 32 argv
878     __ Pop(rbp);
879     __ Ret();
880 }
881 
JSBoundFunctionCallInternal(ExtendedAssembler * assembler,Register jsFuncReg,Label * jsCall)882 void OptimizedCall::JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Register jsFuncReg, Label *jsCall)
883 {
884     Label lAlign16Bytes2;
885     Label lCopyBoundArgument;
886     Label lCopyArgument2;
887     Label lPushCallTarget;
888     Label lCopyBoundArgumentLoop;
889     Label lPopFrame2;
890     Label slowCall;
891     Label aotCall;
892     Label popArgs;
893     Label isJsFunc;
894     Label isNotClass;
895     __ Pushq(rbp);
896     __ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME));
897     __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
898     __ Pushq(r10); // callee save
899     __ Movq(rsp, rdx);
900     __ Addq(QUADRUPLE_SLOT_SIZE, rdx); // skip return addr, prevFp, frame type and callee save
901     __ Mov(Operand(rdx, 0), rax); // get origin argc
902     __ Mov(Operand(rdx, FRAME_SLOT_SIZE), r9); // get origin argv
903     __ Movq(rax, r10);
904     // get bound target
905     __ Mov(Operand(jsFuncReg, JSBoundFunction::BOUND_ARGUMENTS_OFFSET), rcx);
906     // get bound length
907     __ Mov(Operand(rcx, TaggedArray::LENGTH_OFFSET), rcx);
908     __ Addq(rcx, r10);
909 
910     // 16 bytes align check
911     __ Testb(1, r10);
912     __ Je(&lAlign16Bytes2);
913     __ PushAlignBytes(); // push zero to align 16 bytes stack
914 
915     __ Bind(&lAlign16Bytes2);
916     {
917         __ Subq(NUM_MANDATORY_JSFUNC_ARGS, rax);
918         __ Cmp(0, rax);
919         __ Je(&lCopyBoundArgument);
920     }
921 
922     __ Bind(&lCopyArgument2);
923     {
924         __ Movq(Operand(rdx, rax, Scale::Times8,
925             (kungfu::ArgumentAccessor::GetFixArgsNum() + 1) * FRAME_SLOT_SIZE), rcx); // argv
926         __ Pushq(rcx);
927         __ Addq(-1, rax);
928         __ Jne(&lCopyArgument2);
929     }
930 
931     __ Bind(&lCopyBoundArgument);
932     {
933         // get bound target
934         __ Mov(Operand(jsFuncReg, JSBoundFunction::BOUND_ARGUMENTS_OFFSET), rdx);
935         // get bound length
936         __ Mov(Operand(rdx, TaggedArray::LENGTH_OFFSET), rax);
937         __ Addq(TaggedArray::DATA_OFFSET, rdx);
938         __ Cmp(0, rax);
939         __ Je(&lPushCallTarget);
940     }
941     __ Bind(&lCopyBoundArgumentLoop);
942     {
943         __ Addq(-1, rax);
944         __ Movq(Operand(rdx, rax, Scale::Times8, 0), rcx);
945         __ Pushq(rcx);
946         __ Jne(&lCopyBoundArgumentLoop);
947     }
948     __ Bind(&lPushCallTarget);
949     {
950         __ Mov(Operand(jsFuncReg, JSBoundFunction::BOUND_THIS_OFFSET), r8); // thisObj
951         __ Pushq(r8);
952         __ Pushq(JSTaggedValue::VALUE_UNDEFINED); // newTarget
953         __ Mov(Operand(jsFuncReg, JSBoundFunction::BOUND_TARGET_OFFSET), rax); // callTarget
954         __ Pushq(rax);
955         __ Pushq(r9);
956         __ Pushq(r10); // push actual arguments
957     }
958     JSCallCheck(assembler, rax, &slowCall, &slowCall, &isJsFunc); // jsfunc -> rsi hclassfiled -> rax
959     __ Jmp(&slowCall);
960     Register jsfunc = rsi;
961     Register compiledCodeFlag = rcx;
962     __ Bind(&isJsFunc);
963     {
964         __ Btq(JSHClass::IsClassConstructorOrPrototypeBit::START_BIT, rax); // is CallConstructor
965         __ Jnb(&isNotClass);
966         __ Btq(JSHClass::ConstructorBit::START_BIT, rax);
967         __ Jb(&slowCall);
968         __ Bind(&isNotClass);
969         __ Movzwq(Operand(rsi, JSFunctionBase::BIT_FIELD_OFFSET), compiledCodeFlag); // compiled code flag
970         __ Btq(JSFunctionBase::IsCompiledCodeBit::START_BIT, compiledCodeFlag); // is compiled code
971         __ Jnb(&slowCall);
972         __ Bind(&aotCall);
973         {
974             // output: glue:rdi argc:rsi calltarget:rdx argv:rcx this:r8 newtarget:r9
975             __ Movq(jsfunc, rdx);
976             __ Movq(r10, rsi);
977             auto funcSlotOffSet = kungfu::ArgumentAccessor::GetFixArgsNum() +
978                                   kungfu::ArgumentAccessor::GetExtraArgsNum();
979             __ Leaq(Operand(rsp, funcSlotOffSet * FRAME_SLOT_SIZE), rcx); // 5: skip argc and argv func new this
980             __ Movq(JSTaggedValue::VALUE_UNDEFINED, r9);
981             __ Movq(kungfu::CommonStubCSigns::JsBoundCallInternal, r10);
982             __ Movq(Operand(rdi, r10, Scale::Times8, JSThread::GlueData::GetCOStubEntriesOffset(false)), rax);
983             __ Callq(rax); // call JSCall
984             __ Jmp(&popArgs);
985         }
986     }
987     __ Bind(&slowCall);
988     {
989         __ Movq(rdi, rax);
990         __ Callq(jsCall); // call JSCall
991         __ Jmp(&popArgs);
992     }
993     __ Bind(&popArgs);
994     {
995         __ Pop(r10);
996         __ Pop(r9);
997         __ Leaq(Operand(r10, Scale::Times8, 0), rcx); // 8: disp
998         __ Addq(rcx, rsp);
999         __ Testb(1, r10);  // stack 16bytes align check
1000         __ Je(&lPopFrame2);
1001         __ Addq(8, rsp); // 8: align byte
1002     }
1003     __ Bind(&lPopFrame2);
1004     {
1005         __ Pop(r10);
1006         __ Addq(8, rsp); // 8: sp + 8
1007         __ Pop(rbp);
1008         __ Ret();
1009     }
1010 }
1011 
1012 // * uint64_t CallRuntime(uintptr_t glue, uint64_t runtime_id, uint64_t argc, uintptr_t arg0, ...)
1013 // * webkit_jscc calling convention call runtime_id's runtime function(c-abi)
1014 // * Arguments:
1015 //         %rax - glue
1016 //
1017 // * Optimized-leaved-frame layout as the following:
1018 //         +--------------------------+
1019 //         |       argv[N-1]          |
1020 //         |--------------------------|
1021 //         |       . . . . .          |
1022 //         |--------------------------|
1023 //         |       argv[0]            |
1024 //         +--------------------------+-------------
1025 //         |       argc               |            ^
1026 //         |--------------------------|            |
1027 //         |       RuntimeId          |            |
1028 //  sp --> |--------------------------|   OptimizedLeaveFrame
1029 //         |       ret-addr           |            |
1030 //         |--------------------------|            |
1031 //         |       prevFp             |            |
1032 //         |--------------------------|            |
1033 //         |       frameType          |            v
1034 //         +--------------------------+-------------
1035 
CallRuntime(ExtendedAssembler * assembler)1036 void OptimizedCall::CallRuntime(ExtendedAssembler *assembler)
1037 {
1038     __ BindAssemblerStub(RTSTUB_ID(CallRuntime));
1039     __ Pushq(rbp);
1040     __ Movq(rsp, Operand(rax, JSThread::GlueData::GetLeaveFrameOffset(false)));
1041     __ Pushq(static_cast<int32_t>(FrameType::LEAVE_FRAME));
1042     __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);  // 8: skip frame type
1043 
1044     __ Pushq(r10);
1045     __ Pushq(rdx);
1046     __ Pushq(rax);
1047 
1048     __ Movq(rbp, rdx);
1049     // 2: rbp & return address
1050     __ Addq(2 * FRAME_SLOT_SIZE, rdx);
1051 
1052     __ Movq(Operand(rdx, 0), r10);
1053     __ Movq(Operand(rax, r10, Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)), r10);
1054     __ Movq(rax, rdi);
1055     // 8: argc
1056     __ Movq(Operand(rdx, FRAME_SLOT_SIZE), rsi);
1057     // 2: argv
1058     __ Addq(2 * FRAME_SLOT_SIZE, rdx);
1059     __ Callq(r10);
1060 
1061     // 8: skip rax
1062     __ Addq(FRAME_SLOT_SIZE, rsp);
1063     __ Popq(rdx);
1064     __ Popq(r10);
1065 
1066     // 8: skip frame type
1067     __ Addq(FRAME_SLOT_SIZE, rsp);
1068     __ Popq(rbp);
1069     __ Ret();
1070 }
1071 
1072 // * uint64_t CallRuntimeWithArgv(uintptr_t glue, uint64_t runtime_id, uint64_t argc, uintptr_t argv)
1073 // * cc calling convention call runtime_id's runtion function(c-abi)
1074 // * Arguments:
1075 //         %rdi - glue
1076 //         %rsi - runtime_id
1077 //         %edx - argc
1078 //         %rcx - argv
1079 //
1080 // * Optimized-leaved-frame-with-argv layout as the following:
1081 //         +--------------------------+
1082 //         |       argv[]             |
1083 //         +--------------------------+-------------
1084 //         |       argc               |            ^
1085 //         |--------------------------|            |
1086 //         |       RuntimeId          |   OptimizedWithArgvLeaveFrame
1087 //  sp --> |--------------------------|            |
1088 //         |       returnAddr         |            |
1089 //         |--------------------------|            |
1090 //         |       callsiteFp         |            |
1091 //         |--------------------------|            |
1092 //         |       frameType          |            v
1093 //         +--------------------------+-------------
1094 
CallRuntimeWithArgv(ExtendedAssembler * assembler)1095 void OptimizedCall::CallRuntimeWithArgv(ExtendedAssembler *assembler)
1096 {
1097     __ BindAssemblerStub(RTSTUB_ID(CallRuntimeWithArgv));
1098     Register glueReg = rdi;
1099     Register runtimeIdReg = rsi;
1100     Register argcReg = rdx;
1101     Register argvReg = rcx;
1102 
1103     __ Movq(rsp, r8);
1104     Register returnAddrReg = r9;
1105     __ Movq(Operand(rsp, 0), returnAddrReg);
1106     __ Pushq(argvReg); // argv[]
1107     __ Pushq(argcReg); // argc
1108     __ Pushq(runtimeIdReg); // runtime_id
1109     __ Pushq(returnAddrReg); // returnAddr
1110 
1111     // construct leave frame
1112     __ Pushq(rbp);
1113     __ Movq(rsp, Operand(glueReg, JSThread::GlueData::GetLeaveFrameOffset(false))); // save to thread->leaveFrame_
1114     __ Pushq(static_cast<int32_t>(FrameType::LEAVE_FRAME_WITH_ARGV));
1115     __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
1116 
1117     __ Movq(Operand(glueReg, runtimeIdReg, Scale::Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)), r9);
1118     __ Movq(argcReg, rsi); // argc
1119     __ Movq(argvReg, rdx); // argv
1120     __ Pushq(r8);
1121     __ Callq(r9);
1122     __ Popq(r8);
1123     __ Addq(FRAME_SLOT_SIZE, rsp); // 8: skip type
1124     __ Popq(rbp);
1125     __ Movq(r8, rsp);
1126     __ Ret();
1127 }
1128 
PushMandatoryJSArgs(ExtendedAssembler * assembler,Register jsfunc,Register thisObj,Register newTarget)1129 void OptimizedCall::PushMandatoryJSArgs(ExtendedAssembler *assembler, Register jsfunc,
1130                                         Register thisObj, Register newTarget)
1131 {
1132     __ Pushq(thisObj);
1133     __ Pushq(newTarget);
1134     __ Pushq(jsfunc);
1135 }
1136 
1137 // output expectedNumArgs (r14)
PushArgsWithArgV(ExtendedAssembler * assembler,Register jsfunc,Register actualNumArgs,Register argV,Label * pushCallThis)1138 void OptimizedCall::PushArgsWithArgV(ExtendedAssembler *assembler, Register jsfunc,
1139                                      Register actualNumArgs, Register argV, Label *pushCallThis)
1140 {
1141     Register expectedNumArgs(r14); // output
1142     Register tmp(rax);
1143     Label align16Bytes;
1144     Label copyArguments;
1145     // get expected num Args
1146     __ Movq(Operand(jsfunc, JSFunctionBase::METHOD_OFFSET), tmp);
1147     __ Movq(Operand(tmp, Method::CALL_FIELD_OFFSET), tmp);
1148     __ Shr(MethodLiteral::NumArgsBits::START_BIT, tmp);
1149     __ Andl(((1LU <<  MethodLiteral::NumArgsBits::SIZE) - 1), tmp);
1150 
1151     __ Mov(tmp, expectedNumArgs);
1152     __ Testb(1, expectedNumArgs);
1153     __ Jne(&align16Bytes);
1154     __ PushAlignBytes();
1155 
1156     __ Bind(&align16Bytes);
1157     {
1158         __ Cmpq(actualNumArgs, expectedNumArgs);
1159         __ Jbe(&copyArguments);
1160         __ Subq(actualNumArgs, tmp);
1161         PushUndefinedWithArgc(assembler, tmp);
1162     }
1163     __ Bind(&copyArguments);
1164     {
1165         __ Cmpq(actualNumArgs, expectedNumArgs);
1166         __ Movq(actualNumArgs, tmp);     // rax -> actualNumArgsReg
1167         __ CMovbe(expectedNumArgs, tmp);
1168         __ Cmpq(0, tmp);
1169         __ Je(pushCallThis);
1170         CopyArgumentWithArgV(assembler, tmp, argV);
1171     }
1172 }
1173 
PopJSFunctionArgs(ExtendedAssembler * assembler,Register expectedNumArgs)1174 void OptimizedCall::PopJSFunctionArgs(ExtendedAssembler *assembler, Register expectedNumArgs)
1175 {
1176     Label align16Bytes;
1177     __ Testb(1, expectedNumArgs);
1178     __ Je(&align16Bytes);
1179     __ Addq(FRAME_SLOT_SIZE, rsp);
1180     __ Bind(&align16Bytes);
1181     __ Leaq(Operand(expectedNumArgs, Scale::Times8, 0), expectedNumArgs);
1182     __ Addq(DOUBLE_SLOT_SIZE, rsp); // 16: skip actual argc and actual argv
1183     __ Addq(expectedNumArgs, rsp);
1184 }
1185 
PushJSFunctionEntryFrame(ExtendedAssembler * assembler,Register prevFp)1186 void OptimizedCall::PushJSFunctionEntryFrame(ExtendedAssembler *assembler, Register prevFp)
1187 {
1188     __ PushCppCalleeSaveRegisters();
1189     __ Pushq(rdi);
1190 
1191     // construct optimized entry frame
1192     __ Pushq(rbp);
1193     __ Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_ENTRY_FRAME));
1194     __ Pushq(prevFp);
1195     // 2: skip prevFp and frameType
1196     __ Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp);
1197 }
1198 
PopJSFunctionEntryFrame(ExtendedAssembler * assembler,Register glue)1199 void OptimizedCall::PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue)
1200 {
1201     Register prevFp(rsi);
1202     __ Popq(prevFp);
1203     __ Addq(FRAME_SLOT_SIZE, rsp); // 8: frame type
1204     __ Popq(rbp);
1205     __ Popq(glue); // caller restore
1206     __ PopCppCalleeSaveRegisters(); // callee restore
1207     __ Movq(prevFp, Operand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
1208 }
1209 
1210 // * uint64_t PushOptimizedUnfoldArgVFrame(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1211 //                                         JSTaggedType new, JSTaggedType this, JSTaggedType, argV[])
1212 // * cc calling convention call js function()
1213 // * arguments:
1214 //              %rdi - glue
1215 //              %rsi - argc
1216 //              %rdx - call-target
1217 //              %rcx - new-target
1218 //              %r8  - this
1219 //              %r9  - argv
1220 //
1221 // * OptimizedUnfoldArgVFrame layout description as the following:
1222 //      sp ----> |--------------------------| ---------------
1223 //               |       returnAddr         |               ^
1224 //  currentFp--> |--------------------------|               |
1225 //               |       prevFp             |               |
1226 //               |--------------------------|   OptimizedUnfoldArgVFrame
1227 //               |       frameType          |               |
1228 //               |--------------------------|               |
1229 //               |       currentFp          |               v
1230 //               +--------------------------+ ---------------
1231 
PushOptimizedUnfoldArgVFrame(ExtendedAssembler * assembler,Register callSiteSp)1232 void OptimizedCall::PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp)
1233 {
1234     __ Pushq(rbp);
1235     // construct frame
1236     __ Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME));
1237     __ Pushq(callSiteSp);
1238     // 2: skip callSiteSp and frameType
1239     __ Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp);
1240 }
1241 
PopOptimizedUnfoldArgVFrame(ExtendedAssembler * assembler)1242 void OptimizedCall::PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler)
1243 {
1244     Register sp(rsp);
1245     // 2 : 2 means pop call site sp and type
1246     __ Addq(Immediate(2 * FRAME_SLOT_SIZE), sp);
1247     __ Popq(rbp);
1248 }
1249 
1250 // * uint64_t JSCallWithArgV(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1251 //                          JSTaggedType new, JSTaggedType this, argV)
1252 // * cc calling convention call js function()
1253 // * arguments:
1254 //              %rdi - glue
1255 //              %rsi - argc
1256 //              %rdx - call-target
1257 //              %rcx - new-target
1258 //              %r8  - this
1259 //              %r9  - argv
1260 //
1261 // * OptimizedJSFunctionFrame layout description as the following:
1262 //               +--------------------------+
1263 //               |       argn               |
1264 //               |--------------------------|
1265 //               |       argn - 1           |
1266 //               |--------------------------|
1267 //               |       .....              |
1268 //               |--------------------------|
1269 //               |       arg2               |
1270 //               |--------------------------|
1271 //               |       arg1               |
1272 //      sp ----> |--------------------------| ---------------
1273 //               |       returnAddr         |               ^
1274 //               |--------------------------|               |
1275 //               |       callsiteFp         |               |
1276 //               |--------------------------|   OptimizedJSFunctionFrame
1277 //               |       frameType          |               |
1278 //               |--------------------------|               |
1279 //               |       call-target        |               v
1280 //               +--------------------------+ ---------------
1281 
GenJSCallWithArgV(ExtendedAssembler * assembler,int id)1282 void OptimizedCall::GenJSCallWithArgV(ExtendedAssembler *assembler, int id)
1283 {
1284     Register sp(rsp);
1285     Register glue(rdi);
1286     Register actualNumArgs(rsi);
1287     Register jsfunc(rdx);
1288     Register newTarget(rcx);
1289     Register thisObj(r8);
1290     Register argV(r9);
1291     Register callsiteSp = __ AvailableRegister2();
1292     Label align16Bytes;
1293     Label pushCallThis;
1294 
1295     __ Movq(sp, callsiteSp);
1296     __ Addq(Immediate(FRAME_SLOT_SIZE), callsiteSp);   // 8 : 8 means skip pc to get last callsitesp
1297     PushOptimizedUnfoldArgVFrame(assembler, callsiteSp);
1298     __ Testb(1, actualNumArgs);
1299     __ Jne(&align16Bytes);
1300     __ PushAlignBytes();
1301     __ Bind(&align16Bytes);
1302     __ Cmp(Immediate(0), actualNumArgs);
1303     __ Jz(&pushCallThis);
1304     __ Mov(actualNumArgs, rax);
1305     CopyArgumentWithArgV(assembler, rax, argV);
1306     __ Bind(&pushCallThis);
1307     PushMandatoryJSArgs(assembler, jsfunc, thisObj, newTarget);
1308     __ Addq(Immediate(NUM_MANDATORY_JSFUNC_ARGS), actualNumArgs);
1309     __ Pushq(sp);
1310     __ Pushq(actualNumArgs);
1311     __ Movq(glue, rax);
1312     __ CallAssemblerStub(id, false);
1313     __ Mov(Operand(sp, 0), actualNumArgs);
1314     PopJSFunctionArgs(assembler, actualNumArgs);
1315     PopOptimizedUnfoldArgVFrame(assembler);
1316     __ Ret();
1317 }
1318 
1319 // * uint64_t JSCallWithArgVAndPushArgv(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1320 //                          JSTaggedType new, JSTaggedType this, argV)
1321 // * cc calling convention call js function()
1322 // * arguments:
1323 //              %rdi - glue
1324 //              %rsi - argc
1325 //              %rdx - call-target
1326 //              %rcx - new-target
1327 //              %r8  - this
1328 //              %r9  - argv
JSCallWithArgVAndPushArgv(ExtendedAssembler * assembler)1329 void OptimizedCall::JSCallWithArgVAndPushArgv(ExtendedAssembler *assembler)
1330 {
1331     __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgVAndPushArgv));
1332     GenJSCallWithArgV(assembler, RTSTUB_ID(OptimizedCallAndPushArgv));
1333 }
1334 
JSCallWithArgV(ExtendedAssembler * assembler)1335 void OptimizedCall::JSCallWithArgV(ExtendedAssembler *assembler)
1336 {
1337     __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgV));
1338     GenJSCallWithArgV(assembler, RTSTUB_ID(CallOptimized));
1339 }
1340 
SuperCallWithArgV(ExtendedAssembler * assembler)1341 void OptimizedCall::SuperCallWithArgV(ExtendedAssembler *assembler)
1342 {
1343     __ BindAssemblerStub(RTSTUB_ID(SuperCallWithArgV));
1344     GenJSCallWithArgV(assembler, RTSTUB_ID(JSCallNew));
1345 }
1346 
CallOptimized(ExtendedAssembler * assembler)1347 void OptimizedCall::CallOptimized(ExtendedAssembler *assembler)
1348 {
1349     __ BindAssemblerStub(RTSTUB_ID(CallOptimized));
1350     Register jsFuncReg = rdi;
1351     Register method = r9;
1352     Register codeAddrReg = rsi;
1353     auto funcSlotOffset = kungfu::ArgumentAccessor::GetExtraArgsNum() + 1;  // 1: return addr
1354     __ Movq(Operand(rsp, funcSlotOffset * FRAME_SLOT_SIZE), jsFuncReg); // sp + 24 get jsFunc
1355     __ Mov(Operand(jsFuncReg, JSFunctionBase::METHOD_OFFSET), method); // get method
1356     __ Mov(Operand(jsFuncReg, JSFunctionBase::CODE_ENTRY_OFFSET), codeAddrReg);
1357     __ Jmp(codeAddrReg);
1358 }
1359 
1360 // Input: %rdi - glue
1361 //        %rsi - context
DeoptEnterAsmInterpOrBaseline(ExtendedAssembler * assembler)1362 void OptimizedCall::DeoptEnterAsmInterpOrBaseline(ExtendedAssembler *assembler)
1363 {
1364     // rdi
1365     Register glueRegister = __ GlueRegister();
1366     Register context = rsi;
1367     // rax, rdx, rcx, r8, r9, r10, r11 is free
1368     Register tempRegister = rax;
1369     Register opRegister = r10;
1370     Register outputCount = rdx;
1371     Register frameStateBase = rcx;
1372     Register depth = r11;
1373     Register hasExceptionRegister = r15;
1374     Label loopBegin;
1375     Label stackOverflow;
1376     Label gotoExceptionHandler;
1377     Label pushArgv;
1378     __ Movq(Operand(context, AsmStackContext::GetHasExceptionOffset(false)), hasExceptionRegister);
1379     __ Movq(Operand(context, AsmStackContext::GetInlineDepthOffset(false)), depth);
1380     __ Leaq(Operand(context, AsmStackContext::GetSize(false)), context);
1381     __ Movq(Immediate(0), r12);
1382     __ Bind(&loopBegin);
1383     __ Movq(Operand(context, 0), outputCount);
1384     __ Leaq(Operand(context, FRAME_SLOT_SIZE), frameStateBase);
1385     __ Cmpq(0, r12);
1386     __ Je(&pushArgv);
1387     __ Movq(rsp, r8);
1388     __ Addq(AsmInterpretedFrame::GetSize(false), r8);
1389     __ Leaq(Operand(frameStateBase, AsmInterpretedFrame::GetBaseOffset(false)), r10);
1390     __ Movq(r8, Operand(r10, InterpretedFrameBase::GetPrevOffset(false)));
1391     __ Testq(15, rsp);  // 15: low 4 bits must be 0b0000
1392     __ Jnz(&pushArgv);
1393     __ PushAlignBytes();
1394     __ Bind(&pushArgv);
1395     // update fp
1396     __ Movq(rsp, Operand(frameStateBase, AsmInterpretedFrame::GetFpOffset(false)));
1397     PushArgsWithArgvAndCheckStack(assembler, glueRegister, outputCount,
1398         frameStateBase, tempRegister, opRegister, &stackOverflow);
1399     __ Leaq(Operand(context, outputCount, Scale::Times8, FRAME_SLOT_SIZE), context);
1400     __ Addq(1, r12);
1401     __ Cmpq(r12, depth);
1402     __ Jae(&loopBegin);
1403 
1404     Register callTargetRegister = r8;
1405     Register methodRegister = r9;
1406     __ Movq(Operand(frameStateBase, AsmInterpretedFrame::GetFunctionOffset(false)), callTargetRegister);
1407     // get baseline code
1408     __ Movq(Operand(callTargetRegister, JSFunction::BASELINECODE_OFFSET), opRegister);
1409     Label baselineCodeUndefined;
1410     __ Cmpq(JSTaggedValue::Undefined().GetRawData(), opRegister);
1411     __ Je(&baselineCodeUndefined);
1412     // check is compiling
1413     __ Cmpq(JSTaggedValue::Hole().GetRawData(), opRegister);
1414     __ Je(&baselineCodeUndefined);
1415     {
1416         Register newSpRegister = r11; // r11 is free
1417         __ Leaq(Operand(rsp, AsmInterpretedFrame::GetSize(false)), newSpRegister);
1418         Label stackAligned;
1419         // align 16 bytes
1420         __ Testq(15, rsp);  // 15: low 4 bits must be 0b0000
1421         __ Jz(&stackAligned);
1422         __ PushAlignBytes();
1423         __ Bind(&stackAligned);
1424 
1425         Register bytecodePc = opRegister;
1426         // get bytecode pc
1427         __ Movq(Operand(frameStateBase, AsmInterpretedFrame::GetPcOffset(false)), bytecodePc);
1428         // get func
1429         Register func = callTargetRegister;
1430         // save glue
1431         __ Push(glueRegister);
1432         // save callTarget
1433         __ Push(callTargetRegister);
1434         // save new sp
1435         __ Push(newSpRegister);
1436         // callee save
1437         __ PushCppCalleeSaveRegisters();
1438 
1439         __ Movq(glueRegister, rax);
1440         // get native pc offset in baselinecode by bytecodePc in func
1441         __ Pushq(bytecodePc);
1442         __ Pushq(func); // argv[0]
1443         __ Pushq(2);    // 2: argc
1444         __ Pushq(kungfu::RuntimeStubCSigns::ID_GetNativePcOfstForBaseline);
1445         __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1446 
1447         __ Addq(4 * FRAME_SLOT_SIZE, rsp); // 4: skip runtimeId argc func bytecodePc
1448 
1449         __ PopCppCalleeSaveRegisters();
1450         __ Pop(newSpRegister);
1451         __ Pop(callTargetRegister);
1452         __ Pop(glueRegister);
1453 
1454         // restore glue, method, rbp
1455         __ Movq(glueRegister, r13);
1456         __ Movq(Operand(callTargetRegister, JSFunctionBase::METHOD_OFFSET), methodRegister);
1457         __ Movq(methodRegister, rbx);
1458         __ Movq(newSpRegister, rbp);
1459 
1460         // update pc
1461         const int32_t pcOffsetFromSp = -24; // -24: 3 slots, frameType, prevFrame, pc
1462         __ Movabs(std::numeric_limits<uint64_t>::max(), opRegister);
1463         __ Movq(opRegister, Operand(rbp, pcOffsetFromSp));
1464 
1465         // jmp to baselinecode
1466         __ Jmp(rax);
1467     }
1468 
1469     __ Bind(&baselineCodeUndefined);
1470     {
1471         // r13, rbp, r12, rbx,      r14,     rsi,  rdi
1472         // glue sp   pc  constpool  profile  acc   hotness
1473         __ Movq(Operand(frameStateBase, AsmInterpretedFrame::GetFunctionOffset(false)), callTargetRegister);
1474         __ Movq(Operand(frameStateBase, AsmInterpretedFrame::GetPcOffset(false)), r12);
1475         __ Movq(Operand(frameStateBase, AsmInterpretedFrame::GetAccOffset(false)), rsi);
1476         __ Movq(Operand(callTargetRegister, JSFunctionBase::METHOD_OFFSET), methodRegister);
1477 
1478         __ Leaq(Operand(rsp, AsmInterpretedFrame::GetSize(false)), opRegister);
1479 
1480         __ Cmpq(0, hasExceptionRegister);
1481         __ Jne(&gotoExceptionHandler);
1482         AsmInterpreterCall::DispatchCall(assembler, r12, opRegister, callTargetRegister, methodRegister, rsi, false);
1483         __ Bind(&gotoExceptionHandler);
1484         AsmInterpreterCall::DispatchCall(assembler, r12, opRegister, callTargetRegister, methodRegister, rsi, true);
1485     }
1486 
1487     __ Bind(&stackOverflow);
1488     {
1489         [[maybe_unused]] TempRegisterScope scope(assembler);
1490         Register temp = __ TempRegister();
1491         AsmInterpreterCall::ThrowStackOverflowExceptionAndReturnToAsmInterpBridgeFrame(assembler,
1492             glueRegister, rsp, temp);
1493     }
1494 }
1495 
1496 
DeoptPushAsmInterpBridgeFrame(ExtendedAssembler * assembler,Register context)1497 void OptimizedCall::DeoptPushAsmInterpBridgeFrame(ExtendedAssembler *assembler, Register context)
1498 {
1499     Label processLazyDeopt;
1500     Label exit;
1501     Register frameTypeRegister = r8;
1502     __ Movq(Operand(context, AsmStackContext::GetIsFrameLazyDeoptOffset(false)), frameTypeRegister);
1503     __ Cmpq(0, frameTypeRegister);
1504     __ Jne(&processLazyDeopt);
1505     {
1506         __ Pushq(static_cast<int64_t>(FrameType::ASM_INTERPRETER_BRIDGE_FRAME));
1507         __ Jmp(&exit);
1508     }
1509     __ Bind(&processLazyDeopt);
1510     {
1511         __ Pushq((static_cast<uint64_t>(FrameType::ASM_INTERPRETER_BRIDGE_FRAME) |
1512                  (1ULL << FrameIterator::LAZY_DEOPT_FLAG_BIT)));
1513     }
1514     __ Bind(&exit);
1515     __ Pushq(rbp);
1516     __ Pushq(0);    // pc
1517     __ Leaq(Operand(rsp, 24), rbp);  // 24: skip pc, prevSp and frame type
1518     __ PushAlignBytes();
1519     if (!assembler->FromInterpreterHandler()) {
1520         __ PushCppCalleeSaveRegisters();
1521     }
1522 }
1523 
1524 // Input: %rdi - glue
1525 // %rsi - deopt type
1526 // %rdx - maybeAcc
DeoptHandlerAsm(ExtendedAssembler * assembler)1527 void OptimizedCall::DeoptHandlerAsm(ExtendedAssembler *assembler)
1528 {
1529     __ BindAssemblerStub(RTSTUB_ID(DeoptHandlerAsm));
1530 
1531     Register glueReg = rdi;
1532     PushAsmBridgeFrame(assembler);
1533     __ Push(glueReg);
1534     __ PushCppCalleeSaveRegisters();
1535 
1536     __ Movq(rdi, rax); // glue
1537     Register deoptType = rsi;
1538     Register maybeAcc = rdx;
1539     __ Subq(FRAME_SLOT_SIZE, rsp);
1540     __ Pushq(maybeAcc);   // acc
1541     __ Pushq(deoptType);  // argv[0]
1542     __ Pushq(2);          // 2: argc
1543     __ Pushq(kungfu::RuntimeStubCSigns::ID_DeoptHandler);
1544     __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1545 
1546     __ Addq(5 * FRAME_SLOT_SIZE, rsp); // 5: skip runtimeId argc deoptType maybeAcc align
1547 
1548     Register context = rsi;
1549     __ Movq(rax, context);
1550 
1551     Label target;
1552     __ PopCppCalleeSaveRegisters();
1553     __ Pop(glueReg);
1554 
1555     Label stackOverflow;
1556     __ Cmpq(JSTaggedValue::VALUE_EXCEPTION, rax);
1557     __ Je(&stackOverflow);
1558 
1559     __ Movq(Operand(context, AsmStackContext::GetCallerFpOffset(false)), rbp);
1560     __ Movq(Operand(context, AsmStackContext::GetCallFrameTopOffset(false)), rsp);
1561     __ Subq(FRAME_SLOT_SIZE, rsp); // skip lr
1562 
1563     DeoptPushAsmInterpBridgeFrame(assembler, context);
1564     __ Callq(&target);
1565     PopAsmInterpBridgeFrame(assembler);
1566     __ Ret();
1567     __ Bind(&target);
1568     DeoptEnterAsmInterpOrBaseline(assembler);
1569     __ Int3();
1570 
1571     __ Bind(&stackOverflow);
1572     {
1573         __ Movq(rdi, rax);
1574         __ Pushq(0); // argc
1575         __ Pushq(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException);
1576         __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1577         __ Addq(FRAME_SLOT_SIZE * 3, rsp); // 3 : skip runtimeId argc & type
1578         __ Popq(rbp);
1579         __ Ret();
1580     }
1581 }
1582 #undef __
1583 }  // namespace panda::ecmascript::x64
1584