1 /*
2 * Copyright (c) 2022-2024 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/aarch64/common_call.h"
17
18 #include "ecmascript/deoptimizer/deoptimizer.h"
19 #include "ecmascript/message_string.h"
20
21 namespace panda::ecmascript::aarch64 {
22 using Label = panda::ecmascript::Label;
23 #define __ assembler->
24
25 // * uint64_t CallRuntime(uintptr_t glue, uint64_t runtime_id, uint64_t argc, uintptr_t arg0, ...)
26 // * webkit_jscc calling convention call runtime_id's runtime function(c-abi)
27 // * Arguments:
28 // %x0 - glue
29 //
30 // * Optimized-leaved-frame layout as the following:
31 // +--------------------------+
32 // | argv[N-1] |
33 // |--------------------------|
34 // | . . . . . |
35 // |--------------------------|
36 // | argv[0] |
37 // +--------------------------+-------------
38 // | argc | ^
39 // |--------------------------| |
40 // | RuntimeId | |
41 // sp --> |--------------------------| OptimizedLeaveFrame
42 // | ret-addr | |
43 // |--------------------------| |
44 // | prevFp | |
45 // |--------------------------| |
46 // | frameType | v
47 // +--------------------------+-------------
48
CallRuntime(ExtendedAssembler * assembler)49 void OptimizedCall::CallRuntime(ExtendedAssembler *assembler)
50 {
51 Register glue(X0);
52 Register fp(FP);
53 Register tmp(X19);
54 Register sp(SP);
55 Register argC(X1);
56 Register argV(X2);
57
58 __ BindAssemblerStub(RTSTUB_ID(CallRuntime));
59 __ PushFpAndLr();
60
61 Register frameType(X2);
62 // construct Leave Frame and callee save
63 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::LEAVE_FRAME)));
64 // 2 : 2 means pairs
65 __ Stp(tmp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
66 __ Add(fp, sp, Immediate(2 * FRAME_SLOT_SIZE)); // 2 : 2 means pairs
67 __ Str(fp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
68
69 // load runtime trampoline address
70 Register rtfunc(X19);
71 __ Ldr(tmp, MemoryOperand(fp, GetStackArgOffSetToFp(0))); // 0: the first arg id
72 // 3 : 3 means 2 << 3 = 8
73 __ Add(tmp, glue, Operand(tmp, LSL, 3));
74 __ Ldr(rtfunc, MemoryOperand(tmp, JSThread::GlueData::GetRTStubEntriesOffset(false)));
75 __ Ldr(argC, MemoryOperand(fp, GetStackArgOffSetToFp(1))); // 1: the second arg id
76 __ Add(argV, fp, Immediate(GetStackArgOffSetToFp(2))); // 2: the third arg id
77 __ Blr(rtfunc);
78
79 // callee restore
80 // 0 : 0 restore size
81 __ Ldr(tmp, MemoryOperand(sp, 0));
82
83 // descontruct frame
84 // 2 :2 means stack frame slot size
85 __ Add(sp, sp, Immediate(2 * FRAME_SLOT_SIZE));
86 __ RestoreFpAndLr();
87 __ Ret();
88 }
89
IncreaseStackForArguments(ExtendedAssembler * assembler,Register argc,Register currentSp,int64_t numExtraArgs)90 void OptimizedCall::IncreaseStackForArguments(ExtendedAssembler *assembler, Register argc, Register currentSp,
91 int64_t numExtraArgs)
92 {
93 Register sp(SP);
94 __ Mov(currentSp, sp);
95 if (numExtraArgs > 0) {
96 // add extra aguments, numArgs
97 __ Add(argc, argc, Immediate(numExtraArgs));
98 }
99 __ Sub(currentSp, currentSp, Operand(argc, UXTW, FRAME_SLOT_SIZE_LOG2));
100 Label aligned;
101 __ Tst(currentSp, LogicalImmediate::Create(0xf, RegXSize)); // 0xf: 0x1111
102 __ B(Condition::EQ, &aligned);
103 __ Sub(currentSp, currentSp, Immediate(FRAME_SLOT_SIZE));
104 __ Bind(&aligned);
105 __ Mov(sp, currentSp);
106 __ Add(currentSp, currentSp, Operand(argc, UXTW, FRAME_SLOT_SIZE_LOG2));
107 }
108
109 // * uint64_t JSFunctionEntry(uintptr_t glue, uint32_t actualNumArgs, const JSTaggedType argV[], uintptr_t prevFp,
110 // size_t callType)
111 // * Arguments:
112 // %x0 - glue
113 // %x1 - actualNumArgs
114 // %x2 - argV
115 // %x3 - prevFp
116 // %x4 - needPushArgv
117 //
118 // * The JSFunctionEntry Frame's structure is illustrated as the following:
119 // +--------------------------+
120 // | . . . . . . |
121 // sp ---> +--------------------------+ -----------------
122 // | prevFP | ^
123 // |--------------------------| |
124 // | frameType | JSFunctionEntryFrame
125 // |--------------------------| |
126 // | preLeaveFrameFp | v
127 // +--------------------------+ -----------------
128
JSFunctionEntry(ExtendedAssembler * assembler)129 void OptimizedCall::JSFunctionEntry(ExtendedAssembler *assembler)
130 {
131 __ BindAssemblerStub(RTSTUB_ID(JSFunctionEntry));
132 Register glueReg(X0);
133 Register argV(X2);
134 Register prevFpReg(X3);
135 Register needPushArgv(X4);
136 Register sp(SP);
137 Register tmpArgV(X7);
138 Label lJSCallWithArgVAndPushArgv;
139 Label lPopFrame;
140
141 PushJSFunctionEntryFrame (assembler, prevFpReg);
142 __ Mov(Register(X6), needPushArgv);
143 __ Mov(tmpArgV, argV);
144 __ Mov(Register(X20), glueReg);
145 __ Ldr(Register(X2), MemoryOperand(tmpArgV, 0));
146 __ Ldr(Register(X3), MemoryOperand(tmpArgV, FRAME_SLOT_SIZE));
147 __ Ldr(Register(X4), MemoryOperand(tmpArgV, DOUBLE_SLOT_SIZE));
148 __ Add(tmpArgV, tmpArgV, Immediate(TRIPLE_SLOT_SIZE));
149 __ Mov(Register(X5), tmpArgV);
150 __ Cmp(Register(X6), Immediate(1));
151 __ B(Condition::EQ, &lJSCallWithArgVAndPushArgv);
152 __ CallAssemblerStub(RTSTUB_ID(JSCallWithArgV), false);
153 __ B(&lPopFrame);
154
155 __ Bind(&lJSCallWithArgVAndPushArgv);
156 __ CallAssemblerStub(RTSTUB_ID(JSCallWithArgVAndPushArgv), false);
157 __ Bind(&lPopFrame);
158 __ Mov(Register(X2), Register(X20));
159 PopJSFunctionEntryFrame(assembler, Register(X2));
160 __ Ret();
161 }
162
163 // * uint64_t OptimizedCallAndPushArgv(uintptr_t glue, uint32_t argc, JSTaggedType calltarget, JSTaggedType new,
164 // JSTaggedType this, arg[0], arg[1], arg[2], ..., arg[N-1])
165 // * webkit_jscc calling convention call js function()
166 //
167 // * OptimizedJSFunctionFrame layout description as the following:
168 // +--------------------------+
169 // | arg[N-1] |
170 // +--------------------------+
171 // | ... |
172 // +--------------------------+
173 // | arg[1] |
174 // +--------------------------+
175 // | arg[0] |
176 // +--------------------------+
177 // | this |
178 // +--------------------------+
179 // | new-target |
180 // +--------------------------+
181 // | call-target |
182 // +--------------------------+
183 // | argv |
184 // +--------------------------+
185 // | argc |
186 // sp ----> |--------------------------| ---------------
187 // | returnAddr | ^
188 // |--------------------------| |
189 // | callsiteFp | |
190 // |--------------------------| OptimizedJSFunctionFrame
191 // | frameType | |
192 // |--------------------------| |
193 // | call-target | v
194 // +--------------------------+ ---------------
OptimizedCallAndPushArgv(ExtendedAssembler * assembler)195 void OptimizedCall::OptimizedCallAndPushArgv(ExtendedAssembler *assembler)
196 {
197 __ BindAssemblerStub(RTSTUB_ID(OptimizedCallAndPushArgv));
198 Register sp(SP);
199 Register jsfunc(X7);
200 Register method(X6);
201 Register expectedNumArgs(X1);
202 Register actualNumArgs(X2);
203 Register codeAddr(X3);
204 Register argV(X4);
205
206 auto funcSlotOffSet = kungfu::ArgumentAccessor::GetExtraArgsNum();
207 __ Ldr(jsfunc, MemoryOperand(sp, funcSlotOffSet * FRAME_SLOT_SIZE));
208 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
209 __ Ldr(codeAddr, MemoryOperand(jsfunc, JSFunction::CODE_ENTRY_OFFSET));
210 __ Ldr(expectedNumArgs, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
211 __ Lsr(expectedNumArgs, expectedNumArgs, MethodLiteral::NumArgsBits::START_BIT);
212 __ And(expectedNumArgs, expectedNumArgs,
213 LogicalImmediate::Create(
214 MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegXSize));
215 __ Add(expectedNumArgs, expectedNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
216
217 __ Add(argV, sp, Immediate(funcSlotOffSet * FRAME_SLOT_SIZE)); // skip numArgs and argv
218 __ Ldr(actualNumArgs, MemoryOperand(sp, 0));
219
220 Register glue(X0);
221 Register currentSp(X5);
222 Label copyArguments;
223 Label invokeCompiledJSFunction;
224
225 // construct frame
226 PushOptimizedArgsConfigFrame(assembler);
227 Register argC(X7);
228 __ Cmp(expectedNumArgs, actualNumArgs);
229 __ CMov(argC, expectedNumArgs, actualNumArgs, Condition::HI);
230 IncreaseStackForArguments(assembler, argC, currentSp, static_cast<int64_t>(CommonArgIdx::ACTUAL_ARGV));
231 {
232 TempRegister1Scope scope1(assembler);
233 TempRegister2Scope scope2(assembler);
234 Register tmp = __ TempRegister1();
235 Register undefinedValue = __ TempRegister2();
236 __ Subs(tmp, expectedNumArgs, actualNumArgs);
237 __ B(Condition::LS, ©Arguments);
238 PushUndefinedWithArgc(assembler, glue, tmp, undefinedValue, currentSp, nullptr, nullptr);
239 }
240 __ Bind(©Arguments);
241 __ Cbz(actualNumArgs, &invokeCompiledJSFunction);
242 {
243 TempRegister1Scope scope1(assembler);
244 TempRegister2Scope scope2(assembler);
245 Register argc = __ TempRegister1();
246 Register argValue = __ TempRegister2();
247 __ Mov(argc, actualNumArgs);
248 PushArgsWithArgv(assembler, glue, argc, argV, argValue, currentSp, &invokeCompiledJSFunction, nullptr);
249 }
250 __ Bind(&invokeCompiledJSFunction);
251 {
252 __ Mov(Register(X19), expectedNumArgs);
253 __ Str(currentSp, MemoryOperand(sp, FRAME_SLOT_SIZE));
254 __ Str(actualNumArgs, MemoryOperand(sp, 0)); // argv, argc
255 __ Blr(codeAddr);
256 }
257
258 // pop argV argC
259 // 3 : 3 means argC * 8
260 __ Ldr(actualNumArgs, MemoryOperand(sp, 0));
261 PopJSFunctionArgs(assembler, Register(X19), actualNumArgs);
262 // pop prevLeaveFrameFp to restore thread->currentFrame_
263 PopOptimizedArgsConfigFrame(assembler);
264 __ Ret();
265 }
266
OptimizedCallAsmInterpreter(ExtendedAssembler * assembler)267 void OptimizedCall::OptimizedCallAsmInterpreter(ExtendedAssembler *assembler)
268 {
269 Label target;
270 PushAsmInterpBridgeFrame(assembler);
271 __ Bl(&target);
272 PopAsmInterpBridgeFrame(assembler);
273 __ Ret();
274 __ Bind(&target);
275 {
276 AsmInterpreterCall::JSCallCommonEntry(assembler, JSCallMode::CALL_FROM_AOT,
277 FrameTransitionType::OTHER_TO_OTHER);
278 }
279 }
280
281 // * uint64_t CallBuiltinTrampoline(uintptr_t glue, uintptr_t codeAddress, uint32_t argc, ...)
282 // * webkit_jscc calling convention call runtime_id's runtime function(c-abi)
283 // * Argument:
284 // %x0: glue
285 //
286 // * Construct Native Leave Frame Layout:
287 // +--------------------------+
288 // | argv[N-1] |
289 // +--------------------------+
290 // | . . . . . . |
291 // +--------------------------+
292 // | argv[3]=a0 |
293 // +--------------------------+
294 // | argv[2]=this |
295 // +--------------------------+
296 // | argv[1]=new-target |
297 // +--------------------------+
298 // | argv[0]=call-target |
299 // +--------------------------+ -----------------
300 // | argc | ^
301 // |--------------------------| |
302 // | thread | |
303 // |--------------------------| |
304 // | returnAddr | OptimizedBuiltinLeaveFrame
305 // sp ---> |--------------------------| |
306 // | callsiteFp | |
307 // |--------------------------| |
308 // | frameType | v
309 // +--------------------------+ -----------------
310
CallBuiltinTrampoline(ExtendedAssembler * assembler)311 void OptimizedCall::CallBuiltinTrampoline(ExtendedAssembler *assembler)
312 {
313 Register glue(X0);
314 Register sp(SP);
315 Register nativeFuncAddr(X4);
316 Register temp(X1);
317
318 // remove argv
319 __ Ldr(temp, MemoryOperand(sp, 0));
320 __ Stp(glue, temp, MemoryOperand(sp, 0)); // argc, glue
321 // returnAddr, callsiteFp
322 __ Stp(Register(X29), Register(X30), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
323 __ Mov(temp, sp);
324 __ Str(temp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false))); // rbp
325 __ Mov(Register(X29), temp); // rbp
326 __ Mov(temp, Immediate(static_cast<int32_t>(FrameType::BUILTIN_CALL_LEAVE_FRAME)));
327 __ Stp(Register(Zero), temp, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX)); // frameType, argv
328 __ Add(Register(X0), sp, Immediate(QUADRUPLE_SLOT_SIZE));
329 __ Blr(nativeFuncAddr);
330
331 __ Mov(sp, Register(FP));
332 __ Ldp(Register(X29), Register(X30), MemoryOperand(sp, DOUBLE_SLOT_SIZE, AddrMode::POSTINDEX));
333 __ Ldr(temp, MemoryOperand(sp, FRAME_SLOT_SIZE)); // argc
334 __ Stp(temp, Register(Zero), MemoryOperand(sp, 0)); // argv, argc
335
336 __ Ret();
337 }
338
339 // * uint64_t CallBuiltinConstructorStub(uintptr_t glue, uintptr_t codeAddress, uint32_t argc, ...)
340 // * webkit_jscc calling convention call runtime_id's runtime function(c-abi)
341 //
342 // * Construct Native Leave Frame Layout:
343 // +--------------------------+
344 // | argv[N-1] |
345 // +--------------------------+
346 // | . . . . . . |
347 // +--------------------------+
348 // | argv[3]=a0 |
349 // +--------------------------+
350 // | argv[2]=this |
351 // +--------------------------+
352 // | argv[1]=new-target |
353 // +--------------------------+
354 // | argv[0]=call-target |
355 // +--------------------------+ -----------------
356 // | argc | ^
357 // |--------------------------| |
358 // | thread | |
359 // |--------------------------| |
360 // | returnAddr | OptimizedBuiltinLeaveFrame
361 // sp ---> |--------------------------| |
362 // | callsiteFp | |
363 // |--------------------------| |
364 // | frameType | v
365 // +--------------------------+ -----------------
366
CallBuiltinConstructorStub(ExtendedAssembler * assembler,Register builtinStub,Register argv,Register glue,Register temp)367 void OptimizedCall::CallBuiltinConstructorStub(ExtendedAssembler *assembler, Register builtinStub, Register argv,
368 Register glue, Register temp)
369 {
370 Register sp(SP);
371
372 __ Ldr(temp, MemoryOperand(sp, 0));
373 __ Stp(glue, temp, MemoryOperand(sp, 0)); // argc, glue
374 // returnAddr, callsiteFp
375 __ Stp(Register(X29), Register(X30), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
376 __ Mov(temp, sp);
377 __ Mov(Register(X29), temp); // rbp
378 __ Mov(temp, Immediate(static_cast<int32_t>(FrameType::BUILTIN_CALL_LEAVE_FRAME)));
379 __ Stp(Register(Zero), temp, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX)); // frameType, argv
380 __ Add(argv, sp, Immediate(NONUPLE_SLOT_SIZE));
381 __ Blr(builtinStub);
382
383 __ Mov(sp, Register(FP));
384 __ Ldp(Register(X29), Register(X30), MemoryOperand(sp, DOUBLE_SLOT_SIZE, AddrMode::POSTINDEX));
385 __ Ldr(temp, MemoryOperand(sp, FRAME_SLOT_SIZE)); // argc
386 __ Stp(temp, Register(Zero), MemoryOperand(sp, 0)); // argv, argc
387
388 __ Ret();
389 }
390
391 // * uint64_t JSCall(uintptr_t glue, uint32_t argc, JSTaggedType calltarget, JSTaggedType new,
392 // JSTaggedType this, arg[0], arg[1], arg[2], ..., arg[N-1])
393 // * webkit_jscc calling convention call js function()
394 //
395 // * OptimizedJSFunctionFrame layout description as the following:
396 // +--------------------------+
397 // | arg[N-1] |
398 // +--------------------------+
399 // | ... |
400 // +--------------------------+
401 // | arg[1] |
402 // +--------------------------+
403 // | arg[0] |
404 // +--------------------------+
405 // | this |
406 // +--------------------------+
407 // | new-target |
408 // +--------------------------+
409 // | call-target |
410 // +--------------------------+
411 // | argv |
412 // |--------------------------|
413 // | argc |
414 // sp ----> |--------------------------| ---------------
415 // | returnAddr | ^
416 // |--------------------------| |
417 // | callsiteFp | |
418 // |--------------------------| OptimizedJSFunctionFrame
419 // | frameType | |
420 // |--------------------------| |
421 // | call-target | v
422 // +--------------------------+ ---------------
423
GenJSCall(ExtendedAssembler * assembler,bool isNew)424 void OptimizedCall::GenJSCall(ExtendedAssembler *assembler, bool isNew)
425 {
426 Register jsfunc(X1);
427 Register sp(SP);
428 __ Ldr(jsfunc, MemoryOperand(sp, DOUBLE_SLOT_SIZE)); // skip 2: argc, argv
429 JSCallInternal(assembler, jsfunc, isNew);
430 }
431
JSCallNew(ExtendedAssembler * assembler)432 void OptimizedCall::JSCallNew(ExtendedAssembler *assembler)
433 {
434 __ BindAssemblerStub(RTSTUB_ID(JSCallNew));
435 GenJSCall(assembler, true);
436 }
437
JSCall(ExtendedAssembler * assembler)438 void OptimizedCall::JSCall(ExtendedAssembler *assembler)
439 {
440 __ BindAssemblerStub(RTSTUB_ID(JSCall));
441 GenJSCall(assembler, false);
442 }
443
JSCallInternal(ExtendedAssembler * assembler,Register jsfunc,bool isNew)444 void OptimizedCall::JSCallInternal(ExtendedAssembler *assembler, Register jsfunc, bool isNew)
445 {
446 Register sp(SP);
447 Register glue(X0);
448 Register taggedValue(X2);
449 Label nonCallable;
450 Label notJSFunction;
451 JSCallCheck(assembler, jsfunc, taggedValue, &nonCallable, ¬JSFunction);
452
453 Register method(X2);
454 Register callField(X3);
455 Register actualArgC(X4);
456 Label callNativeMethod;
457 Label lCallConstructor;
458 Label lCallBuiltinStub;
459 Label lCallNativeCpp;
460 Label lNotClass;
461
462 __ Ldr(Register(X5), MemoryOperand(jsfunc, JSFunction::HCLASS_OFFSET));
463 __ And(Register(X5), Register(X5), LogicalImmediate::Create(TaggedObject::GC_STATE_MASK, RegXSize));
464 __ Ldr(Register(X5), MemoryOperand(Register(X5), JSHClass::BIT_FIELD_OFFSET));
465 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
466 __ Ldr(actualArgC, MemoryOperand(sp, 0));
467 __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
468 __ Tbnz(callField, MethodLiteral::IsNativeBit::START_BIT, &callNativeMethod);
469 if (!isNew) {
470 __ Tbz(Register(X5), JSHClass::IsClassConstructorOrPrototypeBit::START_BIT, &lNotClass);
471 __ Tbnz(Register(X5), JSHClass::ConstructorBit::START_BIT, &lCallConstructor);
472 }
473 __ Bind(&lNotClass);
474 {
475 Register argV(X5);
476 // skip argc and argv
477 __ Add(argV, sp, Immediate(kungfu::ArgumentAccessor::GetExtraArgsNum() * FRAME_SLOT_SIZE));
478 // asm interpreter argV = argv + 24
479 __ Add(argV, argV, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() * FRAME_SLOT_SIZE));
480 __ Sub(actualArgC, actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum()));
481 OptimizedCallAsmInterpreter(assembler);
482 }
483
484 __ Bind(&callNativeMethod);
485 {
486 Register nativeFuncAddr(X4);
487 if (!isNew) {
488 __ Tbz(callField, MethodLiteral::IsFastBuiltinBit::START_BIT, &lCallNativeCpp);
489 // 3 : 3 means call0 call1 call2 call3
490 __ Cmp(actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() + 3));
491 __ B(Condition::LE, &lCallBuiltinStub);
492 } else {
493 __ Tbnz(callField, MethodLiteral::IsFastBuiltinBit::START_BIT, &lCallBuiltinStub);
494 }
495 __ Bind(&lCallNativeCpp);
496 __ Ldr(nativeFuncAddr, MemoryOperand(jsfunc, JSFunctionBase::CODE_ENTRY_OFFSET));
497 CallBuiltinTrampoline(assembler);
498 }
499
500 __ Bind(&lCallBuiltinStub);
501 {
502 TempRegister1Scope scope1(assembler);
503 Register builtinStub = __ TempRegister1();
504 __ Ldr(Register(X5), MemoryOperand(method, Method::EXTRA_LITERAL_INFO_OFFSET)); // get extra literal
505 __ And(Register(X5).W(), Register(X5).W(), LogicalImmediate::Create(0xff, RegWSize));
506 if (!isNew) {
507 __ Cmp(Register(X5).W(), Immediate(BUILTINS_STUB_ID(BUILTINS_CONSTRUCTOR_STUB_FIRST)));
508 __ B(Condition::GE, &lCallNativeCpp);
509 }
510 __ Add(builtinStub, glue, Operand(Register(X5).W(), UXTW, FRAME_SLOT_SIZE_LOG2));
511 __ Ldr(builtinStub, MemoryOperand(builtinStub, JSThread::GlueData::GetBuiltinsStubEntriesOffset(false)));
512
513 __ Ldr(Register(X1), MemoryOperand(jsfunc, JSFunctionBase::CODE_ENTRY_OFFSET));
514 __ Ldr(Register(X2), MemoryOperand(sp, DOUBLE_SLOT_SIZE)); // get jsfunc
515 __ Ldr(Register(X3), MemoryOperand(sp, TRIPLE_SLOT_SIZE)); // get newtarget
516 __ Ldr(Register(X4), MemoryOperand(sp, QUADRUPLE_SLOT_SIZE)); // get this
517 __ Ldr(Register(X5), MemoryOperand(sp, 0)); // get number args
518 __ Sub(Register(X5), Register(X5), Immediate(NUM_MANDATORY_JSFUNC_ARGS));
519 if (!isNew) {
520 Label lCall0;
521 Label lCall1;
522 Label lCall2;
523 Label lCall3;
524 Label lTailCall;
525 Register fp(X29);
526 __ Cmp(Register(X5), Immediate(0));
527 __ B(Condition::EQ, &lCall0);
528 __ Cmp(Register(X5), Immediate(1));
529 __ B(Condition::EQ, &lCall1);
530 __ Cmp(Register(X5), Immediate(2)); // 2: 2 args
531 __ B(Condition::EQ, &lCall2);
532 __ Cmp(Register(X5), Immediate(3)); // 3: 3 args
533 __ B(Condition::EQ, &lCall3);
534
535 __ Bind(&lCall0);
536 {
537 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
538 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
539 __ Str(Register(X7), MemoryOperand(sp, 0)); // reset arg2's position
540 __ B(&lTailCall);
541 }
542
543 __ Bind(&lCall1);
544 {
545 __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE));
546 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); // reset x7
547 __ Str(Register(X7), MemoryOperand(sp, 0)); // reset arg2's position
548 __ B(&lTailCall);
549 }
550
551 __ Bind(&lCall2);
552 {
553 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
554 __ Str(Register(X7), MemoryOperand(sp, 0)); // reset arg2's position
555 __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE));
556 __ B(&lTailCall);
557 }
558
559 __ Bind(&lCall3);
560 __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE)); // get arg0 arg1
561 PushAsmBridgeFrame(assembler);
562 {
563 // push arg2 and call
564 TempRegister2Scope scope2(assembler);
565 Register arg2 = __ TempRegister2();
566 __ Ldr(arg2, MemoryOperand(fp, NONUPLE_SLOT_SIZE));
567 __ Stp(arg2, Register(X8), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
568 __ Blr(builtinStub);
569 __ Add(sp, sp, Immediate(DOUBLE_SLOT_SIZE));
570 }
571 PopAsmBridgeFrame(assembler);
572 __ Ret();
573 __ Bind(&lTailCall);
574 {
575 __ Br(builtinStub);
576 }
577 } else {
578 Register argv(X6);
579 TempRegister2Scope scope2(assembler);
580 Register temp = __ TempRegister2();
581 CallBuiltinConstructorStub(assembler, builtinStub, argv, glue, temp);
582 }
583 }
584
585 Label jsBoundFunction;
586 Label jsProxy;
587 __ Bind(¬JSFunction);
588 {
589 Register bitfield(X2);
590 Register jstype2(X5, W);
591 __ And(jstype2, bitfield.W(), LogicalImmediate::Create(0xff, RegWSize));
592 __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_BOUND_FUNCTION)));
593 __ B(Condition::EQ, &jsBoundFunction);
594 __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_PROXY)));
595 __ B(Condition::EQ, &jsProxy);
596 __ Ret();
597 }
598
599 __ Bind(&jsBoundFunction);
600 {
601 JSBoundFunctionCallInternal(assembler, glue, actualArgC, jsfunc, RTSTUB_ID(JSCall));
602 }
603 __ Bind(&jsProxy);
604 {
605 Register nativeFuncAddr(X4);
606 __ Ldr(method, MemoryOperand(jsfunc, JSProxy::METHOD_OFFSET));
607 __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
608 __ Ldr(actualArgC, MemoryOperand(sp, 0));
609 __ Ldr(nativeFuncAddr, MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
610 CallBuiltinTrampoline(assembler);
611 }
612 __ Bind(&nonCallable);
613 {
614 ThrowNonCallableInternal(assembler, sp);
615 }
616 __ Bind(&lCallConstructor);
617 {
618 Register frameType(X6);
619 __ PushFpAndLr();
620 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
621 // 2 : 2 means pair
622 __ Stp(Register(Zero), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
623 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
624 Register argC(X5);
625 Register runtimeId(X6);
626 __ Mov(argC, Immediate(0));
627 __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowCallConstructorException)));
628 // 2 : 2 means pair
629 __ Stp(runtimeId, argC, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
630 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
631 // 4 : 4 means stack slot
632 __ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
633 __ RestoreFpAndLr();
634 __ Ret();
635 }
636 }
637
638 // After the callee function of common aot call deopt, use this bridge to deal with this aot call.
639 // calling convention: webkit_jsc
640 // Input structure:
641 // %X0 - glue
642 // stack:
643 // +--------------------------+
644 // | arg[N-1] |
645 // +--------------------------+
646 // | ... |
647 // +--------------------------+
648 // | arg[1] |
649 // +--------------------------+
650 // | arg[0] |
651 // +--------------------------+
652 // | this |
653 // +--------------------------+
654 // | new-target |
655 // +--------------------------+
656 // | call-target |
657 // |--------------------------|
658 // | argv |
659 // |--------------------------|
660 // | argc |
661 // +--------------------------+ <---- sp
AOTCallToAsmInterBridge(ExtendedAssembler * assembler)662 void OptimizedCall::AOTCallToAsmInterBridge(ExtendedAssembler *assembler)
663 {
664 __ BindAssemblerStub(RTSTUB_ID(AOTCallToAsmInterBridge));
665 Register sp(SP);
666 // params of c++ calling convention
667 Register glue(X0);
668 Register jsfunc(X1);
669 Register method(X2);
670 Register callField(X3);
671 Register actualArgC(X4);
672 Register argV(X5);
673
674 __ Ldr(jsfunc, MemoryOperand(sp, DOUBLE_SLOT_SIZE));
675 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
676 __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
677 __ Ldr(actualArgC, MemoryOperand(sp, 0));
678 // skip argc
679 __ Add(argV, sp, Immediate(kungfu::ArgumentAccessor::GetExtraArgsNum() * FRAME_SLOT_SIZE));
680 // asm interpreter argV = argv + 24
681 __ Add(argV, argV, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() * FRAME_SLOT_SIZE));
682 __ Sub(actualArgC, actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum()));
683 OptimizedCallAsmInterpreter(assembler);
684 }
685
686 // After the callee function of fast aot call deopt, use this bridge to deal with this fast aot call.
687 // Notice: no argc and new-target params compared with not-fast aot call because these params are not needed
688 // by bytecode-analysis
689 // Intruduction: use expected argc as actual argc below for these reasons:
690 // 1) when expected argc == actual argc, pass.
691 // 2) when expected argc > actual argc, undefineds have been pushed in OptimizedFastCallAndPushArgv.
692 // 3) when expected argc < actual argc, redundant params are useless according to bytecode-analysis, just abandon them.
693 // calling convention: c++ calling convention
694 // Input structure:
695 // %X0 - glue
696 // %X1 - call-target
697 // %X2 - this
698 // %X3 - arg0
699 // %X4 - arg1
700 // %X5 - arg2
701 // %X6 - arg3
702 // %X7 - arg4
703 // stack:
704 // +--------------------------+
705 // | arg[N-1] |
706 // +--------------------------+
707 // | ... |
708 // +--------------------------+
709 // | arg[5] |
710 // +--------------------------+ <---- sp
FastCallToAsmInterBridge(ExtendedAssembler * assembler)711 void OptimizedCall::FastCallToAsmInterBridge(ExtendedAssembler *assembler)
712 {
713 __ BindAssemblerStub(RTSTUB_ID(FastCallToAsmInterBridge));
714
715 // Add a bridge frame to protect the stack map, because args will be put on the stack to construct argv on stack
716 // and the AsmInterpBridgeFrame pushed below cannot protect the stack map anymore.
717 PushAsmBridgeFrame(assembler);
718
719 Register sp(SP);
720 // Input
721 Register glue(X0);
722 Register jsfunc(X1);
723 Register thisReg(X2);
724
725 Register tempArgc = __ AvailableRegister1();
726 {
727 TempRegister2Scope scope2(assembler);
728 Register tempMethod = __ TempRegister2();
729
730 __ Ldr(tempMethod, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
731 __ Ldr(tempArgc, MemoryOperand(tempMethod, Method::CALL_FIELD_OFFSET));
732 __ Lsr(tempArgc, tempArgc, MethodLiteral::NumArgsBits::START_BIT);
733 __ And(tempArgc, tempArgc,
734 LogicalImmediate::Create(
735 MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegXSize));
736 }
737 {
738 TempRegister1Scope scope1(assembler);
739 Register startSp = __ TempRegister1();
740 __ Mov(startSp, sp);
741
742 Label lCall0;
743 Label lCall1;
744 Label lCall2;
745 Label lCall3;
746 Label lCall4;
747 Label lCall5;
748 Label lPushCommonRegs;
749
750 __ Cmp(tempArgc, Immediate(0));
751 __ B(Condition::EQ, &lCall0);
752 __ Cmp(tempArgc, Immediate(1));
753 __ B(Condition::EQ, &lCall1);
754 __ Cmp(tempArgc, Immediate(2)); // 2: 2 args
755 __ B(Condition::EQ, &lCall2);
756 __ Cmp(tempArgc, Immediate(3)); // 3: 3 args
757 __ B(Condition::EQ, &lCall3);
758 __ Cmp(tempArgc, Immediate(4)); // 4: 4 args
759 __ B(Condition::EQ, &lCall4);
760 __ Cmp(tempArgc, Immediate(5)); // 5: 5 args
761 __ B(Condition::EQ, &lCall5);
762 // default: more than 5 args
763 {
764 TempRegister2Scope scope2(assembler);
765 Register onStackArgs = __ TempRegister2();
766 Register op1 = __ AvailableRegister2();
767 Register op2 = __ AvailableRegister3();
768
769 // skip bridge frame, return addr and a callee save
770 __ Add(onStackArgs, sp, Immediate(QUADRUPLE_SLOT_SIZE));
771 __ Sub(tempArgc, tempArgc, Immediate(5)); // 5: the first 5 args are not on stack
772 Register arg4(X7);
773 PushArgsWithArgvInPair(assembler, tempArgc, onStackArgs, arg4, op1, op2, &lCall4);
774 }
775
776 __ Bind(&lCall0);
777 {
778 __ B(&lPushCommonRegs);
779 }
780
781 __ Bind(&lCall1);
782 {
783 __ Stp(Register(X3), Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
784 __ B(&lPushCommonRegs);
785 }
786
787 __ Bind(&lCall2);
788 {
789 __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
790 __ B(&lPushCommonRegs);
791 }
792
793 __ Bind(&lCall3);
794 {
795 __ Stp(Register(X5), Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
796 __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
797 __ B(&lPushCommonRegs);
798 }
799
800 __ Bind(&lCall4);
801 {
802 __ Stp(Register(X5), Register(X6), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
803 __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
804 __ B(&lPushCommonRegs);
805 }
806
807 __ Bind(&lCall5);
808 {
809 __ Stp(Register(X7), Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
810 __ Stp(Register(X5), Register(X6), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
811 __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
812 __ B(&lPushCommonRegs);
813 }
814
815 __ Bind(&lPushCommonRegs);
816 {
817 Register newTarget(X7);
818 __ Mov(newTarget, Immediate(JSTaggedValue::VALUE_UNDEFINED));
819 __ Stp(newTarget, thisReg, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
820 __ Stp(startSp, jsfunc, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
821 // fall through
822 }
823 }
824
825 // params of c++ calling convention
826 // glue: X0
827 // jsfunc: X1
828 Register method(X2);
829 Register methodCallField(X3);
830 Register argc(X4);
831 Register argV(X5);
832 // reload and prepare args for JSCallCommonEntry
833 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
834 __ Ldr(methodCallField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
835 __ Mov(argc, methodCallField);
836 __ Lsr(argc, argc, MethodLiteral::NumArgsBits::START_BIT);
837 __ And(argc, argc,
838 LogicalImmediate::Create(
839 MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegXSize));
840 __ Add(argV, sp, Immediate((kungfu::ArgumentAccessor::GetFixArgsNum() + 1) * FRAME_SLOT_SIZE)); // 1: skip startSp
841
842 Label target;
843 PushAsmInterpBridgeFrame(assembler);
844 __ Bl(&target);
845 {
846 PopAsmInterpBridgeFrame(assembler);
847 TempRegister1Scope scope1(assembler);
848 Register startSp = __ TempRegister1();
849 __ Ldp(startSp, Register(Zero), MemoryOperand(sp, ExtendedAssembler::PAIR_SLOT_SIZE, POSTINDEX));
850 __ Mov(sp, startSp);
851 PopAsmBridgeFrame(assembler);
852 __ Ret();
853 }
854 __ Bind(&target);
855 {
856 AsmInterpreterCall::JSCallCommonEntry(assembler, JSCallMode::CALL_FROM_AOT,
857 FrameTransitionType::OTHER_TO_OTHER);
858 }
859 }
860
JSCallCheck(ExtendedAssembler * assembler,Register jsfunc,Register taggedValue,Label * nonCallable,Label * notJSFunction)861 void OptimizedCall::JSCallCheck(ExtendedAssembler *assembler, Register jsfunc, Register taggedValue,
862 Label *nonCallable, Label *notJSFunction)
863 {
864 __ Mov(taggedValue, JSTaggedValue::TAG_MARK);
865 __ Cmp(jsfunc, taggedValue);
866 __ B(Condition::HS, nonCallable);
867 __ Cbz(jsfunc, nonCallable);
868 __ Mov(taggedValue, JSTaggedValue::TAG_SPECIAL);
869 __ And(taggedValue, jsfunc, taggedValue);
870 __ Cbnz(taggedValue, nonCallable);
871
872 Register jshclass(X2);
873 Register glue(X0);
874 __ Ldr(jshclass, MemoryOperand(jsfunc, JSFunction::HCLASS_OFFSET));
875 __ And(jshclass, jshclass, LogicalImmediate::Create(TaggedObject::GC_STATE_MASK, RegXSize));
876 Register bitfield(X2);
877 __ Ldr(bitfield, MemoryOperand(jshclass, JSHClass::BIT_FIELD_OFFSET));
878 __ Tbz(bitfield, JSHClass::CallableBit::START_BIT, nonCallable);
879
880 Register jstype(X3, W);
881 __ And(jstype, bitfield, LogicalImmediate::Create(0xFF, RegWSize));
882 // 4 : 4 means JSType::JS_FUNCTION_FIRST
883 __ Sub(jstype, jstype, Immediate(static_cast<int>(JSType::JS_FUNCTION_FIRST)));
884 // 9 : 9 means JSType::JS_FUNCTION_LAST - JSType::JS_FUNCTION_FIRST + 1
885 __ Cmp(jstype, Immediate(static_cast<int>(JSType::JS_FUNCTION_LAST) -
886 static_cast<int>(JSType::JS_FUNCTION_FIRST) + 1));
887 __ B(Condition::HS, notJSFunction);
888 }
889
ThrowNonCallableInternal(ExtendedAssembler * assembler,Register sp)890 void OptimizedCall::ThrowNonCallableInternal(ExtendedAssembler *assembler, Register sp)
891 {
892 Register frameType(X6);
893 Register taggedMessageId(X5);
894 __ PushFpAndLr();
895 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
896 __ Mov(taggedMessageId,
897 Immediate(JSTaggedValue(GET_MESSAGE_STRING_ID(NonCallable)).GetRawData()));
898 // 2 : 2 means pair
899 __ Stp(taggedMessageId, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
900 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
901 Register argC(X5);
902 Register runtimeId(X6);
903 __ Mov(argC, Immediate(1));
904 __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowTypeError)));
905 // 2 : 2 means pair
906 __ Stp(runtimeId, argC, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
907 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
908 __ Mov(Register(X0), Immediate(JSTaggedValue::VALUE_EXCEPTION));
909 // 4 : 4 means stack slot
910 __ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
911 __ RestoreFpAndLr();
912 __ Ret();
913 }
914
JSBoundFunctionCallInternal(ExtendedAssembler * assembler,Register glue,Register actualArgC,Register jsfunc,int stubId)915 void OptimizedCall::JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Register glue,
916 Register actualArgC, Register jsfunc, int stubId)
917 {
918 // construct frame
919 PushOptimizedArgsConfigFrame(assembler);
920 Register basefp(X29);
921 Register fp = __ AvailableRegister1();
922
923 Register argV(X5);
924 __ Add(argV, basefp, Immediate(GetStackArgOffSetToFp(0))); // 0: first index id
925 __ Ldr(actualArgC, MemoryOperand(argV, 0));
926
927 Register boundLength(X2);
928 Register realArgC(X7, W);
929 Label copyBoundArgument;
930 Label pushCallTarget;
931 Label popArgs;
932 Label slowCall;
933 Label aotCall;
934 Label notClass;
935 // get bound arguments
936 __ Ldr(boundLength, MemoryOperand(jsfunc, JSBoundFunction::BOUND_ARGUMENTS_OFFSET));
937 // get bound length
938 __ Ldr(boundLength, MemoryOperand(boundLength, TaggedArray::LENGTH_OFFSET));
939 __ Add(realArgC, boundLength.W(), actualArgC.W());
940 __ Mov(Register(X19), realArgC);
941 IncreaseStackForArguments(assembler, realArgC, fp, static_cast<int64_t>(CommonArgIdx::ACTUAL_ARGV));
942 __ Sub(actualArgC.W(), actualArgC.W(), Immediate(NUM_MANDATORY_JSFUNC_ARGS));
943 __ Cmp(actualArgC.W(), Immediate(0));
944 __ B(Condition::EQ, ©BoundArgument);
945 {
946 TempRegister1Scope scope1(assembler);
947 Register tmp = __ TempRegister1();
948 const int64_t argoffsetSlot = static_cast<int64_t>(CommonArgIdx::FUNC) - 1;
949 __ Add(argV, argV, Immediate((NUM_MANDATORY_JSFUNC_ARGS + argoffsetSlot) * FRAME_SLOT_SIZE));
950 PushArgsWithArgv(assembler, glue, actualArgC, argV, tmp, fp, nullptr, nullptr);
951 }
952 __ Bind(©BoundArgument);
953 {
954 Register boundArgs(X4);
955 __ Ldr(boundArgs, MemoryOperand(jsfunc, JSBoundFunction::BOUND_ARGUMENTS_OFFSET));
956 __ Add(boundArgs, boundArgs, Immediate(TaggedArray::DATA_OFFSET));
957 __ Cmp(boundLength.W(), Immediate(0));
958 __ B(Condition::EQ, &pushCallTarget);
959 {
960 TempRegister1Scope scope1(assembler);
961 Register tmp = __ TempRegister1();
962 PushArgsWithArgv(assembler, glue, boundLength, boundArgs, tmp, fp, nullptr, nullptr);
963 }
964 }
965 Register boundTarget(X7);
966 Register newTarget(X6);
967 __ Bind(&pushCallTarget);
968 {
969 Register thisObj(X4);
970 __ Ldr(thisObj, MemoryOperand(jsfunc, JSBoundFunction::BOUND_THIS_OFFSET));
971 __ Mov(newTarget, Immediate(JSTaggedValue::VALUE_UNDEFINED));
972 // 2 : 2 means pair
973 __ Stp(newTarget, thisObj, MemoryOperand(fp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
974 __ Ldr(boundTarget, MemoryOperand(jsfunc, JSBoundFunction::BOUND_TARGET_OFFSET));
975 // 2 : 2 means pair
976 __ Stp(argV, boundTarget, MemoryOperand(fp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
977 __ Str(Register(X19), MemoryOperand(fp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
978 }
979 JSCallCheck(assembler, boundTarget, Register(X9), &slowCall, &slowCall);
980 Register hclass = __ AvailableRegister2();
981 __ Ldr(hclass, MemoryOperand(boundTarget, JSFunction::HCLASS_OFFSET));
982 __ And(hclass, hclass, LogicalImmediate::Create(TaggedObject::GC_STATE_MASK, RegXSize));
983 __ Ldr(hclass, MemoryOperand(hclass, JSHClass::BIT_FIELD_OFFSET));
984 __ Tbz(hclass, JSHClass::IsClassConstructorOrPrototypeBit::START_BIT, ¬Class);
985 __ Tbnz(hclass, JSHClass::ConstructorBit::START_BIT, &slowCall);
986 __ Bind(¬Class);
987 Register compiledCodeFlag(X9, W);
988 __ Ldrh(compiledCodeFlag, MemoryOperand(boundTarget, JSFunctionBase::BIT_FIELD_OFFSET));
989 __ Tbz(compiledCodeFlag, JSFunctionBase::IsCompiledCodeBit::START_BIT, &slowCall);
990 __ Bind(&aotCall);
991 {
992 // output: glue:x0 argc:x1 calltarget:x2 argv:x3 this:x4 newtarget:x5
993 __ Mov(Register(X1), Register(X19));
994 __ Mov(Register(X2), boundTarget);
995 __ Add(X3, fp, Immediate(5 * FRAME_SLOT_SIZE)); // 5: skip argc and argv func new this
996 __ Mov(Register(X5), Register(X6));
997 Register boundCallInternalId(X9);
998 Register baseAddress(X8);
999 Register codeAddress(X10);
1000 __ Mov(baseAddress, Immediate(JSThread::GlueData::GetCOStubEntriesOffset(false)));
1001 __ Mov(boundCallInternalId, Immediate(CommonStubCSigns::JsBoundCallInternal));
1002 __ Add(codeAddress, X0, baseAddress);
1003 __ Ldr(codeAddress, MemoryOperand(codeAddress, boundCallInternalId, UXTW, FRAME_SLOT_SIZE_LOG2));
1004 __ Blr(codeAddress);
1005 __ B(&popArgs);
1006 }
1007 __ Bind(&slowCall);
1008 {
1009 __ CallAssemblerStub(stubId, false);
1010 __ B(&popArgs);
1011 }
1012
1013 __ Bind(&popArgs);
1014 PopJSFunctionArgs(assembler, Register(X19), Register(X19));
1015 PopOptimizedArgsConfigFrame(assembler);
1016 __ Ret();
1017 }
1018
1019 // * uint64_t JSProxyCallInternalWithArgV(uintptr_t glue, JSTaggedType calltarget)
1020 // * c++ calling convention call js function
1021 // * Arguments:
1022 // %x0 - glue
1023 // %x1 - calltarget
1024
JSProxyCallInternalWithArgV(ExtendedAssembler * assembler)1025 void OptimizedCall::JSProxyCallInternalWithArgV(ExtendedAssembler *assembler)
1026 {
1027 __ BindAssemblerStub(RTSTUB_ID(JSProxyCallInternalWithArgV));
1028 Register jsfunc(X1);
1029 Register sp(SP);
1030 __ Str(jsfunc, MemoryOperand(sp, DOUBLE_SLOT_SIZE));
1031 JSCallInternal(assembler, jsfunc);
1032 }
1033
1034 // * uint64_t CallRuntimeWithArgv(uintptr_t glue, uint64_t runtime_id, uint64_t argc, uintptr_t argv)
1035 // * cc calling convention call runtime_id's runtion function(c-abi)
1036 // * Arguments:
1037 // %x0 - glue
1038 // %x1 - runtime_id
1039 // %x2 - argc
1040 // %x3 - argv
1041 //
1042 // * Optimized-leaved-frame-with-argv layout as the following:
1043 // +--------------------------+
1044 // | argv[] |
1045 // +--------------------------+-------------
1046 // | argc | ^
1047 // |--------------------------| |
1048 // | RuntimeId | OptimizedWithArgvLeaveFrame
1049 // sp --> |--------------------------| |
1050 // | returnAddr | |
1051 // |--------------------------| |
1052 // | callsiteFp | |
1053 // |--------------------------| |
1054 // | frameType | v
1055 // +--------------------------+-------------
1056
CallRuntimeWithArgv(ExtendedAssembler * assembler)1057 void OptimizedCall::CallRuntimeWithArgv(ExtendedAssembler *assembler)
1058 {
1059 __ BindAssemblerStub(RTSTUB_ID(CallRuntimeWithArgv));
1060 Register glue(X0);
1061 Register runtimeId(X1);
1062 Register argc(X2);
1063 Register argv(X3);
1064 Register sp(SP);
1065 // 2 : 2 means pair
1066 __ Stp(argc, argv, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1067 __ Stp(Register(X30), runtimeId, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX)); // 2 : 2 means pair
1068 Register fp(X29);
1069 // construct leave frame
1070 Register frameType(X9);
1071 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::LEAVE_FRAME_WITH_ARGV)));
1072 __ Stp(frameType, Register(X29), MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX)); // 2 : 2 means pair
1073 __ Add(Register(FP), sp, Immediate(FRAME_SLOT_SIZE));
1074 __ Str(fp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
1075
1076 // load runtime trampoline address
1077 Register tmp(X9);
1078 Register rtfunc(X9);
1079 // 3 : 3 means 2 << 3 = 8
1080 __ Add(tmp, glue, Operand(runtimeId, LSL, 3));
1081 __ Ldr(rtfunc, MemoryOperand(tmp, JSThread::GlueData::GetRTStubEntriesOffset(false)));
1082 __ Mov(X1, argc);
1083 __ Mov(X2, argv);
1084 __ Blr(rtfunc);
1085 __ Ldp(Register(Zero), Register(X29), MemoryOperand(sp, ExtendedAssembler::PAIR_SLOT_SIZE, POSTINDEX));
1086 __ Ldp(Register(X30), Register(Zero), MemoryOperand(sp, ExtendedAssembler::PAIR_SLOT_SIZE, POSTINDEX));
1087 __ Add(sp, sp, Immediate(2 * FRAME_SLOT_SIZE)); // 2 : 2 means pair
1088 __ Ret();
1089 }
1090
PushMandatoryJSArgs(ExtendedAssembler * assembler,Register jsfunc,Register thisObj,Register newTarget,Register currentSp)1091 void OptimizedCall::PushMandatoryJSArgs(ExtendedAssembler *assembler, Register jsfunc,
1092 Register thisObj, Register newTarget, Register currentSp)
1093 {
1094 __ Str(thisObj, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1095 __ Str(newTarget, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1096 __ Str(jsfunc, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1097 }
1098
PopJSFunctionArgs(ExtendedAssembler * assembler,Register expectedNumArgs,Register actualNumArgs)1099 void OptimizedCall::PopJSFunctionArgs(ExtendedAssembler *assembler, Register expectedNumArgs, Register actualNumArgs)
1100 {
1101 Register sp(SP);
1102 Register fp(X6);
1103 Label aligned;
1104 const int64_t argoffsetSlot = static_cast<int64_t>(CommonArgIdx::FUNC) - 1;
1105 if (expectedNumArgs != actualNumArgs) {
1106 TempRegister1Scope scop1(assembler);
1107 Register tmp = __ TempRegister1();
1108 __ Cmp(expectedNumArgs, actualNumArgs);
1109 __ CMov(tmp, expectedNumArgs, actualNumArgs, Condition::HI);
1110 __ Add(sp, sp, Operand(tmp, UXTW, FRAME_SLOT_SIZE_LOG2));
1111 } else {
1112 __ Add(sp, sp, Operand(expectedNumArgs, UXTW, FRAME_SLOT_SIZE_LOG2));
1113 }
1114 __ Add(sp, sp, Immediate(argoffsetSlot * FRAME_SLOT_SIZE));
1115 __ Mov(fp, sp);
1116 __ Tst(fp, LogicalImmediate::Create(0xf, RegXSize)); // 0xf: 0x1111
1117 __ B(Condition::EQ, &aligned);
1118 __ Add(sp, sp, Immediate(FRAME_SLOT_SIZE));
1119 __ Bind(&aligned);
1120 }
1121
PushJSFunctionEntryFrame(ExtendedAssembler * assembler,Register prevFp)1122 void OptimizedCall::PushJSFunctionEntryFrame(ExtendedAssembler *assembler, Register prevFp)
1123 {
1124 Register fp(X29);
1125 Register sp(SP);
1126 TempRegister2Scope temp2Scope(assembler);
1127 __ PushFpAndLr();
1128 Register frameType = __ TempRegister2();
1129 // construct frame
1130 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_ENTRY_FRAME)));
1131 // 2 : 2 means pairs
1132 __ Stp(prevFp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1133 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
1134 __ CalleeSave();
1135 }
1136
PopJSFunctionEntryFrame(ExtendedAssembler * assembler,Register glue)1137 void OptimizedCall::PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue)
1138 {
1139 Register fp(X29);
1140 Register sp(SP);
1141 Register prevFp(X1);
1142 __ CalleeRestore();
1143
1144 // 2: prevFp and frameType
1145 __ Ldp(prevFp, Register(Zero), MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
1146 // restore return address
1147 __ RestoreFpAndLr();
1148 __ Str(prevFp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
1149 }
1150
PushOptimizedArgsConfigFrame(ExtendedAssembler * assembler)1151 void OptimizedCall::PushOptimizedArgsConfigFrame(ExtendedAssembler *assembler)
1152 {
1153 Register sp(SP);
1154 TempRegister2Scope temp2Scope(assembler);
1155 Register frameType = __ TempRegister2();
1156 __ PushFpAndLr();
1157 // construct frame
1158 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
1159 // 2 : 2 means pairs. X19 means calleesave and 16bytes align
1160 __ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1161 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
1162 }
1163
PopOptimizedArgsConfigFrame(ExtendedAssembler * assembler)1164 void OptimizedCall::PopOptimizedArgsConfigFrame(ExtendedAssembler *assembler)
1165 {
1166 TempRegister2Scope temp2Scope(assembler);
1167 Register sp(SP);
1168 Register frameType = __ TempRegister2();
1169 // 2 : 2 means pop call site sp and type
1170 __ Ldp(Register(X19), frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
1171 __ RestoreFpAndLr();
1172 }
1173
PushAsmBridgeFrame(ExtendedAssembler * assembler)1174 void OptimizedCall::PushAsmBridgeFrame(ExtendedAssembler *assembler)
1175 {
1176 Register sp(SP);
1177 TempRegister2Scope temp2Scope(assembler);
1178 Register frameType = __ TempRegister2();
1179 __ PushFpAndLr();
1180 // construct frame
1181 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::ASM_BRIDGE_FRAME)));
1182 // 2 : 2 means pairs. X19 means calleesave and 16bytes align
1183 __ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1184 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
1185 }
1186
PopAsmBridgeFrame(ExtendedAssembler * assembler)1187 void OptimizedCall::PopAsmBridgeFrame(ExtendedAssembler *assembler)
1188 {
1189 TempRegister2Scope temp2Scope(assembler);
1190 Register sp(SP);
1191 Register frameType = __ TempRegister2();
1192 // 2 : 2 means pop call site sp and type
1193 __ Ldp(Register(X19), frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
1194 __ RestoreFpAndLr();
1195 }
1196
1197 // * uint64_t PushOptimizedUnfoldArgVFrame(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1198 // JSTaggedType new, JSTaggedType this, JSTaggedType argV[])
1199 // * cc calling convention call js function()
1200 // * arguments:
1201 // %x0 - glue
1202 // %x1 - argc
1203 // %x2 - call-target
1204 // %x3 - new-target
1205 // %x4 - this
1206 // %x5 - argv
1207 //
1208 // * OptimizedUnfoldArgVFrame layout description as the following:
1209 // sp ----> |--------------------------| ---------------
1210 // | returnAddr | ^
1211 // currentFp--> |--------------------------| |
1212 // | prevFp | |
1213 // |--------------------------| OptimizedUnfoldArgVFrame
1214 // | frameType | |
1215 // |--------------------------| |
1216 // | currentFp | v
1217 // +--------------------------+ ---------------
1218
PushOptimizedUnfoldArgVFrame(ExtendedAssembler * assembler,Register callSiteSp)1219 void OptimizedCall::PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp)
1220 {
1221 Register sp(SP);
1222 TempRegister2Scope temp2Scope(assembler);
1223 Register frameType = __ TempRegister2();
1224 __ PushFpAndLr();
1225 // construct frame
1226 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)));
1227 // 2 : 2 means pairs
1228 __ Stp(callSiteSp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1229 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
1230 }
1231
PopOptimizedUnfoldArgVFrame(ExtendedAssembler * assembler)1232 void OptimizedCall::PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler)
1233 {
1234 Register sp(SP);
1235 // 2 : 2 means pop call site sp and type
1236 __ Add(sp, sp, Immediate(2 * FRAME_SLOT_SIZE));
1237 __ RestoreFpAndLr();
1238 }
1239
1240 // * uint64_t JSCallWithArgV(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1241 // JSTaggedType new, JSTaggedType this, argV)
1242 // * cc calling convention call js function()
1243 // * arguments:
1244 // %x0 - glue
1245 // %x1 - argc
1246 // %x2 - call-target
1247 // %x3 - new-target
1248 // %x4 - this
1249 // %x5 - argV[]
1250 //
1251 // * OptimizedJSFunctionFrame layout description as the following:
1252 // +--------------------------+
1253 // | argn |
1254 // |--------------------------|
1255 // | argn - 1 |
1256 // |--------------------------|
1257 // | ..... |
1258 // |--------------------------|
1259 // | arg2 |
1260 // |--------------------------|
1261 // | arg1 |
1262 // sp ----> |--------------------------| ---------------
1263 // | returnAddr | ^
1264 // |--------------------------| |
1265 // | callsiteFp | |
1266 // |--------------------------| OptimizedJSFunctionFrame
1267 // | frameType | |
1268 // |--------------------------| |
1269 // | call-target | v
1270 // +--------------------------+ ---------------
1271
GenJSCallWithArgV(ExtendedAssembler * assembler,int id)1272 void OptimizedCall::GenJSCallWithArgV(ExtendedAssembler *assembler, int id)
1273 {
1274 Register sp(SP);
1275 Register glue(X0);
1276 Register actualNumArgs(X1);
1277 Register jsfunc(X2);
1278 Register newTarget(X3);
1279 Register thisObj(X4);
1280 Register argV(X5);
1281 Register currentSp = __ AvailableRegister1();
1282 Register callsiteSp = __ AvailableRegister2();
1283 Label pushCallThis;
1284
1285 __ Mov(callsiteSp, sp);
1286 PushOptimizedUnfoldArgVFrame(assembler, callsiteSp);
1287 Register argC(X7);
1288 __ Add(actualNumArgs, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1289 __ Mov(argC, actualNumArgs);
1290 IncreaseStackForArguments(assembler, argC, currentSp, static_cast<int64_t>(CommonArgIdx::ACTUAL_ARGV));
1291 {
1292 TempRegister1Scope scope1(assembler);
1293 TempRegister2Scope scope2(assembler);
1294 Register tmp = __ TempRegister1();
1295 Register op = __ TempRegister2();
1296 __ Sub(tmp, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1297 PushArgsWithArgv(assembler, glue, tmp, argV, op, currentSp, &pushCallThis, nullptr);
1298 }
1299 __ Bind(&pushCallThis);
1300 PushMandatoryJSArgs(assembler, jsfunc, thisObj, newTarget, currentSp);
1301 {
1302 TempRegister1Scope scope1(assembler);
1303 Register tmp = __ TempRegister1();
1304 __ Mov(tmp, currentSp);
1305 __ Str(tmp, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1306 __ Str(actualNumArgs, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1307 }
1308 __ CallAssemblerStub(id, false);
1309 __ Ldr(actualNumArgs, MemoryOperand(sp, 0));
1310 PopJSFunctionArgs(assembler, actualNumArgs, actualNumArgs);
1311 PopOptimizedUnfoldArgVFrame(assembler);
1312 __ Ret();
1313 }
1314
1315 // * uint64_t JSCallWithArgVAndPushArgv(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1316 // JSTaggedType new, JSTaggedType this, argV)
1317 // * cc calling convention call js function()
1318 // * arguments:
1319 // %x0 - glue
1320 // %x1 - argc
1321 // %x2 - call-target
1322 // %x3 - new-target
1323 // %x4 - this
1324 // %x5 - argv
JSCallWithArgVAndPushArgv(ExtendedAssembler * assembler)1325 void OptimizedCall::JSCallWithArgVAndPushArgv(ExtendedAssembler *assembler)
1326 {
1327 __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgVAndPushArgv));
1328 GenJSCallWithArgV(assembler, RTSTUB_ID(OptimizedCallAndPushArgv));
1329 }
1330
JSCallWithArgV(ExtendedAssembler * assembler)1331 void OptimizedCall::JSCallWithArgV(ExtendedAssembler *assembler)
1332 {
1333 __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgV));
1334 GenJSCallWithArgV(assembler, RTSTUB_ID(CallOptimized));
1335 }
1336
SuperCallWithArgV(ExtendedAssembler * assembler)1337 void OptimizedCall::SuperCallWithArgV(ExtendedAssembler *assembler)
1338 {
1339 __ BindAssemblerStub(RTSTUB_ID(SuperCallWithArgV));
1340 GenJSCallWithArgV(assembler, RTSTUB_ID(JSCallNew));
1341 }
1342
CallOptimized(ExtendedAssembler * assembler)1343 void OptimizedCall::CallOptimized(ExtendedAssembler *assembler)
1344 {
1345 __ BindAssemblerStub(RTSTUB_ID(CallOptimized));
1346 Register sp(SP);
1347 Register jsfunc(X7);
1348 Register method(X6);
1349 Register codeAddr(X5);
1350 auto funcSlotOffset = kungfu::ArgumentAccessor::GetExtraArgsNum();
1351 __ Ldr(jsfunc, MemoryOperand(sp, funcSlotOffset * FRAME_SLOT_SIZE));
1352 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
1353 __ Ldr(codeAddr, MemoryOperand(jsfunc, JSFunction::CODE_ENTRY_OFFSET));
1354 __ Br(codeAddr);
1355 }
1356
DeoptEnterAsmInterpOrBaseline(ExtendedAssembler * assembler)1357 void OptimizedCall::DeoptEnterAsmInterpOrBaseline(ExtendedAssembler *assembler)
1358 {
1359 // rdi
1360 Register glueRegister = __ GlueRegister();
1361 Register context(X2);
1362 Register opRegister(X9);
1363 Register outputCount(X10);
1364 Register frameStateBase(X11);
1365 Register currentSlotRegister(X12);
1366 Register sp(SP);
1367 Register depth(X20);
1368 Register tmpReg(X21);
1369 Register hasExceptionRegister(X25);
1370 Label loopBegin;
1371 Label stackOverflow;
1372 Label pushArgv;
1373 Label gotoExceptionHandler;
1374
1375 __ PushFpAndLr();
1376 __ Ldr(hasExceptionRegister, MemoryOperand(context, AsmStackContext::GetHasExceptionOffset(false)));
1377 __ Ldr(depth, MemoryOperand(context, AsmStackContext::GetInlineDepthOffset(false)));
1378 __ Add(context, context, Immediate(AsmStackContext::GetSize(false)));
1379 __ Mov(Register(X23), Immediate(0));
1380 // update fp
1381 __ Mov(currentSlotRegister, sp);
1382 __ Bind(&loopBegin);
1383 __ Ldr(outputCount, MemoryOperand(context, 0));
1384 __ Add(frameStateBase, context, Immediate(FRAME_SLOT_SIZE));
1385 __ Cmp(Register(X23), Immediate(0));
1386 __ B(Condition::EQ, &pushArgv);
1387 __ Mov(tmpReg, currentSlotRegister);
1388 __ Add(tmpReg, tmpReg, Immediate(AsmInterpretedFrame::GetSize(false)));
1389 __ Add(Register(X9), frameStateBase, Immediate(AsmInterpretedFrame::GetBaseOffset(false)));
1390 __ Str(tmpReg, MemoryOperand(Register(X9), InterpretedFrameBase::GetPrevOffset(false)));
1391 __ Align16(currentSlotRegister);
1392
1393 __ Bind(&pushArgv);
1394 __ Mov(tmpReg, outputCount);
1395 __ Str(currentSlotRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFpOffset(false)));
1396 PushArgsWithArgv(assembler, glueRegister, outputCount, frameStateBase, opRegister,
1397 currentSlotRegister, nullptr, &stackOverflow);
1398 __ Add(context, context, Immediate(FRAME_SLOT_SIZE)); // skip outputCount
1399 __ Add(context, context, Operand(tmpReg, UXTW, FRAME_SLOT_SIZE_LOG2)); // skip args
1400 __ Add(Register(X23), Register(X23), Immediate(1));
1401 __ Cmp(depth, Register(X23));
1402 __ B(Condition::GE, &loopBegin);
1403
1404 Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
1405 Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
1406 __ Ldr(callTargetRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFunctionOffset(false)));
1407 // get baseline code
1408 __ Ldr(opRegister, MemoryOperand(callTargetRegister, JSFunction::BASELINECODE_OFFSET));
1409 Label baselineCodeUndefined;
1410 __ Cmp(opRegister, Immediate(JSTaggedValue::VALUE_UNDEFINED));
1411 __ B(Condition::EQ, &baselineCodeUndefined);
1412
1413 // check is compiling
1414 __ Cmp(opRegister, Immediate(JSTaggedValue::VALUE_HOLE));
1415 __ B(Condition::EQ, &baselineCodeUndefined);
1416 {
1417 // x20 is free and callee save
1418 Register newSpRegister = X20;
1419 // get new sp
1420 __ Add(newSpRegister, currentSlotRegister, Immediate(AsmInterpretedFrame::GetSize(false)));
1421 __ Align16(currentSlotRegister);
1422 __ Mov(sp, currentSlotRegister);
1423
1424 // save glue, callTarget
1425 __ Stp(glueRegister, callTargetRegister, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1426 // callee save
1427 __ CalleeSave();
1428
1429 // get bytecode pc
1430 Register bytecodePc = opRegister;
1431 __ Ldr(bytecodePc, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetPcOffset(false)));
1432 // get func
1433 Register func(X1);
1434 func = callTargetRegister;
1435 Register argC(X2);
1436 Register runtimeId(X3);
1437 __ Mov(argC, Immediate(2)); // 2: argc
1438 __ Mov(runtimeId, Immediate(RTSTUB_ID(GetNativePcOfstForBaseline)));
1439 // get native pc offset in baselinecode by bytecodePc in func
1440 __ Stp(func, bytecodePc, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1441 __ Stp(runtimeId, argC, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1442 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1443
1444 // 2: skip runtimeId argc func bytecodePc
1445 __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE));
1446
1447 __ CalleeRestore();
1448 // restore glue, callTarget
1449 __ Ldp(X19, callTargetRegister, MemoryOperand(sp, DOUBLE_SLOT_SIZE, AddrMode::POSTINDEX));
1450 // restore method, fp
1451 __ Ldr(methodRegister, MemoryOperand(callTargetRegister, JSFunctionBase::METHOD_OFFSET));
1452 __ Mov(X21, methodRegister);
1453 __ Mov(Register(FP), newSpRegister);
1454
1455 // update pc
1456 const int64_t pcOffsetFromSp = -24; // -24: 3 slots, frameType, prevFrame, pc
1457 __ Mov(opRegister, Immediate(BASELINEJIT_PC_FLAG));
1458 __ Stur(opRegister, MemoryOperand(Register(FP), pcOffsetFromSp));
1459
1460 // jmp to baselinecode
1461 __ Br(X0);
1462 }
1463
1464 __ Bind(&baselineCodeUndefined);
1465 {
1466 // X19, fp, x20, x21, x22, x23, x24
1467 // glue sp pc constpool profile acc hotness
1468 __ Ldr(callTargetRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFunctionOffset(false)));
1469 __ Ldr(Register(X20), MemoryOperand(frameStateBase, AsmInterpretedFrame::GetPcOffset(false)));
1470 __ Ldr(Register(X23), MemoryOperand(frameStateBase, AsmInterpretedFrame::GetAccOffset(false)));
1471 __ Ldr(methodRegister, MemoryOperand(callTargetRegister, JSFunctionBase::METHOD_OFFSET));
1472
1473 __ Add(opRegister, currentSlotRegister, Immediate(AsmInterpretedFrame::GetSize(false)));
1474
1475 __ Align16(currentSlotRegister);
1476 __ Mov(Register(SP), currentSlotRegister);
1477
1478 __ Cmp(hasExceptionRegister, Immediate(0));
1479 __ B(Condition::NE, &gotoExceptionHandler);
1480 AsmInterpreterCall::DispatchCall(assembler, Register(X20), opRegister, Register(X23), false);
1481 __ Bind(&gotoExceptionHandler);
1482 AsmInterpreterCall::DispatchCall(assembler, Register(X20), opRegister, Register(X23), true);
1483 }
1484 __ Bind(&stackOverflow);
1485 {
1486 Register temp(X1);
1487 AsmInterpreterCall::ThrowStackOverflowExceptionAndReturnToAsmInterpBridgeFrame(
1488 assembler, glueRegister, sp, temp);
1489 }
1490 }
1491
DeoptPushAsmInterpBridgeFrame(ExtendedAssembler * assembler,Register context)1492 void OptimizedCall::DeoptPushAsmInterpBridgeFrame(ExtendedAssembler *assembler, Register context)
1493 {
1494 Register fp(X29);
1495 Register sp(SP);
1496
1497 [[maybe_unused]] TempRegister1Scope scope1(assembler);
1498 Label processLazyDeopt;
1499 Label exit;
1500 Register frameTypeRegister = __ TempRegister1();
1501
1502 __ Ldr(frameTypeRegister, MemoryOperand(context, AsmStackContext::GetIsFrameLazyDeoptOffset(false)));
1503 __ Cmp(frameTypeRegister, Immediate(0));
1504 __ B(Condition::NE, &processLazyDeopt);
1505 {
1506 __ Mov(frameTypeRegister, Immediate(static_cast<int64_t>(FrameType::ASM_INTERPRETER_BRIDGE_FRAME)));
1507 __ B(&exit);
1508 }
1509 __ Bind(&processLazyDeopt);
1510 {
1511 __ Mov(frameTypeRegister, (static_cast<uint64_t>(FrameType::ASM_INTERPRETER_BRIDGE_FRAME) |
1512 (1ULL << FrameIterator::LAZY_DEOPT_FLAG_BIT)));
1513 }
1514 __ Bind(&exit);
1515 // 2 : return addr & frame type
1516 __ Stp(frameTypeRegister, Register(X30), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1517 // 2 : prevSp & pc
1518 __ Stp(Register(Zero), Register(FP), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1519 __ Add(fp, sp, Immediate(24)); // 24: skip frame type, prevSp, pc
1520
1521 if (!assembler->FromInterpreterHandler()) {
1522 __ CalleeSave();
1523 }
1524 }
1525
DeoptHandlerAsm(ExtendedAssembler * assembler)1526 void OptimizedCall::DeoptHandlerAsm(ExtendedAssembler *assembler)
1527 {
1528 __ BindAssemblerStub(RTSTUB_ID(DeoptHandlerAsm));
1529 __ PushFpAndLr();
1530 Register sp(SP);
1531 Register fp(FP);
1532 Register frameType(X3);
1533 Register glueReg(X0);
1534
1535 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::ASM_BRIDGE_FRAME)));
1536 __ Stp(glueReg, frameType, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1537 __ Add(fp, sp, Immediate(DOUBLE_SLOT_SIZE));
1538 __ CalleeSave();
1539
1540 Register deoptType(X1);
1541 Register maybeAcc(X2);
1542 Register argC(X3);
1543 Register runtimeId(X4);
1544 __ Stp(deoptType, maybeAcc, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1545 __ Mov(argC, Immediate(2)); // 2: argc
1546 __ Mov(runtimeId, Immediate(RTSTUB_ID(DeoptHandler)));
1547 __ Stp(runtimeId, argC, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1548 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1549 __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE)); // 2: skip runtimeId, argc, depth, shiftLen
1550
1551 __ CalleeRestore();
1552 Register context(X2);
1553 __ Mov(context, Register(X0));
1554 __ Ldr(glueReg, MemoryOperand(sp, 0));
1555
1556 Register ret(X0);
1557 Label stackOverflow;
1558 __ Cmp(ret, Immediate(JSTaggedValue::VALUE_EXCEPTION));
1559 __ B(Condition::EQ, &stackOverflow);
1560
1561 Label target;
1562 Register temp(X1);
1563 __ Ldr(fp, MemoryOperand(context, AsmStackContext::GetCallerFpOffset(false)));
1564 __ Ldr(temp, MemoryOperand(context, AsmStackContext::GetCallFrameTopOffset(false)));
1565 __ Mov(sp, temp);
1566 __ Ldr(Register(X30), MemoryOperand(context, AsmStackContext::GetReturnAddressOffset(false)));
1567
1568 DeoptPushAsmInterpBridgeFrame(assembler, context);
1569 __ Bl(&target);
1570 PopAsmInterpBridgeFrame(assembler);
1571 __ Ret();
1572 __ Bind(&target);
1573 DeoptEnterAsmInterpOrBaseline(assembler);
1574
1575 __ Bind(&stackOverflow);
1576 {
1577 __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowStackOverflowException)));
1578 // 2 : 2 means pair
1579 __ Stp(runtimeId, Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1580 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1581 __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE)); // 2: skip runtimeId&argc glue&type
1582 __ RestoreFpAndLr();
1583 __ Ret();
1584 }
1585 }
1586 #undef __
1587 } // panda::ecmascript::aarch64
1588