• 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/ecma_runtime_call_info.h"
22 #include "ecmascript/frames.h"
23 #include "ecmascript/js_function.h"
24 #include "ecmascript/js_thread.h"
25 #include "ecmascript/js_generator_object.h"
26 #include "ecmascript/message_string.h"
27 #include "ecmascript/method.h"
28 #include "ecmascript/runtime_call_id.h"
29 
30 namespace panda::ecmascript::x64 {
31 #define __ assembler->
32 
33 // Generate code for Entering asm interpreter
34 // Input: glue           - %rdi
35 //        callTarget     - %rsi
36 //        method         - %rdx
37 //        callField      - %rcx
38 //        argc           - %r8
39 //        argv           - %r9(<callTarget, newTarget, this> are at the beginning of argv)
AsmInterpreterEntry(ExtendedAssembler * assembler)40 void AsmInterpreterCall::AsmInterpreterEntry(ExtendedAssembler *assembler)
41 {
42     __ BindAssemblerStub(RTSTUB_ID(AsmInterpreterEntry));
43     Label target;
44     // push asm interpreter entry frame
45     size_t begin = __ GetCurrentPosition();
46     PushAsmInterpEntryFrame(assembler);
47     __ Callq(&target);
48     PopAsmInterpEntryFrame(assembler);
49     size_t end = __ GetCurrentPosition();
50     if ((end - begin) != FrameCompletionPos::X64EntryFrameDuration) {
51         LOG_COMPILER(FATAL) << (end - begin) << " != " << FrameCompletionPos::X64EntryFrameDuration
52                             << "This frame has been modified, and the offset EntryFrameDuration should be updated too.";
53     }
54     __ Ret();
55 
56     __ Bind(&target);
57     AsmInterpEntryDispatch(assembler);
58 }
59 
60 // Generate code for generator re-enter asm interpreter
61 // c++ calling convention
62 // Input: %rdi - glue
63 //        %rsi - context(GeneratorContext)
GeneratorReEnterAsmInterp(ExtendedAssembler * assembler)64 void AsmInterpreterCall::GeneratorReEnterAsmInterp(ExtendedAssembler *assembler)
65 {
66     __ BindAssemblerStub(RTSTUB_ID(GeneratorReEnterAsmInterp));
67     Label target;
68     size_t begin = __ GetCurrentPosition();
69     PushAsmInterpEntryFrame(assembler);
70     __ Callq(&target);
71     PopAsmInterpEntryFrame(assembler);
72     size_t end = __ GetCurrentPosition();
73     if ((end - begin) != FrameCompletionPos::X64EntryFrameDuration) {
74         LOG_COMPILER(FATAL) << (end - begin) << " != " << FrameCompletionPos::X64EntryFrameDuration
75                             << "This frame has been modified, and the offset EntryFrameDuration should be updated too.";
76     }
77     __ Ret();
78 
79     __ Bind(&target);
80     GeneratorReEnterAsmInterpDispatch(assembler);
81 }
82 
GeneratorReEnterAsmInterpDispatch(ExtendedAssembler * assembler)83 void AsmInterpreterCall::GeneratorReEnterAsmInterpDispatch(ExtendedAssembler *assembler)
84 {
85     Register glueRegister = __ GlueRegister();
86     Register contextRegister = rsi;
87     Register prevSpRegister = rbp;
88 
89     Register callTargetRegister = r9;
90     Register methodRegister = rcx;
91     Register tempRegister = r11;  // can not be used to store any variable
92     Register opRegister = r8;  // can not be used to store any variable
93     __ Movq(Operand(rsi, GeneratorContext::GENERATOR_METHOD_OFFSET), callTargetRegister);
94     __ Movq(Operand(callTargetRegister, JSFunctionBase::METHOD_OFFSET), methodRegister);
95 
96     Label stackOverflow;
97 
98     Register fpRegister = r10;
99     __ Movq(rsp, fpRegister);
100     Register nRegsRegister = rdx;
101     Register regsArrayRegister = r12;
102     Register thisRegister = r15;
103     // push context regs
104     __ Movl(Operand(rsi, GeneratorContext::GENERATOR_NREGS_OFFSET), nRegsRegister);
105     __ Movq(Operand(rsi, GeneratorContext::GENERATOR_THIS_OFFSET), thisRegister);
106     __ Movq(Operand(rsi, GeneratorContext::GENERATOR_REGS_ARRAY_OFFSET), regsArrayRegister);
107     __ Addq(TaggedArray::DATA_OFFSET, regsArrayRegister);
108     PushArgsWithArgvAndCheckStack(assembler, glueRegister, nRegsRegister, regsArrayRegister, tempRegister, opRegister,
109         &stackOverflow);
110 
111     // newSp
112     Register newSpRegister = r8;
113     __ Movq(rsp, newSpRegister);
114 
115     // resume asm interp frame
116     Register pcRegister = r12;
117     PushGeneratorFrameState(assembler, prevSpRegister, fpRegister, callTargetRegister, thisRegister, methodRegister,
118         contextRegister, pcRegister, tempRegister);
119 
120     // call bc stub
121     DispatchCall(assembler, pcRegister, newSpRegister, methodRegister);
122     __ Bind(&stackOverflow);
123     {
124         ThrowStackOverflowExceptionAndReturn(assembler, glueRegister, fpRegister, tempRegister);
125     }
126 }
127 
128 // Input: glue           - %rdi
129 //        callTarget     - %rsi
130 //        method         - %rdx
131 //        callField      - %rcx
132 //        argc           - %r8
133 //        argv           - %r9(<callTarget, newTarget, this> are at the beginning of argv)
134 //        prevSp         - %rbp
AsmInterpEntryDispatch(ExtendedAssembler * assembler)135 void AsmInterpreterCall::AsmInterpEntryDispatch(ExtendedAssembler *assembler)
136 {
137     Label notJSFunction;
138     Label callNativeEntry;
139     Label callJSFunctionEntry;
140     Label notCallable;
141     Register glueRegister = rdi;
142     Register callTargetRegister = rsi;
143     Register argvRegister = r9;
144     Register bitFieldRegister = r12;
145     Register tempRegister = r11;  // can not be used to store any variable
146     __ Movq(Operand(callTargetRegister, TaggedObject::HCLASS_OFFSET), tempRegister);  // hclass
147     __ Movq(Operand(tempRegister, JSHClass::BIT_FIELD_OFFSET), bitFieldRegister);
148     __ Cmpb(static_cast<int32_t>(JSType::JS_FUNCTION_FIRST), bitFieldRegister);
149     __ Jb(&notJSFunction);
150     __ Cmpb(static_cast<int32_t>(JSType::JS_FUNCTION_LAST), bitFieldRegister);
151     __ Jbe(&callJSFunctionEntry);
152     __ Bind(&notJSFunction);
153     {
154         __ Testq(static_cast<int64_t>(1ULL << JSHClass::CallableBit::START_BIT), bitFieldRegister);
155         __ Jz(&notCallable);
156         // fall through
157     }
158     __ Bind(&callNativeEntry);
159     CallNativeEntry(assembler);
160     __ Bind(&callJSFunctionEntry);
161     {
162         Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
163         __ Btq(MethodLiteral::IsNativeBit::START_BIT, callFieldRegister);
164         __ Jb(&callNativeEntry);
165 
166         __ Leaq(Operand(argvRegister, NUM_MANDATORY_JSFUNC_ARGS * JSTaggedValue::TaggedTypeSize()),
167             argvRegister);
168         JSCallCommonEntry(assembler, JSCallMode::CALL_ENTRY);
169     }
170     __ Bind(&notCallable);
171     {
172         __ Movq(glueRegister, rax);  // glue
173         __ Pushq(0);                 // argc
174         Register runtimeIdRegister = r12;
175         __ Movq(kungfu::RuntimeStubCSigns::ID_ThrowNotCallableException, runtimeIdRegister);
176         __ Pushq(runtimeIdRegister);  // runtimeId
177         Register trampolineIdRegister = r12;
178         Register trampolineRegister = r10;
179         __ Movq(kungfu::RuntimeStubCSigns::ID_CallRuntime, trampolineIdRegister);
180         __ Movq(Operand(rax, trampolineIdRegister, Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)),
181             trampolineRegister);
182         __ Callq(trampolineRegister);
183         __ Addq(16, rsp);  // 16: skip argc and runtime_id
184         __ Ret();
185     }
186 }
187 
PushFrameState(ExtendedAssembler * assembler,Register prevSpRegister,Register fpRegister,Register callTargetRegister,Register thisRegister,Register methodRegister,Register pcRegister,Register operatorRegister)188 void AsmInterpreterCall::PushFrameState(ExtendedAssembler *assembler, Register prevSpRegister, Register fpRegister,
189     Register callTargetRegister, Register thisRegister, Register methodRegister, Register pcRegister,
190     Register operatorRegister)
191 {
192     __ Pushq(static_cast<int32_t>(FrameType::ASM_INTERPRETER_FRAME));  // frame type
193     __ Pushq(prevSpRegister);                                          // prevSp
194     __ Movq(Operand(methodRegister, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET), pcRegister);
195     __ Pushq(pcRegister);                                              // pc
196     __ Pushq(fpRegister);                                              // fp
197     __ Pushq(0);                                                       // jumpSizeAfterCall
198     __ Movq(Operand(callTargetRegister, JSFunction::LEXICAL_ENV_OFFSET), operatorRegister);
199     __ Pushq(operatorRegister);                                        // env
200     __ Pushq(JSTaggedValue::Hole().GetRawData());                      // acc
201     __ Pushq(thisRegister);                                            // thisObj
202     __ Pushq(callTargetRegister);                                      // callTarget
203 }
204 
PushGeneratorFrameState(ExtendedAssembler * assembler,Register prevSpRegister,Register fpRegister,Register callTargetRegister,Register thisRegister,Register methodRegister,Register contextRegister,Register pcRegister,Register operatorRegister)205 void AsmInterpreterCall::PushGeneratorFrameState(ExtendedAssembler *assembler, Register prevSpRegister,
206     Register fpRegister, Register callTargetRegister, Register thisRegister, Register methodRegister,
207     Register contextRegister, Register pcRegister, Register operatorRegister)
208 {
209     __ Pushq(static_cast<int32_t>(FrameType::ASM_INTERPRETER_FRAME));  // frame type
210     __ Pushq(prevSpRegister);                                          // prevSp
211     __ Movq(Operand(methodRegister, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET), pcRegister);
212     __ Movl(Operand(contextRegister, GeneratorContext::GENERATOR_BC_OFFSET_OFFSET), operatorRegister);
213     __ Addq(operatorRegister, pcRegister);
214     __ Pushq(pcRegister);                                              // pc
215     __ Pushq(fpRegister);                                              // fp
216     __ Pushq(0);                                                       // jumpSizeAfterCall
217     __ Movq(Operand(contextRegister, GeneratorContext::GENERATOR_LEXICALENV_OFFSET), operatorRegister);
218     __ Pushq(operatorRegister);                                        // env
219     __ Movq(Operand(contextRegister, GeneratorContext::GENERATOR_ACC_OFFSET), operatorRegister);
220     __ Pushq(operatorRegister);                                        // acc
221     __ Pushq(thisRegister);                                            // thisObj
222     __ Pushq(callTargetRegister);                                      // callTarget
223 }
224 
PushAsmInterpEntryFrame(ExtendedAssembler * assembler)225 void AsmInterpreterCall::PushAsmInterpEntryFrame(ExtendedAssembler *assembler)
226 {
227     size_t begin = __ GetCurrentPosition();
228     if (!assembler->FromInterpreterHandler()) {
229         __ PushCppCalleeSaveRegisters();
230     }
231     Register fpRegister = r10;
232     __ Pushq(rdi);
233     __ PushAlignBytes();
234     __ Movq(Operand(rdi, JSThread::GlueData::GetLeaveFrameOffset(false)), fpRegister);
235     // construct asm interpreter entry frame
236     __ Pushq(rbp);
237     __ Pushq(static_cast<int64_t>(FrameType::ASM_INTERPRETER_ENTRY_FRAME));
238     __ Pushq(fpRegister);
239     __ Pushq(0);    // pc
240     if (!assembler->FromInterpreterHandler()) {
241         size_t end = __ GetCurrentPosition();
242         if ((end - begin) != FrameCompletionPos::X64CppToAsmInterp) {
243             LOG_COMPILER(FATAL) << (end - begin) << " != " << FrameCompletionPos::X64CppToAsmInterp
244                                 << "This frame has been modified, and the offset CppToAsmInterp should be updated too.";
245         }
246     }
247     __ Leaq(Operand(rsp, 3 * FRAME_SLOT_SIZE), rbp);  // 24: skip frame type, prevSp and pc
248 }
249 
PopAsmInterpEntryFrame(ExtendedAssembler * assembler)250 void AsmInterpreterCall::PopAsmInterpEntryFrame(ExtendedAssembler *assembler)
251 {
252     __ Addq(8, rsp);   // 8: skip pc
253     Register fpRegister = r10;
254     __ Popq(fpRegister);
255     __ Addq(FRAME_SLOT_SIZE, rsp);  // 8: skip frame type
256     __ Popq(rbp);
257     __ PopAlignBytes();
258     __ Popq(rdi);
259     __ Movq(fpRegister, Operand(rdi, JSThread::GlueData::GetLeaveFrameOffset(false)));
260     size_t begin = __ GetCurrentPosition();
261     if (!assembler->FromInterpreterHandler()) {
262         __ PopCppCalleeSaveRegisters();
263         size_t end = __ GetCurrentPosition();
264         if ((end - begin) != FrameCompletionPos::X64AsmInterpToCpp) {
265             LOG_COMPILER(FATAL) << (end - begin) << " != " << FrameCompletionPos::X64AsmInterpToCpp
266                                 << "This frame has been modified, and the offset AsmInterpToCp should be updated too.";
267         }
268     }
269 }
270 
GetDeclaredNumArgsFromCallField(ExtendedAssembler * assembler,Register callFieldRegister,Register declaredNumArgsRegister)271 void AsmInterpreterCall::GetDeclaredNumArgsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister,
272     Register declaredNumArgsRegister)
273 {
274     __ Movq(callFieldRegister, declaredNumArgsRegister);
275     __ Shrq(MethodLiteral::NumArgsBits::START_BIT, declaredNumArgsRegister);
276     __ Andq(MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, declaredNumArgsRegister);
277 }
278 
GetNumVregsFromCallField(ExtendedAssembler * assembler,Register callFieldRegister,Register numVregsRegister)279 void AsmInterpreterCall::GetNumVregsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister,
280     Register numVregsRegister)
281 {
282     __ Movq(callFieldRegister, numVregsRegister);
283     __ Shrq(MethodLiteral::NumVregsBits::START_BIT, numVregsRegister);
284     __ Andq(MethodLiteral::NumVregsBits::Mask() >> MethodLiteral::NumVregsBits::START_BIT, numVregsRegister);
285 }
286 
JSCallCommonEntry(ExtendedAssembler * assembler,JSCallMode mode)287 void AsmInterpreterCall::JSCallCommonEntry(ExtendedAssembler *assembler, JSCallMode mode)
288 {
289     Label stackOverflow;
290     Register glueRegister = __ GlueRegister();
291     Register fpRegister = __ AvailableRegister1();
292     Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
293     Register argcRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
294     // save fp
295     __ Movq(rsp, fpRegister);
296     Register declaredNumArgsRegister = __ AvailableRegister2();
297     GetDeclaredNumArgsFromCallField(assembler, callFieldRegister, declaredNumArgsRegister);
298 
299     Label slowPathEntry;
300     Label fastPathEntry;
301     Label pushCallThis;
302     auto argc = kungfu::AssemblerModule::GetArgcFromJSCallMode(mode);
303     if (argc >= 0) {
304         __ Cmpq(argc, declaredNumArgsRegister);
305     } else {
306         __ Cmpq(argcRegister, declaredNumArgsRegister);
307     }
308     __ Jne(&slowPathEntry);
309     __ Bind(&fastPathEntry);
310     JSCallCommonFastPath(assembler, mode, &stackOverflow);
311     __ Bind(&pushCallThis);
312     PushCallThis(assembler, mode, &stackOverflow);
313     __ Bind(&slowPathEntry);
314     JSCallCommonSlowPath(assembler, mode, &fastPathEntry, &pushCallThis, &stackOverflow);
315 
316     __ Bind(&stackOverflow);
317     if (kungfu::AssemblerModule::IsJumpToCallCommonEntry(mode)) {
318         __ Movq(fpRegister, rsp);
319         Register tempRegister = __ AvailableRegister1();
320         // only glue and acc are useful in exception handler
321         if (glueRegister != r13) {
322             __ Movq(glueRegister, r13);
323         }
324         Register acc = rsi;
325         __ Movq(JSTaggedValue::VALUE_EXCEPTION, acc);
326         Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
327         Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
328         // Reload pc to make sure stack trace is right
329         __ Movq(callTargetRegister, tempRegister);
330         __ Movq(Operand(methodRegister, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET), r12);  // pc: r12
331         // Reload constpool and profileInfo to make sure gc map work normally
332         __ Movq(Operand(methodRegister, Method::PROFILE_TYPE_INFO_OFFSET), r14);       // profileTypeInfo: r14
333         __ Movq(Operand(methodRegister, Method::CONSTANT_POOL_OFFSET), rbx);           // constantPool: rbx
334 
335         __ Movq(kungfu::BytecodeStubCSigns::ID_ThrowStackOverflowException, tempRegister);
336         __ Movq(Operand(glueRegister, tempRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)),
337             tempRegister);
338         __ Jmp(tempRegister);
339     } else {
340         [[maybe_unused]] TempRegisterScope scope(assembler);
341         Register temp = __ TempRegister();
342         ThrowStackOverflowExceptionAndReturn(assembler, glueRegister, fpRegister, temp);
343     }
344 }
345 
346 // void PushCallArgsxAndDispatch(uintptr_t glue, uintptr_t sp, uint64_t callTarget, uintptr_t method,
347 //     uint64_t callField, ...)
348 // GHC calling convention
349 // Input1: for callarg0/1/2/3         Input2: for callrange
350 // %r13 - glue                        // %r13 - glue
351 // %rbp - sp                          // %rbp - sp
352 // %r12 - callTarget                  // %r12 - callTarget
353 // %rbx - method                      // %rbx - method
354 // %r14 - callField                   // %r14 - callField
355 // %rsi - arg0                        // %rsi - actualArgc
356 // %rdi - arg1                        // %rdi - argv
357 // %r8  - arg2
PushCallThisRangeAndDispatch(ExtendedAssembler * assembler)358 void AsmInterpreterCall::PushCallThisRangeAndDispatch(ExtendedAssembler *assembler)
359 {
360     __ BindAssemblerStub(RTSTUB_ID(PushCallThisRangeAndDispatch));
361     JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_WITH_ARGV);
362 }
363 
PushCallRangeAndDispatch(ExtendedAssembler * assembler)364 void AsmInterpreterCall::PushCallRangeAndDispatch(ExtendedAssembler *assembler)
365 {
366     __ BindAssemblerStub(RTSTUB_ID(PushCallRangeAndDispatch));
367     JSCallCommonEntry(assembler, JSCallMode::CALL_WITH_ARGV);
368 }
369 
PushCallNewAndDispatch(ExtendedAssembler * assembler)370 void AsmInterpreterCall::PushCallNewAndDispatch(ExtendedAssembler *assembler)
371 {
372     __ BindAssemblerStub(RTSTUB_ID(PushCallNewAndDispatch));
373     JSCallCommonEntry(assembler, JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV);
374 }
375 
PushSuperCallAndDispatch(ExtendedAssembler * assembler)376 void AsmInterpreterCall::PushSuperCallAndDispatch(ExtendedAssembler *assembler)
377 {
378     __ BindAssemblerStub(RTSTUB_ID(PushSuperCallAndDispatch));
379     JSCallCommonEntry(assembler, JSCallMode::SUPER_CALL_WITH_ARGV);
380 }
381 
PushCallArgs3AndDispatch(ExtendedAssembler * assembler)382 void AsmInterpreterCall::PushCallArgs3AndDispatch(ExtendedAssembler *assembler)
383 {
384     __ BindAssemblerStub(RTSTUB_ID(PushCallArgs3AndDispatch));
385     JSCallCommonEntry(assembler, JSCallMode::CALL_ARG3);
386 }
387 
PushCallArgs2AndDispatch(ExtendedAssembler * assembler)388 void AsmInterpreterCall::PushCallArgs2AndDispatch(ExtendedAssembler *assembler)
389 {
390     __ BindAssemblerStub(RTSTUB_ID(PushCallArgs2AndDispatch));
391     JSCallCommonEntry(assembler, JSCallMode::CALL_ARG2);
392 }
393 
PushCallArg1AndDispatch(ExtendedAssembler * assembler)394 void AsmInterpreterCall::PushCallArg1AndDispatch(ExtendedAssembler *assembler)
395 {
396     __ BindAssemblerStub(RTSTUB_ID(PushCallArg1AndDispatch));
397     JSCallCommonEntry(assembler, JSCallMode::CALL_ARG1);
398 }
399 
PushCallArg0AndDispatch(ExtendedAssembler * assembler)400 void AsmInterpreterCall::PushCallArg0AndDispatch(ExtendedAssembler *assembler)
401 {
402     __ BindAssemblerStub(RTSTUB_ID(PushCallArg0AndDispatch));
403     JSCallCommonEntry(assembler, JSCallMode::CALL_ARG0);
404 }
PushCallThisArg0AndDispatch(ExtendedAssembler * assembler)405 void AsmInterpreterCall::PushCallThisArg0AndDispatch(ExtendedAssembler *assembler)
406 {
407     __ BindAssemblerStub(RTSTUB_ID(PushCallThisArg0AndDispatch));
408     JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG0);
409 }
410 
PushCallThisArg1AndDispatch(ExtendedAssembler * assembler)411 void AsmInterpreterCall::PushCallThisArg1AndDispatch(ExtendedAssembler *assembler)
412 {
413     __ BindAssemblerStub(RTSTUB_ID(PushCallThisArg1AndDispatch));
414     JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG1);
415 }
416 
PushCallThisArgs2AndDispatch(ExtendedAssembler * assembler)417 void AsmInterpreterCall::PushCallThisArgs2AndDispatch(ExtendedAssembler *assembler)
418 {
419     __ BindAssemblerStub(RTSTUB_ID(PushCallThisArgs2AndDispatch));
420     JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG2);
421 }
422 
PushCallThisArgs3AndDispatch(ExtendedAssembler * assembler)423 void AsmInterpreterCall::PushCallThisArgs3AndDispatch(ExtendedAssembler *assembler)
424 {
425     __ BindAssemblerStub(RTSTUB_ID(PushCallThisArgs3AndDispatch));
426     JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG3);
427 }
428 
JSCallCommonFastPath(ExtendedAssembler * assembler,JSCallMode mode,Label * stackOverflow)429 void AsmInterpreterCall::JSCallCommonFastPath(ExtendedAssembler *assembler, JSCallMode mode, Label *stackOverflow)
430 {
431     Register glueRegister = __ GlueRegister();
432     Register arg0 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
433     Register arg1 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
434 
435     Label pushCallThis;
436     auto argc = kungfu::AssemblerModule::GetArgcFromJSCallMode(mode);
437     // call range
438     if (argc < 0) {
439         Register argcRegister = arg0;
440         Register argvRegister = arg1;
441         __ Cmpq(0, argcRegister);
442         __ Jbe(&pushCallThis);
443         // fall through
444         {
445             [[maybe_unused]] TempRegisterScope scope(assembler);
446             Register opRegister = __ TempRegister();
447             Register op2Register = __ AvailableRegister2();
448             PushArgsWithArgvAndCheckStack(assembler, glueRegister, argcRegister, argvRegister, opRegister, op2Register,
449                 stackOverflow);
450         }
451         __ Bind(&pushCallThis);
452     } else if (argc > 0) {
453         if (argc > 2) { // 2: call arg2
454             if (mode == JSCallMode::CALL_THIS_ARG3_WITH_RETURN) {
455                 Register arg2 = __ CppJSCallAvailableRegister1();
456                 __ Pushq(arg2);
457             } else {
458                 Register arg2 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG2);
459                 __ Pushq(arg2);
460             }
461         }
462         if (argc > 1) {
463             __ Pushq(arg1);
464         }
465         if (argc > 0) {
466             __ Pushq(arg0);
467         }
468     }
469 }
470 
JSCallCommonSlowPath(ExtendedAssembler * assembler,JSCallMode mode,Label * fastPathEntry,Label * pushCallThis,Label * stackOverflow)471 void AsmInterpreterCall::JSCallCommonSlowPath(ExtendedAssembler *assembler, JSCallMode mode,
472                                               Label *fastPathEntry, Label *pushCallThis, Label *stackOverflow)
473 {
474     Register glueRegister = __ GlueRegister();
475     Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
476     Register argcRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
477     Register arg0 = argcRegister;
478     Register arg1 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
479     Label noExtraEntry;
480     Label pushArgsEntry;
481 
482     auto argc = kungfu::AssemblerModule::GetArgcFromJSCallMode(mode);
483     Register declaredNumArgsRegister = __ AvailableRegister2();
484     __ Testq(MethodLiteral::HaveExtraBit::Mask(), callFieldRegister);
485     __ Jz(&noExtraEntry);
486     // extra entry
487     {
488         [[maybe_unused]] TempRegisterScope scope(assembler);
489         Register tempArgcRegister = __ TempRegister();
490         if (argc >= 0) {
491             __ PushArgc(argc, tempArgcRegister);
492         } else {
493             __ PushArgc(argcRegister, tempArgcRegister);
494         }
495     }
496     __ Bind(&noExtraEntry);
497     {
498         if (argc == 0) {
499             Register op1 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
500             [[maybe_unused]] TempRegisterScope scope(assembler);
501             Register op2 = __ TempRegister();
502             PushUndefinedWithArgcAndCheckStack(assembler, glueRegister, declaredNumArgsRegister, op1, op2,
503                 stackOverflow);
504             __ Jmp(fastPathEntry);
505             return;
506         }
507         [[maybe_unused]] TempRegisterScope scope(assembler);
508         Register diffRegister = __ TempRegister();
509         __ Movq(declaredNumArgsRegister, diffRegister);
510         if (argc >= 0) {
511             __ Subq(argc, diffRegister);
512         } else {
513             __ Subq(argcRegister, diffRegister);
514         }
515         __ Cmpq(0, diffRegister);
516         __ Jle(&pushArgsEntry);
517         PushUndefinedWithArgc(assembler, diffRegister);
518         __ Jmp(fastPathEntry);
519     }
520     __ Bind(&pushArgsEntry);
521     __ Testq(MethodLiteral::HaveExtraBit::Mask(), callFieldRegister);
522     __ Jnz(fastPathEntry);
523     // arg1, declare must be 0
524     if (argc == 1) {
525         __ Jmp(pushCallThis);
526         return;
527     }
528     // decalare < actual
529     __ Cmpq(0, declaredNumArgsRegister);
530     __ Je(pushCallThis);
531     if (argc < 0) {
532         Register argvRegister = arg1;
533         [[maybe_unused]] TempRegisterScope scope(assembler);
534         Register opRegister = __ TempRegister();
535         PushArgsWithArgvAndCheckStack(assembler, glueRegister, declaredNumArgsRegister, argvRegister, opRegister,
536             opRegister, stackOverflow);
537     } else if (argc > 0) {
538         Label pushArgs0;
539         if (argc > 2) { // 2: call arg2
540             // decalare is 2 or 1 now
541             __ Cmpq(1, declaredNumArgsRegister);
542             __ Je(&pushArgs0);
543             __ Pushq(arg1);
544         }
545         if (argc > 1) {
546             __ Bind(&pushArgs0);
547             // decalare is is 1 now
548             __ Pushq(arg0);
549         }
550     }
551     __ Jmp(pushCallThis);
552 }
553 
GetThisRegsiter(ExtendedAssembler * assembler,JSCallMode mode,Register defaultRegister)554 Register AsmInterpreterCall::GetThisRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister)
555 {
556     switch (mode) {
557         case JSCallMode::CALL_GETTER:
558         case JSCallMode::CALL_THIS_ARG0:
559             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
560         case JSCallMode::CALL_SETTER:
561         case JSCallMode::CALL_THIS_ARG1:
562             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
563         case JSCallMode::CALL_THIS_ARG2:
564         case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
565         case JSCallMode::CALL_THIS_WITH_ARGV:
566         case JSCallMode::SUPER_CALL_WITH_ARGV:
567         case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
568             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG2);
569         case JSCallMode::CALL_THIS_ARG3:
570             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG3);
571         case JSCallMode::CALL_ENTRY:
572         case JSCallMode::CALL_FROM_AOT: {
573             Register argvRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
574             __ Movq(Operand(argvRegister, -FRAME_SLOT_SIZE), defaultRegister);  // 8: this is just before the argv list
575             return defaultRegister;
576         }
577         case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
578             return __ CppJSCallAvailableRegister2();
579         case JSCallMode::CALL_THIS_ARGV_WITH_RETURN: {
580             return __ CppJSCallAvailableRegister1();
581         }
582         default:
583             LOG_ECMA(FATAL) << "this branch is unreachable";
584             UNREACHABLE();
585     }
586     return rInvalid;
587 }
588 
GetNewTargetRegsiter(ExtendedAssembler * assembler,JSCallMode mode,Register defaultRegister)589 Register AsmInterpreterCall::GetNewTargetRegsiter(ExtendedAssembler *assembler, JSCallMode mode,
590                                                   Register defaultRegister)
591 {
592     switch (mode) {
593         case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
594         case JSCallMode::CALL_THIS_WITH_ARGV:
595             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
596         case JSCallMode::SUPER_CALL_WITH_ARGV:
597         case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
598             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG3);
599         case JSCallMode::CALL_FROM_AOT:
600         case JSCallMode::CALL_ENTRY: {
601             Register argvRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
602             // -2: new Target offset
603             __ Movq(Operand(argvRegister, -2 * FRAME_SLOT_SIZE), defaultRegister);
604             return defaultRegister;
605         }
606         default:
607             LOG_ECMA(FATAL) << "this branch is unreachable";
608             UNREACHABLE();
609     }
610     return rInvalid;
611 }
612 
613 // Input: %r14 - callField
614 //        %rdi - argv
PushCallThis(ExtendedAssembler * assembler,JSCallMode mode,Label * stackOverflow)615 void AsmInterpreterCall::PushCallThis(ExtendedAssembler *assembler, JSCallMode mode, Label *stackOverflow)
616 {
617     Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
618     Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
619     Register thisRegister = __ AvailableRegister2();
620 
621     Label pushVregs;
622     Label pushNewTarget;
623     Label pushCallTarget;
624     bool haveThis = kungfu::AssemblerModule::JSModeHaveThisArg(mode);
625     bool haveNewTarget = kungfu::AssemblerModule::JSModeHaveNewTargetArg(mode);
626     if (!haveThis) {
627         __ Movq(JSTaggedValue::VALUE_UNDEFINED, thisRegister);  // default this: undefined
628     } else {
629         Register thisArgRegister = GetThisRegsiter(assembler, mode, thisRegister);
630         if (thisRegister != thisArgRegister) {
631             __ Movq(thisArgRegister, thisRegister);
632         }
633     }
634     __ Testb(CALL_TYPE_MASK, callFieldRegister);
635     __ Jz(&pushVregs);
636     // fall through
637     __ Testq(MethodLiteral::HaveThisBit::Mask(), callFieldRegister);
638     __ Jz(&pushNewTarget);
639     // push this
640     if (!haveThis) {
641         __ Pushq(JSTaggedValue::Undefined().GetRawData());
642     } else {
643         __ Pushq(thisRegister);
644     }
645     // fall through
646     __ Bind(&pushNewTarget);
647     {
648         __ Testq(MethodLiteral::HaveNewTargetBit::Mask(), callFieldRegister);
649         __ Jz(&pushCallTarget);
650         if (!haveNewTarget) {
651             __ Pushq(JSTaggedValue::Undefined().GetRawData());
652         } else {
653             [[maybe_unused]] TempRegisterScope scope(assembler);
654             Register defaultRegister = __ TempRegister();
655             Register newTargetRegister = GetNewTargetRegsiter(assembler, mode, defaultRegister);
656             __ Pushq(newTargetRegister);
657         }
658     }
659     // fall through
660     __ Bind(&pushCallTarget);
661     {
662         __ Testq(MethodLiteral::HaveFuncBit::Mask(), callFieldRegister);
663         __ Jz(&pushVregs);
664         __ Pushq(callTargetRegister);
665     }
666     // fall through
667     __ Bind(&pushVregs);
668     {
669         PushVregs(assembler, stackOverflow);
670     }
671 }
672 
673 // Input: %rbp - sp
674 //        %r12 - callTarget
675 //        %rbx - method
676 //        %r14 - callField
677 //        %rdx - jumpSizeAfterCall
678 //        %r10 - fp
PushVregs(ExtendedAssembler * assembler,Label * stackOverflow)679 void AsmInterpreterCall::PushVregs(ExtendedAssembler *assembler, Label *stackOverflow)
680 {
681     Register glueRegister = __ GlueRegister();
682     Register prevSpRegister = rbp;
683     Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
684     Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
685     Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
686     Register fpRegister = __ AvailableRegister1();
687     Register thisRegister = __ AvailableRegister2();
688 
689     Label pushFrameState;
690 
691     [[maybe_unused]] TempRegisterScope scope(assembler);
692     Register tempRegister = __ TempRegister();
693     // args register can reused now.
694     Register pcRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
695     Register numVregsRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
696     GetNumVregsFromCallField(assembler, callFieldRegister, numVregsRegister);
697     __ Cmpq(0, numVregsRegister);
698     __ Jz(&pushFrameState);
699     Register temp2Register = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);  // reuse
700     PushUndefinedWithArgcAndCheckStack(assembler, glueRegister, numVregsRegister, tempRegister, temp2Register,
701         stackOverflow);
702     // fall through
703     Register newSpRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
704     __ Bind(&pushFrameState);
705     {
706         StackOverflowCheck(assembler, glueRegister, numVregsRegister, tempRegister, temp2Register, stackOverflow);
707         __ Movq(rsp, newSpRegister);
708 
709         PushFrameState(assembler, prevSpRegister, fpRegister,
710             callTargetRegister, thisRegister, methodRegister, pcRegister, tempRegister);
711     }
712     DispatchCall(assembler, pcRegister, newSpRegister, methodRegister);
713 }
714 
715 // Input: %r13 - glue
716 //        %rbp - sp
717 //        %r12 - callTarget
718 //        %rbx - method
DispatchCall(ExtendedAssembler * assembler,Register pcRegister,Register newSpRegister,Register methodRegister,Register accRegister)719 void AsmInterpreterCall::DispatchCall(ExtendedAssembler *assembler, Register pcRegister,
720     Register newSpRegister, Register methodRegister, Register accRegister)
721 {
722     Register glueRegister = __ GlueRegister();
723     Label dispatchCall;
724     // align 16 bytes
725     __ Testq(15, rsp);  // 15: low 4 bits must be 0b0000
726     __ Jnz(&dispatchCall);
727     __ PushAlignBytes();
728     __ Bind(&dispatchCall);
729     // profileTypeInfo: r14
730     __ Movq(Operand(methodRegister, Method::PROFILE_TYPE_INFO_OFFSET), r14);
731     // glue may rdi
732     if (glueRegister != r13) {
733         __ Movq(glueRegister, r13);
734     }
735     // sp: rbp
736     __ Movq(newSpRegister, rbp);
737     // hotnessCounter: rdi
738     __ Movzwq(Operand(methodRegister, Method::LITERAL_INFO_OFFSET), rdi);
739     // constantPool: rbx
740     __ Movq(Operand(methodRegister, Method::CONSTANT_POOL_OFFSET), rbx);
741     // pc: r12
742     if (pcRegister != r12) {
743         __ Movq(pcRegister, r12);
744     }
745 
746     Register bcIndexRegister = rax;
747     Register tempRegister = __ AvailableRegister1();
748     __ Movzbq(Operand(pcRegister, 0), bcIndexRegister);
749     // acc: rsi
750     if (accRegister != rInvalid) {
751         ASSERT(accRegister == rsi);
752     } else {
753         __ Movq(JSTaggedValue::Hole().GetRawData(), rsi);
754     }
755     __ Movq(Operand(r13, bcIndexRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)), tempRegister);
756     __ Jmp(tempRegister);
757 }
758 
759 // uint64_t PushCallRangeAndDispatchNative(uintptr_t glue, uint32_t argc, JSTaggedType calltarget, uintptr_t argv[])
760 // c++ calling convention call js function
761 // Input: %rdi - glue
762 //        %rsi - nativeCode
763 //        %rdx - func
764 //        %rcx - thisValue
765 //        %r8  - argc
766 //        %r9  - argV (...)
PushCallRangeAndDispatchNative(ExtendedAssembler * assembler)767 void AsmInterpreterCall::PushCallRangeAndDispatchNative(ExtendedAssembler *assembler)
768 {
769     __ BindAssemblerStub(RTSTUB_ID(PushCallRangeAndDispatchNative));
770     CallNativeWithArgv(assembler, false);
771 }
772 
PushCallNewAndDispatchNative(ExtendedAssembler * assembler)773 void AsmInterpreterCall::PushCallNewAndDispatchNative(ExtendedAssembler *assembler)
774 {
775     __ BindAssemblerStub(RTSTUB_ID(PushCallNewAndDispatchNative));
776     CallNativeWithArgv(assembler, true);
777 }
778 
PushNewTargetAndDispatchNative(ExtendedAssembler * assembler)779 void AsmInterpreterCall::PushNewTargetAndDispatchNative(ExtendedAssembler *assembler)
780 {
781     __ BindAssemblerStub(RTSTUB_ID(PushNewTargetAndDispatchNative));
782     CallNativeWithArgv(assembler, true, true);
783 }
784 
CallNativeWithArgv(ExtendedAssembler * assembler,bool callNew,bool hasNewTarget)785 void AsmInterpreterCall::CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew, bool hasNewTarget)
786 {
787     Register glue = rdi;
788     Register nativeCode = rsi;
789     Register func = rdx;
790     Register thisValue = rcx;
791     Register numArgs = r8;
792     Register stackArgs = r9;
793     Register temporary = rax;
794     Register temporary2 = r11;
795     Register opNumArgs = r10;
796     Label aligned;
797     Label pushThis;
798     Label stackOverflow;
799 
800     PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_FRAME_WITH_ARGV);
801 
802     __ Push(numArgs);
803     __ Cmpq(0, numArgs);
804     __ Jz(&pushThis);
805     __ Movq(numArgs, opNumArgs);
806     PushArgsWithArgvAndCheckStack(assembler, glue, opNumArgs, stackArgs, temporary, temporary2, &stackOverflow);
807 
808     __ Bind(&pushThis);
809     __ Push(thisValue);
810     // new.target
811     if (callNew) {
812         if (hasNewTarget) {
813             Register newTarget = r12;
814             __ Movq(Operand(rbp, DOUBLE_SLOT_SIZE), newTarget);
815             __ Pushq(newTarget);
816         } else {
817             __ Pushq(func);
818         }
819     } else {
820         __ Pushq(JSTaggedValue::Undefined().GetRawData());
821     }
822     __ Pushq(func);
823     // 40: skip frame type, numArgs, func, newTarget and this
824     __ Leaq(Operand(rsp, numArgs, Times8, 5 * FRAME_SLOT_SIZE), rbp);
825     __ Movq(rsp, stackArgs);
826 
827     // push argc
828     __ Addl(NUM_MANDATORY_JSFUNC_ARGS, numArgs);
829     __ Pushq(numArgs);
830     // push thread
831     __ Pushq(glue);
832     // EcmaRuntimeCallInfo
833     __ Movq(rsp, rdi);
834 
835     __ Testq(0xf, rsp);  // 0xf: 0x1111
836     __ Jz(&aligned, Distance::Near);
837     __ PushAlignBytes();
838 
839     __ Bind(&aligned);
840     CallNativeInternal(assembler, nativeCode);
841     __ Ret();
842 
843     __ Bind(&stackOverflow);
844     {
845         Label aligneThrow;
846         __ Movq(static_cast<int32_t>(FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME),
847             Operand(rsp, FRAME_SLOT_SIZE));
848         __ Pushq(0);  // argc
849         __ Pushq(JSTaggedValue::VALUE_UNDEFINED);  // this
850         __ Pushq(JSTaggedValue::VALUE_UNDEFINED);  // newTarget
851         __ Pushq(JSTaggedValue::VALUE_UNDEFINED);  // callTarget
852 
853         __ Testq(0xf, rsp);  // 0xf: 0x1111
854         __ Jz(&aligneThrow, Distance::Near);
855         __ PushAlignBytes();
856 
857         __ Bind(&aligneThrow);
858         Register trampolineIdRegister = r9;
859         Register trampolineRegister = r10;
860         __ Movq(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException, trampolineIdRegister);
861         __ Movq(Operand(glue, trampolineIdRegister, Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)),
862             trampolineRegister);
863         __ Callq(trampolineRegister);
864 
865         // resume rsp
866         __ Movq(rbp, rsp);
867         __ Pop(rbp);
868         __ Ret();
869     }
870 }
871 
CallNativeEntry(ExtendedAssembler * assembler)872 void AsmInterpreterCall::CallNativeEntry(ExtendedAssembler *assembler)
873 {
874     Register glue = rdi;
875     Register argv = r9;
876     Register method = rdx;
877     Register function = rsi;
878     Register nativeCode = r10;
879 
880     __ PushAlignBytes();
881     __ Push(function);
882     // 24: skip thread & argc & returnAddr
883     __ Subq(3 * FRAME_SLOT_SIZE, rsp);
884     PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_ENTRY_FRAME);
885     __ Movq(Operand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET), nativeCode); // get native pointer
886     __ Movq(argv, r11);
887     // 16: skip numArgs & thread
888     __ Subq(2 * FRAME_SLOT_SIZE, r11);
889     // EcmaRuntimeCallInfo
890     __ Movq(r11, rdi);
891 
892     CallNativeInternal(assembler, nativeCode);
893 
894     // 40: skip function
895     __ Addq(5 * FRAME_SLOT_SIZE, rsp);
896     __ Ret();
897 }
898 
899 // uint64_t PushCallArgsAndDispatchNative(uintptr_t codeAddress, uintptr_t glue, uint32_t argc, ...)
900 // webkit_jscc calling convention call runtime_id's runtion function(c-abi)
901 // Input:        %rax - codeAddress
902 // stack layout: sp + N*8 argvN
903 //               ........
904 //               sp + 24: argv1
905 //               sp + 16: argv0
906 //               sp + 8:  actualArgc
907 //               sp:      thread
908 // construct Native Leave Frame
909 //               +--------------------------+
910 //               |     argV[N - 1]          |
911 //               |--------------------------|
912 //               |       . . . .            |
913 //               |--------------------------+
914 //               |     argV[2]=this         |
915 //               +--------------------------+
916 //               |     argV[1]=new-target   |
917 //               +--------------------------+
918 //               |     argV[0]=call-target  |
919 //               +--------------------------+ ---------
920 //               |       argc               |         ^
921 //               |--------------------------|         |
922 //               |       thread             |         |
923 //               |--------------------------|         |
924 //               |       returnAddr         |     BuiltinFrame
925 //               |--------------------------|         |
926 //               |       callsiteFp         |         |
927 //               |--------------------------|         |
928 //               |       frameType          |         v
929 //               +--------------------------+ ---------
930 
PushCallArgsAndDispatchNative(ExtendedAssembler * assembler)931 void AsmInterpreterCall::PushCallArgsAndDispatchNative(ExtendedAssembler *assembler)
932 {
933     __ BindAssemblerStub(RTSTUB_ID(PushCallArgsAndDispatchNative));
934     Register nativeCode = rax;
935     Register glue = rdi;
936 
937     __ Movq(Operand(rsp, FRAME_SLOT_SIZE), glue); // 8: glue
938     PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_FRAME);
939     __ Leaq(Operand(rbp, 2 * FRAME_SLOT_SIZE), rdi); // 16: skip argc & thread
940     __ PushAlignBytes();
941     CallNativeInternal(assembler, nativeCode);
942     __ Ret();
943 }
944 
PushBuiltinFrame(ExtendedAssembler * assembler,Register glue,FrameType type)945 void AsmInterpreterCall::PushBuiltinFrame(ExtendedAssembler *assembler,
946                                           Register glue, FrameType type)
947 {
948     __ Pushq(rbp);
949     __ Movq(rsp, Operand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
950     __ Pushq(static_cast<int32_t>(type));
951     __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);  // 8: skip frame type
952 }
953 
CallNativeInternal(ExtendedAssembler * assembler,Register nativeCode)954 void AsmInterpreterCall::CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode)
955 {
956     __ Callq(nativeCode);
957     // resume rsp
958     __ Movq(rbp, rsp);
959     __ Pop(rbp);
960 }
961 
962 // ResumeRspAndDispatch(uintptr_t glue, uintptr_t sp, uintptr_t pc, uintptr_t constantPool,
963 //     uint64_t profileTypeInfo, uint64_t acc, uint32_t hotnessCounter, size_t jumpSize)
964 // GHC calling convention
965 // %r13 - glue
966 // %rbp - sp
967 // %r12 - pc
968 // %rbx - constantPool
969 // %r14 - profileTypeInfo
970 // %rsi - acc
971 // %rdi - hotnessCounter
972 // %r8  - jumpSizeAfterCall
ResumeRspAndDispatch(ExtendedAssembler * assembler)973 void AsmInterpreterCall::ResumeRspAndDispatch(ExtendedAssembler *assembler)
974 {
975     __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndDispatch));
976     Register glueRegister = __ GlueRegister();
977     Register spRegister = rbp;
978     Register pcRegister = r12;
979     Register ret = rsi;
980     Register jumpSizeRegister = r8;
981 
982     Register frameStateBaseRegister = r11;
983     __ Movq(spRegister, frameStateBaseRegister);
984     __ Subq(AsmInterpretedFrame::GetSize(false), frameStateBaseRegister);
985 
986     Label dispatch;
987     Label newObjectRangeReturn;
988     __ Cmpq(0, jumpSizeRegister);
989     __ Jle(&newObjectRangeReturn);
990 
991     __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetBaseOffset(false)), spRegister);  // update sp
992     __ Addq(jumpSizeRegister, pcRegister);  // newPC
993     Register temp = rax;
994     Register opcodeRegister = rax;
995     __ Movzbq(Operand(pcRegister, 0), opcodeRegister);
996 
997     __ Bind(&dispatch);
998     {
999         __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetFpOffset(false)), rsp);   // resume rsp
1000         Register bcStubRegister = r11;
1001         __ Movq(Operand(glueRegister, opcodeRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)),
1002             bcStubRegister);
1003         __ Jmp(bcStubRegister);
1004     }
1005 
1006     Label getThis;
1007     Label notUndefined;
1008     __ Bind(&newObjectRangeReturn);
1009     __ Cmpq(JSTaggedValue::Undefined().GetRawData(), ret);
1010     __ Jne(&notUndefined);
1011 
1012     __ Bind(&getThis);
1013     __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetBaseOffset(false)), spRegister);  // update sp
1014     __ Subq(jumpSizeRegister, pcRegister);  // sub negative jmupSize
1015     __ Movzbq(Operand(pcRegister, 0), opcodeRegister);
1016     {
1017         __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetThisOffset(false)), ret);
1018         __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetFpOffset(false)), rsp);   // resume rsp
1019         Register bcStubRegister = r11;
1020         __ Movq(Operand(glueRegister, opcodeRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)),
1021             bcStubRegister);
1022         __ Jmp(bcStubRegister);
1023     }
1024 
1025     __ Bind(&notUndefined);
1026     {
1027         Label notEcmaObject;
1028         __ Movabs(JSTaggedValue::TAG_HEAPOBJECT_MASK, temp);
1029         __ And(ret, temp);
1030         __ Cmpq(0, temp);
1031         __ Jne(&notEcmaObject);
1032         // acc is heap object
1033         __ Movq(Operand(ret, 0), temp);  // hclass
1034         __ Movl(Operand(temp, JSHClass::BIT_FIELD_OFFSET), temp);
1035         __ Cmpb(static_cast<int32_t>(JSType::ECMA_OBJECT_LAST), temp);
1036         __ Ja(&notEcmaObject);
1037         __ Cmpb(static_cast<int32_t>(JSType::ECMA_OBJECT_FIRST), temp);
1038         __ Jb(&notEcmaObject);
1039         // acc is ecma object
1040         __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetBaseOffset(false)), spRegister);  // update sp
1041         __ Subq(jumpSizeRegister, pcRegister);  // sub negative jmupSize
1042         __ Movzbq(Operand(pcRegister, 0), opcodeRegister);
1043         __ Jmp(&dispatch);
1044 
1045         __ Bind(&notEcmaObject);
1046         {
1047             // load constructor
1048             __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetFunctionOffset(false)), temp);
1049             __ Movq(Operand(temp, JSFunctionBase::METHOD_OFFSET), temp);
1050             __ Movq(Operand(temp, Method::EXTRA_LITERAL_INFO_OFFSET), temp);
1051             __ Shr(MethodLiteral::FunctionKindBits::START_BIT, temp);
1052             __ Andl((1LU << MethodLiteral::FunctionKindBits::SIZE) - 1, temp);
1053             __ Cmpl(static_cast<int32_t>(FunctionKind::CLASS_CONSTRUCTOR), temp);
1054             __ Jbe(&getThis);  // constructor is base
1055             // fall through
1056         }
1057         // exception branch
1058         {
1059             __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetBaseOffset(false)), spRegister);
1060             __ Movq(kungfu::BytecodeStubCSigns::ID_NewObjectRangeThrowException, opcodeRegister);
1061             __ Jmp(&dispatch);
1062         }
1063     }
1064 }
1065 
1066 // c++ calling convention
1067 // %rdi - glue
1068 // %rsi - callTarget
1069 // %rdx - method
1070 // %rcx - callField
1071 // %r8 - receiver
1072 // %r9 - value
CallGetter(ExtendedAssembler * assembler)1073 void AsmInterpreterCall::CallGetter(ExtendedAssembler *assembler)
1074 {
1075     __ BindAssemblerStub(RTSTUB_ID(CallGetter));
1076     Label target;
1077 
1078     PushAsmInterpBridgeFrame(assembler);
1079     __ Callq(&target);
1080     PopAsmInterpBridgeFrame(assembler);
1081     __ Ret();
1082     __ Bind(&target);
1083     JSCallCommonEntry(assembler, JSCallMode::CALL_GETTER);
1084 }
1085 
CallSetter(ExtendedAssembler * assembler)1086 void AsmInterpreterCall::CallSetter(ExtendedAssembler *assembler)
1087 {
1088     __ BindAssemblerStub(RTSTUB_ID(CallSetter));
1089     Label target;
1090     PushAsmInterpBridgeFrame(assembler);
1091     __ Callq(&target);
1092     PopAsmInterpBridgeFrame(assembler);
1093     __ Ret();
1094     __ Bind(&target);
1095     JSCallCommonEntry(assembler, JSCallMode::CALL_SETTER);
1096 }
1097 
1098 // Input: glue             - %rdi
1099 //        callTarget       - %rsi
1100 //        method           - %rdx
1101 //        callField        - %rcx
1102 //        arg0(argc)       - %r8
1103 //        arg1(arglist)    - %r9
1104 //        argthis          - stack
CallReturnWithArgv(ExtendedAssembler * assembler)1105 void AsmInterpreterCall::CallReturnWithArgv(ExtendedAssembler *assembler)
1106 {
1107     __ BindAssemblerStub(RTSTUB_ID(CallReturnWithArgv));
1108     Label target;
1109     PushAsmInterpBridgeFrame(assembler);
1110     Register r13 = __ CppJSCallAvailableRegister1();
1111     __ Movq(Operand(rbp, FRAME_SLOT_SIZE), r13);
1112     __ Callq(&target);
1113     PopAsmInterpBridgeFrame(assembler);
1114     __ Ret();
1115     __ Bind(&target);
1116     {
1117         JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARGV_WITH_RETURN);
1118     }
1119 }
1120 
CallContainersArgs3(ExtendedAssembler * assembler)1121 void AsmInterpreterCall::CallContainersArgs3(ExtendedAssembler *assembler)
1122 {
1123     __ BindAssemblerStub(RTSTUB_ID(CallContainersArgs3));
1124     Label target;
1125     PushAsmInterpBridgeFrame(assembler);
1126     GetArgvAtStack(assembler);
1127     __ Callq(&target);
1128     PopAsmInterpBridgeFrame(assembler);
1129     __ Ret();
1130     __ Bind(&target);
1131     {
1132         JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
1133     }
1134 }
1135 
1136 // ResumeRspAndReturn(uintptr_t acc)
1137 // GHC calling convention
1138 // %r13 - acc
1139 // %rbp - prevSp
1140 // %r12 - sp
ResumeRspAndReturn(ExtendedAssembler * assembler)1141 void AsmInterpreterCall::ResumeRspAndReturn(ExtendedAssembler *assembler)
1142 {
1143     __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndReturn));
1144     Register currentSp = r12;
1145     Register fpRegister = r10;
1146     intptr_t offset = AsmInterpretedFrame::GetFpOffset(false) - AsmInterpretedFrame::GetSize(false);
1147     __ Movq(Operand(currentSp, static_cast<int32_t>(offset)), fpRegister);
1148     __ Movq(fpRegister, rsp);
1149     // return
1150     {
1151         __ Movq(r13, rax);
1152         __ Ret();
1153     }
1154 }
1155 
1156 // ResumeCaughtFrameAndDispatch(uintptr_t glue, uintptr_t sp, uintptr_t pc, uintptr_t constantPool,
1157 //     uint64_t profileTypeInfo, uint64_t acc, uint32_t hotnessCounter)
1158 // GHC calling convention
1159 // %r13 - glue
1160 // %rbp - sp
1161 // %r12 - pc
1162 // %rbx - constantPool
1163 // %r14 - profileTypeInfo
1164 // %rsi - acc
1165 // %rdi - hotnessCounter
ResumeCaughtFrameAndDispatch(ExtendedAssembler * assembler)1166 void AsmInterpreterCall::ResumeCaughtFrameAndDispatch(ExtendedAssembler *assembler)
1167 {
1168     __ BindAssemblerStub(RTSTUB_ID(ResumeCaughtFrameAndDispatch));
1169     Register glueRegister = __ GlueRegister();
1170     Register pcRegister = r12;
1171 
1172     Label dispatch;
1173     Register fpRegister = r11;
1174     __ Movq(Operand(glueRegister, JSThread::GlueData::GetLastFpOffset(false)), fpRegister);
1175     __ Cmpq(0, fpRegister);
1176     __ Jz(&dispatch);
1177     __ Movq(fpRegister, rsp);  // resume rsp
1178     __ Bind(&dispatch);
1179     {
1180         Register opcodeRegister = rax;
1181         __ Movzbq(Operand(pcRegister, 0), opcodeRegister);
1182         Register bcStubRegister = r11;
1183         __ Movq(Operand(glueRegister, opcodeRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)),
1184             bcStubRegister);
1185         __ Jmp(bcStubRegister);
1186     }
1187 }
1188 
1189 // ResumeUncaughtFrameAndReturn(uintptr_t glue)
1190 // GHC calling convention
1191 // %r13 - glue
1192 // %rbp - sp
1193 // %r12 - acc
ResumeUncaughtFrameAndReturn(ExtendedAssembler * assembler)1194 void AsmInterpreterCall::ResumeUncaughtFrameAndReturn(ExtendedAssembler *assembler)
1195 {
1196     __ BindAssemblerStub(RTSTUB_ID(ResumeUncaughtFrameAndReturn));
1197     Register glueRegister = __ GlueRegister();
1198     Register acc(r12);
1199     Register cppRet(rax);
1200 
1201     Label ret;
1202     Register fpRegister = r11;
1203     __ Movq(Operand(glueRegister, JSThread::GlueData::GetLastFpOffset(false)), fpRegister);
1204     __ Cmpq(0, fpRegister);
1205     __ Jz(&ret);
1206     __ Movq(fpRegister, rsp);  // resume rsp
1207     __ Bind(&ret);
1208     // this method will return to Execute(cpp calling convention), and the return value should be put into rax.
1209     __ Movq(acc, cppRet);
1210     __ Ret();
1211 }
1212 
1213 // ResumeRspAndRollback(uintptr_t glue, uintptr_t sp, uintptr_t pc, uintptr_t constantPool,
1214 //     uint64_t profileTypeInfo, uint64_t acc, uint32_t hotnessCounter, size_t jumpSize)
1215 // GHC calling convention
1216 // %r13 - glue
1217 // %rbp - sp
1218 // %r12 - pc
1219 // %rbx - constantPool
1220 // %r14 - profileTypeInfo
1221 // %rsi - acc
1222 // %rdi - hotnessCounter
1223 // %r8  - jumpSizeAfterCall
ResumeRspAndRollback(ExtendedAssembler * assembler)1224 void AsmInterpreterCall::ResumeRspAndRollback(ExtendedAssembler *assembler)
1225 {
1226     __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndRollback));
1227     Register glueRegister = __ GlueRegister();
1228     Register spRegister = rbp;
1229     Register pcRegister = r12;
1230     Register ret = rsi;
1231     Register jumpSizeRegister = r8;
1232 
1233     Register frameStateBaseRegister = r11;
1234     __ Movq(spRegister, frameStateBaseRegister);
1235     __ Subq(AsmInterpretedFrame::GetSize(false), frameStateBaseRegister);
1236 
1237     __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetBaseOffset(false)), spRegister);  // update sp
1238     __ Addq(jumpSizeRegister, pcRegister);  // newPC
1239     Register opcodeRegister = rax;
1240     __ Movzbq(Operand(pcRegister, 0), opcodeRegister);
1241 
1242     __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetFunctionOffset(false)), ret); // restore acc
1243 
1244     __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetFpOffset(false)), rsp);   // resume rsp
1245     Register bcStubRegister = r11;
1246     __ Movq(Operand(glueRegister, opcodeRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)),
1247         bcStubRegister);
1248     __ Jmp(bcStubRegister);
1249 }
1250 
PushUndefinedWithArgcAndCheckStack(ExtendedAssembler * assembler,Register glue,Register argc,Register op1,Register op2,Label * stackOverflow)1251 void AsmInterpreterCall::PushUndefinedWithArgcAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc,
1252     Register op1, Register op2, Label *stackOverflow)
1253 {
1254     ASSERT(stackOverflow != nullptr);
1255     StackOverflowCheck(assembler, glue, argc, op1, op2, stackOverflow);
1256     PushUndefinedWithArgc(assembler, argc);
1257 }
1258 
ThrowStackOverflowExceptionAndReturn(ExtendedAssembler * assembler,Register glue,Register fp,Register op)1259 void AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(ExtendedAssembler *assembler, Register glue, Register fp,
1260     Register op)
1261 {
1262     if (fp != rsp) {
1263         __ Movq(fp, rsp);
1264     }
1265     __ Movq(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException, op);
1266     __ Movq(Operand(glue, op, Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)), op);
1267     if (glue != r13) {
1268         __ Movq(glue, r13);
1269     }
1270 
1271     __ Pushq(rbp);
1272     __ Pushq(static_cast<int64_t>(FrameType::ASM_BRIDGE_FRAME)); // set frame type
1273     __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp); // skip frame type
1274 
1275     __ Pushq(r10); // caller save
1276     __ Pushq(0); // argc
1277     __ Pushq(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException); // runtime id
1278     __ Movq(glue, rax); // glue
1279     __ Movq(kungfu::RuntimeStubCSigns::ID_CallRuntime, r10);
1280     __ Movq(Operand(rax, r10, Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)), r10);
1281     __ Callq(r10); // call CallRuntime
1282     __ Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip argc and runtime_id
1283     __ Popq(r10);
1284     __ Addq(FRAME_SLOT_SIZE, rsp); // skip frame type
1285     __ Popq(rbp);
1286     __ Ret();
1287 }
1288 
HasPendingException(ExtendedAssembler * assembler,Register threadRegister)1289 void AsmInterpreterCall::HasPendingException([[maybe_unused]] ExtendedAssembler *assembler,
1290     [[maybe_unused]] Register threadRegister)
1291 {
1292 }
1293 #undef __
1294 }  // namespace panda::ecmascript::x64