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 30namespace panda::ecmascript::aarch64 { 31using 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 58void 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 99void 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 138void 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// +--------------------------+ --------------- 204void 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 276void 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 320void 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 376void 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 433void 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 441void OptimizedCall::JSCallNew(ExtendedAssembler *assembler) 442{ 443 __ BindAssemblerStub(RTSTUB_ID(JSCallNew)); 444 GenJSCall(assembler, true); 445} 446 447void OptimizedCall::JSCall(ExtendedAssembler *assembler) 448{ 449 __ BindAssemblerStub(RTSTUB_ID(JSCall)); 450 GenJSCall(assembler, false); 451} 452 453void 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 668void 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 717void 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 867void 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 894void 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 919void 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 1028void 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 1060void 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 1094void 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 1102void 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 1125void 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 1140void 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 1154void 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 1167void 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 1199void 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 1212void 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 1252void 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 1305void OptimizedCall::JSCallWithArgVAndPushArgv(ExtendedAssembler *assembler) 1306{ 1307 __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgVAndPushArgv)); 1308 GenJSCallWithArgV(assembler, RTSTUB_ID(OptimizedCallAndPushArgv)); 1309} 1310 1311void OptimizedCall::JSCallWithArgV(ExtendedAssembler *assembler) 1312{ 1313 __ BindAssemblerStub(RTSTUB_ID(JSCallWithArgV)); 1314 GenJSCallWithArgV(assembler, RTSTUB_ID(CallOptimized)); 1315} 1316 1317void OptimizedCall::SuperCallWithArgV(ExtendedAssembler *assembler) 1318{ 1319 __ BindAssemblerStub(RTSTUB_ID(SuperCallWithArgV)); 1320 GenJSCallWithArgV(assembler, RTSTUB_ID(JSCallNew)); 1321} 1322 1323void 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 1337void 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 1406void 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