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/compiler/argument_accessor.h"
22 #include "ecmascript/deoptimizer/deoptimizer.h"
23 #include "ecmascript/ecma_runtime_call_info.h"
24 #include "ecmascript/frames.h"
25 #include "ecmascript/js_function.h"
26 #include "ecmascript/js_thread.h"
27 #include "ecmascript/message_string.h"
28 #include "ecmascript/method.h"
29 #include "ecmascript/runtime_call_id.h"
30
31 namespace panda::ecmascript::x64 {
32 #define __ assembler->
33
34 // * uint64_t JSFunctionEntry(uintptr_t glue, uint32_t actualNumArgs, const JSTaggedType argV[], uintptr_t prevFp)
35 // * Arguments:
36 // %rdi - glue
37 // %rsi - actualNumArgs
38 // %rdx - argV
39 // %rcx - prevFp
40 // %r8 - needPushUndefined
41 //
42 // * The JSFunctionEntry Frame's structure is illustrated as the following:
43 // +--------------------------+
44 // | . . . . . . |
45 // sp ---> +--------------------------+ -----------------
46 // | prevFP | ^
47 // |--------------------------| |
48 // | frameType | JSFunctionEntryFrame
49 // |--------------------------| |
50 // | preLeaveFrameFp | v
51 // +--------------------------+ -----------------
52
JSFunctionEntry(ExtendedAssembler * assembler)53 void OptimizedCall::JSFunctionEntry(ExtendedAssembler *assembler)
54 {
55 __ BindAssemblerStub(RTSTUB_ID(JSFunctionEntry));
56 Register glueReg = rdi;
57 Register argv = rdx;
58 Register prevFpReg = rcx;
59 Register needPushUndefined = r8;
60 Label lJSCallWithArgVAndPushUndefined;
61 Label lPopFrame;
62 PushJSFunctionEntryFrame(assembler, prevFpReg);
63 __ Movq(argv, rbx);
64 __ Movq(needPushUndefined, r12);
65 __ Movq(Operand(rbx, 0), rdx);
66 __ Movq(Operand(rbx, FRAME_SLOT_SIZE), rcx);
67 __ Movq(Operand(rbx, DOUBLE_SLOT_SIZE), r8);
68 __ Addq(TRIPLE_SLOT_SIZE, rbx);
69 __ Movq(rbx, r9);
70 __ Cmp(1, r12);
71 __ Je(&lJSCallWithArgVAndPushUndefined);
72 __ CallAssemblerStub(RTSTUB_ID(JSCallWithArgV), false);
73 __ Jmp(&lPopFrame);
74
75 __ Bind(&lJSCallWithArgVAndPushUndefined);
76 __ CallAssemblerStub(RTSTUB_ID(JSCallWithArgVAndPushUndefined), false);
77
78 __ Bind(&lPopFrame);
79 __ Popq(prevFpReg);
80 __ Addq(FRAME_SLOT_SIZE, rsp); // 8: frame type
81 __ Popq(rbp);
82 __ Popq(glueReg); // caller restore
83 __ PopCppCalleeSaveRegisters(); // callee restore
84 __ Movq(prevFpReg, Operand(glueReg, JSThread::GlueData::GetLeaveFrameOffset(false)));
85 __ Ret();
86 }
87
88 // * uint64_t OptimizedCallAndPushUndefined(uintptr_t glue, uint32_t argc, JSTaggedType calltarget, JSTaggedType new,
89 // JSTaggedType this, arg[0], arg[1], arg[2], ..., arg[N-1])
90 // * webkit_jscc calling convention call js function()
91 //
92 // * OptimizedJSFunctionFrame layout description as the following:
93 // +--------------------------+
94 // | arg[N-1] |
95 // +--------------------------+
96 // | ... |
97 // +--------------------------+
98 // | arg[1] |
99 // +--------------------------+
100 // | arg[0] |
101 // +--------------------------+
102 // | this |
103 // +--------------------------+
104 // | new-target |
105 // +--------------------------+
106 // | call-target |
107 // |--------------------------|
108 // | argc |
109 // |--------------------------| ---------------
110 // | returnAddr | ^
111 // sp ----> |--------------------------| |
112 // | callsiteFp | |
113 // |--------------------------| OptimizedJSFunctionFrame
114 // | frameType | |
115 // |--------------------------| |
116 // | call-target | v
117 // +--------------------------+ ---------------
OptimizedCallAndPushUndefined(ExtendedAssembler * assembler)118 void OptimizedCall::OptimizedCallAndPushUndefined(ExtendedAssembler *assembler)
119 {
120 __ BindAssemblerStub(RTSTUB_ID(OptimizedCallAndPushUndefined));
121 Register jsFuncReg = rdi;
122 Register method = r9;
123 Register codeAddrReg = rsi;
124 __ Movq(Operand(rsp, DOUBLE_SLOT_SIZE), jsFuncReg); // sp + 16 get jsFunc
125 __ Mov(Operand(jsFuncReg, JSFunctionBase::METHOD_OFFSET), method); // get method
126 __ Mov(Operand(method, Method::CODE_ENTRY_OFFSET), codeAddrReg);
127
128 Register methodCallField = rcx;
129 __ Mov(Operand(method, Method::CALL_FIELD_OFFSET), methodCallField); // get call field
130 __ Shr(MethodLiteral::NumArgsBits::START_BIT, methodCallField);
131 __ Andl(((1LU << MethodLiteral::NumArgsBits::SIZE) - 1), methodCallField);
132 __ Addl(NUM_MANDATORY_JSFUNC_ARGS, methodCallField); // add mandatory argumentr
133
134 __ Movl(Operand(rsp, FRAME_SLOT_SIZE), rdx); // argc rdx
135 __ Movq(rsp, r8);
136 Register argvReg = r8;
137 auto funcSlotOffset = kungfu::ArgumentAccessor::GetExtraArgsNum() + 1; // 1: return addr
138 __ Addq(funcSlotOffset * FRAME_SLOT_SIZE, argvReg); // skip return addr and argc
139
140 Register expectedNumArgsReg = rcx;
141 Register actualNumArgsReg = rdx;
142
143 Label lCopyExtraAument1;
144 Label lCopyLoop1;
145 Label lPopFrame1;
146 __ Pushq(rbp);
147 __ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME));
148 __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
149 // callee save
150 __ Pushq(r14);
151 __ Pushq(rbx);
152 __ Pushq(rax);
153
154 // 16 bytes align check
155 __ Movl(expectedNumArgsReg, r14);
156 __ Testb(1, r14);
157 __ Jne(&lCopyExtraAument1);
158 __ Pushq(0);
159
160 __ Bind(&lCopyExtraAument1); // copy undefined value to stack
161 __ Pushq(JSTaggedValue::VALUE_UNDEFINED);
162 __ Addq(-1, expectedNumArgsReg);
163 __ Cmpq(actualNumArgsReg, expectedNumArgsReg);
164 __ Ja(&lCopyExtraAument1);
165
166 __ Bind(&lCopyLoop1);
167 __ Movq(Operand(argvReg, expectedNumArgsReg, Scale::Times8, -FRAME_SLOT_SIZE), rbx); // -8: stack index
168 __ Pushq(rbx);
169 __ Addq(-1, expectedNumArgsReg);
170 __ Jne(&lCopyLoop1);
171 __ Pushq(actualNumArgsReg); // actual argc
172
173 __ Callq(codeAddrReg); // then call jsFunction
174 __ Leaq(Operand(r14, Scale::Times8, 0), codeAddrReg);
175 __ Addq(codeAddrReg, rsp);
176 __ Addq(FRAME_SLOT_SIZE, rsp); // skip actualNumArgsReg
177 __ Testb(1, r14); // stack 16bytes align check
178 __ Jne(&lPopFrame1);
179 __ Addq(8, rsp); // 8: align byte
180
181 __ Bind(&lPopFrame1);
182 __ Addq(8, rsp); // 8: skip rax
183 __ Popq(rbx);
184 __ Popq(r14);
185 __ Addq(FRAME_SLOT_SIZE, rsp); // skip frame type
186 __ Pop(rbp);
187 __ Ret();
188 }
189
OptimizedCallAsmInterpreter(ExtendedAssembler * assembler)190 void OptimizedCall::OptimizedCallAsmInterpreter(ExtendedAssembler *assembler)
191 {
192 Label target;
193 PushAsmInterpBridgeFrame(assembler);
194 __ Callq(&target);
195 PopAsmInterpBridgeFrame(assembler);
196 __ Ret();
197 __ Bind(&target);
198 AsmInterpreterCall::JSCallCommonEntry(assembler, JSCallMode::CALL_FROM_AOT);
199 }
200
201 // * uint64_t CallBuiltinTrampoline(uintptr_t glue, uintptr_t codeAddress, uint32_t argc, ...)
202 // * webkit_jscc calling convention call runtime_id's runtime function(c-abi)
203 //
204 // * Construct Native Leave Frame Layout:
205 // +--------------------------+
206 // | argv[N-1] |
207 // +--------------------------+
208 // | . . . . . . |
209 // +--------------------------+
210 // | argv[3]=a0 |
211 // +--------------------------+
212 // | argv[2]=this |
213 // +--------------------------+
214 // | argv[1]=new-target |
215 // +--------------------------+
216 // | argv[0]=call-target |
217 // +--------------------------+ -----------------
218 // | argc | ^
219 // |--------------------------| |
220 // | thread | |
221 // |--------------------------| |
222 // | returnAddr | OptimizedBuiltinLeaveFrame
223 // sp ---> |--------------------------| |
224 // | callsiteFp | |
225 // |--------------------------| |
226 // | frameType | |
227 // |--------------------------| |
228 // | align byte | v
229 // +--------------------------+ -----------------
230
CallBuiltinTrampoline(ExtendedAssembler * assembler)231 void OptimizedCall::CallBuiltinTrampoline(ExtendedAssembler *assembler)
232 {
233 Register glueReg = rax;
234 Register nativeCode = rsi;
235
236 __ Movq(Operand(rsp, 0), rdx);
237 __ Movq(glueReg, Operand(rsp, 0));
238 __ Push(rdx);
239
240 AsmInterpreterCall::PushBuiltinFrame(assembler, glueReg, FrameType::BUILTIN_CALL_LEAVE_FRAME);
241 __ Leaq(Operand(rbp, 2 * FRAME_SLOT_SIZE), rdi); // 2: skip rbp & return Addr
242 AsmInterpreterCall::CallNativeInternal(assembler, nativeCode);
243 __ Pop(rdx);
244 __ Movq(rdx, Operand(rsp, 0));
245 __ Ret();
246 }
247
248 // * uint64_t JSProxyCallInternalWithArgV(uintptr_t glue, JSTaggedType calltarget)
249 // * c++ calling convention call js function
250 // * Arguments:
251 // %rdi - glue
252 // %rsi - calltarget
253
JSProxyCallInternalWithArgV(ExtendedAssembler * assembler)254 void OptimizedCall::JSProxyCallInternalWithArgV(ExtendedAssembler *assembler)
255 {
256 __ BindAssemblerStub(RTSTUB_ID(JSProxyCallInternalWithArgV));
257 Register ccGlueReg = rdi;
258 Register jsccGlueReg = rax;
259 Register callTarget = rsi;
260 __ Movq(ccGlueReg, jsccGlueReg); // c++ calling convention as webkit_jscc calling convention
261 __ Movq(callTarget, Operand(rsp, DOUBLE_SLOT_SIZE)); // update callTarget slot
262 GenJSCall(assembler, false);
263 }
264
265 // * uint64_t JSCall(uintptr_t glue, uint32_t argc, JSTaggedType calltarget, JSTaggedType new,
266 // JSTaggedType this, arg[0], arg[1], arg[2], ..., arg[N-1])
267 // * webkit_jscc calling convention call js function()
268 //
269 // * OptimizedJSFunctionFrame layout description as the following:
270 // +--------------------------+
271 // | arg[N-1] |
272 // +--------------------------+
273 // | ... |
274 // +--------------------------+
275 // | arg[1] |
276 // +--------------------------+
277 // | arg[0] |
278 // +--------------------------+
279 // | this |
280 // +--------------------------+
281 // | new-target |
282 // +--------------------------+
283 // | call-target |
284 // |--------------------------|
285 // | argc |
286 // |--------------------------| ---------------
287 // | returnAddr | ^
288 // sp ----> |--------------------------| |
289 // | callsiteFp | |
290 // |--------------------------| OptimizedJSFunctionFrame
291 // | frameType | |
292 // |--------------------------| |
293 // | call-target | v
294 // +--------------------------+ ---------------
JSCallNew(ExtendedAssembler * assembler)295 void OptimizedCall::JSCallNew(ExtendedAssembler *assembler)
296 {
297 __ BindAssemblerStub(RTSTUB_ID(JSCallNew));
298 GenJSCall(assembler, true);
299 }
300
JSCall(ExtendedAssembler * assembler)301 void OptimizedCall::JSCall(ExtendedAssembler *assembler)
302 {
303 __ BindAssemblerStub(RTSTUB_ID(JSCall));
304 GenJSCall(assembler, false);
305 }
306
GenJSCall(ExtendedAssembler * assembler,bool isNew)307 void OptimizedCall::GenJSCall(ExtendedAssembler *assembler, bool isNew)
308 {
309 Label jsCall;
310 Label lJSCallStart;
311 Label lNotJSFunction;
312 Label lNonCallable;
313 Label lJSFunctionCall;
314 Label lJSBoundFunction;
315 Label lJSProxy;
316 Label lCallNativeMethod;
317 Label lCallNativeCpp;
318 Label lCallNativeBuiltinStub;
319 Register glueReg = rax;
320 __ Bind(&jsCall);
321 {
322 __ Movq(glueReg, rdi);
323 glueReg = rdi;
324 __ Movq(Operand(rsp, DOUBLE_SLOT_SIZE), rax); // sp + 16 get jsFunc
325 }
326 __ Bind(&lJSCallStart);
327 Register jsFuncReg = rax;
328 {
329 JSCallCheck(assembler, jsFuncReg, &lNonCallable, &lNotJSFunction, &lJSFunctionCall);
330 }
331
332 __ Bind(&lNotJSFunction);
333 {
334 __ Cmpb(static_cast<uint8_t>(JSType::JS_BOUND_FUNCTION), rax); // IsBoundFunction
335 __ Je(&lJSBoundFunction);
336 __ Cmpb(static_cast<uint8_t>(JSType::JS_PROXY), rax); // IsJsProxy
337 __ Je(&lJSProxy);
338 }
339
340 __ Bind(&lNonCallable);
341 {
342 ThrowNonCallableInternal(assembler, glueReg);
343 }
344
345 __ Bind(&lJSFunctionCall);
346 jsFuncReg = rsi;
347 Register argc = r8;
348 Register methodCallField = rcx;
349 Register method = rdx;
350 Register argV = r9;
351 {
352 Label lCallConstructor;
353 __ Mov(Operand(jsFuncReg, JSFunctionBase::METHOD_OFFSET), method); // get method
354 __ Movl(Operand(rsp, FRAME_SLOT_SIZE), argc); // skip return addr
355 __ Mov(Operand(method, Method::CALL_FIELD_OFFSET), methodCallField); // get call field
356 __ Btq(MethodLiteral::IsNativeBit::START_BIT, methodCallField); // is native
357 __ Jb(&lCallNativeMethod);
358 if (!isNew) {
359 __ Btq(JSHClass::ClassConstructorBit::START_BIT, rax); // is CallConstructor
360 __ Jb(&lCallConstructor);
361 }
362 __ Movq(rsp, argV);
363 auto argvSlotOffset = kungfu::ArgumentAccessor::GetExtraArgsNum() + 1; // 1: return addr
364 __ Addq(argvSlotOffset * FRAME_SLOT_SIZE, argV); // skip return addr and argc
365 __ Subq(Immediate(kungfu::ArgumentAccessor::GetFixArgsNum()), argc);
366 // argv + 24 get asm interpreter argv
367 __ Addq(kungfu::ArgumentAccessor::GetFixArgsNum() * FRAME_SLOT_SIZE, argV);
368 OptimizedCallAsmInterpreter(assembler);
369 __ Bind(&lCallConstructor);
370 {
371 __ Pushq(rbp);
372 __ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)); // set frame type
373 __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
374 __ Pushq(0); // PushAlign
375 __ Pushq(0); // argc
376 __ Pushq(RTSTUB_ID(ThrowCallConstructorException)); // runtime id
377 __ Movq(glueReg, rax); // glue
378 __ Movq(kungfu::RuntimeStubCSigns::ID_CallRuntime, r10);
379 __ Movq(Operand(rax, r10, Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)), r10);
380 __ Callq(r10); // call CallRuntime
381 __ Addq(4 * FRAME_SLOT_SIZE, rsp);
382 __ Pop(rbp);
383 __ Ret();
384 }
385 }
386
387 __ Bind(&lCallNativeMethod);
388 {
389 Register nativePointer = rsi;
390 method = rax;
391 __ Movq(jsFuncReg, rdx);
392 __ Mov(Operand(jsFuncReg, JSFunctionBase::METHOD_OFFSET), method); // get method
393 __ Mov(Operand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET), nativePointer); // native pointer
394 __ Mov(Operand(method, Method::CALL_FIELD_OFFSET), methodCallField); // get call field
395 __ Btq(MethodLiteral::IsFastBuiltinBit::START_BIT, methodCallField); // is builtin stub
396
397 if (!isNew) {
398 __ Jnb(&lCallNativeCpp);
399 __ Cmpl(NUM_MANDATORY_JSFUNC_ARGS + 3, argc); // 3:call0, call1, call2, call3
400 __ Jbe(&lCallNativeBuiltinStub);
401 } else {
402 __ Jb(&lCallNativeBuiltinStub);
403 }
404 }
405
406 __ Bind(&lCallNativeCpp);
407 {
408 __ Movq(glueReg, rax);
409 CallBuiltinTrampoline(assembler);
410 }
411
412 __ Bind(&lCallNativeBuiltinStub);
413 {
414 Register methodExtraLiteralInfo = rax;
415 __ Mov(Operand(method, Method::EXTRA_LITERAL_INFO_OFFSET), methodExtraLiteralInfo); // get extra literal
416 __ Shr(MethodLiteral::BuiltinIdBits::START_BIT, methodExtraLiteralInfo);
417 __ Andl(((1LU << MethodLiteral::BuiltinIdBits::SIZE) - 1), methodExtraLiteralInfo); // get builtin stub id
418 if (!isNew) {
419 __ Cmpl(kungfu::BuiltinsStubCSigns::BUILTINS_CONSTRUCTOR_STUB_FIRST, methodExtraLiteralInfo);
420 __ Jnb(&lCallNativeCpp);
421 }
422
423 __ Movq(glueReg, rdi);
424 __ Movq(methodExtraLiteralInfo, r10);
425 __ Movq(Operand(glueReg, r10, Times8, JSThread::GlueData::GetBuiltinsStubEntriesOffset(false)), r10);
426
427 __ Movq(argc, r9);
428 __ Movq(Operand(rsp, TRIPLE_SLOT_SIZE), rcx); // newTarget
429 __ Movq(Operand(rsp, QUADRUPLE_SLOT_SIZE), r8); // this
430 __ Subq(NUM_MANDATORY_JSFUNC_ARGS, r9); // argc
431
432 Label lCall0;
433 Label lCall1;
434 Label lCall2;
435 Label lCall3;
436 Label lexit;
437 argV = rax;
438
439 __ Movq(rsp, argV);
440 auto argvSlotOffset = kungfu::ArgumentAccessor::GetFixArgsNum() +
441 kungfu::ArgumentAccessor::GetExtraArgsNum() + 1; // 1: return addr
442 __ Addq(argvSlotOffset *FRAME_SLOT_SIZE, argV);
443 __ Pushq(rbp);
444 __ Pushq(static_cast<int32_t>(FrameType::ASM_BRIDGE_FRAME));
445 __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
446
447 if (!isNew) {
448 __ Cmpl(0, r9); // 0: callarg0
449 __ Je(&lCall0);
450 __ Cmpl(1, r9); // 1: callarg1
451 __ Je(&lCall1);
452 __ Cmpl(2, r9); // 2: callarg2
453 __ Je(&lCall2);
454 __ Cmpl(3, r9); // 3: callarg3
455 __ Je(&lCall3);
456
457 __ Bind(&lCall0);
458 {
459 __ PushAlignBytes();
460 __ Callq(r10);
461 __ Addq(DOUBLE_SLOT_SIZE, rsp);
462 __ Jmp(&lexit);
463 }
464
465 __ Bind(&lCall1);
466 {
467 __ Movq(Operand(argV, 0), r11); // arg0
468 __ Pushq(r11);
469 __ Callq(r10);
470 __ Addq(DOUBLE_SLOT_SIZE, rsp);
471 __ Jmp(&lexit);
472 }
473
474 __ Bind(&lCall2);
475 {
476 __ PushAlignBytes();
477 __ Movq(Operand(argV, FRAME_SLOT_SIZE), r11); // arg1
478 __ Pushq(r11);
479 __ Movq(Operand(argV, 0), r11); // arg0
480 __ Pushq(r11);
481 __ Callq(r10);
482 __ Addq(QUADRUPLE_SLOT_SIZE, rsp);
483 __ Jmp(&lexit);
484 }
485
486 __ Bind(&lCall3);
487 {
488 __ Movq(Operand(argV, DOUBLE_SLOT_SIZE), r11); // arg2
489 __ Pushq(r11);
490 __ Movq(Operand(argV, FRAME_SLOT_SIZE), r11); // arg1
491 __ Pushq(r11);
492 __ Movq(Operand(argV, 0), r11); // arg0
493 __ Pushq(r11);
494 __ Callq(r10);
495 __ Addq(QUADRUPLE_SLOT_SIZE, rsp);
496 }
497 } else {
498 __ Pushq(argV); // argv
499 __ Callq(r10);
500 __ Addq(DOUBLE_SLOT_SIZE, rsp);
501 }
502
503 __ Bind(&lexit);
504 {
505 __ Pop(rbp);
506 __ Ret();
507 }
508 }
509
510 __ Bind(&lJSBoundFunction);
511 {
512 JSBoundFunctionCallInternal(assembler, jsFuncReg, &jsCall);
513 }
514 __ Bind(&lJSProxy);
515 JSProxyCallInternal(assembler, jsFuncReg);
516 }
517
JSCallCheck(ExtendedAssembler * assembler,Register jsFuncReg,Label * lNonCallable,Label * lNotJSFunction,Label * lJSFunctionCall)518 void OptimizedCall::JSCallCheck(ExtendedAssembler *assembler, Register jsFuncReg,
519 Label *lNonCallable, Label *lNotJSFunction, Label *lJSFunctionCall)
520 {
521 __ Movabs(JSTaggedValue::TAG_INT, rdx); // IsTaggedInt
522 __ And(jsFuncReg, rdx);
523 __ Cmp(0x0, rdx);
524 __ Jne(lNonCallable);
525 __ Cmp(0x0, jsFuncReg); // IsHole
526 __ Je(lNonCallable);
527 __ Movabs(JSTaggedValue::TAG_SPECIAL, rdx);
528 __ And(jsFuncReg, rdx); // IsSpecial
529 __ Cmp(0x0, rdx);
530 __ Jne(lNonCallable);
531
532 __ Movq(jsFuncReg, rsi); // save jsFunc
533 __ Movq(Operand(jsFuncReg, JSFunction::HCLASS_OFFSET), rax); // get jsHclass
534 Register jsHclassReg = rax;
535 __ Movl(Operand(jsHclassReg, JSHClass::BIT_FIELD_OFFSET), rax);
536 __ Btl(JSHClass::CallableBit::START_BIT, rax); // IsCallable
537 __ Jnb(lNonCallable);
538
539 __ Cmpb(static_cast<int32_t>(JSType::JS_FUNCTION_FIRST), rax);
540 __ Jb(lNotJSFunction);
541 __ Cmpb(static_cast<int32_t>(JSType::JS_FUNCTION_LAST), rax);
542 __ Jbe(lJSFunctionCall); // objecttype in (0x04 ~ 0x0c)
543 }
544
ThrowNonCallableInternal(ExtendedAssembler * assembler,Register glueReg)545 void OptimizedCall::ThrowNonCallableInternal(ExtendedAssembler *assembler, Register glueReg)
546 {
547 __ Pushq(rbp);
548 __ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)); // set frame type
549 __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
550 __ Movq(MessageString::Message_NonCallable, rax);
551 __ Movabs(JSTaggedValue::TAG_INT, r10);
552 __ Orq(r10, rax);
553 __ Pushq(rax); // message id
554 __ Pushq(1); // argc
555 __ Pushq(RTSTUB_ID(ThrowTypeError)); // runtime id
556 __ Movq(glueReg, rax); // glue
557 __ Movq(kungfu::RuntimeStubCSigns::ID_CallRuntime, r10);
558 __ Movq(Operand(rax, r10, Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)), r10);
559 __ Callq(r10); // call CallRuntime
560 __ Movabs(JSTaggedValue::VALUE_EXCEPTION, rax); // return exception
561 __ Addq(4 * FRAME_SLOT_SIZE, rsp); // 32: sp + 32 argv
562 __ Pop(rbp);
563 __ Ret();
564 }
565
JSBoundFunctionCallInternal(ExtendedAssembler * assembler,Register jsFuncReg,Label * jsCall)566 void OptimizedCall::JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Register jsFuncReg, Label *jsCall)
567 {
568 Label lAlign16Bytes2;
569 Label lCopyBoundArgument;
570 Label lCopyArgument2;
571 Label lPushCallTarget;
572 Label lCopyBoundArgumentLoop;
573 Label lPopFrame2;
574 Label slowCall;
575 Label aotCall;
576 Label popArgs;
577 Label isJsFunc;
578 __ Pushq(rbp);
579 __ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME));
580 __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
581 __ Pushq(r10); // callee save
582 __ Movq(rsp, rdx);
583 __ Addq(QUADRUPLE_SLOT_SIZE, rdx); // skip return addr, prevFp, frame type and callee save
584 __ Mov(Operand(rdx, 0), rax); // get origin argc
585 __ Movq(rax, r10);
586 // get bound target
587 __ Mov(Operand(jsFuncReg, JSBoundFunction::BOUND_ARGUMENTS_OFFSET), rcx);
588 // get bound length
589 __ Mov(Operand(rcx, TaggedArray::LENGTH_OFFSET), rcx);
590 __ Addq(rcx, r10);
591
592 // 16 bytes align check
593 __ Testb(1, r10);
594 __ Jne(&lAlign16Bytes2);
595 __ PushAlignBytes(); // push zero to align 16 bytes stack
596
597 __ Bind(&lAlign16Bytes2);
598 {
599 __ Subq(NUM_MANDATORY_JSFUNC_ARGS, rax);
600 __ Cmp(0, rax);
601 __ Je(&lCopyBoundArgument);
602 }
603
604 __ Bind(&lCopyArgument2);
605 {
606 __ Movq(Operand(rdx, rax, Scale::Times8, kungfu::ArgumentAccessor::GetFixArgsNum() * FRAME_SLOT_SIZE), rcx);
607 __ Pushq(rcx);
608 __ Addq(-1, rax);
609 __ Jne(&lCopyArgument2);
610 }
611
612 __ Bind(&lCopyBoundArgument);
613 {
614 // get bound target
615 __ Mov(Operand(jsFuncReg, JSBoundFunction::BOUND_ARGUMENTS_OFFSET), rdx);
616 // get bound length
617 __ Mov(Operand(rdx, TaggedArray::LENGTH_OFFSET), rax);
618 __ Addq(TaggedArray::DATA_OFFSET, rdx);
619 __ Cmp(0, rax);
620 __ Je(&lPushCallTarget);
621 }
622 __ Bind(&lCopyBoundArgumentLoop);
623 {
624 __ Addq(-1, rax);
625 __ Movq(Operand(rdx, rax, Scale::Times8, 0), rcx);
626 __ Pushq(rcx);
627 __ Jne(&lCopyBoundArgumentLoop);
628 }
629 __ Bind(&lPushCallTarget);
630 {
631 __ Mov(Operand(jsFuncReg, JSBoundFunction::BOUND_THIS_OFFSET), r8); // thisObj
632 __ Pushq(r8);
633 __ Pushq(JSTaggedValue::VALUE_UNDEFINED); // newTarget
634 __ Mov(Operand(jsFuncReg, JSBoundFunction::BOUND_TARGET_OFFSET), rax); // callTarget
635 __ Pushq(rax);
636 __ Pushq(r10); // push actual arguments
637 }
638 JSCallCheck(assembler, rax, &slowCall, &slowCall, &isJsFunc); // jsfunc -> rsi hclassfiled -> rax
639 __ Jmp(&slowCall);
640 Register jsfunc = rsi;
641 __ Bind(&isJsFunc);
642 {
643 __ Btq(JSHClass::ClassConstructorBit::START_BIT, rax); // is CallConstructor
644 __ Jb(&slowCall);
645 __ Btq(JSHClass::IsOptimizedBit::START_BIT, rax); // is aot
646 __ Jnb(&slowCall);
647 __ Bind(&aotCall);
648 {
649 // output: glue:rdi argc:rsi calltarget:rdx argv:rcx this:r8 newtarget:r9
650 __ Movq(jsfunc, rdx);
651 __ Movq(r10, rsi);
652 __ Leaq(Operand(rsp, 4 * FRAME_SLOT_SIZE), rcx); // 4: skip argc and func new this
653 __ Movq(JSTaggedValue::VALUE_UNDEFINED, r9);
654 __ Movq(kungfu::CommonStubCSigns::JsBoundCallInternal, r10);
655 __ Movq(Operand(rdi, r10, Scale::Times8, JSThread::GlueData::GetCOStubEntriesOffset(false)), rax);
656 __ Callq(rax); // call JSCall
657 __ Jmp(&popArgs);
658 }
659 }
660 __ Bind(&slowCall);
661 {
662 __ Movq(rdi, rax);
663 __ Callq(jsCall); // call JSCall
664 __ Jmp(&popArgs);
665 }
666 __ Bind(&popArgs);
667 {
668 __ Pop(r10);
669 __ Leaq(Operand(r10, Scale::Times8, 0), rcx); // 8: disp
670 __ Addq(rcx, rsp);
671 __ Testb(1, r10); // stack 16bytes align check
672 __ Jne(&lPopFrame2);
673 __ Addq(8, rsp); // 8: align byte
674 }
675 __ Bind(&lPopFrame2);
676 {
677 __ Pop(r10);
678 __ Addq(8, rsp); // 8: sp + 8
679 __ Pop(rbp);
680 __ Ret();
681 }
682 }
683
JSProxyCallInternal(ExtendedAssembler * assembler,Register jsFuncReg)684 void OptimizedCall::JSProxyCallInternal(ExtendedAssembler *assembler, Register jsFuncReg)
685 {
686 __ Movq(jsFuncReg, rdx); // calltarget
687 __ Movq(rsp, rcx);
688 __ Addq(FRAME_SLOT_SIZE, rcx); // skip returnAddr
689 __ Mov(Operand(rcx, 0), rsi); // get origin argc
690 __ Addq(kungfu::ArgumentAccessor::GetExtraArgsNum() * FRAME_SLOT_SIZE, rcx); // skip extra args: argc
691 __ Movq(kungfu::CommonStubCSigns::JsProxyCallInternal, r9);
692 __ Movq(Operand(rdi, r9, Scale::Times8, JSThread::GlueData::GetCOStubEntriesOffset(false)), r8);
693 __ Jmp(r8);
694 __ Ret();
695 }
696
697 // * uint64_t CallRuntime(uintptr_t glue, uint64_t runtime_id, uint64_t argc, uintptr_t arg0, ...)
698 // * webkit_jscc calling convention call runtime_id's runtime function(c-abi)
699 // * Arguments:
700 // %rax - glue
701 //
702 // * Optimized-leaved-frame layout as the following:
703 // +--------------------------+
704 // | argv[N-1] |
705 // |--------------------------|
706 // | . . . . . |
707 // |--------------------------|
708 // | argv[0] |
709 // +--------------------------+-------------
710 // | argc | ^
711 // |--------------------------| |
712 // | RuntimeId | |
713 // sp --> |--------------------------| OptimizedLeaveFrame
714 // | ret-addr | |
715 // |--------------------------| |
716 // | prevFp | |
717 // |--------------------------| |
718 // | frameType | v
719 // +--------------------------+-------------
720
CallRuntime(ExtendedAssembler * assembler)721 void OptimizedCall::CallRuntime(ExtendedAssembler *assembler)
722 {
723 __ BindAssemblerStub(RTSTUB_ID(CallRuntime));
724 __ Pushq(rbp);
725 __ Movq(rsp, Operand(rax, JSThread::GlueData::GetLeaveFrameOffset(false)));
726 __ Pushq(static_cast<int32_t>(FrameType::LEAVE_FRAME));
727 __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp); // 8: skip frame type
728
729 __ Pushq(r10);
730 __ Pushq(rdx);
731 __ Pushq(rax);
732
733 __ Movq(rbp, rdx);
734 // 16: rbp & return address
735 __ Addq(2 * FRAME_SLOT_SIZE, rdx);
736
737 __ Movq(Operand(rdx, 0), r10);
738 __ Movq(Operand(rax, r10, Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)), r10);
739 __ Movq(rax, rdi);
740 // 8: argc
741 __ Movq(Operand(rdx, FRAME_SLOT_SIZE), rsi);
742 // 16: argv
743 __ Addq(2 * FRAME_SLOT_SIZE, rdx);
744 __ Callq(r10);
745
746 // 8: skip rax
747 __ Addq(FRAME_SLOT_SIZE, rsp);
748 __ Popq(rdx);
749 __ Popq(r10);
750
751 // 8: skip frame type
752 __ Addq(FRAME_SLOT_SIZE, rsp);
753 __ Popq(rbp);
754 __ Ret();
755 }
756
757 // * uint64_t CallRuntimeWithArgv(uintptr_t glue, uint64_t runtime_id, uint64_t argc, uintptr_t argv)
758 // * cc calling convention call runtime_id's runtion function(c-abi)
759 // * Arguments:
760 // %rdi - glue
761 // %rsi - runtime_id
762 // %edx - argc
763 // %rcx - argv
764 //
765 // * Optimized-leaved-frame-with-argv layout as the following:
766 // +--------------------------+
767 // | argv[] |
768 // +--------------------------+-------------
769 // | argc | ^
770 // |--------------------------| |
771 // | RuntimeId | OptimizedWithArgvLeaveFrame
772 // sp --> |--------------------------| |
773 // | returnAddr | |
774 // |--------------------------| |
775 // | callsiteFp | |
776 // |--------------------------| |
777 // | frameType | v
778 // +--------------------------+-------------
779
CallRuntimeWithArgv(ExtendedAssembler * assembler)780 void OptimizedCall::CallRuntimeWithArgv(ExtendedAssembler *assembler)
781 {
782 __ BindAssemblerStub(RTSTUB_ID(CallRuntimeWithArgv));
783 Register glueReg = rdi;
784 Register runtimeIdReg = rsi;
785 Register argcReg = rdx;
786 Register argvReg = rcx;
787
788 __ Movq(rsp, r8);
789 Register returnAddrReg = r9;
790 __ Movq(Operand(rsp, 0), returnAddrReg);
791 __ Pushq(argvReg); // argv[]
792 __ Pushq(argcReg); // argc
793 __ Pushq(runtimeIdReg); // runtime_id
794 __ Pushq(returnAddrReg); // returnAddr
795
796 // construct leave frame
797 __ Pushq(rbp);
798 __ Movq(rsp, Operand(glueReg, JSThread::GlueData::GetLeaveFrameOffset(false))); // save to thread->leaveFrame_
799 __ Pushq(static_cast<int32_t>(FrameType::LEAVE_FRAME_WITH_ARGV));
800 __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
801
802 __ Movq(Operand(glueReg, runtimeIdReg, Scale::Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)), r9);
803 __ Movq(argcReg, rsi); // argc
804 __ Movq(argvReg, rdx); // argv
805 __ Pushq(r8);
806 __ Callq(r9);
807 __ Popq(r8);
808 __ Addq(FRAME_SLOT_SIZE, rsp); // 8: skip type
809 __ Popq(rbp);
810 __ Movq(r8, rsp);
811 __ Ret();
812 }
813
PushMandatoryJSArgs(ExtendedAssembler * assembler,Register jsfunc,Register thisObj,Register newTarget)814 void OptimizedCall::PushMandatoryJSArgs(ExtendedAssembler *assembler, Register jsfunc,
815 Register thisObj, Register newTarget)
816 {
817 __ Pushq(thisObj);
818 __ Pushq(newTarget);
819 __ Pushq(jsfunc);
820 }
821
822 // output expectedNumArgs (r14)
PushArgsWithArgV(ExtendedAssembler * assembler,Register jsfunc,Register actualNumArgs,Register argV,Label * pushCallThis)823 void OptimizedCall::PushArgsWithArgV(ExtendedAssembler *assembler, Register jsfunc,
824 Register actualNumArgs, Register argV, Label *pushCallThis)
825 {
826 Register expectedNumArgs(r14); // output
827 Register tmp(rax);
828 Label align16Bytes;
829 Label copyArguments;
830 // get expected num Args
831 __ Movq(Operand(jsfunc, JSFunctionBase::METHOD_OFFSET), tmp);
832 __ Movq(Operand(tmp, Method::CALL_FIELD_OFFSET), tmp);
833 __ Shr(MethodLiteral::NumArgsBits::START_BIT, tmp);
834 __ Andl(((1LU << MethodLiteral::NumArgsBits::SIZE) - 1), tmp);
835
836 __ Mov(tmp, expectedNumArgs);
837 __ Testb(1, expectedNumArgs);
838 __ Jne(&align16Bytes);
839 __ PushAlignBytes();
840
841 __ Bind(&align16Bytes);
842 {
843 __ Cmpq(actualNumArgs, expectedNumArgs);
844 __ Jbe(©Arguments);
845 __ Subq(actualNumArgs, tmp);
846 PushUndefinedWithArgc(assembler, tmp);
847 }
848 __ Bind(©Arguments);
849 {
850 __ Cmpq(actualNumArgs, expectedNumArgs);
851 __ Movq(actualNumArgs, tmp); // rax -> actualNumArgsReg
852 __ CMovbe(expectedNumArgs, tmp);
853 __ Cmpq(0, tmp);
854 __ Je(pushCallThis);
855 CopyArgumentWithArgV(assembler, tmp, argV);
856 }
857 }
858
PopJSFunctionArgs(ExtendedAssembler * assembler,Register expectedNumArgs)859 void OptimizedCall::PopJSFunctionArgs(ExtendedAssembler *assembler, Register expectedNumArgs)
860 {
861 Label align16Bytes;
862 __ Testb(1, expectedNumArgs);
863 __ Jne(&align16Bytes);
864 __ Addq(FRAME_SLOT_SIZE, rsp);
865 __ Bind(&align16Bytes);
866 __ Leaq(Operand(expectedNumArgs, Scale::Times8, 0), expectedNumArgs);
867 __ Addq(expectedNumArgs, rsp);
868 __ Addq(FRAME_SLOT_SIZE, rsp); // 8: skip expectedNumArgs
869 }
870
PushJSFunctionEntryFrame(ExtendedAssembler * assembler,Register prevFp)871 void OptimizedCall::PushJSFunctionEntryFrame(ExtendedAssembler *assembler, Register prevFp)
872 {
873 __ PushCppCalleeSaveRegisters();
874 __ Pushq(rdi);
875
876 // construct optimized entry frame
877 __ Pushq(rbp);
878 __ Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_ENTRY_FRAME));
879 __ Pushq(prevFp);
880 // 2: skip prevFp and frameType
881 __ Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp);
882 }
883
PopJSFunctionEntryFrame(ExtendedAssembler * assembler,Register glue)884 void OptimizedCall::PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue)
885 {
886 Register prevFp(rsi);
887 __ Popq(prevFp);
888 __ Addq(FRAME_SLOT_SIZE, rsp); // 8: frame type
889 __ Popq(rbp);
890 __ Popq(glue); // caller restore
891 __ PopCppCalleeSaveRegisters(); // callee restore
892 __ Movq(prevFp, Operand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
893 }
894
895 // * uint64_t PushOptimizedUnfoldArgVFrame(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
896 // JSTaggedType new, JSTaggedType this, JSTaggedType, argV[])
897 // * cc calling convention call js function()
898 // * arguments:
899 // %rdi - glue
900 // %rsi - argc
901 // %rdx - call-target
902 // %rcx - new-target
903 // %r8 - this
904 // %r9 - argv
905 //
906 // * OptimizedUnfoldArgVFrame layout description as the following:
907 // sp ----> |--------------------------| ---------------
908 // | returnAddr | ^
909 // currentFp--> |--------------------------| |
910 // | prevFp | |
911 // |--------------------------| OptimizedUnfoldArgVFrame
912 // | frameType | |
913 // |--------------------------| |
914 // | currentFp | v
915 // +--------------------------+ ---------------
916
PushOptimizedUnfoldArgVFrame(ExtendedAssembler * assembler,Register callSiteSp)917 void OptimizedCall::PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp)
918 {
919 __ Pushq(rbp);
920 // construct frame
921 __ Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME));
922 __ Pushq(callSiteSp);
923 // 2: skip callSiteSp and frameType
924 __ Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp);
925 }
926
PopOptimizedUnfoldArgVFrame(ExtendedAssembler * assembler)927 void OptimizedCall::PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler)
928 {
929 Register sp(rsp);
930 // 16 : 16 means pop call site sp and type
931 __ Addq(Immediate(2 * FRAME_SLOT_SIZE), sp);
932 __ Popq(rbp);
933 }
934
935 // * uint64_t JSCallWithArgV(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
936 // JSTaggedType new, JSTaggedType this, argV)
937 // * cc calling convention call js function()
938 // * arguments:
939 // %rdi - glue
940 // %rsi - argc
941 // %rdx - call-target
942 // %rcx - new-target
943 // %r8 - this
944 // %r9 - argv
945 //
946 // * OptimizedJSFunctionFrame layout description as the following:
947 // +--------------------------+
948 // | argn |
949 // |--------------------------|
950 // | argn - 1 |
951 // |--------------------------|
952 // | ..... |
953 // |--------------------------|
954 // | arg2 |
955 // |--------------------------|
956 // | arg1 |
957 // sp ----> |--------------------------| ---------------
958 // | returnAddr | ^
959 // |--------------------------| |
960 // | callsiteFp | |
961 // |--------------------------| OptimizedJSFunctionFrame
962 // | frameType | |
963 // |--------------------------| |
964 // | call-target | v
965 // +--------------------------+ ---------------
966
GenJSCallWithArgV(ExtendedAssembler * assembler,bool needAddExpectedArgs)967 void OptimizedCall::GenJSCallWithArgV(ExtendedAssembler *assembler, bool needAddExpectedArgs)
968 {
969 Register sp(rsp);
970 Register glue(rdi);
971 Register actualNumArgs(rsi);
972 Register jsfunc(rdx);
973 Register newTarget(rcx);
974 Register thisObj(r8);
975 Register argV(r9);
976 Register callsiteSp = __ AvailableRegister2();
977 Label align16Bytes;
978 Label pushCallThis;
979
980 __ Movq(sp, callsiteSp);
981 __ Addq(Immediate(FRAME_SLOT_SIZE), callsiteSp); // 8 : 8 means skip pc to get last callsitesp
982 PushOptimizedUnfoldArgVFrame(assembler, callsiteSp);
983 __ Testb(1, actualNumArgs);
984 __ Je(&align16Bytes);
985 __ PushAlignBytes();
986 __ Bind(&align16Bytes);
987 __ Cmp(Immediate(0), actualNumArgs);
988 __ Jz(&pushCallThis);
989 __ Mov(actualNumArgs, rax);
990 CopyArgumentWithArgV(assembler, rax, argV);
991 __ Bind(&pushCallThis);
992 PushMandatoryJSArgs(assembler, jsfunc, thisObj, newTarget);
993 __ Addq(Immediate(NUM_MANDATORY_JSFUNC_ARGS), actualNumArgs);
994 __ Pushq(actualNumArgs);
995 __ Movq(glue, rax);
996 if (needAddExpectedArgs) {
997 __ CallAssemblerStub(RTSTUB_ID(OptimizedCallAndPushUndefined), false);
998 } else {
999 __ CallAssemblerStub(RTSTUB_ID(CallOptimized), false);
1000 }
1001
1002 __ Mov(Operand(sp, 0), actualNumArgs);
1003 PopJSFunctionArgs(assembler, actualNumArgs);
1004 PopOptimizedUnfoldArgVFrame(assembler);
1005 __ Ret();
1006 }
1007
1008 // * uint64_t JSCallWithArgVAndPushUndefined(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1009 // JSTaggedType new, JSTaggedType this, argV)
1010 // * cc calling convention call js function()
1011 // * arguments:
1012 // %rdi - glue
1013 // %rsi - argc
1014 // %rdx - call-target
1015 // %rcx - new-target
1016 // %r8 - this
1017 // %r9 - argv
JSCallWithArgVAndPushUndefined(ExtendedAssembler * assembler)1018 void OptimizedCall::JSCallWithArgVAndPushUndefined(ExtendedAssembler *assembler)
1019 {
1020 __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgVAndPushUndefined));
1021 GenJSCallWithArgV(assembler, true);
1022 }
1023
JSCallWithArgV(ExtendedAssembler * assembler)1024 void OptimizedCall::JSCallWithArgV(ExtendedAssembler *assembler)
1025 {
1026 __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgV));
1027 GenJSCallWithArgV(assembler, false);
1028 }
1029
CallOptimized(ExtendedAssembler * assembler)1030 void OptimizedCall::CallOptimized(ExtendedAssembler *assembler)
1031 {
1032 __ BindAssemblerStub(RTSTUB_ID(CallOptimized));
1033 Register jsFuncReg = rdi;
1034 Register method = r9;
1035 Register codeAddrReg = rsi;
1036 __ Movq(Operand(rsp, DOUBLE_SLOT_SIZE), jsFuncReg); // sp + 16 get jsFunc
1037 __ Mov(Operand(jsFuncReg, JSFunctionBase::METHOD_OFFSET), method); // get method
1038 __ Mov(Operand(method, Method::CODE_ENTRY_OFFSET), codeAddrReg);
1039 __ Jmp(codeAddrReg);
1040 }
1041
1042 // Input: %rdi - glue
1043 // %rsi - context
DeoptEnterAsmInterp(ExtendedAssembler * assembler)1044 void OptimizedCall::DeoptEnterAsmInterp(ExtendedAssembler *assembler)
1045 {
1046 // rdi
1047 Register glueRegister = __ GlueRegister();
1048 Register context = rsi;
1049 // rax, rdx, rcx, r8, r9, r10, r11 is free
1050 Register tempRegister = rax;
1051 Register opRegister = r10;
1052 Register outputCount = rdx;
1053 Register frameStateBase = rcx;
1054 Register depth = r11;
1055 Label loopBegin;
1056 Label stackOverflow;
1057 Label pushArgv;
1058 __ Movq(Operand(context, AsmStackContext::GetInlineDepthOffset(false)), depth);
1059 __ Leaq(Operand(context, AsmStackContext::GetSize(false)), context);
1060 __ Movq(Immediate(0), r12);
1061 __ Bind(&loopBegin);
1062 __ Movq(Operand(context, 0), outputCount);
1063 __ Leaq(Operand(context, FRAME_SLOT_SIZE), frameStateBase);
1064 __ Cmpq(0, r12);
1065 __ Je(&pushArgv);
1066 __ Movq(rsp, r8);
1067 __ Addq(AsmInterpretedFrame::GetSize(false), r8);
1068 __ Leaq(Operand(frameStateBase, AsmInterpretedFrame::GetBaseOffset(false)), r10);
1069 __ Movq(r8, Operand(r10, InterpretedFrameBase::GetPrevOffset(false)));
1070 __ Testq(15, rsp); // 15: low 4 bits must be 0b0000
1071 __ Jnz(&pushArgv);
1072 __ PushAlignBytes();
1073 __ Bind(&pushArgv);
1074 // update fp
1075 __ Movq(rsp, Operand(frameStateBase, AsmInterpretedFrame::GetFpOffset(false)));
1076 PushArgsWithArgvAndCheckStack(assembler, glueRegister, outputCount,
1077 frameStateBase, tempRegister, opRegister, &stackOverflow);
1078 __ Leaq(Operand(context, outputCount, Scale::Times8, FRAME_SLOT_SIZE), context);
1079 __ Addq(1, r12);
1080 __ Cmpq(r12, depth);
1081 __ Jae(&loopBegin);
1082 Register callTargetRegister = r8;
1083 Register methodRegister = r9;
1084 {
1085 // r13, rbp, r12, rbx, r14, rsi, rdi
1086 // glue sp pc constpool profile acc hotness
1087 __ Movq(Operand(frameStateBase, AsmInterpretedFrame::GetFunctionOffset(false)), callTargetRegister);
1088 __ Movq(Operand(frameStateBase, AsmInterpretedFrame::GetPcOffset(false)), r12);
1089 __ Movq(Operand(frameStateBase, AsmInterpretedFrame::GetAccOffset(false)), rsi);
1090 __ Movq(Operand(callTargetRegister, JSFunctionBase::METHOD_OFFSET), methodRegister);
1091
1092 __ Leaq(Operand(rsp, AsmInterpretedFrame::GetSize(false)), opRegister);
1093 AsmInterpreterCall::DispatchCall(assembler, r12, opRegister, methodRegister, rsi);
1094 }
1095
1096 __ Bind(&stackOverflow);
1097 {
1098 [[maybe_unused]] TempRegisterScope scope(assembler);
1099 Register temp = __ TempRegister();
1100 AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(assembler,
1101 glueRegister, rsp, temp);
1102 }
1103 }
1104
1105 // Input: %rdi - glue
DeoptHandlerAsm(ExtendedAssembler * assembler)1106 void OptimizedCall::DeoptHandlerAsm(ExtendedAssembler *assembler)
1107 {
1108 __ BindAssemblerStub(RTSTUB_ID(DeoptHandlerAsm));
1109
1110 Register glueReg = rdi;
1111 __ Pushq(rbp);
1112 __ Pushq(static_cast<int32_t>(FrameType::ASM_BRIDGE_FRAME));
1113 __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
1114 __ Push(glueReg);
1115 __ PushCppCalleeSaveRegisters();
1116
1117 __ Movq(rdi, rax); // glue
1118 Register deoptType = rsi;
1119 Register depth = rdx;
1120 __ Subq(FRAME_SLOT_SIZE, rsp);
1121 __ Pushq(depth);
1122 __ Pushq(deoptType); // argv[0]
1123 __ Pushq(2); // 2: argc
1124 __ Pushq(kungfu::RuntimeStubCSigns::ID_DeoptHandler);
1125 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1126
1127 __ Addq(5 * FRAME_SLOT_SIZE, rsp); // 5: skip runtimeId argc deoptType depth align
1128
1129 Register context = rsi;
1130 __ Movq(rax, context);
1131
1132 Label target;
1133 __ PopCppCalleeSaveRegisters();
1134 __ Pop(glueReg);
1135
1136 Label stackOverflow;
1137 __ Cmpq(JSTaggedValue::VALUE_EXCEPTION, rax);
1138 __ Je(&stackOverflow);
1139
1140 __ Movq(Operand(context, AsmStackContext::GetCallerFpOffset(false)), rbp);
1141 __ Movq(Operand(context, AsmStackContext::GetCallFrameTopOffset(false)), rsp);
1142 __ Subq(FRAME_SLOT_SIZE, rsp); // skip lr
1143
1144 PushAsmInterpBridgeFrame(assembler);
1145 __ Callq(&target);
1146 PopAsmInterpBridgeFrame(assembler);
1147 __ Ret();
1148 __ Bind(&target);
1149 DeoptEnterAsmInterp(assembler);
1150 __ Int3();
1151
1152 __ Bind(&stackOverflow);
1153 {
1154 __ Movq(rdi, rax);
1155 __ Pushq(0); // argc
1156 __ Pushq(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException);
1157 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1158 __ Addq(FRAME_SLOT_SIZE * 3, rsp); // 3 : skip runtimeId argc & type
1159 __ Popq(rbp);
1160 __ Ret();
1161 }
1162 }
1163 #undef __
1164 } // namespace panda::ecmascript::x64