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, 0));
463 __ Ldr(Register(X5), MemoryOperand(Register(X5), JSHClass::BIT_FIELD_OFFSET));
464 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
465 __ Ldr(actualArgC, MemoryOperand(sp, 0));
466 __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
467 __ Tbnz(callField, MethodLiteral::IsNativeBit::START_BIT, &callNativeMethod);
468 if (!isNew) {
469 __ Tbz(Register(X5), JSHClass::IsClassConstructorOrPrototypeBit::START_BIT, &lNotClass);
470 __ Tbnz(Register(X5), JSHClass::ConstructorBit::START_BIT, &lCallConstructor);
471 }
472 __ Bind(&lNotClass);
473 {
474 Register argV(X5);
475 // skip argc and argv
476 __ Add(argV, sp, Immediate(kungfu::ArgumentAccessor::GetExtraArgsNum() * FRAME_SLOT_SIZE));
477 // asm interpreter argV = argv + 24
478 __ Add(argV, argV, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() * FRAME_SLOT_SIZE));
479 __ Sub(actualArgC, actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum()));
480 OptimizedCallAsmInterpreter(assembler);
481 }
482
483 __ Bind(&callNativeMethod);
484 {
485 Register nativeFuncAddr(X4);
486 if (!isNew) {
487 __ Tbz(callField, MethodLiteral::IsFastBuiltinBit::START_BIT, &lCallNativeCpp);
488 // 3 : 3 means call0 call1 call2 call3
489 __ Cmp(actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() + 3));
490 __ B(Condition::LE, &lCallBuiltinStub);
491 } else {
492 __ Tbnz(callField, MethodLiteral::IsFastBuiltinBit::START_BIT, &lCallBuiltinStub);
493 }
494 __ Bind(&lCallNativeCpp);
495 __ Ldr(nativeFuncAddr, MemoryOperand(jsfunc, JSFunctionBase::CODE_ENTRY_OFFSET));
496 CallBuiltinTrampoline(assembler);
497 }
498
499 __ Bind(&lCallBuiltinStub);
500 {
501 TempRegister1Scope scope1(assembler);
502 Register builtinStub = __ TempRegister1();
503 __ Ldr(Register(X5), MemoryOperand(method, Method::EXTRA_LITERAL_INFO_OFFSET)); // get extra literal
504 __ And(Register(X5).W(), Register(X5).W(), LogicalImmediate::Create(0xff, RegWSize));
505 if (!isNew) {
506 __ Cmp(Register(X5).W(), Immediate(kungfu::BuiltinsStubCSigns::BUILTINS_CONSTRUCTOR_STUB_FIRST));
507 __ B(Condition::GE, &lCallNativeCpp);
508 }
509 __ Add(builtinStub, glue, Operand(Register(X5).W(), UXTW, FRAME_SLOT_SIZE_LOG2));
510 __ Ldr(builtinStub, MemoryOperand(builtinStub, JSThread::GlueData::GetBuiltinsStubEntriesOffset(false)));
511
512 __ Ldr(Register(X1), MemoryOperand(jsfunc, JSFunctionBase::CODE_ENTRY_OFFSET));
513 __ Ldr(Register(X2), MemoryOperand(sp, DOUBLE_SLOT_SIZE)); // get jsfunc
514 __ Ldr(Register(X3), MemoryOperand(sp, TRIPLE_SLOT_SIZE)); // get newtarget
515 __ Ldr(Register(X4), MemoryOperand(sp, QUADRUPLE_SLOT_SIZE)); // get this
516 __ Ldr(Register(X5), MemoryOperand(sp, 0)); // get number args
517 __ Sub(Register(X5), Register(X5), Immediate(NUM_MANDATORY_JSFUNC_ARGS));
518 if (!isNew) {
519 Label lCall0;
520 Label lCall1;
521 Label lCall2;
522 Label lCall3;
523 Label lTailCall;
524 Register fp(X29);
525 __ Cmp(Register(X5), Immediate(0));
526 __ B(Condition::EQ, &lCall0);
527 __ Cmp(Register(X5), Immediate(1));
528 __ B(Condition::EQ, &lCall1);
529 __ Cmp(Register(X5), Immediate(2)); // 2: 2 args
530 __ B(Condition::EQ, &lCall2);
531 __ Cmp(Register(X5), Immediate(3)); // 3: 3 args
532 __ B(Condition::EQ, &lCall3);
533
534 __ Bind(&lCall0);
535 {
536 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
537 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
538 __ Str(Register(X7), MemoryOperand(sp, 0)); // reset arg2's position
539 __ B(&lTailCall);
540 }
541
542 __ Bind(&lCall1);
543 {
544 __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE));
545 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); // reset x7
546 __ Str(Register(X7), MemoryOperand(sp, 0)); // reset arg2's position
547 __ B(&lTailCall);
548 }
549
550 __ Bind(&lCall2);
551 {
552 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
553 __ Str(Register(X7), MemoryOperand(sp, 0)); // reset arg2's position
554 __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE));
555 __ B(&lTailCall);
556 }
557
558 __ Bind(&lCall3);
559 __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE)); // get arg0 arg1
560 PushAsmBridgeFrame(assembler);
561 {
562 // push arg2 and call
563 TempRegister2Scope scope2(assembler);
564 Register arg2 = __ TempRegister2();
565 __ Ldr(arg2, MemoryOperand(fp, NONUPLE_SLOT_SIZE));
566 __ Stp(arg2, Register(X8), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
567 __ Blr(builtinStub);
568 __ Add(sp, sp, Immediate(DOUBLE_SLOT_SIZE));
569 }
570 PopAsmBridgeFrame(assembler);
571 __ Ret();
572 __ Bind(&lTailCall);
573 {
574 __ Br(builtinStub);
575 }
576 } else {
577 Register argv(X6);
578 TempRegister2Scope scope2(assembler);
579 Register temp = __ TempRegister2();
580 CallBuiltinConstructorStub(assembler, builtinStub, argv, glue, temp);
581 }
582 }
583
584 Label jsBoundFunction;
585 Label jsProxy;
586 __ Bind(¬JSFunction);
587 {
588 Register bitfield(X2);
589 Register jstype2(X5, W);
590 __ And(jstype2, bitfield.W(), LogicalImmediate::Create(0xff, RegWSize));
591 __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_BOUND_FUNCTION)));
592 __ B(Condition::EQ, &jsBoundFunction);
593 __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_PROXY)));
594 __ B(Condition::EQ, &jsProxy);
595 __ Ret();
596 }
597
598 __ Bind(&jsBoundFunction);
599 {
600 JSBoundFunctionCallInternal(assembler, glue, actualArgC, jsfunc, RTSTUB_ID(JSCall));
601 }
602 __ Bind(&jsProxy);
603 {
604 Register nativeFuncAddr(X4);
605 __ Ldr(method, MemoryOperand(jsfunc, JSProxy::METHOD_OFFSET));
606 __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
607 __ Ldr(actualArgC, MemoryOperand(sp, 0));
608 __ Ldr(nativeFuncAddr, MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
609 CallBuiltinTrampoline(assembler);
610 }
611 __ Bind(&nonCallable);
612 {
613 ThrowNonCallableInternal(assembler, sp);
614 }
615 __ Bind(&lCallConstructor);
616 {
617 Register frameType(X6);
618 __ PushFpAndLr();
619 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
620 // 2 : 2 means pair
621 __ Stp(Register(Zero), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
622 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
623 Register argC(X5);
624 Register runtimeId(X6);
625 __ Mov(argC, Immediate(0));
626 __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowCallConstructorException)));
627 // 2 : 2 means pair
628 __ Stp(runtimeId, argC, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
629 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
630 // 4 : 4 means stack slot
631 __ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
632 __ RestoreFpAndLr();
633 __ Ret();
634 }
635 }
636
637 // After the callee function of common aot call deopt, use this bridge to deal with this aot call.
638 // calling convention: webkit_jsc
639 // Input structure:
640 // %X0 - glue
641 // stack:
642 // +--------------------------+
643 // | arg[N-1] |
644 // +--------------------------+
645 // | ... |
646 // +--------------------------+
647 // | arg[1] |
648 // +--------------------------+
649 // | arg[0] |
650 // +--------------------------+
651 // | this |
652 // +--------------------------+
653 // | new-target |
654 // +--------------------------+
655 // | call-target |
656 // |--------------------------|
657 // | argv |
658 // |--------------------------|
659 // | argc |
660 // +--------------------------+ <---- sp
AOTCallToAsmInterBridge(ExtendedAssembler * assembler)661 void OptimizedCall::AOTCallToAsmInterBridge(ExtendedAssembler *assembler)
662 {
663 __ BindAssemblerStub(RTSTUB_ID(AOTCallToAsmInterBridge));
664 Register sp(SP);
665 // params of c++ calling convention
666 Register glue(X0);
667 Register jsfunc(X1);
668 Register method(X2);
669 Register callField(X3);
670 Register actualArgC(X4);
671 Register argV(X5);
672
673 __ Ldr(jsfunc, MemoryOperand(sp, DOUBLE_SLOT_SIZE));
674 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
675 __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
676 __ Ldr(actualArgC, MemoryOperand(sp, 0));
677 // skip argc
678 __ Add(argV, sp, Immediate(kungfu::ArgumentAccessor::GetExtraArgsNum() * FRAME_SLOT_SIZE));
679 // asm interpreter argV = argv + 24
680 __ Add(argV, argV, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() * FRAME_SLOT_SIZE));
681 __ Sub(actualArgC, actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum()));
682 OptimizedCallAsmInterpreter(assembler);
683 }
684
685 // After the callee function of fast aot call deopt, use this bridge to deal with this fast aot call.
686 // Notice: no argc and new-target params compared with not-fast aot call because these params are not needed
687 // by bytecode-analysis
688 // Intruduction: use expected argc as actual argc below for these reasons:
689 // 1) when expected argc == actual argc, pass.
690 // 2) when expected argc > actual argc, undefineds have been pushed in OptimizedFastCallAndPushArgv.
691 // 3) when expected argc < actual argc, redundant params are useless according to bytecode-analysis, just abandon them.
692 // calling convention: c++ calling convention
693 // Input structure:
694 // %X0 - glue
695 // %X1 - call-target
696 // %X2 - this
697 // %X3 - arg0
698 // %X4 - arg1
699 // %X5 - arg2
700 // %X6 - arg3
701 // %X7 - arg4
702 // stack:
703 // +--------------------------+
704 // | arg[N-1] |
705 // +--------------------------+
706 // | ... |
707 // +--------------------------+
708 // | arg[5] |
709 // +--------------------------+ <---- sp
FastCallToAsmInterBridge(ExtendedAssembler * assembler)710 void OptimizedCall::FastCallToAsmInterBridge(ExtendedAssembler *assembler)
711 {
712 __ BindAssemblerStub(RTSTUB_ID(FastCallToAsmInterBridge));
713
714 // Add a bridge frame to protect the stack map, because args will be put on the stack to construct argv on stack
715 // and the AsmInterpBridgeFrame pushed below cannot protect the stack map anymore.
716 PushAsmBridgeFrame(assembler);
717
718 Register sp(SP);
719 // Input
720 Register glue(X0);
721 Register jsfunc(X1);
722 Register thisReg(X2);
723
724 Register tempArgc = __ AvailableRegister1();
725 {
726 TempRegister2Scope scope2(assembler);
727 Register tempMethod = __ TempRegister2();
728
729 __ Ldr(tempMethod, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
730 __ Ldr(tempArgc, MemoryOperand(tempMethod, Method::CALL_FIELD_OFFSET));
731 __ Lsr(tempArgc, tempArgc, MethodLiteral::NumArgsBits::START_BIT);
732 __ And(tempArgc, tempArgc,
733 LogicalImmediate::Create(
734 MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegXSize));
735 }
736 {
737 TempRegister1Scope scope1(assembler);
738 Register startSp = __ TempRegister1();
739 __ Mov(startSp, sp);
740
741 Label lCall0;
742 Label lCall1;
743 Label lCall2;
744 Label lCall3;
745 Label lCall4;
746 Label lCall5;
747 Label lPushCommonRegs;
748
749 __ Cmp(tempArgc, Immediate(0));
750 __ B(Condition::EQ, &lCall0);
751 __ Cmp(tempArgc, Immediate(1));
752 __ B(Condition::EQ, &lCall1);
753 __ Cmp(tempArgc, Immediate(2)); // 2: 2 args
754 __ B(Condition::EQ, &lCall2);
755 __ Cmp(tempArgc, Immediate(3)); // 3: 3 args
756 __ B(Condition::EQ, &lCall3);
757 __ Cmp(tempArgc, Immediate(4)); // 4: 4 args
758 __ B(Condition::EQ, &lCall4);
759 __ Cmp(tempArgc, Immediate(5)); // 5: 5 args
760 __ B(Condition::EQ, &lCall5);
761 // default: more than 5 args
762 {
763 TempRegister2Scope scope2(assembler);
764 Register onStackArgs = __ TempRegister2();
765 Register op1 = __ AvailableRegister2();
766 Register op2 = __ AvailableRegister3();
767
768 // skip bridge frame, return addr and a callee save
769 __ Add(onStackArgs, sp, Immediate(QUADRUPLE_SLOT_SIZE));
770 __ Sub(tempArgc, tempArgc, Immediate(5)); // 5: the first 5 args are not on stack
771 Register arg4(X7);
772 PushArgsWithArgvInPair(assembler, tempArgc, onStackArgs, arg4, op1, op2, &lCall4);
773 }
774
775 __ Bind(&lCall0);
776 {
777 __ B(&lPushCommonRegs);
778 }
779
780 __ Bind(&lCall1);
781 {
782 __ Stp(Register(X3), Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
783 __ B(&lPushCommonRegs);
784 }
785
786 __ Bind(&lCall2);
787 {
788 __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
789 __ B(&lPushCommonRegs);
790 }
791
792 __ Bind(&lCall3);
793 {
794 __ Stp(Register(X5), Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
795 __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
796 __ B(&lPushCommonRegs);
797 }
798
799 __ Bind(&lCall4);
800 {
801 __ Stp(Register(X5), Register(X6), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
802 __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
803 __ B(&lPushCommonRegs);
804 }
805
806 __ Bind(&lCall5);
807 {
808 __ Stp(Register(X7), Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
809 __ Stp(Register(X5), Register(X6), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
810 __ Stp(Register(X3), Register(X4), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
811 __ B(&lPushCommonRegs);
812 }
813
814 __ Bind(&lPushCommonRegs);
815 {
816 Register newTarget(X7);
817 __ Mov(newTarget, Immediate(JSTaggedValue::VALUE_UNDEFINED));
818 __ Stp(newTarget, thisReg, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
819 __ Stp(startSp, jsfunc, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
820 // fall through
821 }
822 }
823
824 // params of c++ calling convention
825 // glue: X0
826 // jsfunc: X1
827 Register method(X2);
828 Register methodCallField(X3);
829 Register argc(X4);
830 Register argV(X5);
831 // reload and prepare args for JSCallCommonEntry
832 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
833 __ Ldr(methodCallField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
834 __ Mov(argc, methodCallField);
835 __ Lsr(argc, argc, MethodLiteral::NumArgsBits::START_BIT);
836 __ And(argc, argc,
837 LogicalImmediate::Create(
838 MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegXSize));
839 __ Add(argV, sp, Immediate((kungfu::ArgumentAccessor::GetFixArgsNum() + 1) * FRAME_SLOT_SIZE)); // 1: skip startSp
840
841 Label target;
842 PushAsmInterpBridgeFrame(assembler);
843 __ Bl(&target);
844 {
845 PopAsmInterpBridgeFrame(assembler);
846 TempRegister1Scope scope1(assembler);
847 Register startSp = __ TempRegister1();
848 __ Ldp(startSp, Register(Zero), MemoryOperand(sp, ExtendedAssembler::PAIR_SLOT_SIZE, POSTINDEX));
849 __ Mov(sp, startSp);
850 PopAsmBridgeFrame(assembler);
851 __ Ret();
852 }
853 __ Bind(&target);
854 {
855 AsmInterpreterCall::JSCallCommonEntry(assembler, JSCallMode::CALL_FROM_AOT,
856 FrameTransitionType::OTHER_TO_OTHER);
857 }
858 }
859
JSCallCheck(ExtendedAssembler * assembler,Register jsfunc,Register taggedValue,Label * nonCallable,Label * notJSFunction)860 void OptimizedCall::JSCallCheck(ExtendedAssembler *assembler, Register jsfunc, Register taggedValue,
861 Label *nonCallable, Label *notJSFunction)
862 {
863 __ Mov(taggedValue, JSTaggedValue::TAG_MARK);
864 __ Cmp(jsfunc, taggedValue);
865 __ B(Condition::HS, nonCallable);
866 __ Cbz(jsfunc, nonCallable);
867 __ Mov(taggedValue, JSTaggedValue::TAG_SPECIAL);
868 __ And(taggedValue, jsfunc, taggedValue);
869 __ Cbnz(taggedValue, nonCallable);
870
871 Register jshclass(X2);
872 __ Ldr(jshclass, MemoryOperand(jsfunc, JSFunction::HCLASS_OFFSET));
873 Register bitfield(X2);
874 __ Ldr(bitfield, MemoryOperand(jshclass, JSHClass::BIT_FIELD_OFFSET));
875 __ Tbz(bitfield, JSHClass::CallableBit::START_BIT, nonCallable);
876
877 Register jstype(X3, W);
878 __ And(jstype, bitfield, LogicalImmediate::Create(0xFF, RegWSize));
879 // 4 : 4 means JSType::JS_FUNCTION_FIRST
880 __ Sub(jstype, jstype, Immediate(static_cast<int>(JSType::JS_FUNCTION_FIRST)));
881 // 9 : 9 means JSType::JS_FUNCTION_LAST - JSType::JS_FUNCTION_FIRST + 1
882 __ Cmp(jstype, Immediate(static_cast<int>(JSType::JS_FUNCTION_LAST) -
883 static_cast<int>(JSType::JS_FUNCTION_FIRST) + 1));
884 __ B(Condition::HS, notJSFunction);
885 }
886
ThrowNonCallableInternal(ExtendedAssembler * assembler,Register sp)887 void OptimizedCall::ThrowNonCallableInternal(ExtendedAssembler *assembler, Register sp)
888 {
889 Register frameType(X6);
890 Register taggedMessageId(X5);
891 __ PushFpAndLr();
892 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
893 __ Mov(taggedMessageId,
894 Immediate(JSTaggedValue(GET_MESSAGE_STRING_ID(NonCallable)).GetRawData()));
895 // 2 : 2 means pair
896 __ Stp(taggedMessageId, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
897 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
898 Register argC(X5);
899 Register runtimeId(X6);
900 __ Mov(argC, Immediate(1));
901 __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowTypeError)));
902 // 2 : 2 means pair
903 __ Stp(runtimeId, argC, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
904 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
905 __ Mov(Register(X0), Immediate(JSTaggedValue::VALUE_EXCEPTION));
906 // 4 : 4 means stack slot
907 __ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
908 __ RestoreFpAndLr();
909 __ Ret();
910 }
911
JSBoundFunctionCallInternal(ExtendedAssembler * assembler,Register glue,Register actualArgC,Register jsfunc,int stubId)912 void OptimizedCall::JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Register glue,
913 Register actualArgC, Register jsfunc, int stubId)
914 {
915 // construct frame
916 PushOptimizedArgsConfigFrame(assembler);
917 Register basefp(X29);
918 Register fp = __ AvailableRegister1();
919
920 Register argV(X5);
921 __ Add(argV, basefp, Immediate(GetStackArgOffSetToFp(0))); // 0: first index id
922 __ Ldr(actualArgC, MemoryOperand(argV, 0));
923
924 Register boundLength(X2);
925 Register realArgC(X7, W);
926 Label copyBoundArgument;
927 Label pushCallTarget;
928 Label popArgs;
929 Label slowCall;
930 Label aotCall;
931 Label notClass;
932 // get bound arguments
933 __ Ldr(boundLength, MemoryOperand(jsfunc, JSBoundFunction::BOUND_ARGUMENTS_OFFSET));
934 // get bound length
935 __ Ldr(boundLength, MemoryOperand(boundLength, TaggedArray::LENGTH_OFFSET));
936 __ Add(realArgC, boundLength.W(), actualArgC.W());
937 __ Mov(Register(X19), realArgC);
938 IncreaseStackForArguments(assembler, realArgC, fp, static_cast<int64_t>(CommonArgIdx::ACTUAL_ARGV));
939 __ Sub(actualArgC.W(), actualArgC.W(), Immediate(NUM_MANDATORY_JSFUNC_ARGS));
940 __ Cmp(actualArgC.W(), Immediate(0));
941 __ B(Condition::EQ, ©BoundArgument);
942 {
943 TempRegister1Scope scope1(assembler);
944 Register tmp = __ TempRegister1();
945 const int64_t argoffsetSlot = static_cast<int64_t>(CommonArgIdx::FUNC) - 1;
946 __ Add(argV, argV, Immediate((NUM_MANDATORY_JSFUNC_ARGS + argoffsetSlot) * FRAME_SLOT_SIZE));
947 PushArgsWithArgv(assembler, glue, actualArgC, argV, tmp, fp, nullptr, nullptr);
948 }
949 __ Bind(©BoundArgument);
950 {
951 Register boundArgs(X4);
952 __ Ldr(boundArgs, MemoryOperand(jsfunc, JSBoundFunction::BOUND_ARGUMENTS_OFFSET));
953 __ Add(boundArgs, boundArgs, Immediate(TaggedArray::DATA_OFFSET));
954 __ Cmp(boundLength.W(), Immediate(0));
955 __ B(Condition::EQ, &pushCallTarget);
956 {
957 TempRegister1Scope scope1(assembler);
958 Register tmp = __ TempRegister1();
959 PushArgsWithArgv(assembler, glue, boundLength, boundArgs, tmp, fp, nullptr, nullptr);
960 }
961 }
962 Register boundTarget(X7);
963 Register newTarget(X6);
964 __ Bind(&pushCallTarget);
965 {
966 Register thisObj(X4);
967 __ Ldr(thisObj, MemoryOperand(jsfunc, JSBoundFunction::BOUND_THIS_OFFSET));
968 __ Mov(newTarget, Immediate(JSTaggedValue::VALUE_UNDEFINED));
969 // 2 : 2 means pair
970 __ Stp(newTarget, thisObj, MemoryOperand(fp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
971 __ Ldr(boundTarget, MemoryOperand(jsfunc, JSBoundFunction::BOUND_TARGET_OFFSET));
972 // 2 : 2 means pair
973 __ Stp(argV, boundTarget, MemoryOperand(fp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
974 __ Str(Register(X19), MemoryOperand(fp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
975 }
976 JSCallCheck(assembler, boundTarget, Register(X9), &slowCall, &slowCall);
977 Register hclass = __ AvailableRegister2();
978 __ Ldr(hclass, MemoryOperand(boundTarget, 0));
979 __ Ldr(hclass, MemoryOperand(hclass, JSHClass::BIT_FIELD_OFFSET));
980 __ Tbz(hclass, JSHClass::IsClassConstructorOrPrototypeBit::START_BIT, ¬Class);
981 __ Tbnz(hclass, JSHClass::ConstructorBit::START_BIT, &slowCall);
982 __ Bind(¬Class);
983 Register compiledCodeFlag(X9, W);
984 __ Ldrh(compiledCodeFlag, MemoryOperand(boundTarget, JSFunctionBase::BIT_FIELD_OFFSET));
985 __ Tbz(compiledCodeFlag, JSFunctionBase::IsCompiledCodeBit::START_BIT, &slowCall);
986 __ Bind(&aotCall);
987 {
988 // output: glue:x0 argc:x1 calltarget:x2 argv:x3 this:x4 newtarget:x5
989 __ Mov(Register(X1), Register(X19));
990 __ Mov(Register(X2), boundTarget);
991 __ Add(X3, fp, Immediate(5 * FRAME_SLOT_SIZE)); // 5: skip argc and argv func new this
992 __ Mov(Register(X5), Register(X6));
993 Register boundCallInternalId(X9);
994 Register baseAddress(X8);
995 Register codeAddress(X10);
996 __ Mov(baseAddress, Immediate(JSThread::GlueData::GetCOStubEntriesOffset(false)));
997 __ Mov(boundCallInternalId, Immediate(CommonStubCSigns::JsBoundCallInternal));
998 __ Add(codeAddress, X0, baseAddress);
999 __ Ldr(codeAddress, MemoryOperand(codeAddress, boundCallInternalId, UXTW, FRAME_SLOT_SIZE_LOG2));
1000 __ Blr(codeAddress);
1001 __ B(&popArgs);
1002 }
1003 __ Bind(&slowCall);
1004 {
1005 __ CallAssemblerStub(stubId, false);
1006 __ B(&popArgs);
1007 }
1008
1009 __ Bind(&popArgs);
1010 PopJSFunctionArgs(assembler, Register(X19), Register(X19));
1011 PopOptimizedArgsConfigFrame(assembler);
1012 __ Ret();
1013 }
1014
1015 // * uint64_t JSProxyCallInternalWithArgV(uintptr_t glue, JSTaggedType calltarget)
1016 // * c++ calling convention call js function
1017 // * Arguments:
1018 // %x0 - glue
1019 // %x1 - calltarget
1020
JSProxyCallInternalWithArgV(ExtendedAssembler * assembler)1021 void OptimizedCall::JSProxyCallInternalWithArgV(ExtendedAssembler *assembler)
1022 {
1023 __ BindAssemblerStub(RTSTUB_ID(JSProxyCallInternalWithArgV));
1024 Register jsfunc(X1);
1025 Register sp(SP);
1026 __ Str(jsfunc, MemoryOperand(sp, DOUBLE_SLOT_SIZE));
1027 JSCallInternal(assembler, jsfunc);
1028 }
1029
1030 // * uint64_t CallRuntimeWithArgv(uintptr_t glue, uint64_t runtime_id, uint64_t argc, uintptr_t argv)
1031 // * cc calling convention call runtime_id's runtion function(c-abi)
1032 // * Arguments:
1033 // %x0 - glue
1034 // %x1 - runtime_id
1035 // %x2 - argc
1036 // %x3 - argv
1037 //
1038 // * Optimized-leaved-frame-with-argv layout as the following:
1039 // +--------------------------+
1040 // | argv[] |
1041 // +--------------------------+-------------
1042 // | argc | ^
1043 // |--------------------------| |
1044 // | RuntimeId | OptimizedWithArgvLeaveFrame
1045 // sp --> |--------------------------| |
1046 // | returnAddr | |
1047 // |--------------------------| |
1048 // | callsiteFp | |
1049 // |--------------------------| |
1050 // | frameType | v
1051 // +--------------------------+-------------
1052
CallRuntimeWithArgv(ExtendedAssembler * assembler)1053 void OptimizedCall::CallRuntimeWithArgv(ExtendedAssembler *assembler)
1054 {
1055 __ BindAssemblerStub(RTSTUB_ID(CallRuntimeWithArgv));
1056 Register glue(X0);
1057 Register runtimeId(X1);
1058 Register argc(X2);
1059 Register argv(X3);
1060 Register sp(SP);
1061 // 2 : 2 means pair
1062 __ Stp(argc, argv, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1063 __ Stp(Register(X30), runtimeId, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX)); // 2 : 2 means pair
1064 Register fp(X29);
1065 // construct leave frame
1066 Register frameType(X9);
1067 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::LEAVE_FRAME_WITH_ARGV)));
1068 __ Stp(frameType, Register(X29), MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX)); // 2 : 2 means pair
1069 __ Add(Register(FP), sp, Immediate(FRAME_SLOT_SIZE));
1070 __ Str(fp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
1071
1072 // load runtime trampoline address
1073 Register tmp(X9);
1074 Register rtfunc(X9);
1075 // 3 : 3 means 2 << 3 = 8
1076 __ Add(tmp, glue, Operand(runtimeId, LSL, 3));
1077 __ Ldr(rtfunc, MemoryOperand(tmp, JSThread::GlueData::GetRTStubEntriesOffset(false)));
1078 __ Mov(X1, argc);
1079 __ Mov(X2, argv);
1080 __ Blr(rtfunc);
1081 __ Ldp(Register(Zero), Register(X29), MemoryOperand(sp, ExtendedAssembler::PAIR_SLOT_SIZE, POSTINDEX));
1082 __ Ldp(Register(X30), Register(Zero), MemoryOperand(sp, ExtendedAssembler::PAIR_SLOT_SIZE, POSTINDEX));
1083 __ Add(sp, sp, Immediate(2 * FRAME_SLOT_SIZE)); // 2 : 2 means pair
1084 __ Ret();
1085 }
1086
PushMandatoryJSArgs(ExtendedAssembler * assembler,Register jsfunc,Register thisObj,Register newTarget,Register currentSp)1087 void OptimizedCall::PushMandatoryJSArgs(ExtendedAssembler *assembler, Register jsfunc,
1088 Register thisObj, Register newTarget, Register currentSp)
1089 {
1090 __ Str(thisObj, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1091 __ Str(newTarget, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1092 __ Str(jsfunc, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1093 }
1094
PopJSFunctionArgs(ExtendedAssembler * assembler,Register expectedNumArgs,Register actualNumArgs)1095 void OptimizedCall::PopJSFunctionArgs(ExtendedAssembler *assembler, Register expectedNumArgs, Register actualNumArgs)
1096 {
1097 Register sp(SP);
1098 Register fp(X6);
1099 Label aligned;
1100 const int64_t argoffsetSlot = static_cast<int64_t>(CommonArgIdx::FUNC) - 1;
1101 if (expectedNumArgs != actualNumArgs) {
1102 TempRegister1Scope scop1(assembler);
1103 Register tmp = __ TempRegister1();
1104 __ Cmp(expectedNumArgs, actualNumArgs);
1105 __ CMov(tmp, expectedNumArgs, actualNumArgs, Condition::HI);
1106 __ Add(sp, sp, Operand(tmp, UXTW, FRAME_SLOT_SIZE_LOG2));
1107 } else {
1108 __ Add(sp, sp, Operand(expectedNumArgs, UXTW, FRAME_SLOT_SIZE_LOG2));
1109 }
1110 __ Add(sp, sp, Immediate(argoffsetSlot * FRAME_SLOT_SIZE));
1111 __ Mov(fp, sp);
1112 __ Tst(fp, LogicalImmediate::Create(0xf, RegXSize)); // 0xf: 0x1111
1113 __ B(Condition::EQ, &aligned);
1114 __ Add(sp, sp, Immediate(FRAME_SLOT_SIZE));
1115 __ Bind(&aligned);
1116 }
1117
PushJSFunctionEntryFrame(ExtendedAssembler * assembler,Register prevFp)1118 void OptimizedCall::PushJSFunctionEntryFrame(ExtendedAssembler *assembler, Register prevFp)
1119 {
1120 Register fp(X29);
1121 Register sp(SP);
1122 TempRegister2Scope temp2Scope(assembler);
1123 __ PushFpAndLr();
1124 Register frameType = __ TempRegister2();
1125 // construct frame
1126 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_ENTRY_FRAME)));
1127 // 2 : 2 means pairs
1128 __ Stp(prevFp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1129 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
1130 __ CalleeSave();
1131 }
1132
PopJSFunctionEntryFrame(ExtendedAssembler * assembler,Register glue)1133 void OptimizedCall::PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue)
1134 {
1135 Register fp(X29);
1136 Register sp(SP);
1137 Register prevFp(X1);
1138 __ CalleeRestore();
1139
1140 // 2: prevFp and frameType
1141 __ Ldp(prevFp, Register(Zero), MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
1142 // restore return address
1143 __ RestoreFpAndLr();
1144 __ Str(prevFp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
1145 }
1146
PushOptimizedArgsConfigFrame(ExtendedAssembler * assembler)1147 void OptimizedCall::PushOptimizedArgsConfigFrame(ExtendedAssembler *assembler)
1148 {
1149 Register sp(SP);
1150 TempRegister2Scope temp2Scope(assembler);
1151 Register frameType = __ TempRegister2();
1152 __ PushFpAndLr();
1153 // construct frame
1154 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
1155 // 2 : 2 means pairs. X19 means calleesave and 16bytes align
1156 __ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1157 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
1158 }
1159
PopOptimizedArgsConfigFrame(ExtendedAssembler * assembler)1160 void OptimizedCall::PopOptimizedArgsConfigFrame(ExtendedAssembler *assembler)
1161 {
1162 TempRegister2Scope temp2Scope(assembler);
1163 Register sp(SP);
1164 Register frameType = __ TempRegister2();
1165 // 2 : 2 means pop call site sp and type
1166 __ Ldp(Register(X19), frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
1167 __ RestoreFpAndLr();
1168 }
1169
1170 // * uint64_t PushOptimizedUnfoldArgVFrame(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1171 // JSTaggedType new, JSTaggedType this, JSTaggedType argV[])
1172 // * cc calling convention call js function()
1173 // * arguments:
1174 // %x0 - glue
1175 // %x1 - argc
1176 // %x2 - call-target
1177 // %x3 - new-target
1178 // %x4 - this
1179 // %x5 - argv
1180 //
1181 // * OptimizedUnfoldArgVFrame layout description as the following:
1182 // sp ----> |--------------------------| ---------------
1183 // | returnAddr | ^
1184 // currentFp--> |--------------------------| |
1185 // | prevFp | |
1186 // |--------------------------| OptimizedUnfoldArgVFrame
1187 // | frameType | |
1188 // |--------------------------| |
1189 // | currentFp | v
1190 // +--------------------------+ ---------------
1191
PushOptimizedUnfoldArgVFrame(ExtendedAssembler * assembler,Register callSiteSp)1192 void OptimizedCall::PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp)
1193 {
1194 Register sp(SP);
1195 TempRegister2Scope temp2Scope(assembler);
1196 Register frameType = __ TempRegister2();
1197 __ PushFpAndLr();
1198 // construct frame
1199 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)));
1200 // 2 : 2 means pairs
1201 __ Stp(callSiteSp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
1202 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
1203 }
1204
PopOptimizedUnfoldArgVFrame(ExtendedAssembler * assembler)1205 void OptimizedCall::PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler)
1206 {
1207 Register sp(SP);
1208 // 2 : 2 means pop call site sp and type
1209 __ Add(sp, sp, Immediate(2 * FRAME_SLOT_SIZE));
1210 __ RestoreFpAndLr();
1211 }
1212
1213 // * uint64_t JSCallWithArgV(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1214 // JSTaggedType new, JSTaggedType this, argV)
1215 // * cc calling convention call js function()
1216 // * arguments:
1217 // %x0 - glue
1218 // %x1 - argc
1219 // %x2 - call-target
1220 // %x3 - new-target
1221 // %x4 - this
1222 // %x5 - argV[]
1223 //
1224 // * OptimizedJSFunctionFrame layout description as the following:
1225 // +--------------------------+
1226 // | argn |
1227 // |--------------------------|
1228 // | argn - 1 |
1229 // |--------------------------|
1230 // | ..... |
1231 // |--------------------------|
1232 // | arg2 |
1233 // |--------------------------|
1234 // | arg1 |
1235 // sp ----> |--------------------------| ---------------
1236 // | returnAddr | ^
1237 // |--------------------------| |
1238 // | callsiteFp | |
1239 // |--------------------------| OptimizedJSFunctionFrame
1240 // | frameType | |
1241 // |--------------------------| |
1242 // | call-target | v
1243 // +--------------------------+ ---------------
1244
GenJSCallWithArgV(ExtendedAssembler * assembler,int id)1245 void OptimizedCall::GenJSCallWithArgV(ExtendedAssembler *assembler, int id)
1246 {
1247 Register sp(SP);
1248 Register glue(X0);
1249 Register actualNumArgs(X1);
1250 Register jsfunc(X2);
1251 Register newTarget(X3);
1252 Register thisObj(X4);
1253 Register argV(X5);
1254 Register currentSp = __ AvailableRegister1();
1255 Register callsiteSp = __ AvailableRegister2();
1256 Label pushCallThis;
1257
1258 __ Mov(callsiteSp, sp);
1259 PushOptimizedUnfoldArgVFrame(assembler, callsiteSp);
1260 Register argC(X7);
1261 __ Add(actualNumArgs, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1262 __ Mov(argC, actualNumArgs);
1263 IncreaseStackForArguments(assembler, argC, currentSp, static_cast<int64_t>(CommonArgIdx::ACTUAL_ARGV));
1264 {
1265 TempRegister1Scope scope1(assembler);
1266 TempRegister2Scope scope2(assembler);
1267 Register tmp = __ TempRegister1();
1268 Register op = __ TempRegister2();
1269 __ Sub(tmp, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1270 PushArgsWithArgv(assembler, glue, tmp, argV, op, currentSp, &pushCallThis, nullptr);
1271 }
1272 __ Bind(&pushCallThis);
1273 PushMandatoryJSArgs(assembler, jsfunc, thisObj, newTarget, currentSp);
1274 {
1275 TempRegister1Scope scope1(assembler);
1276 Register tmp = __ TempRegister1();
1277 __ Mov(tmp, currentSp);
1278 __ Str(tmp, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1279 __ Str(actualNumArgs, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1280 }
1281 __ CallAssemblerStub(id, false);
1282 __ Ldr(actualNumArgs, MemoryOperand(sp, 0));
1283 PopJSFunctionArgs(assembler, actualNumArgs, actualNumArgs);
1284 PopOptimizedUnfoldArgVFrame(assembler);
1285 __ Ret();
1286 }
1287
1288 // * uint64_t JSCallWithArgVAndPushArgv(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1289 // JSTaggedType new, JSTaggedType this, argV)
1290 // * cc calling convention call js function()
1291 // * arguments:
1292 // %x0 - glue
1293 // %x1 - argc
1294 // %x2 - call-target
1295 // %x3 - new-target
1296 // %x4 - this
1297 // %x5 - argv
JSCallWithArgVAndPushArgv(ExtendedAssembler * assembler)1298 void OptimizedCall::JSCallWithArgVAndPushArgv(ExtendedAssembler *assembler)
1299 {
1300 __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgVAndPushArgv));
1301 GenJSCallWithArgV(assembler, RTSTUB_ID(OptimizedCallAndPushArgv));
1302 }
1303
JSCallWithArgV(ExtendedAssembler * assembler)1304 void OptimizedCall::JSCallWithArgV(ExtendedAssembler *assembler)
1305 {
1306 __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgV));
1307 GenJSCallWithArgV(assembler, RTSTUB_ID(CallOptimized));
1308 }
1309
SuperCallWithArgV(ExtendedAssembler * assembler)1310 void OptimizedCall::SuperCallWithArgV(ExtendedAssembler *assembler)
1311 {
1312 __ BindAssemblerStub(RTSTUB_ID(SuperCallWithArgV));
1313 GenJSCallWithArgV(assembler, RTSTUB_ID(JSCallNew));
1314 }
1315
CallOptimized(ExtendedAssembler * assembler)1316 void OptimizedCall::CallOptimized(ExtendedAssembler *assembler)
1317 {
1318 __ BindAssemblerStub(RTSTUB_ID(CallOptimized));
1319 Register sp(SP);
1320 Register jsfunc(X7);
1321 Register method(X6);
1322 Register codeAddr(X5);
1323 auto funcSlotOffset = kungfu::ArgumentAccessor::GetExtraArgsNum();
1324 __ Ldr(jsfunc, MemoryOperand(sp, funcSlotOffset * FRAME_SLOT_SIZE));
1325 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
1326 __ Ldr(codeAddr, MemoryOperand(jsfunc, JSFunction::CODE_ENTRY_OFFSET));
1327 __ Br(codeAddr);
1328 }
1329
DeoptEnterAsmInterpOrBaseline(ExtendedAssembler * assembler)1330 void OptimizedCall::DeoptEnterAsmInterpOrBaseline(ExtendedAssembler *assembler)
1331 {
1332 // rdi
1333 Register glueRegister = __ GlueRegister();
1334 Register context(X2);
1335 Register opRegister(X9);
1336 Register outputCount(X10);
1337 Register frameStateBase(X11);
1338 Register currentSlotRegister(X12);
1339 Register sp(SP);
1340 Register depth(X20);
1341 Register tmpReg(X21);
1342 Label loopBegin;
1343 Label stackOverflow;
1344 Label pushArgv;
1345
1346 __ PushFpAndLr();
1347
1348 __ Ldr(depth, MemoryOperand(context, AsmStackContext::GetInlineDepthOffset(false)));
1349 __ Add(context, context, Immediate(AsmStackContext::GetSize(false)));
1350 __ Mov(Register(X23), Immediate(0));
1351 // update fp
1352 __ Mov(currentSlotRegister, sp);
1353 __ Bind(&loopBegin);
1354 __ Ldr(outputCount, MemoryOperand(context, 0));
1355 __ Add(frameStateBase, context, Immediate(FRAME_SLOT_SIZE));
1356 __ Cmp(Register(X23), Immediate(0));
1357 __ B(Condition::EQ, &pushArgv);
1358 __ Mov(tmpReg, currentSlotRegister);
1359 __ Add(tmpReg, tmpReg, Immediate(AsmInterpretedFrame::GetSize(false)));
1360 __ Add(Register(X9), frameStateBase, Immediate(AsmInterpretedFrame::GetBaseOffset(false)));
1361 __ Str(tmpReg, MemoryOperand(Register(X9), InterpretedFrameBase::GetPrevOffset(false)));
1362 __ Align16(currentSlotRegister);
1363
1364 __ Bind(&pushArgv);
1365 __ Mov(tmpReg, outputCount);
1366 __ Str(currentSlotRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFpOffset(false)));
1367 PushArgsWithArgv(assembler, glueRegister, outputCount, frameStateBase, opRegister,
1368 currentSlotRegister, nullptr, &stackOverflow);
1369 __ Add(context, context, Immediate(FRAME_SLOT_SIZE)); // skip outputCount
1370 __ Add(context, context, Operand(tmpReg, UXTW, FRAME_SLOT_SIZE_LOG2)); // skip args
1371 __ Add(Register(X23), Register(X23), Immediate(1));
1372 __ Cmp(depth, Register(X23));
1373 __ B(Condition::GE, &loopBegin);
1374
1375 Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
1376 Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
1377 __ Ldr(callTargetRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFunctionOffset(false)));
1378 // get baseline code
1379 __ Ldr(opRegister, MemoryOperand(callTargetRegister, JSFunction::BASELINECODE_OFFSET));
1380 Label baselineCodeUndefined;
1381 __ Cmp(opRegister, Immediate(JSTaggedValue::VALUE_UNDEFINED));
1382 __ B(Condition::EQ, &baselineCodeUndefined);
1383
1384 // check is compiling
1385 __ Cmp(opRegister, Immediate(JSTaggedValue::VALUE_HOLE));
1386 __ B(Condition::EQ, &baselineCodeUndefined);
1387 {
1388 // x20 is free and callee save
1389 Register newSpRegister = X20;
1390 // get new sp
1391 __ Add(newSpRegister, currentSlotRegister, Immediate(AsmInterpretedFrame::GetSize(false)));
1392 __ Align16(currentSlotRegister);
1393 __ Mov(sp, currentSlotRegister);
1394
1395 // save glue, callTarget
1396 __ Stp(glueRegister, callTargetRegister, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1397 // callee save
1398 __ CalleeSave();
1399
1400 // get bytecode pc
1401 Register bytecodePc = opRegister;
1402 __ Ldr(bytecodePc, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetPcOffset(false)));
1403 // get func
1404 Register func(X1);
1405 func = callTargetRegister;
1406 Register argC(X2);
1407 Register runtimeId(X3);
1408 __ Mov(argC, Immediate(2)); // 2: argc
1409 __ Mov(runtimeId, Immediate(RTSTUB_ID(GetNativePcOfstForBaseline)));
1410 // get native pc offset in baselinecode by bytecodePc in func
1411 __ Stp(func, bytecodePc, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1412 __ Stp(runtimeId, argC, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1413 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1414
1415 // 2: skip runtimeId argc func bytecodePc
1416 __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE));
1417
1418 __ CalleeRestore();
1419 // restore glue, callTarget
1420 __ Ldp(X19, callTargetRegister, MemoryOperand(sp, DOUBLE_SLOT_SIZE, AddrMode::POSTINDEX));
1421 // restore method, fp
1422 __ Ldr(methodRegister, MemoryOperand(callTargetRegister, JSFunctionBase::METHOD_OFFSET));
1423 __ Mov(X21, methodRegister);
1424 __ Mov(Register(FP), newSpRegister);
1425
1426 // update pc
1427 const int64_t pcOffsetFromSp = -24; // -24: 3 slots, frameType, prevFrame, pc
1428 __ Mov(opRegister, Immediate(BASELINEJIT_PC_FLAG));
1429 __ Stur(opRegister, MemoryOperand(Register(FP), pcOffsetFromSp));
1430
1431 // jmp to baselinecode
1432 __ Br(X0);
1433 }
1434
1435 __ Bind(&baselineCodeUndefined);
1436 {
1437 // X19, fp, x20, x21, x22, x23, x24
1438 // glue sp pc constpool profile acc hotness
1439 __ Ldr(callTargetRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFunctionOffset(false)));
1440 __ Ldr(Register(X20), MemoryOperand(frameStateBase, AsmInterpretedFrame::GetPcOffset(false)));
1441 __ Ldr(Register(X23), MemoryOperand(frameStateBase, AsmInterpretedFrame::GetAccOffset(false)));
1442 __ Ldr(methodRegister, MemoryOperand(callTargetRegister, JSFunctionBase::METHOD_OFFSET));
1443
1444 __ Add(opRegister, currentSlotRegister, Immediate(AsmInterpretedFrame::GetSize(false)));
1445
1446 __ Align16(currentSlotRegister);
1447 __ Mov(Register(SP), currentSlotRegister);
1448 AsmInterpreterCall::DispatchCall(assembler, Register(X20), opRegister, Register(X23));
1449 }
1450 __ Bind(&stackOverflow);
1451 {
1452 Register temp(X1);
1453 AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(
1454 assembler, glueRegister, sp, temp);
1455 }
1456 }
1457
DeoptHandlerAsm(ExtendedAssembler * assembler)1458 void OptimizedCall::DeoptHandlerAsm(ExtendedAssembler *assembler)
1459 {
1460 __ BindAssemblerStub(RTSTUB_ID(DeoptHandlerAsm));
1461 __ PushFpAndLr();
1462 Register sp(SP);
1463 Register fp(FP);
1464 Register frameType(X3);
1465 Register glueReg(X0);
1466
1467 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::ASM_BRIDGE_FRAME)));
1468 __ Stp(glueReg, frameType, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1469 __ Add(fp, sp, Immediate(DOUBLE_SLOT_SIZE));
1470 __ CalleeSave();
1471
1472 Register deoptType(X1);
1473 Register depth(X2);
1474 Register argC(X3);
1475 Register runtimeId(X4);
1476 __ Stp(deoptType, depth, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1477 __ Mov(argC, Immediate(2)); // 2: argc
1478 __ Mov(runtimeId, Immediate(RTSTUB_ID(DeoptHandler)));
1479 __ Stp(runtimeId, argC, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1480 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1481 __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE)); // 2: skip runtimeId, argc, depth, shiftLen
1482
1483 __ CalleeRestore();
1484 Register context(X2);
1485 __ Mov(context, Register(X0));
1486 __ Ldr(glueReg, MemoryOperand(sp, 0));
1487
1488 Register ret(X0);
1489 Label stackOverflow;
1490 __ Cmp(ret, Immediate(JSTaggedValue::VALUE_EXCEPTION));
1491 __ B(Condition::EQ, &stackOverflow);
1492
1493 Label target;
1494 Register temp(X1);
1495 __ Ldr(fp, MemoryOperand(context, AsmStackContext::GetCallerFpOffset(false)));
1496 __ Ldr(temp, MemoryOperand(context, AsmStackContext::GetCallFrameTopOffset(false)));
1497 __ Mov(sp, temp);
1498 __ Ldr(Register(X30), MemoryOperand(context, AsmStackContext::GetReturnAddressOffset(false)));
1499
1500 PushAsmInterpBridgeFrame(assembler);
1501 __ Bl(&target);
1502 PopAsmInterpBridgeFrame(assembler);
1503 __ Ret();
1504 __ Bind(&target);
1505 DeoptEnterAsmInterpOrBaseline(assembler);
1506
1507 __ Bind(&stackOverflow);
1508 {
1509 __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowStackOverflowException)));
1510 // 2 : 2 means pair
1511 __ Stp(runtimeId, Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1512 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1513 __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE)); // 2: skip runtimeId&argc glue&type
1514 __ RestoreFpAndLr();
1515 __ Ret();
1516 }
1517 }
1518 #undef __
1519 } // panda::ecmascript::aarch64
1520