• 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         case JSCallMode::CALL_THIS_ARGV_WITH_RETURN: {
572             return __ CppJSCallAvailableRegister1();
573         }
574         default:
575             LOG_ECMA(FATAL) << "this branch is unreachable";
576             UNREACHABLE();
577     }
578     return rInvalid;
579 }
580 
GetNewTargetRegsiter(ExtendedAssembler * assembler,JSCallMode mode,Register defaultRegister)581 Register AsmInterpreterCall::GetNewTargetRegsiter(ExtendedAssembler *assembler, JSCallMode mode,
582                                                   Register defaultRegister)
583 {
584     switch (mode) {
585         case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
586         case JSCallMode::CALL_THIS_WITH_ARGV:
587             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
588         case JSCallMode::CALL_FROM_AOT:
589         case JSCallMode::CALL_ENTRY: {
590             Register argvRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
591             // -2: new Target offset
592             __ Movq(Operand(argvRegister, -2 * FRAME_SLOT_SIZE), defaultRegister);
593             return defaultRegister;
594         }
595         default:
596             LOG_ECMA(FATAL) << "this branch is unreachable";
597             UNREACHABLE();
598     }
599     return rInvalid;
600 }
601 
602 // Input: %r14 - callField
603 //        %rdi - argv
PushCallThis(ExtendedAssembler * assembler,JSCallMode mode,Label * stackOverflow)604 void AsmInterpreterCall::PushCallThis(ExtendedAssembler *assembler, JSCallMode mode, Label *stackOverflow)
605 {
606     Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
607     Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
608     Register thisRegister = __ AvailableRegister2();
609 
610     Label pushVregs;
611     Label pushNewTarget;
612     Label pushCallTarget;
613     bool haveThis = kungfu::AssemblerModule::JSModeHaveThisArg(mode);
614     bool haveNewTarget = kungfu::AssemblerModule::JSModeHaveNewTargetArg(mode);
615     if (!haveThis) {
616         __ Movq(JSTaggedValue::VALUE_UNDEFINED, thisRegister);  // default this: undefined
617     } else {
618         Register thisArgRegister = GetThisRegsiter(assembler, mode, thisRegister);
619         if (thisRegister != thisArgRegister) {
620             __ Movq(thisArgRegister, thisRegister);
621         }
622     }
623     __ Testb(CALL_TYPE_MASK, callFieldRegister);
624     __ Jz(&pushVregs);
625     // fall through
626     __ Testq(MethodLiteral::HaveThisBit::Mask(), callFieldRegister);
627     __ Jz(&pushNewTarget);
628     // push this
629     if (!haveThis) {
630         __ Pushq(JSTaggedValue::Undefined().GetRawData());
631     } else {
632         __ Pushq(thisRegister);
633     }
634     // fall through
635     __ Bind(&pushNewTarget);
636     {
637         __ Testq(MethodLiteral::HaveNewTargetBit::Mask(), callFieldRegister);
638         __ Jz(&pushCallTarget);
639         if (!haveNewTarget) {
640             __ Pushq(JSTaggedValue::Undefined().GetRawData());
641         } else {
642             [[maybe_unused]] TempRegisterScope scope(assembler);
643             Register defaultRegister = __ TempRegister();
644             Register newTargetRegister = GetNewTargetRegsiter(assembler, mode, defaultRegister);
645             __ Pushq(newTargetRegister);
646         }
647     }
648     // fall through
649     __ Bind(&pushCallTarget);
650     {
651         __ Testq(MethodLiteral::HaveFuncBit::Mask(), callFieldRegister);
652         __ Jz(&pushVregs);
653         __ Pushq(callTargetRegister);
654     }
655     // fall through
656     __ Bind(&pushVregs);
657     {
658         PushVregs(assembler, stackOverflow);
659     }
660 }
661 
662 // Input: %rbp - sp
663 //        %r12 - callTarget
664 //        %rbx - method
665 //        %r14 - callField
666 //        %rdx - jumpSizeAfterCall
667 //        %r10 - fp
PushVregs(ExtendedAssembler * assembler,Label * stackOverflow)668 void AsmInterpreterCall::PushVregs(ExtendedAssembler *assembler, Label *stackOverflow)
669 {
670     Register glueRegister = __ GlueRegister();
671     Register prevSpRegister = rbp;
672     Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
673     Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
674     Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
675     Register fpRegister = __ AvailableRegister1();
676     Register thisRegister = __ AvailableRegister2();
677 
678     Label pushFrameState;
679 
680     [[maybe_unused]] TempRegisterScope scope(assembler);
681     Register tempRegister = __ TempRegister();
682     // args register can reused now.
683     Register pcRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
684     Register numVregsRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
685     GetNumVregsFromCallField(assembler, callFieldRegister, numVregsRegister);
686     __ Cmpq(0, numVregsRegister);
687     __ Jz(&pushFrameState);
688     Register temp2Register = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);  // reuse
689     PushUndefinedWithArgcAndCheckStack(assembler, glueRegister, numVregsRegister, tempRegister, temp2Register,
690         stackOverflow);
691     // fall through
692     Register newSpRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
693     __ Bind(&pushFrameState);
694     {
695         __ Movq(rsp, newSpRegister);
696 
697         PushFrameState(assembler, prevSpRegister, fpRegister,
698             callTargetRegister, thisRegister, methodRegister, pcRegister, tempRegister);
699     }
700     DispatchCall(assembler, pcRegister, newSpRegister, methodRegister);
701 }
702 
703 // Input: %r13 - glue
704 //        %rbp - sp
705 //        %r12 - callTarget
706 //        %rbx - method
DispatchCall(ExtendedAssembler * assembler,Register pcRegister,Register newSpRegister,Register methodRegister,Register accRegister)707 void AsmInterpreterCall::DispatchCall(ExtendedAssembler *assembler, Register pcRegister,
708     Register newSpRegister, Register methodRegister, Register accRegister)
709 {
710     Register glueRegister = __ GlueRegister();
711     Label dispatchCall;
712     // align 16 bytes
713     __ Testq(15, rsp);  // 15: low 4 bits must be 0b0000
714     __ Jnz(&dispatchCall);
715     __ PushAlignBytes();
716     __ Bind(&dispatchCall);
717     // profileTypeInfo: r14
718     __ Movq(Operand(methodRegister, Method::PROFILE_TYPE_INFO_OFFSET), r14);
719     // glue may rdi
720     if (glueRegister != r13) {
721         __ Movq(glueRegister, r13);
722     }
723     // sp: rbp
724     __ Movq(newSpRegister, rbp);
725     // hotnessCounter: rdi
726     __ Movzwq(Operand(methodRegister, Method::LITERAL_INFO_OFFSET), rdi);
727     // constantPool: rbx
728     __ Movq(Operand(methodRegister, Method::CONSTANT_POOL_OFFSET), rbx);
729     // pc: r12
730     if (pcRegister != r12) {
731         __ Movq(pcRegister, r12);
732     }
733 
734     Register bcIndexRegister = rax;
735     Register tempRegister = __ AvailableRegister1();
736     __ Movzbq(Operand(pcRegister, 0), bcIndexRegister);
737     // acc: rsi
738     if (accRegister != rInvalid) {
739         ASSERT(accRegister == rsi);
740     } else {
741         __ Movq(JSTaggedValue::Hole().GetRawData(), rsi);
742     }
743     __ Movq(Operand(r13, bcIndexRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)), tempRegister);
744     __ Jmp(tempRegister);
745 }
746 
747 // uint64_t PushCallRangeAndDispatchNative(uintptr_t glue, uint32_t argc, JSTaggedType calltarget, uintptr_t argv[])
748 // c++ calling convention call js function
749 // Input: %rdi - glue
750 //        %rsi - nativeCode
751 //        %rdx - func
752 //        %rcx - thisValue
753 //        %r8  - argc
754 //        %r9  - argV (...)
PushCallRangeAndDispatchNative(ExtendedAssembler * assembler)755 void AsmInterpreterCall::PushCallRangeAndDispatchNative(ExtendedAssembler *assembler)
756 {
757     __ BindAssemblerStub(RTSTUB_ID(PushCallRangeAndDispatchNative));
758     CallNativeWithArgv(assembler, false);
759 }
760 
PushCallNewAndDispatchNative(ExtendedAssembler * assembler)761 void AsmInterpreterCall::PushCallNewAndDispatchNative(ExtendedAssembler *assembler)
762 {
763     __ BindAssemblerStub(RTSTUB_ID(PushCallNewAndDispatchNative));
764     CallNativeWithArgv(assembler, true);
765 }
766 
CallNativeWithArgv(ExtendedAssembler * assembler,bool callNew)767 void AsmInterpreterCall::CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew)
768 {
769     Register glue = rdi;
770     Register nativeCode = rsi;
771     Register func = rdx;
772     Register thisValue = rcx;
773     Register numArgs = r8;
774     Register stackArgs = r9;
775     Register temporary = rax;
776     Register temporary2 = r11;
777     Register opNumArgs = r10;
778     Label aligned;
779     Label pushThis;
780     Label stackOverflow;
781 
782     PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_FRAME_WITH_ARGV);
783 
784     __ Push(numArgs);
785     __ Cmpq(0, numArgs);
786     __ Jz(&pushThis);
787     __ Movq(numArgs, opNumArgs);
788     PushArgsWithArgvAndCheckStack(assembler, glue, opNumArgs, stackArgs, temporary, temporary2, &stackOverflow);
789 
790     __ Bind(&pushThis);
791     __ Push(thisValue);
792     // new.target
793     if (callNew) {
794         __ Pushq(func);
795     } else {
796         __ Pushq(JSTaggedValue::Undefined().GetRawData());
797     }
798     __ Pushq(func);
799     // 40: skip frame type, numArgs, func, newTarget and this
800     __ Leaq(Operand(rsp, numArgs, Times8, 5 * FRAME_SLOT_SIZE), rbp);
801     __ Movq(rsp, stackArgs);
802 
803     // push argc
804     __ Addl(NUM_MANDATORY_JSFUNC_ARGS, numArgs);
805     __ Pushq(numArgs);
806     // push thread
807     __ Pushq(glue);
808     // EcmaRuntimeCallInfo
809     __ Movq(rsp, rdi);
810 
811     __ Testq(0xf, rsp);  // 0xf: 0x1111
812     __ Jz(&aligned, Distance::Near);
813     __ PushAlignBytes();
814 
815     __ Bind(&aligned);
816     CallNativeInternal(assembler, nativeCode);
817     __ Ret();
818 
819     __ Bind(&stackOverflow);
820     {
821         Label aligneThrow;
822         __ Movq(static_cast<int32_t>(FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME),
823             Operand(rsp, FRAME_SLOT_SIZE));
824         __ Pushq(0);  // argc
825         __ Pushq(JSTaggedValue::VALUE_UNDEFINED);  // this
826         __ Pushq(JSTaggedValue::VALUE_UNDEFINED);  // newTarget
827         __ Pushq(JSTaggedValue::VALUE_UNDEFINED);  // callTarget
828 
829         __ Testq(0xf, rsp);  // 0xf: 0x1111
830         __ Jz(&aligneThrow, Distance::Near);
831         __ PushAlignBytes();
832 
833         __ Bind(&aligneThrow);
834         Register trampolineIdRegister = r9;
835         Register trampolineRegister = r10;
836         __ Movq(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException, trampolineIdRegister);
837         __ Movq(Operand(glue, trampolineIdRegister, Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)),
838             trampolineRegister);
839         __ Callq(trampolineRegister);
840 
841         // resume rsp
842         __ Movq(rbp, rsp);
843         __ Pop(rbp);
844         __ Ret();
845     }
846 }
847 
CallNativeEntry(ExtendedAssembler * assembler)848 void AsmInterpreterCall::CallNativeEntry(ExtendedAssembler *assembler)
849 {
850     Register glue = rdi;
851     Register argv = r9;
852     Register method = rdx;
853     Register function = rsi;
854     Register nativeCode = r10;
855 
856     __ PushAlignBytes();
857     __ Push(function);
858     // 24: skip thread & argc & returnAddr
859     __ Subq(3 * FRAME_SLOT_SIZE, rsp);
860     PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_ENTRY_FRAME);
861     __ Movq(Operand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET), nativeCode); // get native pointer
862     __ Movq(argv, r11);
863     // 16: skip numArgs & thread
864     __ Subq(2 * FRAME_SLOT_SIZE, r11);
865     // EcmaRuntimeCallInfo
866     __ Movq(r11, rdi);
867 
868     CallNativeInternal(assembler, nativeCode);
869 
870     // 40: skip function
871     __ Addq(5 * FRAME_SLOT_SIZE, rsp);
872     __ Ret();
873 }
874 
875 // uint64_t PushCallArgsAndDispatchNative(uintptr_t codeAddress, uintptr_t glue, uint32_t argc, ...)
876 // webkit_jscc calling convention call runtime_id's runtion function(c-abi)
877 // Input:        %rax - codeAddress
878 // stack layout: sp + N*8 argvN
879 //               ........
880 //               sp + 24: argv1
881 //               sp + 16: argv0
882 //               sp + 8:  actualArgc
883 //               sp:      thread
884 // construct Native Leave Frame
885 //               +--------------------------+
886 //               |     argV[N - 1]          |
887 //               |--------------------------|
888 //               |       . . . .            |
889 //               |--------------------------+
890 //               |     argV[2]=this         |
891 //               +--------------------------+
892 //               |     argV[1]=new-target   |
893 //               +--------------------------+
894 //               |     argV[0]=call-target  |
895 //               +--------------------------+ ---------
896 //               |       argc               |         ^
897 //               |--------------------------|         |
898 //               |       thread             |         |
899 //               |--------------------------|         |
900 //               |       returnAddr         |     BuiltinFrame
901 //               |--------------------------|         |
902 //               |       callsiteFp         |         |
903 //               |--------------------------|         |
904 //               |       frameType          |         v
905 //               +--------------------------+ ---------
906 
PushCallArgsAndDispatchNative(ExtendedAssembler * assembler)907 void AsmInterpreterCall::PushCallArgsAndDispatchNative(ExtendedAssembler *assembler)
908 {
909     __ BindAssemblerStub(RTSTUB_ID(PushCallArgsAndDispatchNative));
910     Register nativeCode = rax;
911     Register glue = rdi;
912 
913     __ Movq(Operand(rsp, FRAME_SLOT_SIZE), glue); // 8: glue
914     PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_FRAME);
915     __ Leaq(Operand(rbp, 2 * FRAME_SLOT_SIZE), rdi); // 16: skip argc & thread
916     __ PushAlignBytes();
917     CallNativeInternal(assembler, nativeCode);
918     __ Ret();
919 }
920 
PushBuiltinFrame(ExtendedAssembler * assembler,Register glue,FrameType type)921 void AsmInterpreterCall::PushBuiltinFrame(ExtendedAssembler *assembler,
922                                           Register glue, FrameType type)
923 {
924     __ Pushq(rbp);
925     __ Movq(rsp, Operand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
926     __ Pushq(static_cast<int32_t>(type));
927     __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);  // 8: skip frame type
928 }
929 
CallNativeInternal(ExtendedAssembler * assembler,Register nativeCode)930 void AsmInterpreterCall::CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode)
931 {
932     __ Callq(nativeCode);
933     // resume rsp
934     __ Movq(rbp, rsp);
935     __ Pop(rbp);
936 }
937 
938 // ResumeRspAndDispatch(uintptr_t glue, uintptr_t sp, uintptr_t pc, uintptr_t constantPool,
939 //     uint64_t profileTypeInfo, uint64_t acc, uint32_t hotnessCounter, size_t jumpSize)
940 // GHC calling convention
941 // %r13 - glue
942 // %rbp - sp
943 // %r12 - pc
944 // %rbx - constantPool
945 // %r14 - profileTypeInfo
946 // %rsi - acc
947 // %rdi - hotnessCounter
948 // %r8  - jumpSizeAfterCall
ResumeRspAndDispatch(ExtendedAssembler * assembler)949 void AsmInterpreterCall::ResumeRspAndDispatch(ExtendedAssembler *assembler)
950 {
951     __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndDispatch));
952     Register glueRegister = __ GlueRegister();
953     Register spRegister = rbp;
954     Register pcRegister = r12;
955     Register ret = rsi;
956     Register jumpSizeRegister = r8;
957 
958     Register frameStateBaseRegister = r11;
959     __ Movq(spRegister, frameStateBaseRegister);
960     __ Subq(AsmInterpretedFrame::GetSize(false), frameStateBaseRegister);
961 
962     Label dispatch;
963     Label newObjectRangeReturn;
964     __ Cmpq(0, jumpSizeRegister);
965     __ Jle(&newObjectRangeReturn);
966 
967     __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetBaseOffset(false)), spRegister);  // update sp
968     __ Addq(jumpSizeRegister, pcRegister);  // newPC
969     Register temp = rax;
970     Register opcodeRegister = rax;
971     __ Movzbq(Operand(pcRegister, 0), opcodeRegister);
972 
973     __ Bind(&dispatch);
974     {
975         __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetFpOffset(false)), rsp);   // resume rsp
976         Register bcStubRegister = r11;
977         __ Movq(Operand(glueRegister, opcodeRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)),
978             bcStubRegister);
979         __ Jmp(bcStubRegister);
980     }
981 
982     Label getThis;
983     Label notUndefined;
984     __ Bind(&newObjectRangeReturn);
985     __ Cmpq(JSTaggedValue::Undefined().GetRawData(), ret);
986     __ Jne(&notUndefined);
987 
988     __ Bind(&getThis);
989     __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetBaseOffset(false)), spRegister);  // update sp
990     __ Subq(jumpSizeRegister, pcRegister);  // sub negative jmupSize
991     __ Movzbq(Operand(pcRegister, 0), opcodeRegister);
992     {
993         __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetThisOffset(false)), ret);
994         __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetFpOffset(false)), rsp);   // resume rsp
995         Register bcStubRegister = r11;
996         __ Movq(Operand(glueRegister, opcodeRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)),
997             bcStubRegister);
998         __ Jmp(bcStubRegister);
999     }
1000 
1001     __ Bind(&notUndefined);
1002     {
1003         Label notEcmaObject;
1004         __ Movabs(JSTaggedValue::TAG_HEAPOBJECT_MASK, temp);
1005         __ And(ret, temp);
1006         __ Cmpq(0, temp);
1007         __ Jne(&notEcmaObject);
1008         // acc is heap object
1009         __ Movq(Operand(ret, 0), temp);  // hclass
1010         __ Movl(Operand(temp, JSHClass::BIT_FIELD_OFFSET), temp);
1011         __ Cmpb(static_cast<int32_t>(JSType::ECMA_OBJECT_LAST), temp);
1012         __ Ja(&notEcmaObject);
1013         __ Cmpb(static_cast<int32_t>(JSType::ECMA_OBJECT_FIRST), temp);
1014         __ Jb(&notEcmaObject);
1015         // acc is ecma object
1016         __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetBaseOffset(false)), spRegister);  // update sp
1017         __ Subq(jumpSizeRegister, pcRegister);  // sub negative jmupSize
1018         __ Movzbq(Operand(pcRegister, 0), opcodeRegister);
1019         __ Jmp(&dispatch);
1020 
1021         __ Bind(&notEcmaObject);
1022         {
1023             // load constructor
1024             __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetFunctionOffset(false)), temp);
1025             __ Movq(Operand(temp, JSFunctionBase::METHOD_OFFSET), temp);
1026             __ Movq(Operand(temp, Method::EXTRA_LITERAL_INFO_OFFSET), temp);
1027             __ Shr(MethodLiteral::FunctionKindBits::START_BIT, temp);
1028             __ Andl((1LU << MethodLiteral::FunctionKindBits::SIZE) - 1, temp);
1029             __ Cmpl(static_cast<int32_t>(FunctionKind::CLASS_CONSTRUCTOR), temp);
1030             __ Jbe(&getThis);  // constructor is base
1031             // fall through
1032         }
1033         // exception branch
1034         {
1035             __ Movq(Operand(frameStateBaseRegister, AsmInterpretedFrame::GetBaseOffset(false)), spRegister);
1036             __ Movq(kungfu::BytecodeStubCSigns::ID_NewObjectRangeThrowException, opcodeRegister);
1037             __ Jmp(&dispatch);
1038         }
1039     }
1040 }
1041 
1042 // c++ calling convention
1043 // %rdi - glue
1044 // %rsi - callTarget
1045 // %rdx - method
1046 // %rcx - callField
1047 // %r8 - receiver
1048 // %r9 - value
CallGetter(ExtendedAssembler * assembler)1049 void AsmInterpreterCall::CallGetter(ExtendedAssembler *assembler)
1050 {
1051     __ BindAssemblerStub(RTSTUB_ID(CallGetter));
1052     Label target;
1053 
1054     PushAsmInterpBridgeFrame(assembler);
1055     __ Callq(&target);
1056     PopAsmInterpBridgeFrame(assembler);
1057     __ Ret();
1058     __ Bind(&target);
1059     JSCallCommonEntry(assembler, JSCallMode::CALL_GETTER);
1060 }
1061 
CallSetter(ExtendedAssembler * assembler)1062 void AsmInterpreterCall::CallSetter(ExtendedAssembler *assembler)
1063 {
1064     __ BindAssemblerStub(RTSTUB_ID(CallSetter));
1065     Label target;
1066     PushAsmInterpBridgeFrame(assembler);
1067     __ Callq(&target);
1068     PopAsmInterpBridgeFrame(assembler);
1069     __ Ret();
1070     __ Bind(&target);
1071     JSCallCommonEntry(assembler, JSCallMode::CALL_SETTER);
1072 }
1073 
1074 // Input: glue             - %rdi
1075 //        callTarget       - %rsi
1076 //        method           - %rdx
1077 //        callField        - %rcx
1078 //        arg0(argc)       - %r8
1079 //        arg1(arglist)    - %r9
1080 //        argthis          - stack
CallReturnWithArgv(ExtendedAssembler * assembler)1081 void AsmInterpreterCall::CallReturnWithArgv(ExtendedAssembler *assembler)
1082 {
1083     __ BindAssemblerStub(RTSTUB_ID(CallReturnWithArgv));
1084     Label target;
1085     PushAsmInterpBridgeFrame(assembler);
1086     Register r13 = __ CppJSCallAvailableRegister1();
1087     __ Movq(Operand(rbp, FRAME_SLOT_SIZE), r13);
1088     __ Callq(&target);
1089     PopAsmInterpBridgeFrame(assembler);
1090     __ Ret();
1091     __ Bind(&target);
1092     {
1093         JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARGV_WITH_RETURN);
1094     }
1095 }
1096 
CallContainersArgs3(ExtendedAssembler * assembler)1097 void AsmInterpreterCall::CallContainersArgs3(ExtendedAssembler *assembler)
1098 {
1099     __ BindAssemblerStub(RTSTUB_ID(CallContainersArgs3));
1100     Label target;
1101     PushAsmInterpBridgeFrame(assembler);
1102     GetArgvAtStack(assembler);
1103     __ Callq(&target);
1104     PopAsmInterpBridgeFrame(assembler);
1105     __ Ret();
1106     __ Bind(&target);
1107     {
1108         JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
1109     }
1110 }
1111 
1112 // ResumeRspAndReturn(uintptr_t acc)
1113 // GHC calling convention
1114 // %r13 - acc
1115 // %rbp - prevSp
1116 // %r12 - sp
ResumeRspAndReturn(ExtendedAssembler * assembler)1117 void AsmInterpreterCall::ResumeRspAndReturn(ExtendedAssembler *assembler)
1118 {
1119     __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndReturn));
1120     Register currentSp = r12;
1121     Register fpRegister = r10;
1122     intptr_t offset = AsmInterpretedFrame::GetFpOffset(false) - AsmInterpretedFrame::GetSize(false);
1123     __ Movq(Operand(currentSp, static_cast<int32_t>(offset)), fpRegister);
1124     __ Movq(fpRegister, rsp);
1125     // return
1126     {
1127         __ Movq(r13, rax);
1128         __ Ret();
1129     }
1130 }
1131 
1132 // ResumeCaughtFrameAndDispatch(uintptr_t glue, uintptr_t sp, uintptr_t pc, uintptr_t constantPool,
1133 //     uint64_t profileTypeInfo, uint64_t acc, uint32_t hotnessCounter)
1134 // GHC calling convention
1135 // %r13 - glue
1136 // %rbp - sp
1137 // %r12 - pc
1138 // %rbx - constantPool
1139 // %r14 - profileTypeInfo
1140 // %rsi - acc
1141 // %rdi - hotnessCounter
ResumeCaughtFrameAndDispatch(ExtendedAssembler * assembler)1142 void AsmInterpreterCall::ResumeCaughtFrameAndDispatch(ExtendedAssembler *assembler)
1143 {
1144     __ BindAssemblerStub(RTSTUB_ID(ResumeCaughtFrameAndDispatch));
1145     Register glueRegister = __ GlueRegister();
1146     Register pcRegister = r12;
1147 
1148     Label dispatch;
1149     Register fpRegister = r11;
1150     __ Movq(Operand(glueRegister, JSThread::GlueData::GetLastFpOffset(false)), fpRegister);
1151     __ Cmpq(0, fpRegister);
1152     __ Jz(&dispatch);
1153     __ Movq(fpRegister, rsp);  // resume rsp
1154     __ Bind(&dispatch);
1155     {
1156         Register opcodeRegister = rax;
1157         __ Movzbq(Operand(pcRegister, 0), opcodeRegister);
1158         Register bcStubRegister = r11;
1159         __ Movq(Operand(glueRegister, opcodeRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)),
1160             bcStubRegister);
1161         __ Jmp(bcStubRegister);
1162     }
1163 }
1164 
1165 // ResumeUncaughtFrameAndReturn(uintptr_t glue)
1166 // GHC calling convention
1167 // %r13 - glue
1168 // %rbp - sp
1169 // %r12 - acc
ResumeUncaughtFrameAndReturn(ExtendedAssembler * assembler)1170 void AsmInterpreterCall::ResumeUncaughtFrameAndReturn(ExtendedAssembler *assembler)
1171 {
1172     __ BindAssemblerStub(RTSTUB_ID(ResumeUncaughtFrameAndReturn));
1173     Register glueRegister = __ GlueRegister();
1174     Register acc(r12);
1175     Register cppRet(rax);
1176 
1177     Label ret;
1178     Register fpRegister = r11;
1179     __ Movq(Operand(glueRegister, JSThread::GlueData::GetLastFpOffset(false)), fpRegister);
1180     __ Cmpq(0, fpRegister);
1181     __ Jz(&ret);
1182     __ Movq(fpRegister, rsp);  // resume rsp
1183     __ Bind(&ret);
1184     // this method will return to Execute(cpp calling convention), and the return value should be put into rax.
1185     __ Movq(acc, cppRet);
1186     __ Ret();
1187 }
1188 
PushUndefinedWithArgcAndCheckStack(ExtendedAssembler * assembler,Register glue,Register argc,Register op1,Register op2,Label * stackOverflow)1189 void AsmInterpreterCall::PushUndefinedWithArgcAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc,
1190     Register op1, Register op2, Label *stackOverflow)
1191 {
1192     ASSERT(stackOverflow != nullptr);
1193     StackOverflowCheck(assembler, glue, argc, op1, op2, stackOverflow);
1194     PushUndefinedWithArgc(assembler, argc);
1195 }
1196 
ThrowStackOverflowExceptionAndReturn(ExtendedAssembler * assembler,Register glue,Register fp,Register op)1197 void AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(ExtendedAssembler *assembler, Register glue, Register fp,
1198     Register op)
1199 {
1200     if (fp != rsp) {
1201         __ Movq(fp, rsp);
1202     }
1203     __ Movq(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException, op);
1204     __ Movq(Operand(glue, op, Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)), op);
1205     if (glue != r13) {
1206         __ Movq(glue, r13);
1207     }
1208     __ Callq(op);
1209     __ Ret();
1210 }
1211 
HasPendingException(ExtendedAssembler * assembler,Register threadRegister)1212 void AsmInterpreterCall::HasPendingException([[maybe_unused]] ExtendedAssembler *assembler,
1213     [[maybe_unused]] Register threadRegister)
1214 {
1215 }
1216 #undef __
1217 }  // namespace panda::ecmascript::x64