1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/compiler/trampoline/aarch64/common_call.h"
17
18 #include "ecmascript/compiler/assembler/assembler.h"
19 #include "ecmascript/compiler/argument_accessor.h"
20 #include "ecmascript/compiler/common_stubs.h"
21 #include "ecmascript/compiler/rt_call_signature.h"
22 #include "ecmascript/deoptimizer/deoptimizer.h"
23 #include "ecmascript/ecma_runtime_call_info.h"
24 #include "ecmascript/frames.h"
25 #include "ecmascript/js_function.h"
26 #include "ecmascript/method.h"
27 #include "ecmascript/js_thread.h"
28 #include "ecmascript/message_string.h"
29 #include "ecmascript/runtime_call_id.h"
30
31 namespace panda::ecmascript::aarch64 {
32 using Label = panda::ecmascript::Label;
33 #define __ assembler->
34
35 // * uint64_t CallRuntime(uintptr_t glue, uint64_t runtime_id, uint64_t argc, uintptr_t arg0, ...)
36 // * webkit_jscc calling convention call runtime_id's runtime function(c-abi)
37 // * Arguments:
38 // %x0 - glue
39 //
40 // * Optimized-leaved-frame layout as the following:
41 // +--------------------------+
42 // | argv[N-1] |
43 // |--------------------------|
44 // | . . . . . |
45 // |--------------------------|
46 // | argv[0] |
47 // +--------------------------+-------------
48 // | argc | ^
49 // |--------------------------| |
50 // | RuntimeId | |
51 // sp --> |--------------------------| OptimizedLeaveFrame
52 // | ret-addr | |
53 // |--------------------------| |
54 // | prevFp | |
55 // |--------------------------| |
56 // | frameType | v
57 // +--------------------------+-------------
58
CallRuntime(ExtendedAssembler * assembler)59 void OptimizedCall::CallRuntime(ExtendedAssembler *assembler)
60 {
61 Register glue(X0);
62 Register fp(FP);
63 Register tmp(X19);
64 Register sp(SP);
65 Register argC(X1);
66 Register argV(X2);
67
68 __ BindAssemblerStub(RTSTUB_ID(CallRuntime));
69 __ PushFpAndLr();
70
71 Register frameType(X2);
72 // construct Leave Frame and callee save
73 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::LEAVE_FRAME)));
74 // 2 : 2 means pairs
75 __ Stp(tmp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
76 __ Add(fp, sp, Immediate(2 * FRAME_SLOT_SIZE)); // 16: skip frame type and tmp
77 __ Str(fp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
78
79 // load runtime trampoline address
80 Register rtfunc(X19);
81 __ Ldr(tmp, MemoryOperand(fp, GetStackArgOffSetToFp(0))); // 0: the first arg id
82 // 3 : 3 means 2 << 3 = 8
83 __ Add(tmp, glue, Operand(tmp, LSL, 3));
84 __ Ldr(rtfunc, MemoryOperand(tmp, JSThread::GlueData::GetRTStubEntriesOffset(false)));
85 __ Ldr(argC, MemoryOperand(fp, GetStackArgOffSetToFp(1))); // 1: the second arg id
86 __ Add(argV, fp, Immediate(GetStackArgOffSetToFp(2))); // 2: the third arg id
87 __ Blr(rtfunc);
88
89 // callee restore
90 // 0 : 0 restore size
91 __ Ldr(tmp, MemoryOperand(sp, 0));
92
93 // descontruct frame
94 // 2 :2 means stack frame slot size
95 __ Add(sp, sp, Immediate(2 * FRAME_SLOT_SIZE));
96 __ RestoreFpAndLr();
97 __ Ret();
98 }
99
IncreaseStackForArguments(ExtendedAssembler * assembler,Register argc,Register currentSp)100 void OptimizedCall::IncreaseStackForArguments(ExtendedAssembler *assembler, Register argc, Register currentSp)
101 {
102 Register sp(SP);
103 __ Mov(currentSp, sp);
104 // add extra aguments, env and numArgs
105 __ Add(argc, argc, Immediate(static_cast<int64_t>(CommonArgIdx::ACTUAL_ARGC)));
106 __ Sub(currentSp, currentSp, Operand(argc, UXTW, FRAME_SLOT_SIZE_LOG2));
107 Label aligned;
108 __ Tst(currentSp, LogicalImmediate::Create(0xf, RegXSize)); // 0xf: 0x1111
109 __ B(Condition::EQ, &aligned);
110 __ Sub(currentSp, currentSp, Immediate(FRAME_SLOT_SIZE));
111 __ Bind(&aligned);
112 __ Mov(sp, currentSp);
113 __ Add(currentSp, currentSp, Operand(argc, UXTW, FRAME_SLOT_SIZE_LOG2));
114 }
115
116 // * uint64_t JSFunctionEntry(uintptr_t glue, uint32_t actualNumArgs, const JSTaggedType argV[], uintptr_t prevFp,
117 // size_t callType)
118 // * Arguments:
119 // %x0 - glue
120 // %x1 - actualNumArgs
121 // %x2 - argV
122 // %x3 - prevFp
123 // %x4 - callType
124 //
125 // * The JSFunctionEntry Frame's structure is illustrated as the following:
126 // +--------------------------+
127 // | . . . . . . |
128 // sp ---> +--------------------------+ -----------------
129 // | prevFP | ^
130 // |--------------------------| |
131 // | frameType | JSFunctionEntryFrame
132 // |--------------------------| |
133 // | preLeaveFrameFp | v
134 // +--------------------------+ -----------------
135
JSFunctionEntry(ExtendedAssembler * assembler)136 void OptimizedCall::JSFunctionEntry(ExtendedAssembler *assembler)
137 {
138 __ BindAssemblerStub(RTSTUB_ID(JSFunctionEntry));
139 Register glueReg(X0);
140 Register argV(X2);
141 Register prevFpReg(X3);
142 Register flag(X4);
143 Register sp(SP);
144 Register tmpArgV(X7);
145 Label lJSCallNewWithArgV;
146 Label lPopFrame;
147
148 PushJSFunctionEntryFrame (assembler, prevFpReg);
149 __ Mov(Register(X6), flag);
150 __ Mov(tmpArgV, argV);
151 __ Mov(Register(X20), glueReg);
152 __ Ldr(Register(X2), MemoryOperand(tmpArgV, 0));
153 __ Ldr(Register(X3), MemoryOperand(tmpArgV, FRAME_SLOT_SIZE));
154 __ Ldr(Register(X4), MemoryOperand(tmpArgV, DOUBLE_SLOT_SIZE));
155 __ Add(tmpArgV, tmpArgV, Immediate(TRIPLE_SLOT_SIZE));
156 __ Mov(Register(X5), tmpArgV);
157 __ Cmp(Register(X6), Immediate(1));
158 __ B(Condition::EQ, &lJSCallNewWithArgV);
159 __ CallAssemblerStub(RTSTUB_ID(JSCallWithArgV), false);
160 __ B(&lPopFrame);
161
162 __ Bind(&lJSCallNewWithArgV);
163 {
164 __ CallAssemblerStub(RTSTUB_ID(JSCallNewWithArgV), false);
165 }
166
167 __ Bind(&lPopFrame);
168 __ Mov(Register(X2), Register(X20));
169 PopJSFunctionEntryFrame(assembler, Register(X2));
170 __ Ret();
171 }
172
173 // * uint64_t OptimizedCallOptimized(uintptr_t glue, uint32_t expectedNumArgs, uint32_t actualNumArgs,
174 // uintptr_t codeAddr, uintptr_t argv, uintptr_t lexEnv)
175 // * Arguments wil CC calling convention:
176 // %x0 - glue
177 // %x1 - codeAddr
178 // %x2 - actualNumArgs
179 // %x3 - expectedNumArgs
180 // %x4 - argv
181 // %x5 - lexEnv
182 //
183 // * The OptimizedJSFunctionArgsConfig Frame's structure is illustrated as the following:
184 // +--------------------------+
185 // | arg[N-1] |
186 // +--------------------------+
187 // | . . . . |
188 // +--------------------------+
189 // | arg[0] |
190 // +--------------------------+
191 // | argC |
192 // sp ---> +--------------------------+ -----------------
193 // | | ^
194 // | prevFP | |
195 // |--------------------------| OptimizedJSFunctionArgsConfigFrame
196 // | frameType | |
197 // | | V
198 // +--------------------------+ -----------------
199
OptimizedCallOptimized(ExtendedAssembler * assembler)200 void OptimizedCall::OptimizedCallOptimized(ExtendedAssembler *assembler)
201 {
202 __ BindAssemblerStub(RTSTUB_ID(OptimizedCallOptimized));
203 Register glue(X0);
204 Register expectedNumArgs(X1);
205 Register actualNumArgs(X2);
206 Register codeAddr(X3);
207 Register argV(X4);
208 Register env(X5);
209 Register currentSp(X6);
210 Register sp(SP);
211 Label copyArguments;
212 Label invokeCompiledJSFunction;
213
214 // construct frame
215 PushOptimizedArgsConfigFrame(assembler);
216 Register argC(X7);
217 __ Cmp(expectedNumArgs, actualNumArgs);
218 __ CMov(argC, expectedNumArgs, actualNumArgs, Condition::HI);
219 IncreaseStackForArguments(assembler, argC, currentSp);
220 {
221 TempRegister1Scope scope1(assembler);
222 TempRegister2Scope scope2(assembler);
223 Register tmp = __ TempRegister1();
224 Register undefinedValue = __ TempRegister2();
225 __ Subs(tmp, expectedNumArgs, actualNumArgs);
226 __ B(Condition::LS, ©Arguments);
227 PushUndefinedWithArgc(assembler, glue, tmp, undefinedValue, currentSp, nullptr, nullptr);
228 }
229 __ Bind(©Arguments);
230 __ Cbz(actualNumArgs, &invokeCompiledJSFunction);
231 {
232 TempRegister1Scope scope1(assembler);
233 TempRegister2Scope scope2(assembler);
234 Register argc = __ TempRegister1();
235 Register argValue = __ TempRegister2();
236 __ Mov(argc, actualNumArgs);
237 PushArgsWithArgv(assembler, glue, argc, argV, argValue, currentSp, &invokeCompiledJSFunction, nullptr);
238 }
239 __ Bind(&invokeCompiledJSFunction);
240 {
241 __ Mov(Register(X19), expectedNumArgs);
242 __ Str(actualNumArgs, MemoryOperand(sp, FRAME_SLOT_SIZE));
243 __ Str(env, MemoryOperand(sp, 0)); // 0: means zero size
244 __ Blr(codeAddr);
245 }
246
247 // pop argV argC
248 // 3 : 3 means argC * 8
249 __ Ldr(actualNumArgs, MemoryOperand(sp, FRAME_SLOT_SIZE));
250 PopJSFunctionArgs(assembler, Register(X19), actualNumArgs);
251 // pop prevLeaveFrameFp to restore thread->currentFrame_
252 PopOptimizedArgsConfigFrame(assembler);
253 __ Ret();
254 }
255
OptimizedCallAsmInterpreter(ExtendedAssembler * assembler)256 void OptimizedCall::OptimizedCallAsmInterpreter(ExtendedAssembler *assembler)
257 {
258 Label target;
259 PushAsmInterpBridgeFrame(assembler);
260 __ Bl(&target);
261 PopAsmInterpBridgeFrame(assembler);
262 __ Ret();
263 __ Bind(&target);
264 {
265 AsmInterpreterCall::JSCallCommonEntry(assembler, JSCallMode::CALL_FROM_AOT);
266 }
267 }
268
269 // * uint64_t CallBuiltinTrampoline(uintptr_t glue, uintptr_t codeAddress, uint32_t argc, ...)
270 // * webkit_jscc calling convention call runtime_id's runtime function(c-abi)
271 // * Argument:
272 // %x0: glue
273 //
274 // * Construct Native Leave Frame Layout:
275 // +--------------------------+
276 // | argv[N-1] |
277 // +--------------------------+
278 // | . . . . . . |
279 // +--------------------------+
280 // | argv[3]=a0 |
281 // +--------------------------+
282 // | argv[2]=this |
283 // +--------------------------+
284 // | argv[1]=new-target |
285 // +--------------------------+
286 // | argv[0]=call-target |
287 // +--------------------------+ -----------------
288 // | argc | ^
289 // |--------------------------| |
290 // | env or thread | |
291 // |--------------------------| |
292 // | returnAddr | OptimizedBuiltinLeaveFrame
293 // sp ---> |--------------------------| |
294 // | callsiteFp | |
295 // |--------------------------| |
296 // | frameType | |
297 // |--------------------------| |
298 // | align byte | v
299 // +--------------------------+ -----------------
300
CallBuiltinTrampoline(ExtendedAssembler * assembler)301 void OptimizedCall::CallBuiltinTrampoline(ExtendedAssembler *assembler)
302 {
303 Register glue(X0);
304 Register sp(SP);
305 Register nativeFuncAddr(X4);
306 Register glueTemp(X2);
307 Register temp(X1);
308 Register zero(Zero);
309
310 __ Mov(glueTemp, glue);
311 __ Str(glue, MemoryOperand(sp, 0)); // thread (instead of env)
312 __ Add(Register(X0), sp, Immediate(0));
313 AsmInterpreterCall::PushBuiltinFrame(assembler, glueTemp, FrameType::BUILTIN_CALL_LEAVE_FRAME, temp, zero);
314
315 AsmInterpreterCall::CallNativeInternal(assembler, nativeFuncAddr);
316 __ Ret();
317 }
318
319 // * uint64_t JSCall(uintptr_t glue, JSTaggedType env, uint32_t argc, JSTaggedType calltarget, JSTaggedType new,
320 // JSTaggedType this, arg[0], arg[1], arg[2], ..., arg[N-1])
321 // * webkit_jscc calling convention call js function()
322 //
323 // * OptimizedJSFunctionFrame layout description as the following:
324 // +--------------------------+
325 // | arg[N-1] |
326 // +--------------------------+
327 // | ... |
328 // +--------------------------+
329 // | arg[1] |
330 // +--------------------------+
331 // | arg[0] |
332 // +--------------------------+
333 // | this |
334 // +--------------------------+
335 // | new-target |
336 // +--------------------------+
337 // | call-target |
338 // |--------------------------|
339 // | argc |
340 // |--------------------------|
341 // | lexEnv |
342 // sp ----> |--------------------------| ---------------
343 // | returnAddr | ^
344 // |--------------------------| |
345 // | callsiteFp | |
346 // |--------------------------| OptimizedJSFunctionFrame
347 // | frameType | |
348 // |--------------------------| |
349 // | call-target | v
350 // +--------------------------+ ---------------
351
GenJSCall(ExtendedAssembler * assembler,bool isNew)352 void OptimizedCall::GenJSCall(ExtendedAssembler *assembler, bool isNew)
353 {
354 Register jsfunc(X1);
355 Register sp(SP);
356 __ Ldr(jsfunc, MemoryOperand(sp, FRAME_SLOT_SIZE * 2)); // 2: skip env and argc
357 JSCallInternal(assembler, jsfunc, isNew);
358 }
359
JSCallNew(ExtendedAssembler * assembler)360 void OptimizedCall::JSCallNew(ExtendedAssembler *assembler)
361 {
362 __ BindAssemblerStub(RTSTUB_ID(JSCallNew));
363 GenJSCall(assembler, true);
364 }
365
JSCall(ExtendedAssembler * assembler)366 void OptimizedCall::JSCall(ExtendedAssembler *assembler)
367 {
368 __ BindAssemblerStub(RTSTUB_ID(JSCall));
369 GenJSCall(assembler, false);
370 }
371
JSCallInternal(ExtendedAssembler * assembler,Register jsfunc,bool isNew)372 void OptimizedCall::JSCallInternal(ExtendedAssembler *assembler, Register jsfunc, bool isNew)
373 {
374 Register sp(SP);
375 Register glue(X0);
376 Register taggedValue(X2);
377 Label nonCallable;
378 Label notJSFunction;
379 JSCallCheck(assembler, jsfunc, taggedValue, &nonCallable, ¬JSFunction);
380
381 Register method(X2);
382 Register callField(X3);
383 Register actualArgC(X4);
384 Label callNativeMethod;
385 Label callOptimizedMethod;
386 Label lCallConstructor;
387 Label lCallBuiltinStub;
388 Label lCallNativeCpp;
389
390 __ Ldr(Register(X5), MemoryOperand(jsfunc, JSFunction::LEXICAL_ENV_OFFSET));
391 __ Str(Register(X5), MemoryOperand(sp, 0));
392 __ Ldr(Register(X5), MemoryOperand(jsfunc, 0));
393 __ Ldr(Register(X5), MemoryOperand(Register(X5), JSHClass::BIT_FIELD_OFFSET));
394 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
395 __ Ldr(actualArgC, MemoryOperand(sp, FRAME_SLOT_SIZE));
396 __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
397 __ Tbnz(callField, MethodLiteral::IsNativeBit::START_BIT, &callNativeMethod);
398 if (!isNew) {
399 __ Tbnz(Register(X5), JSHClass::ClassConstructorBit::START_BIT, &lCallConstructor);
400 }
401 __ Tbnz(callField, MethodLiteral::IsAotCodeBit::START_BIT, &callOptimizedMethod);
402 {
403 Register argV(X5);
404 // aot argV = sp + 16
405 __ Add(argV, sp, Immediate(DOUBLE_SLOT_SIZE));
406 // asm interpreter argV = argv + 24
407 __ Add(argV, argV, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() * FRAME_SLOT_SIZE));
408 __ Sub(actualArgC, actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum()));
409 OptimizedCallAsmInterpreter(assembler);
410 }
411
412 __ Bind(&callNativeMethod);
413 {
414 Register nativeFuncAddr(X4);
415 if (!isNew) {
416 __ Tbz(callField, MethodLiteral::IsFastBuiltinBit::START_BIT, &lCallNativeCpp);
417 // 3 : 3 means call0 call1 call2 call3
418 __ Cmp(actualArgC, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() + 3));
419 __ B(Condition::LE, &lCallBuiltinStub);
420 } else {
421 __ Tbnz(callField, MethodLiteral::IsFastBuiltinBit::START_BIT, &lCallBuiltinStub);
422 }
423 __ Bind(&lCallNativeCpp);
424 __ Ldr(nativeFuncAddr, MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
425 CallBuiltinTrampoline(assembler);
426 }
427
428 __ Bind(&lCallBuiltinStub);
429 {
430 TempRegister1Scope scope1(assembler);
431 Register builtinStub = __ TempRegister1();
432 __ Ldr(Register(X5), MemoryOperand(method, Method::EXTRA_LITERAL_INFO_OFFSET)); // get extra literal
433 __ And(Register(X5).W(), Register(X5).W(), LogicalImmediate::Create(0xff, RegWSize));
434 if (!isNew) {
435 __ Cmp(Register(X5).W(), Immediate(kungfu::BuiltinsStubCSigns::BUILTINS_CONSTRUCTOR_STUB_FIRST));
436 __ B(Condition::GE, &lCallNativeCpp);
437 }
438 __ Add(builtinStub, glue, Operand(Register(X5).W(), UXTW, FRAME_SLOT_SIZE_LOG2));
439 __ Ldr(builtinStub, MemoryOperand(builtinStub, JSThread::GlueData::GetBuiltinsStubEntriesOffset(false)));
440
441 __ Ldr(Register(X1), MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
442 __ Ldr(Register(X2), MemoryOperand(sp, DOUBLE_SLOT_SIZE)); // get jsfunc
443 __ Ldr(Register(X3), MemoryOperand(sp, TRIPLE_SLOT_SIZE)); // get newtarget
444 __ Ldr(Register(X4), MemoryOperand(sp, QUADRUPLE_SLOT_SIZE)); // get this
445 __ Ldr(Register(X5), MemoryOperand(sp, FRAME_SLOT_SIZE)); // get number args
446 __ Sub(Register(X5), Register(X5), Immediate(NUM_MANDATORY_JSFUNC_ARGS));
447 if (!isNew) {
448 Label lTailCall;
449 Register fp(X29);
450 __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE)); // get arg0 arg1
451 __ Cmp(Register(X5), Immediate(3)); // 3: callarg3
452 __ B(Condition::NE, &lTailCall);
453 PushOptimizedFrame(assembler);
454 {
455 // push arg3 and call
456 TempRegister2Scope scope2(assembler);
457 Register arg3 = __ TempRegister2();
458 __ Ldr(arg3, MemoryOperand(fp, DECUPLE_SLOT_SIZE)); // get arg2
459 __ Stp(arg3, Register(X8), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
460 __ Blr(builtinStub);
461 __ Add(sp, sp, Immediate(DOUBLE_SLOT_SIZE));
462 }
463 PopOptimizedFrame(assembler);
464 __ Ret();
465 __ Bind(&lTailCall);
466 {
467 __ Br(builtinStub);
468 }
469 } else {
470 __ Add(Register(X6), sp, Immediate(QUINTUPLE_SLOT_SIZE)); // get argV
471 __ Br(builtinStub);
472 }
473 }
474
475 __ Bind(&callOptimizedMethod);
476 {
477 CallOptimziedMethodInternal(assembler, jsfunc, actualArgC, callField, sp);
478 }
479 Label jsBoundFunction;
480 Label jsProxy;
481 __ Bind(¬JSFunction);
482 {
483 Register bitfield(X2);
484 Register jstype2(X5, W);
485 __ And(jstype2, bitfield.W(), LogicalImmediate::Create(0xff, RegWSize));
486 __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_BOUND_FUNCTION)));
487 __ B(Condition::EQ, &jsBoundFunction);
488 __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_PROXY)));
489 __ B(Condition::EQ, &jsProxy);
490 __ Ret();
491 }
492
493 __ Bind(&jsBoundFunction);
494 {
495 JSBoundFunctionCallInternal(assembler, glue, actualArgC, jsfunc, RTSTUB_ID(JSCall));
496 }
497 __ Bind(&jsProxy);
498 {
499 JSProxyCallInternal(assembler, sp, jsfunc);
500 }
501 __ Bind(&nonCallable);
502 {
503 ThrowNonCallableInternal(assembler, sp);
504 }
505 __ Bind(&lCallConstructor);
506 {
507 Register frameType(X6);
508 __ PushFpAndLr();
509 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
510 // 2 : 2 means pair
511 __ Stp(Register(Zero), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
512 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
513 Register argC(X5);
514 Register runtimeId(X6);
515 __ Mov(argC, Immediate(0));
516 __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowCallConstructorException)));
517 // 2 : 2 means pair
518 __ Stp(runtimeId, argC, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
519 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
520 // 4 : 4 means stack slot
521 __ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
522 __ RestoreFpAndLr();
523 __ Ret();
524 }
525 }
526
ConstructorJSCall(ExtendedAssembler * assembler)527 void OptimizedCall::ConstructorJSCall([[maybe_unused]]ExtendedAssembler *assembler)
528 {
529 __ BindAssemblerStub(RTSTUB_ID(ConstructorJSCall));
530 Register jsfunc(X1);
531 Register sp(SP);
532 __ Ldr(jsfunc, MemoryOperand(sp, FRAME_SLOT_SIZE * 2)); // 2: skip env and argc
533 ConstructorJSCallInternal(assembler, jsfunc);
534 }
535
ConstructorJSCallInternal(ExtendedAssembler * assembler,Register jsfunc)536 void OptimizedCall::ConstructorJSCallInternal(ExtendedAssembler *assembler, Register jsfunc)
537 {
538 Register sp(SP);
539 Register glue(X0);
540 Register taggedValue(X2);
541 Label nonCallable;
542 Label notJSFunction;
543 JSCallCheck(assembler, jsfunc, taggedValue, &nonCallable, ¬JSFunction);
544
545 Register method(X2);
546 Register callField(X3);
547 Register actualArgC(X4);
548 Label callNativeMethod;
549 Label callOptimizedMethod;
550 __ Ldr(Register(X5), MemoryOperand(jsfunc, JSFunction::LEXICAL_ENV_OFFSET));
551 __ Str(Register(X5), MemoryOperand(sp, 0));
552 __ Ldr(Register(X5), MemoryOperand(jsfunc, JSFunction::HCLASS_OFFSET));
553 __ Ldr(Register(X5), MemoryOperand(Register(X5), JSHClass::BIT_FIELD_OFFSET));
554 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
555 __ Ldr(actualArgC, MemoryOperand(sp, FRAME_SLOT_SIZE));
556 __ Ldr(callField, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
557 __ Tbnz(callField, MethodLiteral::IsNativeBit::START_BIT, &callNativeMethod);
558 __ Tbnz(callField, MethodLiteral::IsAotCodeBit::START_BIT, &callOptimizedMethod);
559 {
560 Register argV(X5);
561 // aot argV = sp + 16
562 __ Add(argV, sp, Immediate(DOUBLE_SLOT_SIZE));
563 // asm interpreter argV = argv + 24
564 __ Add(argV, argV, Immediate(kungfu::ArgumentAccessor::GetFixArgsNum() * FRAME_SLOT_SIZE));
565 OptimizedCallAsmInterpreter(assembler);
566 }
567
568 __ Bind(&callNativeMethod);
569 {
570 Register nativeFuncAddr(X4);
571 __ Ldr(nativeFuncAddr, MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
572 CallBuiltinTrampoline(assembler);
573 }
574
575 __ Bind(&callOptimizedMethod);
576 {
577 CallOptimziedMethodInternal(assembler, jsfunc, actualArgC, callField, sp);
578 }
579 Label jsBoundFunction;
580 Label jsProxy;
581 __ Bind(¬JSFunction);
582 {
583 Register bitfield(X2);
584 Register jstype2(X5, W);
585 __ And(jstype2, bitfield.W(), LogicalImmediate::Create(0xff, RegWSize));
586 __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_BOUND_FUNCTION)));
587 __ B(Condition::EQ, &jsBoundFunction);
588 __ Cmp(jstype2, Immediate(static_cast<int64_t>(JSType::JS_PROXY)));
589 __ B(Condition::EQ, &jsProxy);
590 __ Ret();
591 }
592
593 __ Bind(&jsBoundFunction);
594 {
595 JSBoundFunctionCallInternal(assembler, glue, actualArgC, jsfunc, RTSTUB_ID(ConstructorJSCall));
596 }
597 __ Bind(&jsProxy);
598 {
599 JSProxyCallInternal(assembler, sp, jsfunc);
600 }
601 __ Bind(&nonCallable);
602 {
603 ThrowNonCallableInternal(assembler, sp);
604 }
605 }
606
JSCallCheck(ExtendedAssembler * assembler,Register jsfunc,Register taggedValue,Label * nonCallable,Label * notJSFunction)607 void OptimizedCall::JSCallCheck(ExtendedAssembler *assembler, Register jsfunc, Register taggedValue,
608 Label *nonCallable, Label *notJSFunction)
609 {
610 __ Mov(taggedValue, JSTaggedValue::TAG_MARK);
611 __ Cmp(jsfunc, taggedValue);
612 __ B(Condition::HS, nonCallable);
613 __ Cbz(jsfunc, nonCallable);
614 __ Mov(taggedValue, JSTaggedValue::TAG_SPECIAL);
615 __ And(taggedValue, jsfunc, taggedValue);
616 __ Cbnz(taggedValue, nonCallable);
617
618 Register jshclass(X2);
619 __ Ldr(jshclass, MemoryOperand(jsfunc, JSFunction::HCLASS_OFFSET));
620 Register bitfield(X2);
621 __ Ldr(bitfield, MemoryOperand(jshclass, JSHClass::BIT_FIELD_OFFSET));
622 __ Tbz(bitfield, JSHClass::CallableBit::START_BIT, nonCallable);
623
624 Register jstype(X3, W);
625 __ And(jstype, bitfield, LogicalImmediate::Create(0xFF, RegWSize));
626 // 4 : 4 means JSType::JS_FUNCTION_FIRST
627 __ Sub(jstype, jstype, Immediate(static_cast<int>(JSType::JS_FUNCTION_FIRST)));
628 // 9 : 9 means JSType::JS_FUNCTION_LAST - JSType::JS_FUNCTION_FIRST + 1
629 __ Cmp(jstype, Immediate(static_cast<int>(JSType::JS_FUNCTION_LAST)
630 - static_cast<int>(JSType::JS_FUNCTION_FIRST) + 1));
631 __ B(Condition::HS, notJSFunction);
632 }
633
ThrowNonCallableInternal(ExtendedAssembler * assembler,Register sp)634 void OptimizedCall::ThrowNonCallableInternal(ExtendedAssembler *assembler, Register sp)
635 {
636 Register frameType(X6);
637 Register taggedMessageId(X5);
638 __ PushFpAndLr();
639 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
640 __ Mov(taggedMessageId,
641 Immediate(JSTaggedValue(GET_MESSAGE_STRING_ID(NonCallable)).GetRawData()));
642 // 2 : 2 means pair
643 __ Stp(taggedMessageId, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
644 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
645 Register argC(X5);
646 Register runtimeId(X6);
647 __ Mov(argC, Immediate(1));
648 __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowTypeError)));
649 // 2 : 2 means pair
650 __ Stp(runtimeId, argC, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
651 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
652 __ Mov(Register(X0), Immediate(JSTaggedValue::VALUE_EXCEPTION));
653 // 4 : 4 means stack slot
654 __ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
655 __ RestoreFpAndLr();
656 __ Ret();
657 }
658
CallOptimziedMethodInternal(ExtendedAssembler * assembler,Register jsfunc,Register actualArgC,Register callField,Register sp)659 void OptimizedCall::CallOptimziedMethodInternal(ExtendedAssembler *assembler, Register jsfunc, Register actualArgC,
660 Register callField, Register sp)
661 {
662 Register expectedNumArgs(X1, W);
663 Register arg2(X2);
664 Register codeAddress(X3);
665 Register argV(X4);
666 Register env(X5);
667 Register method(X6);
668 Label directCallCodeEntry;
669 const int64_t argoffsetSlot = static_cast<int64_t>(CommonArgIdx::FUNC) - 1;
670 __ Mov(Register(X5), jsfunc);
671 __ Mov(arg2, actualArgC);
672 __ Lsr(callField, callField, MethodLiteral::NumArgsBits::START_BIT);
673 __ And(callField.W(), callField.W(),
674 LogicalImmediate::Create(
675 MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegWSize));
676 __ Add(expectedNumArgs, callField.W(), Immediate(NUM_MANDATORY_JSFUNC_ARGS));
677 __ Cmp(arg2.W(), expectedNumArgs);
678 __ Add(argV, sp, Immediate(argoffsetSlot * FRAME_SLOT_SIZE)); // skip env and numArgs
679 __ Ldr(method, MemoryOperand(Register(X5), JSFunctionBase::METHOD_OFFSET)); // get method
680 __ Ldr(codeAddress, MemoryOperand(method, Method::CODE_ENTRY_OFFSET)); // get codeAddress
681 __ Ldr(env, MemoryOperand(sp, 0));
682 __ B(Condition::HS, &directCallCodeEntry);
683 __ CallAssemblerStub(RTSTUB_ID(OptimizedCallOptimized), true);
684 __ Bind(&directCallCodeEntry);
685 __ Br(codeAddress);
686 }
687
JSBoundFunctionCallInternal(ExtendedAssembler * assembler,Register glue,Register actualArgC,Register jsfunc,int stubId)688 void OptimizedCall::JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Register glue,
689 Register actualArgC, Register jsfunc, int stubId)
690 {
691 // construct frame
692 PushOptimizedArgsConfigFrame(assembler);
693 Register basefp(X29);
694 Register fp = __ AvailableRegister1();
695 Register env(X5);
696
697 Register argV(X6);
698 __ Add(argV, basefp, Immediate(GetStackArgOffSetToFp(0))); // 0: first index id
699 __ Ldr(actualArgC, MemoryOperand(argV, FRAME_SLOT_SIZE));
700 __ Ldr(env, MemoryOperand(argV, 0));
701
702 Register boundLength(X2);
703 Register realArgC(X7, W);
704 Label copyBoundArgument;
705 Label pushCallTarget;
706 // get bound arguments
707 __ Ldr(boundLength, MemoryOperand(jsfunc, JSBoundFunction::BOUND_ARGUMENTS_OFFSET));
708 // get bound length
709 __ Ldr(boundLength, MemoryOperand(boundLength, TaggedArray::LENGTH_OFFSET));
710 __ Add(realArgC, boundLength.W(), actualArgC.W());
711 __ Mov(Register(X19), realArgC);
712 IncreaseStackForArguments(assembler, realArgC, fp);
713 __ Sub(actualArgC.W(), actualArgC.W(), Immediate(NUM_MANDATORY_JSFUNC_ARGS));
714 __ Cmp(actualArgC.W(), Immediate(0));
715 __ B(Condition::EQ, ©BoundArgument);
716 {
717 TempRegister1Scope scope1(assembler);
718 Register tmp = __ TempRegister1();
719 const int64_t argoffsetSlot = static_cast<int64_t>(CommonArgIdx::FUNC) - 1;
720 __ Add(argV, argV, Immediate((NUM_MANDATORY_JSFUNC_ARGS + argoffsetSlot) *FRAME_SLOT_SIZE));
721 PushArgsWithArgv(assembler, glue, actualArgC, argV, tmp, fp, nullptr, nullptr);
722 }
723 __ Bind(©BoundArgument);
724 {
725 Register boundArgs(X4);
726 __ Ldr(boundArgs, MemoryOperand(jsfunc, JSBoundFunction::BOUND_ARGUMENTS_OFFSET));
727 __ Add(boundArgs, boundArgs, Immediate(TaggedArray::DATA_OFFSET));
728 __ Cmp(boundLength.W(), Immediate(0));
729 __ B(Condition::EQ, &pushCallTarget);
730 {
731 TempRegister1Scope scope1(assembler);
732 Register tmp = __ TempRegister1();
733 PushArgsWithArgv(assembler, glue, boundLength, boundArgs, tmp, fp, nullptr, nullptr);
734 }
735 }
736 __ Bind(&pushCallTarget);
737 {
738 Register thisObj(X4);
739 Register newTarget(X6);
740 Register boundTarget(X7);
741 __ Ldr(thisObj, MemoryOperand(jsfunc, JSBoundFunction::BOUND_THIS_OFFSET));
742 __ Mov(newTarget, Immediate(JSTaggedValue::VALUE_UNDEFINED));
743 // 2 : 2 means pair
744 __ Stp(newTarget, thisObj, MemoryOperand(fp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
745 __ Ldr(boundTarget, MemoryOperand(jsfunc, JSBoundFunction::BOUND_TARGET_OFFSET));
746 // 2 : 2 means pair
747 __ Stp(Register(X19), boundTarget, MemoryOperand(fp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
748 __ Str(env, MemoryOperand(fp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
749 }
750 __ CallAssemblerStub(stubId, false);
751
752 PopJSFunctionArgs(assembler, Register(X19), Register(X19));
753 PopOptimizedArgsConfigFrame(assembler);
754 __ Ret();
755 }
756
JSProxyCallInternal(ExtendedAssembler * assembler,Register sp,Register jsfunc)757 void OptimizedCall::JSProxyCallInternal(ExtendedAssembler *assembler, Register sp, Register jsfunc)
758 {
759 // input: x1(calltarget)
760 // output: glue:x0 argc:x1 calltarget:x2 argv:x3
761 __ Mov(Register(X2), jsfunc);
762 __ Ldr(Register(X1), MemoryOperand(sp, FRAME_SLOT_SIZE)); // 8: skip env
763 __ Add(X3, sp, Immediate(FRAME_SLOT_SIZE * 2)); // 2: get argv
764
765 Register proxyCallInternalId(X9);
766 Register baseAddress(X8);
767 Register codeAddress(X10);
768 __ Mov(baseAddress, Immediate(JSThread::GlueData::GetCOStubEntriesOffset(false)));
769 __ Mov(proxyCallInternalId, Immediate(CommonStubCSigns::JsProxyCallInternal));
770 __ Add(codeAddress, X0, baseAddress);
771 __ Ldr(codeAddress, MemoryOperand(codeAddress, proxyCallInternalId, UXTW, FRAME_SLOT_SIZE_LOG2));
772 __ Br(codeAddress);
773 }
774
775 // * uint64_t JSProxyCallInternalWithArgV(uintptr_t glue, uint32_t argc, JSTaggedType calltarget, uintptr_t argv[])
776 // * c++ calling convention call js function
777 // * Arguments:
778 // %x0 - glue
779 // %x1 - argc
780 // %x2 - calltarget
781 // %x3 - argV[] = { calltarget, newtarget, thisObj, arg[0], arg[1], ..., arg[N-1])
782
JSProxyCallInternalWithArgV(ExtendedAssembler * assembler)783 void OptimizedCall::JSProxyCallInternalWithArgV(ExtendedAssembler *assembler)
784 {
785 __ BindAssemblerStub(RTSTUB_ID(JSProxyCallInternalWithArgV));
786 Register jsfunc(X1);
787 Register argv(X3);
788 __ Mov(jsfunc, Register(X2));
789 __ Str(jsfunc, MemoryOperand(argv, 0));
790 JSCallInternal(assembler, jsfunc);
791 }
792
793 // * uint64_t CallRuntimeWithArgv(uintptr_t glue, uint64_t runtime_id, uint64_t argc, uintptr_t argv)
794 // * cc calling convention call runtime_id's runtion function(c-abi)
795 // * Arguments:
796 // %x0 - glue
797 // %x1 - runtime_id
798 // %x2 - argc
799 // %x3 - argv
800 //
801 // * Optimized-leaved-frame-with-argv layout as the following:
802 // +--------------------------+
803 // | argv[] |
804 // +--------------------------+-------------
805 // | argc | ^
806 // |--------------------------| |
807 // | RuntimeId | OptimizedWithArgvLeaveFrame
808 // sp --> |--------------------------| |
809 // | returnAddr | |
810 // |--------------------------| |
811 // | callsiteFp | |
812 // |--------------------------| |
813 // | frameType | v
814 // +--------------------------+-------------
815
CallRuntimeWithArgv(ExtendedAssembler * assembler)816 void OptimizedCall::CallRuntimeWithArgv(ExtendedAssembler *assembler)
817 {
818 __ BindAssemblerStub(RTSTUB_ID(CallRuntimeWithArgv));
819 Register glue(X0);
820 Register runtimeId(X1);
821 Register argc(X2);
822 Register argv(X3);
823 Register sp(SP);
824 // 2 : 2 means pair
825 __ Stp(argc, argv, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
826 __ Str(runtimeId, MemoryOperand(sp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
827 __ PushFpAndLr();
828 Register fp(X29);
829 __ Str(fp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
830 // construct leave frame
831 Register frameType(X9);
832 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::LEAVE_FRAME_WITH_ARGV)));
833 __ Str(frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
834 __ Add(Register(FP), sp, Immediate(FRAME_SLOT_SIZE));
835
836 // load runtime trampoline address
837 Register tmp(X9);
838 Register rtfunc(X9);
839 // 3 : 3 means 2 << 3 = 8
840 __ Add(tmp, glue, Operand(runtimeId, LSL, 3));
841 __ Ldr(rtfunc, MemoryOperand(tmp, JSThread::GlueData::GetRTStubEntriesOffset(false)));
842 __ Mov(X1, argc);
843 __ Mov(X2, argv);
844 __ Blr(rtfunc);
845 __ Add(sp, sp, Immediate(FRAME_SLOT_SIZE));
846 __ RestoreFpAndLr();
847 __ Add(sp, sp, Immediate(3 * FRAME_SLOT_SIZE)); // 3 : 3 means pair
848 __ Ret();
849 }
850
PushMandatoryJSArgs(ExtendedAssembler * assembler,Register jsfunc,Register thisObj,Register newTarget,Register currentSp)851 void OptimizedCall::PushMandatoryJSArgs(ExtendedAssembler *assembler, Register jsfunc,
852 Register thisObj, Register newTarget, Register currentSp)
853 {
854 __ Str(thisObj, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
855 __ Str(newTarget, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
856 __ Str(jsfunc, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
857 }
858
PopJSFunctionArgs(ExtendedAssembler * assembler,Register expectedNumArgs,Register actualNumArgs)859 void OptimizedCall::PopJSFunctionArgs(ExtendedAssembler *assembler, Register expectedNumArgs, Register actualNumArgs)
860 {
861 Register sp(SP);
862 Register fp(X6);
863 Label aligned;
864 const int64_t argoffsetSlot = static_cast<int64_t>(CommonArgIdx::FUNC) - 1;
865 if (expectedNumArgs != actualNumArgs) {
866 TempRegister1Scope scop1(assembler);
867 Register tmp = __ TempRegister1();
868 __ Cmp(expectedNumArgs, actualNumArgs);
869 __ CMov(tmp, expectedNumArgs, actualNumArgs, Condition::HI);
870 __ Add(sp, sp, Operand(tmp, UXTW, FRAME_SLOT_SIZE_LOG2));
871 } else {
872 __ Add(sp, sp, Operand(expectedNumArgs, UXTW, FRAME_SLOT_SIZE_LOG2));
873 }
874 __ Add(sp, sp, Immediate(argoffsetSlot * FRAME_SLOT_SIZE));
875 __ Mov(fp, sp);
876 __ Tst(fp, LogicalImmediate::Create(0xf, RegXSize)); // 0xf: 0x1111
877 __ B(Condition::EQ, &aligned);
878 __ Add(sp, sp, Immediate(FRAME_SLOT_SIZE));
879 __ Bind(&aligned);
880 }
881
PushJSFunctionEntryFrame(ExtendedAssembler * assembler,Register prevFp)882 void OptimizedCall::PushJSFunctionEntryFrame (ExtendedAssembler *assembler, Register prevFp)
883 {
884 Register fp(X29);
885 Register sp(SP);
886 TempRegister2Scope temp2Scope(assembler);
887 __ PushFpAndLr();
888 Register frameType = __ TempRegister2();
889 // construct frame
890 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_ENTRY_FRAME)));
891 // 2 : 2 means pairs
892 __ Stp(prevFp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
893 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
894 __ CalleeSave();
895 }
896
PopJSFunctionEntryFrame(ExtendedAssembler * assembler,Register glue)897 void OptimizedCall::PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue)
898 {
899 Register fp(X29);
900 Register sp(SP);
901 Register prevFp(X1);
902 __ CalleeRestore();
903
904 // 2: prevFp and frameType
905 __ Ldp(prevFp, Register(Zero), MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
906 // restore return address
907 __ RestoreFpAndLr();
908 __ Str(prevFp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
909 }
910
PushOptimizedArgsConfigFrame(ExtendedAssembler * assembler)911 void OptimizedCall::PushOptimizedArgsConfigFrame(ExtendedAssembler *assembler)
912 {
913 Register sp(SP);
914 TempRegister2Scope temp2Scope(assembler);
915 Register frameType = __ TempRegister2();
916 __ PushFpAndLr();
917 // construct frame
918 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
919 // 2 : 2 means pairs. X19 means calleesave and 16bytes align
920 __ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
921 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
922 }
923
PopOptimizedArgsConfigFrame(ExtendedAssembler * assembler)924 void OptimizedCall::PopOptimizedArgsConfigFrame(ExtendedAssembler *assembler)
925 {
926 TempRegister2Scope temp2Scope(assembler);
927 Register sp(SP);
928 Register frameType = __ TempRegister2();
929 // 2 : 2 means pop call site sp and type
930 __ Ldp(Register(X19), frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
931 __ RestoreFpAndLr();
932 }
933
PushOptimizedFrame(ExtendedAssembler * assembler)934 void OptimizedCall::PushOptimizedFrame(ExtendedAssembler *assembler)
935 {
936 Register sp(SP);
937 TempRegister2Scope temp2Scope(assembler);
938 Register frameType = __ TempRegister2();
939 __ PushFpAndLr();
940 // construct frame
941 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_FRAME)));
942 // 2 : 2 means pairs. X19 means calleesave and 16bytes align
943 __ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
944 __ Add(Register(FP), sp, Immediate(FRAME_SLOT_SIZE));
945 }
946
PopOptimizedFrame(ExtendedAssembler * assembler)947 void OptimizedCall::PopOptimizedFrame(ExtendedAssembler *assembler)
948 {
949 TempRegister2Scope temp2Scope(assembler);
950 Register sp(SP);
951 Register frameType = __ TempRegister2();
952 // 2 : 2 means pop call site sp and type
953 __ Ldp(Register(X19), frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
954 __ RestoreFpAndLr();
955 }
956
957 // * uint64_t PushOptimizedUnfoldArgVFrame(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
958 // JSTaggedType new, JSTaggedType this, JSTaggedType argV[])
959 // * cc calling convention call js function()
960 // * arguments:
961 // %x0 - glue
962 // %x1 - argc
963 // %x2 - call-target
964 // %x3 - new-target
965 // %x4 - this
966 // %x5 - argv
967 //
968 // * OptimizedUnfoldArgVFrame layout description as the following:
969 // sp ----> |--------------------------| ---------------
970 // | returnAddr | ^
971 // currentFp--> |--------------------------| |
972 // | prevFp | |
973 // |--------------------------| OptimizedUnfoldArgVFrame
974 // | frameType | |
975 // |--------------------------| |
976 // | currentFp | v
977 // +--------------------------+ ---------------
978
PushOptimizedUnfoldArgVFrame(ExtendedAssembler * assembler,Register callSiteSp)979 void OptimizedCall::PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp)
980 {
981 Register sp(SP);
982 TempRegister2Scope temp2Scope(assembler);
983 Register frameType = __ TempRegister2();
984 __ PushFpAndLr();
985 // construct frame
986 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)));
987 // 2 : 2 means pairs
988 __ Stp(callSiteSp, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
989 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
990 }
991
PopOptimizedUnfoldArgVFrame(ExtendedAssembler * assembler)992 void OptimizedCall::PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler)
993 {
994 Register sp(SP);
995 // 2 : 2 means pop call site sp and type
996 __ Add(sp, sp, Immediate(2 * FRAME_SLOT_SIZE));
997 __ RestoreFpAndLr();
998 }
999
1000 // * uint64_t JSCallWithArgV(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
1001 // JSTaggedType new, JSTaggedType this, argV)
1002 // * cc calling convention call js function()
1003 // * arguments:
1004 // %x0 - glue
1005 // %x1 - argc
1006 // %x2 - call-target
1007 // %x3 - new-target
1008 // %x4 - this
1009 // %x5 - argV[]
1010 //
1011 // * OptimizedJSFunctionFrame layout description as the following:
1012 // +--------------------------+
1013 // | arg[N-1] |
1014 // +--------------------------+
1015 // | . . . . . |
1016 // +--------------------------+
1017 // | arg[0] |
1018 // +--------------------------+
1019 // | this |
1020 // +--------------------------+
1021 // | new-target |
1022 // +--------------------------+
1023 // | call-target |
1024 // |--------------------------|
1025 // | argc |
1026 // sp ----> |--------------------------| ---------------
1027 // | returnAddr | ^
1028 // |--------------------------| |
1029 // | callsiteFp | |
1030 // |--------------------------| OptimizedJSFunctionFrame
1031 // | frameType | |
1032 // |--------------------------| |
1033 // | call-target | v
1034 // +--------------------------+ ---------------
1035
GenJSCallWithArgV(ExtendedAssembler * assembler,bool isNew)1036 void OptimizedCall::GenJSCallWithArgV(ExtendedAssembler *assembler, bool isNew)
1037 {
1038 Register sp(SP);
1039 Register glue(X0);
1040 Register actualNumArgs(X1);
1041 Register jsfunc(X2);
1042 Register newTarget(X3);
1043 Register thisObj(X4);
1044 Register argV(X5);
1045 Register env(X6);
1046 Register currentSp = __ AvailableRegister1();
1047 Register callsiteSp = __ AvailableRegister2();
1048 Label pushCallThis;
1049
1050 __ Mov(callsiteSp, sp);
1051 PushOptimizedUnfoldArgVFrame(assembler, callsiteSp);
1052 Register argC(X7);
1053 __ Add(actualNumArgs, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1054 __ Mov(argC, actualNumArgs);
1055 IncreaseStackForArguments(assembler, argC, currentSp);
1056 {
1057 TempRegister1Scope scope1(assembler);
1058 TempRegister2Scope scope2(assembler);
1059 Register tmp = __ TempRegister1();
1060 Register op = __ TempRegister2();
1061 __ Sub(tmp, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1062 PushArgsWithArgv(assembler, glue, tmp, argV, op, currentSp, &pushCallThis, nullptr);
1063 }
1064 __ Bind(&pushCallThis);
1065 PushMandatoryJSArgs(assembler, jsfunc, thisObj, newTarget, currentSp);
1066 __ Str(actualNumArgs, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1067 __ Ldr(env, MemoryOperand(jsfunc, JSFunction::LEXICAL_ENV_OFFSET));
1068 __ Str(env, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1069
1070 if (isNew) {
1071 __ CallAssemblerStub(RTSTUB_ID(JSCallNew), false);
1072 } else {
1073 __ CallAssemblerStub(RTSTUB_ID(JSCall), false);
1074 }
1075
1076 __ Ldr(actualNumArgs, MemoryOperand(sp, FRAME_SLOT_SIZE));
1077 PopJSFunctionArgs(assembler, actualNumArgs, actualNumArgs);
1078 PopOptimizedUnfoldArgVFrame(assembler);
1079 __ Ret();
1080 }
1081
JSCallNewWithArgV(ExtendedAssembler * assembler)1082 void OptimizedCall::JSCallNewWithArgV(ExtendedAssembler *assembler)
1083 {
1084 __ BindAssemblerStub(RTSTUB_ID(JSCallNewWithArgV));
1085 GenJSCallWithArgV(assembler, true);
1086 }
1087
JSCallWithArgV(ExtendedAssembler * assembler)1088 void OptimizedCall::JSCallWithArgV(ExtendedAssembler *assembler)
1089 {
1090 __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgV));
1091 GenJSCallWithArgV(assembler, false);
1092 }
1093
ConstructorJSCallWithArgV(ExtendedAssembler * assembler)1094 void OptimizedCall::ConstructorJSCallWithArgV([[maybe_unused]]ExtendedAssembler *assembler)
1095 {
1096 __ BindAssemblerStub(RTSTUB_ID(ConstructorJSCallWithArgV));
1097 Register sp(SP);
1098 Register glue(X0);
1099 Register actualNumArgs(X1);
1100 Register jsfunc(X2);
1101 Register newTarget(X3);
1102 Register thisObj(X4);
1103 Register argV(X5);
1104 Register env(X6);
1105 Register currentSp = __ AvailableRegister1();
1106 Register callsiteSp = __ AvailableRegister2();
1107 Label pushCallThis;
1108
1109 __ Mov(callsiteSp, sp);
1110 PushOptimizedUnfoldArgVFrame(assembler, callsiteSp);
1111 Register argC(X7);
1112 __ Add(actualNumArgs, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1113 __ Mov(argC, actualNumArgs);
1114 IncreaseStackForArguments(assembler, argC, currentSp);
1115 {
1116 TempRegister1Scope scope1(assembler);
1117 TempRegister2Scope scope2(assembler);
1118 Register tmp = __ TempRegister1();
1119 Register op = __ TempRegister2();
1120 __ Sub(tmp, actualNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1121 PushArgsWithArgv(assembler, glue, tmp, argV, op, currentSp, &pushCallThis, nullptr);
1122 }
1123 __ Bind(&pushCallThis);
1124 PushMandatoryJSArgs(assembler, jsfunc, thisObj, newTarget, currentSp);
1125 __ Str(actualNumArgs, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1126 __ Ldr(env, MemoryOperand(jsfunc, JSFunction::LEXICAL_ENV_OFFSET));
1127 __ Str(env, MemoryOperand(currentSp, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1128
1129 __ CallAssemblerStub(RTSTUB_ID(ConstructorJSCall), false);
1130
1131 __ Ldr(actualNumArgs, MemoryOperand(sp, FRAME_SLOT_SIZE));
1132 PopJSFunctionArgs(assembler, actualNumArgs, actualNumArgs);
1133 PopOptimizedUnfoldArgVFrame(assembler);
1134 __ Ret();
1135 }
1136
DeoptEnterAsmInterp(ExtendedAssembler * assembler)1137 void OptimizedCall::DeoptEnterAsmInterp(ExtendedAssembler *assembler)
1138 {
1139 // rdi
1140 Register glueRegister = __ GlueRegister();
1141 Register context(X2);
1142 Register opRegister(X9);
1143 Register outputCount(X10);
1144 Register frameStateBase(X11);
1145 Register currentSlotRegister(X12);
1146 Register sp(SP);
1147
1148 __ PushFpAndLr();
1149
1150 __ Mov(currentSlotRegister, sp);
1151 __ Ldr(outputCount, MemoryOperand(context, AsmStackContext::GetOutputCountOffset(false)));
1152 __ Add(frameStateBase, context, Immediate(AsmStackContext::GetSize(false)));
1153
1154 Label stackOverflow;
1155 // update fp
1156 __ Str(currentSlotRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFpOffset(false)));
1157 PushArgsWithArgv(assembler, glueRegister, outputCount, frameStateBase, opRegister,
1158 currentSlotRegister, nullptr, &stackOverflow);
1159
1160 Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
1161 Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
1162 {
1163 // X19, fp, x20, x21, x22, x23, x24
1164 // glue sp pc constpool profile acc hotness
1165 __ Ldr(callTargetRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFunctionOffset(false)));
1166 __ Ldr(Register(X20), MemoryOperand(frameStateBase, AsmInterpretedFrame::GetPcOffset(false)));
1167 __ Ldr(Register(X23), MemoryOperand(frameStateBase, AsmInterpretedFrame::GetAccOffset(false)));
1168 __ Ldr(methodRegister, MemoryOperand(callTargetRegister, JSFunctionBase::METHOD_OFFSET));
1169
1170 __ Add(opRegister, currentSlotRegister, Immediate(AsmInterpretedFrame::GetSize(false)));
1171
1172 __ Align16(currentSlotRegister);
1173 __ Mov(Register(SP), currentSlotRegister);
1174 AsmInterpreterCall::DispatchCall(assembler, Register(X20), opRegister, Register(X23));
1175 }
1176 __ Bind(&stackOverflow);
1177 {
1178 Register temp(X1);
1179 AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(
1180 assembler, glueRegister, sp, temp);
1181 }
1182 }
1183
DeoptHandlerAsm(ExtendedAssembler * assembler)1184 void OptimizedCall::DeoptHandlerAsm(ExtendedAssembler *assembler)
1185 {
1186 __ BindAssemblerStub(RTSTUB_ID(DeoptHandlerAsm));
1187 __ PushFpAndLr();
1188 Register sp(SP);
1189 Register fp(FP);
1190 Register frameType(X2);
1191 Register glueReg(X0);
1192
1193 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_FRAME)));
1194 __ Stp(glueReg, frameType, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1195 __ Add(fp, sp, Immediate(DOUBLE_SLOT_SIZE));
1196 __ CalleeSave();
1197
1198 Register deoptType(X1);
1199 Register align(X3);
1200 Register argC(X3);
1201 Register runtimeId(X2);
1202 __ Stp(deoptType, align, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1203 __ Mov(argC, Immediate(1));
1204 __ Mov(runtimeId, Immediate(RTSTUB_ID(DeoptHandler)));
1205 __ Stp(runtimeId, argC, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1206 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1207 __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE)); // 2: skip runtimeId, argc, deoptType, align
1208
1209 __ CalleeRestore();
1210 Register context(X2);
1211 __ Mov(context, Register(X0));
1212 __ Ldr(glueReg, MemoryOperand(sp, 0));
1213
1214 Register ret(X0);
1215 Label stackOverflow;
1216 __ Cmp(ret, Immediate(JSTaggedValue::VALUE_EXCEPTION));
1217 __ B(Condition::EQ, &stackOverflow);
1218
1219 Label target;
1220 Register temp(X1);
1221 __ Ldr(fp, MemoryOperand(context, AsmStackContext::GetCallerFpOffset(false)));
1222 __ Ldr(temp, MemoryOperand(context, AsmStackContext::GetCallFrameTopOffset(false)));
1223 __ Mov(sp, temp);
1224 __ Ldr(Register(X30), MemoryOperand(context, AsmStackContext::GetReturnAddressOffset(false)));
1225
1226 PushAsmInterpBridgeFrame(assembler);
1227 __ Bl(&target);
1228 PopAsmInterpBridgeFrame(assembler);
1229 __ Ret();
1230 __ Bind(&target);
1231 DeoptEnterAsmInterp(assembler);
1232
1233 __ Bind(&stackOverflow);
1234 {
1235 __ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowStackOverflowException)));
1236 // 2 : 2 means pair
1237 __ Stp(runtimeId, Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
1238 __ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
1239 __ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE)); // 2: skip runtimeId&argc glue&type
1240 __ RestoreFpAndLr();
1241 __ Ret();
1242 }
1243 }
1244 #undef __
1245 } // panda::ecmascript::aarch64