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(¬JSFunction);
150 __ Cmpb(static_cast<int32_t>(JSType::JS_FUNCTION_LAST), bitFieldRegister);
151 __ Jbe(&callJSFunctionEntry);
152 __ Bind(¬JSFunction);
153 {
154 __ Testq(static_cast<int64_t>(1ULL << JSHClass::CallableBit::START_BIT), bitFieldRegister);
155 __ Jz(¬Callable);
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(¬Callable);
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(¬Undefined);
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(¬Undefined);
1002 {
1003 Label notEcmaObject;
1004 __ Movabs(JSTaggedValue::TAG_HEAPOBJECT_MASK, temp);
1005 __ And(ret, temp);
1006 __ Cmpq(0, temp);
1007 __ Jne(¬EcmaObject);
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(¬EcmaObject);
1013 __ Cmpb(static_cast<int32_t>(JSType::ECMA_OBJECT_FIRST), temp);
1014 __ Jb(¬EcmaObject);
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(¬EcmaObject);
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