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