• 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 
PushCallArgs3AndDispatch(ExtendedAssembler * assembler)376 void AsmInterpreterCall::PushCallArgs3AndDispatch(ExtendedAssembler *assembler)
377 {
378     __ BindAssemblerStub(RTSTUB_ID(PushCallArgs3AndDispatch));
379     JSCallCommonEntry(assembler, JSCallMode::CALL_ARG3);
380 }
381 
PushCallArgs2AndDispatch(ExtendedAssembler * assembler)382 void AsmInterpreterCall::PushCallArgs2AndDispatch(ExtendedAssembler *assembler)
383 {
384     __ BindAssemblerStub(RTSTUB_ID(PushCallArgs2AndDispatch));
385     JSCallCommonEntry(assembler, JSCallMode::CALL_ARG2);
386 }
387 
PushCallArg1AndDispatch(ExtendedAssembler * assembler)388 void AsmInterpreterCall::PushCallArg1AndDispatch(ExtendedAssembler *assembler)
389 {
390     __ BindAssemblerStub(RTSTUB_ID(PushCallArg1AndDispatch));
391     JSCallCommonEntry(assembler, JSCallMode::CALL_ARG1);
392 }
393 
PushCallArg0AndDispatch(ExtendedAssembler * assembler)394 void AsmInterpreterCall::PushCallArg0AndDispatch(ExtendedAssembler *assembler)
395 {
396     __ BindAssemblerStub(RTSTUB_ID(PushCallArg0AndDispatch));
397     JSCallCommonEntry(assembler, JSCallMode::CALL_ARG0);
398 }
PushCallThisArg0AndDispatch(ExtendedAssembler * assembler)399 void AsmInterpreterCall::PushCallThisArg0AndDispatch(ExtendedAssembler *assembler)
400 {
401     __ BindAssemblerStub(RTSTUB_ID(PushCallThisArg0AndDispatch));
402     JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG0);
403 }
404 
PushCallThisArg1AndDispatch(ExtendedAssembler * assembler)405 void AsmInterpreterCall::PushCallThisArg1AndDispatch(ExtendedAssembler *assembler)
406 {
407     __ BindAssemblerStub(RTSTUB_ID(PushCallThisArg1AndDispatch));
408     JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG1);
409 }
410 
PushCallThisArgs2AndDispatch(ExtendedAssembler * assembler)411 void AsmInterpreterCall::PushCallThisArgs2AndDispatch(ExtendedAssembler *assembler)
412 {
413     __ BindAssemblerStub(RTSTUB_ID(PushCallThisArgs2AndDispatch));
414     JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG2);
415 }
416 
PushCallThisArgs3AndDispatch(ExtendedAssembler * assembler)417 void AsmInterpreterCall::PushCallThisArgs3AndDispatch(ExtendedAssembler *assembler)
418 {
419     __ BindAssemblerStub(RTSTUB_ID(PushCallThisArgs3AndDispatch));
420     JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG3);
421 }
422 
JSCallCommonFastPath(ExtendedAssembler * assembler,JSCallMode mode,Label * stackOverflow)423 void AsmInterpreterCall::JSCallCommonFastPath(ExtendedAssembler *assembler, JSCallMode mode, Label *stackOverflow)
424 {
425     Register glueRegister = __ GlueRegister();
426     Register arg0 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
427     Register arg1 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
428 
429     Label pushCallThis;
430     auto argc = kungfu::AssemblerModule::GetArgcFromJSCallMode(mode);
431     // call range
432     if (argc < 0) {
433         Register argcRegister = arg0;
434         Register argvRegister = arg1;
435         __ Cmpq(0, argcRegister);
436         __ Jbe(&pushCallThis);
437         // fall through
438         {
439             [[maybe_unused]] TempRegisterScope scope(assembler);
440             Register opRegister = __ TempRegister();
441             Register op2Register = __ AvailableRegister2();
442             PushArgsWithArgvAndCheckStack(assembler, glueRegister, argcRegister, argvRegister, opRegister, op2Register,
443                 stackOverflow);
444         }
445         __ Bind(&pushCallThis);
446     } else if (argc > 0) {
447         if (argc > 2) { // 2: call arg2
448             if (mode == JSCallMode::CALL_THIS_ARG3_WITH_RETURN) {
449                 Register arg2 = __ CppJSCallAvailableRegister1();
450                 __ Pushq(arg2);
451             } else {
452                 Register arg2 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG2);
453                 __ Pushq(arg2);
454             }
455         }
456         if (argc > 1) {
457             __ Pushq(arg1);
458         }
459         if (argc > 0) {
460             __ Pushq(arg0);
461         }
462     }
463 }
464 
JSCallCommonSlowPath(ExtendedAssembler * assembler,JSCallMode mode,Label * fastPathEntry,Label * pushCallThis,Label * stackOverflow)465 void AsmInterpreterCall::JSCallCommonSlowPath(ExtendedAssembler *assembler, JSCallMode mode,
466                                               Label *fastPathEntry, Label *pushCallThis, Label *stackOverflow)
467 {
468     Register glueRegister = __ GlueRegister();
469     Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
470     Register argcRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
471     Register arg0 = argcRegister;
472     Register arg1 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
473     Label noExtraEntry;
474     Label pushArgsEntry;
475 
476     auto argc = kungfu::AssemblerModule::GetArgcFromJSCallMode(mode);
477     Register declaredNumArgsRegister = __ AvailableRegister2();
478     __ Testq(MethodLiteral::HaveExtraBit::Mask(), callFieldRegister);
479     __ Jz(&noExtraEntry);
480     // extra entry
481     {
482         [[maybe_unused]] TempRegisterScope scope(assembler);
483         Register tempArgcRegister = __ TempRegister();
484         if (argc >= 0) {
485             __ PushArgc(argc, tempArgcRegister);
486         } else {
487             __ PushArgc(argcRegister, tempArgcRegister);
488         }
489     }
490     __ Bind(&noExtraEntry);
491     {
492         if (argc == 0) {
493             Register op1 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
494             [[maybe_unused]] TempRegisterScope scope(assembler);
495             Register op2 = __ TempRegister();
496             PushUndefinedWithArgcAndCheckStack(assembler, glueRegister, declaredNumArgsRegister, op1, op2,
497                 stackOverflow);
498             __ Jmp(fastPathEntry);
499             return;
500         }
501         [[maybe_unused]] TempRegisterScope scope(assembler);
502         Register diffRegister = __ TempRegister();
503         __ Movq(declaredNumArgsRegister, diffRegister);
504         if (argc >= 0) {
505             __ Subq(argc, diffRegister);
506         } else {
507             __ Subq(argcRegister, diffRegister);
508         }
509         __ Cmpq(0, diffRegister);
510         __ Jle(&pushArgsEntry);
511         PushUndefinedWithArgc(assembler, diffRegister);
512         __ Jmp(fastPathEntry);
513     }
514     __ Bind(&pushArgsEntry);
515     __ Testq(MethodLiteral::HaveExtraBit::Mask(), callFieldRegister);
516     __ Jnz(fastPathEntry);
517     // arg1, declare must be 0
518     if (argc == 1) {
519         __ Jmp(pushCallThis);
520         return;
521     }
522     // decalare < actual
523     __ Cmpq(0, declaredNumArgsRegister);
524     __ Je(pushCallThis);
525     if (argc < 0) {
526         Register argvRegister = arg1;
527         [[maybe_unused]] TempRegisterScope scope(assembler);
528         Register opRegister = __ TempRegister();
529         PushArgsWithArgvAndCheckStack(assembler, glueRegister, declaredNumArgsRegister, argvRegister, opRegister,
530             opRegister, stackOverflow);
531     } else if (argc > 0) {
532         Label pushArgs0;
533         if (argc > 2) { // 2: call arg2
534             // decalare is 2 or 1 now
535             __ Cmpq(1, declaredNumArgsRegister);
536             __ Je(&pushArgs0);
537             __ Pushq(arg1);
538         }
539         if (argc > 1) {
540             __ Bind(&pushArgs0);
541             // decalare is is 1 now
542             __ Pushq(arg0);
543         }
544     }
545     __ Jmp(pushCallThis);
546 }
547 
GetThisRegsiter(ExtendedAssembler * assembler,JSCallMode mode,Register defaultRegister)548 Register AsmInterpreterCall::GetThisRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister)
549 {
550     switch (mode) {
551         case JSCallMode::CALL_GETTER:
552         case JSCallMode::CALL_THIS_ARG0:
553             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
554         case JSCallMode::CALL_SETTER:
555         case JSCallMode::CALL_THIS_ARG1:
556             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
557         case JSCallMode::CALL_THIS_ARG2:
558         case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
559         case JSCallMode::CALL_THIS_WITH_ARGV:
560             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG2);
561         case JSCallMode::CALL_THIS_ARG3:
562             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG3);
563         case JSCallMode::CALL_ENTRY:
564         case JSCallMode::CALL_FROM_AOT: {
565             Register argvRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
566             __ Movq(Operand(argvRegister, -FRAME_SLOT_SIZE), defaultRegister);  // 8: this is just before the argv list
567             return defaultRegister;
568         }
569         case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
570             return __ CppJSCallAvailableRegister2();
571         default:
572             UNREACHABLE();
573     }
574     return rInvalid;
575 }
576 
GetNewTargetRegsiter(ExtendedAssembler * assembler,JSCallMode mode,Register defaultRegister)577 Register AsmInterpreterCall::GetNewTargetRegsiter(ExtendedAssembler *assembler, JSCallMode mode,
578                                                   Register defaultRegister)
579 {
580     switch (mode) {
581         case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
582         case JSCallMode::CALL_THIS_WITH_ARGV:
583             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
584         case JSCallMode::CALL_FROM_AOT:
585         case JSCallMode::CALL_ENTRY: {
586             Register argvRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
587             // -2: new Target offset
588             __ Movq(Operand(argvRegister, -2 * FRAME_SLOT_SIZE), defaultRegister);
589             return defaultRegister;
590         }
591         default:
592             UNREACHABLE();
593     }
594     return rInvalid;
595 }
596 
597 // Input: %r14 - callField
598 //        %rdi - argv
PushCallThis(ExtendedAssembler * assembler,JSCallMode mode,Label * stackOverflow)599 void AsmInterpreterCall::PushCallThis(ExtendedAssembler *assembler, JSCallMode mode, Label *stackOverflow)
600 {
601     Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
602     Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
603     Register thisRegister = __ AvailableRegister2();
604 
605     Label pushVregs;
606     Label pushNewTarget;
607     Label pushCallTarget;
608     bool haveThis = kungfu::AssemblerModule::JSModeHaveThisArg(mode);
609     bool haveNewTarget = kungfu::AssemblerModule::JSModeHaveNewTargetArg(mode);
610     if (!haveThis) {
611         __ Movq(JSTaggedValue::VALUE_UNDEFINED, thisRegister);  // default this: undefined
612     } else {
613         Register thisArgRegister = GetThisRegsiter(assembler, mode, thisRegister);
614         if (thisRegister != thisArgRegister) {
615             __ Movq(thisArgRegister, thisRegister);
616         }
617     }
618     __ Testb(CALL_TYPE_MASK, callFieldRegister);
619     __ Jz(&pushVregs);
620     // fall through
621     __ Testq(MethodLiteral::HaveThisBit::Mask(), callFieldRegister);
622     __ Jz(&pushNewTarget);
623     // push this
624     if (!haveThis) {
625         __ Pushq(JSTaggedValue::Undefined().GetRawData());
626     } else {
627         __ Pushq(thisRegister);
628     }
629     // fall through
630     __ Bind(&pushNewTarget);
631     {
632         __ Testq(MethodLiteral::HaveNewTargetBit::Mask(), callFieldRegister);
633         __ Jz(&pushCallTarget);
634         if (!haveNewTarget) {
635             __ Pushq(JSTaggedValue::Undefined().GetRawData());
636         } else {
637             [[maybe_unused]] TempRegisterScope scope(assembler);
638             Register defaultRegister = __ TempRegister();
639             Register newTargetRegister = GetNewTargetRegsiter(assembler, mode, defaultRegister);
640             __ Pushq(newTargetRegister);
641         }
642     }
643     // fall through
644     __ Bind(&pushCallTarget);
645     {
646         __ Testq(MethodLiteral::HaveFuncBit::Mask(), callFieldRegister);
647         __ Jz(&pushVregs);
648         __ Pushq(callTargetRegister);
649     }
650     // fall through
651     __ Bind(&pushVregs);
652     {
653         PushVregs(assembler, stackOverflow);
654     }
655 }
656 
657 // Input: %rbp - sp
658 //        %r12 - callTarget
659 //        %rbx - method
660 //        %r14 - callField
661 //        %rdx - jumpSizeAfterCall
662 //        %r10 - fp
PushVregs(ExtendedAssembler * assembler,Label * stackOverflow)663 void AsmInterpreterCall::PushVregs(ExtendedAssembler *assembler, Label *stackOverflow)
664 {
665     Register glueRegister = __ GlueRegister();
666     Register prevSpRegister = rbp;
667     Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
668     Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
669     Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
670     Register fpRegister = __ AvailableRegister1();
671     Register thisRegister = __ AvailableRegister2();
672 
673     Label pushFrameState;
674 
675     [[maybe_unused]] TempRegisterScope scope(assembler);
676     Register tempRegister = __ TempRegister();
677     // args register can reused now.
678     Register pcRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
679     Register numVregsRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
680     GetNumVregsFromCallField(assembler, callFieldRegister, numVregsRegister);
681     __ Cmpq(0, numVregsRegister);
682     __ Jz(&pushFrameState);
683     Register temp2Register = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);  // reuse
684     PushUndefinedWithArgcAndCheckStack(assembler, glueRegister, numVregsRegister, tempRegister, temp2Register,
685         stackOverflow);
686     // fall through
687     Register newSpRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
688     __ Bind(&pushFrameState);
689     {
690         __ Movq(rsp, newSpRegister);
691 
692         PushFrameState(assembler, prevSpRegister, fpRegister,
693             callTargetRegister, thisRegister, methodRegister, pcRegister, tempRegister);
694     }
695     DispatchCall(assembler, pcRegister, newSpRegister, methodRegister);
696 }
697 
698 // Input: %r13 - glue
699 //        %rbp - sp
700 //        %r12 - callTarget
701 //        %rbx - method
DispatchCall(ExtendedAssembler * assembler,Register pcRegister,Register newSpRegister,Register methodRegister,Register accRegister)702 void AsmInterpreterCall::DispatchCall(ExtendedAssembler *assembler, Register pcRegister,
703     Register newSpRegister, Register methodRegister, Register accRegister)
704 {
705     Register glueRegister = __ GlueRegister();
706     Label dispatchCall;
707     // align 16 bytes
708     __ Testq(15, rsp);  // 15: low 4 bits must be 0b0000
709     __ Jnz(&dispatchCall);
710     __ PushAlignBytes();
711     __ Bind(&dispatchCall);
712     // profileTypeInfo: r14
713     __ Movq(Operand(methodRegister, Method::PROFILE_TYPE_INFO_OFFSET), r14);
714     // glue may rdi
715     if (glueRegister != r13) {
716         __ Movq(glueRegister, r13);
717     }
718     // sp: rbp
719     __ Movq(newSpRegister, rbp);
720     // hotnessCounter: rdi
721     __ Movzwq(Operand(methodRegister, Method::LITERAL_INFO_OFFSET), rdi);
722     // constantPool: rbx
723     __ Movq(Operand(methodRegister, Method::CONSTANT_POOL_OFFSET), rbx);
724     // pc: r12
725     if (pcRegister != r12) {
726         __ Movq(pcRegister, r12);
727     }
728 
729     Register bcIndexRegister = rax;
730     Register tempRegister = __ AvailableRegister1();
731     __ Movzbq(Operand(pcRegister, 0), bcIndexRegister);
732     // acc: rsi
733     if (accRegister != rInvalid) {
734         ASSERT(accRegister == rsi);
735     } else {
736         __ Movq(JSTaggedValue::Hole().GetRawData(), rsi);
737     }
738     __ Movq(Operand(r13, bcIndexRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)), tempRegister);
739     __ Jmp(tempRegister);
740 }
741 
742 // uint64_t PushCallRangeAndDispatchNative(uintptr_t glue, uint32_t argc, JSTaggedType calltarget, uintptr_t argv[])
743 // c++ calling convention call js function
744 // Input: %rdi - glue
745 //        %rsi - nativeCode
746 //        %rdx - func
747 //        %rcx - thisValue
748 //        %r8  - argc
749 //        %r9  - argV (...)
PushCallRangeAndDispatchNative(ExtendedAssembler * assembler)750 void AsmInterpreterCall::PushCallRangeAndDispatchNative(ExtendedAssembler *assembler)
751 {
752     __ BindAssemblerStub(RTSTUB_ID(PushCallRangeAndDispatchNative));
753     CallNativeWithArgv(assembler, false);
754 }
755 
PushCallNewAndDispatchNative(ExtendedAssembler * assembler)756 void AsmInterpreterCall::PushCallNewAndDispatchNative(ExtendedAssembler *assembler)
757 {
758     __ BindAssemblerStub(RTSTUB_ID(PushCallNewAndDispatchNative));
759     CallNativeWithArgv(assembler, true);
760 }
761 
CallNativeWithArgv(ExtendedAssembler * assembler,bool callNew)762 void AsmInterpreterCall::CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew)
763 {
764     Register glue = rdi;
765     Register nativeCode = rsi;
766     Register func = rdx;
767     Register thisValue = rcx;
768     Register numArgs = r8;
769     Register stackArgs = r9;
770     Register temporary = rax;
771     Register temporary2 = r11;
772     Register opNumArgs = r10;
773     Label aligned;
774     Label pushThis;
775     Label stackOverflow;
776 
777     PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_FRAME_WITH_ARGV);
778 
779     __ Push(numArgs);
780     __ Cmpq(0, numArgs);
781     __ Jz(&pushThis);
782     __ Movq(numArgs, opNumArgs);
783     PushArgsWithArgvAndCheckStack(assembler, glue, opNumArgs, stackArgs, temporary, temporary2, &stackOverflow);
784 
785     __ Bind(&pushThis);
786     __ Push(thisValue);
787     // new.target
788     if (callNew) {
789         __ Pushq(func);
790     } else {
791         __ Pushq(JSTaggedValue::Undefined().GetRawData());
792     }
793     __ Pushq(func);
794     // 40: skip frame type, numArgs, func, newTarget and this
795     __ Leaq(Operand(rsp, numArgs, Times8, 5 * FRAME_SLOT_SIZE), rbp);
796     __ Movq(rsp, stackArgs);
797 
798     // push argc
799     __ Addl(NUM_MANDATORY_JSFUNC_ARGS, numArgs);
800     __ Pushq(numArgs);
801     // push thread
802     __ Pushq(glue);
803     // EcmaRuntimeCallInfo
804     __ Movq(rsp, rdi);
805 
806     __ Testq(0xf, rsp);  // 0xf: 0x1111
807     __ Jz(&aligned, Distance::Near);
808     __ PushAlignBytes();
809 
810     __ Bind(&aligned);
811     CallNativeInternal(assembler, nativeCode);
812     __ Ret();
813 
814     __ Bind(&stackOverflow);
815     {
816         Label aligneThrow;
817         __ Movq(rsp, Operand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
818         __ Pushq(static_cast<int32_t>(FrameType::BUILTIN_FRAME_WITH_ARGV));  // frame type
819         __ Pushq(0);  // argc
820         __ Pushq(JSTaggedValue::VALUE_UNDEFINED);  // this
821         __ Pushq(JSTaggedValue::VALUE_UNDEFINED);  // newTarget
822         __ Pushq(JSTaggedValue::VALUE_UNDEFINED);  // callTarget
823         __ Leaq(Operand(rsp, 5 * FRAME_SLOT_SIZE), rbp);  // 40: skip frame type, numArgs, func, newTarget and this
824 
825         __ Testq(0xf, rsp);  // 0xf: 0x1111
826         __ Jz(&aligneThrow, Distance::Near);
827         __ PushAlignBytes();
828 
829         __ Bind(&aligneThrow);
830         Register trampolineIdRegister = r9;
831         Register trampolineRegister = r10;
832         __ Movq(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException, trampolineIdRegister);
833         __ Movq(Operand(glue, trampolineIdRegister, Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)),
834             trampolineRegister);
835         __ Callq(trampolineRegister);
836 
837         // resume rsp
838         __ Movq(rbp, rsp);
839         __ Pop(rbp);
840         __ Ret();
841     }
842 }
843 
CallNativeEntry(ExtendedAssembler * assembler)844 void AsmInterpreterCall::CallNativeEntry(ExtendedAssembler *assembler)
845 {
846     Register glue = rdi;
847     Register argv = r9;
848     Register method = rdx;
849     Register function = rsi;
850     Register nativeCode = r10;
851 
852     __ PushAlignBytes();
853     __ Push(function);
854     // 24: skip thread & argc & returnAddr
855     __ Subq(3 * FRAME_SLOT_SIZE, rsp);
856     PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_ENTRY_FRAME);
857     __ Movq(Operand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET), nativeCode); // get native pointer
858     __ Movq(argv, r11);
859     // 16: skip numArgs & thread
860     __ Subq(2 * FRAME_SLOT_SIZE, r11);
861     // EcmaRuntimeCallInfo
862     __ Movq(r11, rdi);
863 
864     CallNativeInternal(assembler, nativeCode);
865 
866     // 40: skip function
867     __ Addq(5 * FRAME_SLOT_SIZE, rsp);
868     __ Ret();
869 }
870 
871 // uint64_t PushCallArgsAndDispatchNative(uintptr_t codeAddress, uintptr_t glue, uint32_t argc, ...)
872 // webkit_jscc calling convention call runtime_id's runtion function(c-abi)
873 // Input:        %rax - codeAddress
874 // stack layout: sp + N*8 argvN
875 //               ........
876 //               sp + 24: argv1
877 //               sp + 16: argv0
878 //               sp + 8:  actualArgc
879 //               sp:      thread
880 // construct Native Leave Frame
881 //               +--------------------------+
882 //               |     argV[N - 1]          |
883 //               |--------------------------|
884 //               |       . . . .            |
885 //               |--------------------------+
886 //               |     argV[2]=this         |
887 //               +--------------------------+
888 //               |     argV[1]=new-target   |
889 //               +--------------------------+
890 //               |     argV[0]=call-target  |
891 //               +--------------------------+ ---------
892 //               |       argc               |         ^
893 //               |--------------------------|         |
894 //               |       thread             |         |
895 //               |--------------------------|         |
896 //               |       returnAddr         |     BuiltinFrame
897 //               |--------------------------|         |
898 //               |       callsiteFp         |         |
899 //               |--------------------------|         |
900 //               |       frameType          |         v
901 //               +--------------------------+ ---------
902 
PushCallArgsAndDispatchNative(ExtendedAssembler * assembler)903 void AsmInterpreterCall::PushCallArgsAndDispatchNative(ExtendedAssembler *assembler)
904 {
905     __ BindAssemblerStub(RTSTUB_ID(PushCallArgsAndDispatchNative));
906     Register nativeCode = rax;
907     Register glue = rdi;
908 
909     __ Movq(Operand(rsp, FRAME_SLOT_SIZE), glue); // 8: glue
910     PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_FRAME);
911     __ Leaq(Operand(rbp, 2 * FRAME_SLOT_SIZE), rdi); // 16: skip argc & thread
912     __ PushAlignBytes();
913     CallNativeInternal(assembler, nativeCode);
914     __ Ret();
915 }
916 
PushBuiltinFrame(ExtendedAssembler * assembler,Register glue,FrameType type)917 void AsmInterpreterCall::PushBuiltinFrame(ExtendedAssembler *assembler,
918                                           Register glue, FrameType type)
919 {
920     __ Pushq(rbp);
921     __ Movq(rsp, Operand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
922     __ Pushq(static_cast<int32_t>(type));
923     if (type != FrameType::BUILTIN_FRAME_WITH_ARGV) {
924         __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);  // 8: skip frame type
925     }
926 }
927 
CallNativeInternal(ExtendedAssembler * assembler,Register nativeCode)928 void AsmInterpreterCall::CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode)
929 {
930     __ Callq(nativeCode);
931     // resume rsp
932     __ Movq(rbp, rsp);
933     __ Pop(rbp);
934 }
935 
936 // ResumeRspAndDispatch(uintptr_t glue, uintptr_t sp, uintptr_t pc, uintptr_t constantPool,
937 //     uint64_t profileTypeInfo, uint64_t acc, uint32_t hotnessCounter, size_t jumpSize)
938 // GHC calling convention
939 // %r13 - glue
940 // %rbp - sp
941 // %r12 - pc
942 // %rbx - constantPool
943 // %r14 - profileTypeInfo
944 // %rsi - acc
945 // %rdi - hotnessCounter
946 // %r8  - jumpSizeAfterCall
ResumeRspAndDispatch(ExtendedAssembler * assembler)947 void AsmInterpreterCall::ResumeRspAndDispatch(ExtendedAssembler *assembler)
948 {
949     __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndDispatch));
950     Register glueRegister = __ GlueRegister();
951     Register spRegister = rbp;
952     Register pcRegister = r12;
953     Register ret = rsi;
954     Register jumpSizeRegister = r8;
955 
956     Register frameStateBaseRegister = r11;
957     __ Movq(spRegister, frameStateBaseRegister);
958     __ Subq(AsmInterpretedFrame::GetSize(false), frameStateBaseRegister);
959 
960     Label dispatch;
961     Label newObjectRangeReturn;
962     __ Cmpq(0, jumpSizeRegister);
963     __ Jle(&newObjectRangeReturn);
964 
965     __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetBaseOffset(false)), spRegister);  // update sp
966     __ Addq(jumpSizeRegister, pcRegister);  // newPC
967     Register temp = rax;
968     Register opcodeRegister = rax;
969     __ Movzbq(Operand(pcRegister, 0), opcodeRegister);
970 
971     __ Bind(&dispatch);
972     {
973         __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetFpOffset(false)), rsp);   // resume rsp
974         Register bcStubRegister = r11;
975         __ Movq(Operand(glueRegister, opcodeRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)),
976             bcStubRegister);
977         __ Jmp(bcStubRegister);
978     }
979 
980     Label getThis;
981     Label notUndefined;
982     __ Bind(&newObjectRangeReturn);
983     __ Cmpq(JSTaggedValue::Undefined().GetRawData(), ret);
984     __ Jne(&notUndefined);
985 
986     __ Bind(&getThis);
987     __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetBaseOffset(false)), spRegister);  // update sp
988     __ Subq(jumpSizeRegister, pcRegister);  // sub negative jmupSize
989     __ Movzbq(Operand(pcRegister, 0), opcodeRegister);
990     {
991         __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetThisOffset(false)), ret);
992         __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetFpOffset(false)), rsp);   // resume rsp
993         Register bcStubRegister = r11;
994         __ Movq(Operand(glueRegister, opcodeRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)),
995             bcStubRegister);
996         __ Jmp(bcStubRegister);
997     }
998 
999     __ Bind(&notUndefined);
1000     {
1001         Label notEcmaObject;
1002         __ Movabs(JSTaggedValue::TAG_HEAPOBJECT_MASK, temp);
1003         __ And(ret, temp);
1004         __ Cmpq(0, temp);
1005         __ Jne(&notEcmaObject);
1006         // acc is heap object
1007         __ Movq(Operand(ret, 0), temp);  // hclass
1008         __ Movl(Operand(temp, JSHClass::BIT_FIELD_OFFSET), temp);
1009         __ Cmpb(static_cast<int32_t>(JSType::ECMA_OBJECT_LAST), temp);
1010         __ Ja(&notEcmaObject);
1011         __ Cmpb(static_cast<int32_t>(JSType::ECMA_OBJECT_FIRST), temp);
1012         __ Jb(&notEcmaObject);
1013         // acc is ecma object
1014         __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetBaseOffset(false)), spRegister);  // update sp
1015         __ Subq(jumpSizeRegister, pcRegister);  // sub negative jmupSize
1016         __ Movzbq(Operand(pcRegister, 0), opcodeRegister);
1017         __ Jmp(&dispatch);
1018 
1019         __ Bind(&notEcmaObject);
1020         {
1021             // load constructor
1022             __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetFunctionOffset(false)), temp);
1023             __ Movq(Operand(temp, JSFunctionBase::METHOD_OFFSET), temp);
1024             __ Movq(Operand(temp, Method::EXTRA_LITERAL_INFO_OFFSET), temp);
1025             __ Shr(MethodLiteral::FunctionKindBits::START_BIT, temp);
1026             __ Andl((1LU << MethodLiteral::FunctionKindBits::SIZE) - 1, temp);
1027             __ Cmpl(static_cast<int32_t>(FunctionKind::CLASS_CONSTRUCTOR), temp);
1028             __ Jbe(&getThis);  // constructor is base
1029             // fall through
1030         }
1031         // exception branch
1032         {
1033             __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetBaseOffset(false)), spRegister);
1034             __ Movq(kungfu::BytecodeStubCSigns::ID_NewObjectRangeThrowException, opcodeRegister);
1035             __ Jmp(&dispatch);
1036         }
1037     }
1038 }
1039 
1040 // c++ calling convention
1041 // %rdi - glue
1042 // %rsi - callTarget
1043 // %rdx - method
1044 // %rcx - callField
1045 // %r8 - receiver
1046 // %r9 - value
CallGetter(ExtendedAssembler * assembler)1047 void AsmInterpreterCall::CallGetter(ExtendedAssembler *assembler)
1048 {
1049     __ BindAssemblerStub(RTSTUB_ID(CallGetter));
1050     Label target;
1051 
1052     PushAsmInterpBridgeFrame(assembler);
1053     __ Callq(&target);
1054     PopAsmInterpBridgeFrame(assembler);
1055     __ Ret();
1056     __ Bind(&target);
1057     JSCallCommonEntry(assembler, JSCallMode::CALL_GETTER);
1058 }
1059 
CallSetter(ExtendedAssembler * assembler)1060 void AsmInterpreterCall::CallSetter(ExtendedAssembler *assembler)
1061 {
1062     __ BindAssemblerStub(RTSTUB_ID(CallSetter));
1063     Label target;
1064     PushAsmInterpBridgeFrame(assembler);
1065     __ Callq(&target);
1066     PopAsmInterpBridgeFrame(assembler);
1067     __ Ret();
1068     __ Bind(&target);
1069     JSCallCommonEntry(assembler, JSCallMode::CALL_SETTER);
1070 }
1071 
CallContainersArgs3(ExtendedAssembler * assembler)1072 void AsmInterpreterCall::CallContainersArgs3(ExtendedAssembler *assembler)
1073 {
1074     __ BindAssemblerStub(RTSTUB_ID(CallContainersArgs3));
1075     Label target;
1076     PushAsmInterpBridgeFrame(assembler);
1077     GetArgvAtStack(assembler);
1078     __ Callq(&target);
1079     PopAsmInterpBridgeFrame(assembler);
1080     __ Ret();
1081     __ Bind(&target);
1082     {
1083         JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
1084     }
1085 }
1086 
1087 // ResumeRspAndReturn(uintptr_t acc)
1088 // GHC calling convention
1089 // %r13 - acc
1090 // %rbp - prevSp
1091 // %r12 - sp
ResumeRspAndReturn(ExtendedAssembler * assembler)1092 void AsmInterpreterCall::ResumeRspAndReturn([[maybe_unused]] ExtendedAssembler *assembler)
1093 {
1094     __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndReturn));
1095     Register currentSp = r12;
1096     Register fpRegister = r10;
1097     intptr_t offset = AsmInterpretedFrame::GetFpOffset(false) - AsmInterpretedFrame::GetSize(false);
1098     __ Movq(Operand(currentSp, static_cast<int32_t>(offset)), fpRegister);
1099     __ Movq(fpRegister, rsp);
1100     // return
1101     {
1102         __ Movq(r13, rax);
1103         __ Ret();
1104     }
1105 }
1106 
1107 // ResumeCaughtFrameAndDispatch(uintptr_t glue, uintptr_t sp, uintptr_t pc, uintptr_t constantPool,
1108 //     uint64_t profileTypeInfo, uint64_t acc, uint32_t hotnessCounter)
1109 // GHC calling convention
1110 // %r13 - glue
1111 // %rbp - sp
1112 // %r12 - pc
1113 // %rbx - constantPool
1114 // %r14 - profileTypeInfo
1115 // %rsi - acc
1116 // %rdi - hotnessCounter
ResumeCaughtFrameAndDispatch(ExtendedAssembler * assembler)1117 void AsmInterpreterCall::ResumeCaughtFrameAndDispatch(ExtendedAssembler *assembler)
1118 {
1119     __ BindAssemblerStub(RTSTUB_ID(ResumeCaughtFrameAndDispatch));
1120     Register glueRegister = __ GlueRegister();
1121     Register pcRegister = r12;
1122 
1123     Label dispatch;
1124     Register fpRegister = r11;
1125     __ Movq(Operand(glueRegister, JSThread::GlueData::GetLastFpOffset(false)), fpRegister);
1126     __ Cmpq(0, fpRegister);
1127     __ Jz(&dispatch);
1128     __ Movq(fpRegister, rsp);  // resume rsp
1129     __ Bind(&dispatch);
1130     {
1131         Register opcodeRegister = rax;
1132         __ Movzbq(Operand(pcRegister, 0), opcodeRegister);
1133         Register bcStubRegister = r11;
1134         __ Movq(Operand(glueRegister, opcodeRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)),
1135             bcStubRegister);
1136         __ Jmp(bcStubRegister);
1137     }
1138 }
1139 
1140 // ResumeUncaughtFrameAndReturn(uintptr_t glue)
1141 // GHC calling convention
1142 // %r13 - glue
1143 // %rbp - sp
1144 // %r12 - acc
ResumeUncaughtFrameAndReturn(ExtendedAssembler * assembler)1145 void AsmInterpreterCall::ResumeUncaughtFrameAndReturn(ExtendedAssembler *assembler)
1146 {
1147     __ BindAssemblerStub(RTSTUB_ID(ResumeUncaughtFrameAndReturn));
1148     Register glueRegister = __ GlueRegister();
1149     Register acc(r12);
1150     Register cppRet(rax);
1151 
1152     Label ret;
1153     Register fpRegister = r11;
1154     __ Movq(Operand(glueRegister, JSThread::GlueData::GetLastFpOffset(false)), fpRegister);
1155     __ Cmpq(0, fpRegister);
1156     __ Jz(&ret);
1157     __ Movq(fpRegister, rsp);  // resume rsp
1158     __ Bind(&ret);
1159     // this method will return to Execute(cpp calling convention), and the return value should be put into rax.
1160     __ Movq(acc, cppRet);
1161     __ Ret();
1162 }
1163 
PushUndefinedWithArgcAndCheckStack(ExtendedAssembler * assembler,Register glue,Register argc,Register op1,Register op2,Label * stackOverflow)1164 void AsmInterpreterCall::PushUndefinedWithArgcAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc,
1165     Register op1, Register op2, Label *stackOverflow)
1166 {
1167     ASSERT(stackOverflow != nullptr);
1168     StackOverflowCheck(assembler, glue, argc, op1, op2, stackOverflow);
1169     PushUndefinedWithArgc(assembler, argc);
1170 }
1171 
ThrowStackOverflowExceptionAndReturn(ExtendedAssembler * assembler,Register glue,Register fp,Register op)1172 void AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(ExtendedAssembler *assembler, Register glue, Register fp,
1173     Register op)
1174 {
1175     if (fp != rsp) {
1176         __ Movq(fp, rsp);
1177     }
1178     __ Movq(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException, op);
1179     __ Movq(Operand(glue, op, Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)), op);
1180     if (glue != r13) {
1181         __ Movq(glue, r13);
1182     }
1183     __ Callq(op);
1184     __ Ret();
1185 }
1186 
HasPendingException(ExtendedAssembler * assembler,Register threadRegister)1187 void AsmInterpreterCall::HasPendingException([[maybe_unused]] ExtendedAssembler *assembler,
1188     [[maybe_unused]] Register threadRegister)
1189 {
1190 }
1191 #undef __
1192 }  // namespace panda::ecmascript::x64