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