1/* 2 * Copyright (c) 2023-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 OptimizedFastCallEntry(uintptr_t glue, uint32_t actualNumArgs, const JSTaggedType argV[], 35// uintptr_t prevFp) 36// * Arguments: 37// %x0 - glue 38// %x1 - actualNumArgs 39// %x2 - argV 40// %x3 - prevFp 41void OptimizedFastCall::OptimizedFastCallEntry(ExtendedAssembler *assembler) 42{ 43 __ BindAssemblerStub(RTSTUB_ID(OptimizedFastCallEntry)); 44 Register glueReg(X0); 45 Register argc(X1); 46 Register argV(X2); 47 Register prevFpReg(X3); 48 Register sp(SP); 49 50 OptimizedCall::PushJSFunctionEntryFrame (assembler, prevFpReg); 51 __ Mov(Register(X3), argc); 52 __ Mov(Register(X4), argV); 53 Register tmpArgc(X3); 54 Register tmpArgV(X4); 55 56 __ Mov(Register(X20), glueReg); 57 __ Ldr(Register(X1), MemoryOperand(tmpArgV, 0)); 58 __ Ldr(Register(X2), MemoryOperand(tmpArgV, FRAME_SLOT_SIZE)); 59 __ Add(tmpArgV, tmpArgV, Immediate(DOUBLE_SLOT_SIZE)); 60 61 __ CallAssemblerStub(RTSTUB_ID(JSFastCallWithArgV), false); 62 __ Mov(Register(X2), Register(X20)); 63 OptimizedCall::PopJSFunctionEntryFrame(assembler, Register(X2)); 64 __ Ret(); 65} 66 67// * uint64_t OptimizedFastCallAndPushArgv(uintptr_t glue, uint32_t expectedNumArgs, uint32_t actualNumArgs, 68// uintptr_t codeAddr, uintptr_t argv) 69// * Arguments wil CC calling convention: 70// %x0 - glue 71// %x1 - actualNumArgs 72// %x2 - actualArgv 73// %x3 - func 74// %x4 - new target 75// %x5 - this 76// %x6 - arg0 77// %x7 - arg1 78// 79// * The OptimizedJSFunctionArgsConfig Frame's structure is illustrated as the following: 80// +--------------------------+ 81// | arg[N-1] | 82// +--------------------------+ 83// | . . . . | 84// +--------------------------+ 85// | arg[0] | 86// +--------------------------+ 87// | argC | 88// sp ---> +--------------------------+ ----------------- 89// | | ^ 90// | prevFP | | 91// |--------------------------| OptimizedJSFunctionArgsConfigFrame 92// | frameType | | 93// | | V 94// +--------------------------+ ----------------- 95void OptimizedFastCall::OptimizedFastCallAndPushArgv(ExtendedAssembler *assembler) 96{ 97 __ BindAssemblerStub(RTSTUB_ID(OptimizedFastCallAndPushArgv)); 98 Register glue(X0); 99 Register actualNumArgs(X1); 100 Register actualArgv(X2); 101 Register jsfunc(X3); 102 Register codeAddr(X4); 103 Register sp(SP); 104 Register currentSp = __ AvailableRegister1(); 105 Register op = __ AvailableRegister1(); 106 Label call; 107 Label arg4; 108 Label arg5; 109 Label arg6; 110 Label argc; 111 Label checkExpectedArgs; 112 Label pushUndefined; 113 114 // construct frame 115 OptimizedCall::PushOptimizedArgsConfigFrame(assembler); 116 117 __ Mov(__ AvailableRegister3(), Register(X1)); 118 __ Add(__ AvailableRegister4(), sp, Immediate(4 * FRAME_SLOT_SIZE)); // 4 skip fp lr type x19 119 Register actualNumArgsReg = __ AvailableRegister3(); 120 Register argV = __ AvailableRegister4(); 121 122 Register method = __ AvailableRegister1(); 123 Register expectedNumArgs = __ AvailableRegister2(); 124 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET)); 125 __ Ldr(expectedNumArgs, MemoryOperand(method, Method::CALL_FIELD_OFFSET)); 126 __ Lsr(expectedNumArgs, expectedNumArgs, MethodLiteral::NumArgsBits::START_BIT); 127 __ And(expectedNumArgs, expectedNumArgs, 128 LogicalImmediate::Create( 129 MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegXSize)); 130 __ Add(expectedNumArgs, expectedNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS)); 131 132 Label arg7; 133 Label arg8; 134 __ Mov(Register(X1), Register(X3)); // func move to argc 135 __ Mov(Register(X2), Register(X5)); // this move to func 136 jsfunc = Register(X1); 137 138 __ Cmp(actualNumArgsReg, Immediate(3)); // 3: 3 args 139 __ B(Condition::NE, &arg4); 140 __ Mov(Register(X3), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 141 __ Mov(Register(X4), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 142 __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 143 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 144 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 145 __ B(&checkExpectedArgs); 146 147 __ Bind(&arg4); 148 { 149 __ Mov(Register(X3), Register(X6)); 150 __ Cmp(actualNumArgsReg, Immediate(4)); // 4: 4 args 151 __ B(Condition::NE, &arg5); 152 __ Mov(Register(X4), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 153 __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 154 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 155 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 156 __ B(&checkExpectedArgs); 157 } 158 159 __ Bind(&arg5); 160 { 161 __ Mov(Register(X4), Register(X7)); 162 __ Cmp(actualNumArgsReg, Immediate(5)); // 5: 5 args 163 __ B(Condition::NE, &arg6); 164 __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 165 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 166 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 167 __ B(&checkExpectedArgs); 168 } 169 170 __ Bind(&arg6); 171 { 172 __ Ldr(op, MemoryOperand(argV, 0)); 173 __ Mov(Register(X5), op); 174 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE)); 175 __ Cmp(actualNumArgsReg, Immediate(6)); // 6: 6 args 176 __ B(Condition::NE, &arg7); 177 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 178 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 179 __ B(&checkExpectedArgs); 180 } 181 182 __ Bind(&arg7); 183 { 184 __ Ldr(op, MemoryOperand(argV, 0)); 185 __ Mov(Register(X6), op); 186 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE)); 187 __ Cmp(actualNumArgsReg, Immediate(7)); // 7: 7 args 188 __ B(Condition::NE, &arg8); 189 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 190 __ B(&checkExpectedArgs); 191 } 192 193 __ Bind(&arg8); 194 { 195 __ Ldr(op, MemoryOperand(argV, 0)); 196 __ Mov(Register(X7), op); 197 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE)); 198 __ Cmp(actualNumArgsReg, Immediate(8)); // 8: 8 args 199 __ B(Condition::NE, &argc); 200 __ B(&checkExpectedArgs); 201 } 202 203 __ Bind(&argc); 204 { 205 TempRegister1Scope scope1(assembler); 206 TempRegister2Scope scope2(assembler); 207 Register tmp = __ TempRegister1(); 208 Register undefinedValue = __ TempRegister2(); 209 210 __ Cmp(expectedNumArgs, actualNumArgsReg); 211 __ B(Condition::GT, &pushUndefined); 212 __ Sub(expectedNumArgs, expectedNumArgs, Immediate(8)); // 8 : register save 8 arg 213 __ Sub(actualNumArgsReg, actualNumArgsReg, Immediate(8)); // 8 : register save 8 arg 214 OptimizedCall::IncreaseStackForArguments(assembler, actualNumArgsReg, currentSp); 215 PushArgsWithArgv(assembler, glue, actualNumArgsReg, argV, undefinedValue, currentSp, nullptr, nullptr); 216 __ B(&call); 217 218 __ Bind(&pushUndefined); 219 __ Sub(expectedNumArgs, expectedNumArgs, Immediate(8)); // 8 : register save 8 arg 220 __ Sub(actualNumArgsReg, actualNumArgsReg, Immediate(8)); // 8 : register save 8 arg 221 OptimizedCall::IncreaseStackForArguments(assembler, expectedNumArgs, currentSp); 222 __ Sub(tmp, expectedNumArgs, actualNumArgsReg); 223 PushUndefinedWithArgc(assembler, glue, tmp, undefinedValue, currentSp, nullptr, nullptr); 224 PushArgsWithArgv(assembler, glue, actualNumArgsReg, argV, undefinedValue, currentSp, nullptr, nullptr); 225 __ B(&call); 226 } 227 228 __ Bind(&checkExpectedArgs); 229 { 230 __ Cmp(expectedNumArgs, Immediate(8)); // 8 : register save 8 arg 231 __ B(Condition::LS, &call); 232 __ Sub(expectedNumArgs, expectedNumArgs, Immediate(8)); // 8 : register save 8 arg 233 OptimizedCall::IncreaseStackForArguments(assembler, expectedNumArgs, currentSp); 234 TempRegister2Scope scope2(assembler); 235 Register undefinedValue = __ TempRegister2(); 236 PushUndefinedWithArgc(assembler, glue, expectedNumArgs, undefinedValue, currentSp, nullptr, nullptr); 237 __ B(&call); 238 } 239 __ Bind(&call); 240 TempRegister1Scope scope1(assembler); 241 Register method1 = __ TempRegister1(); 242 __ Ldr(method1, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET)); 243 __ Ldr(X11, MemoryOperand(jsfunc, JSFunction::CODE_ENTRY_OFFSET)); 244 __ Blr(X11); 245 246 __ Mov(Register(SP), Register(FP)); 247 __ RestoreFpAndLr(); 248 __ Ret(); 249} 250 251// * uint64_t JSFastCallWithArgV(uintptr_t glue, uint32_t argc, JSTaggedType calltarget, 252// JSTaggedType this, argV) 253// * cc calling convention call js function() 254// * arguments: 255// %x0 - glue 256// %x1 - call-target 257// %x2 - this 258// %x3 - artual argc 259// %x4 - argv 260void OptimizedFastCall::JSFastCallWithArgV(ExtendedAssembler *assembler) 261{ 262 __ BindAssemblerStub(RTSTUB_ID(JSFastCallWithArgV)); 263 Register sp(SP); 264 Register glue(X0); 265 Register actualNumArgs(X3); 266 Register jsfunc(X1); 267 Register thisObj(X2); 268 Register currentSp = __ AvailableRegister1(); 269 Register callsiteSp = __ AvailableRegister2(); 270 Label call; 271 __ Mov(callsiteSp, sp); 272 OptimizedCall::PushOptimizedUnfoldArgVFrame(assembler, callsiteSp); 273 TempRegister2Scope scope2(assembler); 274 Register op = __ TempRegister2(); 275 Register argC = __ AvailableRegister3(); 276 Register argV = __ AvailableRegister4(); 277 __ Mov(argC, actualNumArgs); 278 __ Mov(argV, Register(X4)); 279 280 __ Cmp(argC, Immediate(0)); 281 __ B(Condition::EQ, &call); 282 __ Ldr(op, MemoryOperand(argV, 0)); 283 __ Mov(Register(X3), op); // first arg 284 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE)); 285 __ Sub(argC, argC, Immediate(1)); 286 287 __ Cmp(argC, Immediate(0)); 288 __ B(Condition::EQ, &call); 289 __ Ldr(op, MemoryOperand(argV, 0)); 290 __ Mov(Register(X4), op); // second arg 291 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE)); 292 __ Sub(argC, argC, Immediate(1)); 293 294 __ Cmp(argC, Immediate(0)); 295 __ B(Condition::EQ, &call); 296 __ Ldr(op, MemoryOperand(argV, 0)); 297 __ Mov(Register(X5), op); // third arg 298 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE)); 299 __ Sub(argC, argC, Immediate(1)); 300 301 __ Cmp(argC, Immediate(0)); 302 __ B(Condition::EQ, &call); 303 __ Ldr(op, MemoryOperand(argV, 0)); 304 __ Mov(Register(X6), op); 305 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE)); 306 __ Sub(argC, argC, Immediate(1)); 307 308 __ Cmp(argC, Immediate(0)); 309 __ B(Condition::EQ, &call); 310 __ Ldr(op, MemoryOperand(argV, 0)); 311 __ Mov(Register(X7), op); 312 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE)); 313 __ Sub(argC, argC, Immediate(1)); 314 315 __ Cmp(argC, Immediate(0)); 316 __ B(Condition::EQ, &call); 317 OptimizedCall::IncreaseStackForArguments(assembler, argC, currentSp); 318 PushArgsWithArgv(assembler, glue, argC, argV, op, currentSp, nullptr, nullptr); 319 320 __ Bind(&call); 321 TempRegister1Scope scope1(assembler); 322 Register method = __ TempRegister1(); 323 __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET)); 324 __ Ldr(X11, MemoryOperand(jsfunc, JSFunctionBase::CODE_ENTRY_OFFSET)); 325 __ Blr(X11); 326 327 __ Mov(Register(SP), Register(FP)); 328 __ RestoreFpAndLr(); 329 __ Ret(); 330} 331 332// * Arguments: 333// %x0 - glue 334// %x1 - func 335// %x2 - this 336// %x3 - actualNumArgs 337// %x4 - argv 338// %x5 - expectedNumArgs 339void OptimizedFastCall::JSFastCallWithArgVAndPushArgv(ExtendedAssembler *assembler) 340{ 341 __ BindAssemblerStub(RTSTUB_ID(JSFastCallWithArgVAndPushArgv)); 342 Register sp(SP); 343 Register glue(X0); 344 Register jsfunc(X1); 345 Register thisObj(X2); 346 Register currentSp = __ AvailableRegister1(); 347 Register op = __ AvailableRegister1(); 348 Register callsiteSp = __ AvailableRegister2(); 349 Label call; 350 Label arg1; 351 Label arg2; 352 Label arg3; 353 Label arg4; 354 Label arg5; 355 Label argc; 356 Label checkExpectedArgs; 357 Label pushUndefined; 358 __ Mov(callsiteSp, sp); 359 OptimizedCall::PushOptimizedUnfoldArgVFrame(assembler, callsiteSp); 360 Register actualNumArgsReg = __ AvailableRegister3(); 361 Register argV = __ AvailableRegister4(); 362 Register expectedNumArgs = __ AvailableRegister2(); 363 __ Mov(actualNumArgsReg, Register(X3)); 364 __ Mov(argV, Register(X4)); 365 __ Mov(expectedNumArgs, Register(X5)); 366 367 __ Cmp(actualNumArgsReg, Immediate(0)); 368 __ B(Condition::NE, &arg1); 369 __ Mov(Register(X3), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 370 __ Mov(Register(X4), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 371 __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 372 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 373 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 374 __ B(&checkExpectedArgs); 375 376 __ Bind(&arg1); 377 { 378 __ Ldr(op, MemoryOperand(argV, 0)); 379 __ Mov(Register(X3), op); 380 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE)); 381 __ Cmp(actualNumArgsReg, Immediate(1)); 382 __ B(Condition::NE, &arg2); 383 __ Mov(Register(X4), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 384 __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 385 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 386 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 387 __ B(&checkExpectedArgs); 388 } 389 390 __ Bind(&arg2); 391 { 392 __ Ldr(op, MemoryOperand(argV, 0)); 393 __ Mov(Register(X4), op); 394 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE)); 395 __ Cmp(actualNumArgsReg, Immediate(2)); // 2: 2 args 396 __ B(Condition::NE, &arg3); 397 __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 398 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 399 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 400 __ B(&checkExpectedArgs); 401 } 402 403 __ Bind(&arg3); 404 { 405 __ Ldr(op, MemoryOperand(argV, 0)); 406 __ Mov(Register(X5), op); 407 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE)); 408 __ Cmp(actualNumArgsReg, Immediate(3)); // 3: 3 args 409 __ B(Condition::NE, &arg4); 410 __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 411 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 412 __ B(&checkExpectedArgs); 413 } 414 415 __ Bind(&arg4); 416 { 417 __ Ldr(op, MemoryOperand(argV, 0)); 418 __ Mov(Register(X6), op); 419 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE)); 420 __ Cmp(actualNumArgsReg, Immediate(4)); // 4: 4 args 421 __ B(Condition::NE, &arg5); 422 __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); 423 __ B(&checkExpectedArgs); 424 } 425 426 __ Bind(&arg5); 427 { 428 __ Ldr(op, MemoryOperand(argV, 0)); 429 __ Mov(Register(X7), op); 430 __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE)); 431 __ Cmp(actualNumArgsReg, Immediate(5)); // 5: 5 args 432 __ B(Condition::NE, &argc); 433 __ B(&checkExpectedArgs); 434 } 435 436 __ Bind(&argc); 437 { 438 TempRegister1Scope scope1(assembler); 439 TempRegister2Scope scope2(assembler); 440 Register tmp = __ TempRegister1(); 441 Register undefinedValue = __ TempRegister2(); 442 443 __ Cmp(expectedNumArgs, actualNumArgsReg); 444 __ B(Condition::GT, &pushUndefined); 445 __ Sub(expectedNumArgs, expectedNumArgs, Immediate(5)); // 5 : register save 5 arg 446 __ Sub(actualNumArgsReg, actualNumArgsReg, Immediate(5)); // 5 : register save 5 arg 447 OptimizedCall::IncreaseStackForArguments(assembler, actualNumArgsReg, currentSp); 448 PushArgsWithArgv(assembler, glue, actualNumArgsReg, argV, undefinedValue, currentSp, nullptr, nullptr); 449 __ B(&call); 450 451 __ Bind(&pushUndefined); 452 __ Sub(expectedNumArgs, expectedNumArgs, Immediate(5)); // 5 : register save 5 arg 453 __ Sub(actualNumArgsReg, actualNumArgsReg, Immediate(5)); // 5 : register save 5 arg 454 OptimizedCall::IncreaseStackForArguments(assembler, expectedNumArgs, currentSp); 455 __ Sub(tmp, expectedNumArgs, actualNumArgsReg); 456 PushUndefinedWithArgc(assembler, glue, tmp, undefinedValue, currentSp, nullptr, nullptr); 457 PushArgsWithArgv(assembler, glue, actualNumArgsReg, argV, undefinedValue, currentSp, nullptr, nullptr); 458 __ B(&call); 459 } 460 461 __ Bind(&checkExpectedArgs); 462 { 463 __ Cmp(expectedNumArgs, Immediate(5)); // 5 : register save 5 arg 464 __ B(Condition::LS, &call); 465 __ Sub(expectedNumArgs, expectedNumArgs, Immediate(5)); // 5 : register save 5 arg 466 OptimizedCall::IncreaseStackForArguments(assembler, expectedNumArgs, currentSp); 467 TempRegister2Scope scope2(assembler); 468 Register undefinedValue = __ TempRegister2(); 469 PushUndefinedWithArgc(assembler, glue, expectedNumArgs, undefinedValue, currentSp, nullptr, nullptr); 470 __ B(&call); 471 } 472 473 __ Bind(&call); 474 TempRegister1Scope scope1(assembler); 475 Register method = __ TempRegister1(); 476 __ Ldr(method, MemoryOperand(X1, JSFunction::METHOD_OFFSET)); 477 __ Ldr(X11, MemoryOperand(X1, JSFunction::CODE_ENTRY_OFFSET)); 478 __ Blr(X11); 479 480 __ Mov(Register(SP), Register(FP)); 481 __ RestoreFpAndLr(); 482 __ Ret(); 483} 484#undef __ 485} // panda::ecmascript::aarch64