14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#include "ecmascript/compiler/trampoline/aarch64/common_call.h"
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ci#include "ecmascript/compiler/assembler/assembler.h"
194514f5e3Sopenharmony_ci#include "ecmascript/compiler/argument_accessor.h"
204514f5e3Sopenharmony_ci#include "ecmascript/compiler/rt_call_signature.h"
214514f5e3Sopenharmony_ci#include "ecmascript/deoptimizer/deoptimizer.h"
224514f5e3Sopenharmony_ci#include "ecmascript/ecma_runtime_call_info.h"
234514f5e3Sopenharmony_ci#include "ecmascript/frames.h"
244514f5e3Sopenharmony_ci#include "ecmascript/js_function.h"
254514f5e3Sopenharmony_ci#include "ecmascript/method.h"
264514f5e3Sopenharmony_ci#include "ecmascript/js_thread.h"
274514f5e3Sopenharmony_ci#include "ecmascript/message_string.h"
284514f5e3Sopenharmony_ci#include "ecmascript/runtime_call_id.h"
294514f5e3Sopenharmony_ci
304514f5e3Sopenharmony_cinamespace panda::ecmascript::aarch64 {
314514f5e3Sopenharmony_ciusing Label = panda::ecmascript::Label;
324514f5e3Sopenharmony_ci#define __ assembler->
334514f5e3Sopenharmony_ci
344514f5e3Sopenharmony_ci// * uint64_t OptimizedFastCallEntry(uintptr_t glue, uint32_t actualNumArgs, const JSTaggedType argV[],
354514f5e3Sopenharmony_ci//                                   uintptr_t prevFp)
364514f5e3Sopenharmony_ci// * Arguments:
374514f5e3Sopenharmony_ci//        %x0 - glue
384514f5e3Sopenharmony_ci//        %x1 - actualNumArgs
394514f5e3Sopenharmony_ci//        %x2 - argV
404514f5e3Sopenharmony_ci//        %x3 - prevFp
414514f5e3Sopenharmony_civoid OptimizedFastCall::OptimizedFastCallEntry(ExtendedAssembler *assembler)
424514f5e3Sopenharmony_ci{
434514f5e3Sopenharmony_ci    __ BindAssemblerStub(RTSTUB_ID(OptimizedFastCallEntry));
444514f5e3Sopenharmony_ci    Register glueReg(X0);
454514f5e3Sopenharmony_ci    Register argc(X1);
464514f5e3Sopenharmony_ci    Register argV(X2);
474514f5e3Sopenharmony_ci    Register prevFpReg(X3);
484514f5e3Sopenharmony_ci    Register sp(SP);
494514f5e3Sopenharmony_ci
504514f5e3Sopenharmony_ci    OptimizedCall::PushJSFunctionEntryFrame (assembler, prevFpReg);
514514f5e3Sopenharmony_ci    __ Mov(Register(X3), argc);
524514f5e3Sopenharmony_ci    __ Mov(Register(X4), argV);
534514f5e3Sopenharmony_ci    Register tmpArgc(X3);
544514f5e3Sopenharmony_ci    Register tmpArgV(X4);
554514f5e3Sopenharmony_ci
564514f5e3Sopenharmony_ci    __ Mov(Register(X20), glueReg);
574514f5e3Sopenharmony_ci    __ Ldr(Register(X1), MemoryOperand(tmpArgV, 0));
584514f5e3Sopenharmony_ci    __ Ldr(Register(X2), MemoryOperand(tmpArgV, FRAME_SLOT_SIZE));
594514f5e3Sopenharmony_ci    __ Add(tmpArgV, tmpArgV, Immediate(DOUBLE_SLOT_SIZE));
604514f5e3Sopenharmony_ci
614514f5e3Sopenharmony_ci    __ CallAssemblerStub(RTSTUB_ID(JSFastCallWithArgV), false);
624514f5e3Sopenharmony_ci    __ Mov(Register(X2), Register(X20));
634514f5e3Sopenharmony_ci    OptimizedCall::PopJSFunctionEntryFrame(assembler, Register(X2));
644514f5e3Sopenharmony_ci    __ Ret();
654514f5e3Sopenharmony_ci}
664514f5e3Sopenharmony_ci
674514f5e3Sopenharmony_ci// * uint64_t OptimizedFastCallAndPushArgv(uintptr_t glue, uint32_t expectedNumArgs, uint32_t actualNumArgs,
684514f5e3Sopenharmony_ci//                                   uintptr_t codeAddr, uintptr_t argv)
694514f5e3Sopenharmony_ci// * Arguments wil CC calling convention:
704514f5e3Sopenharmony_ci//         %x0 - glue
714514f5e3Sopenharmony_ci//         %x1 - actualNumArgs
724514f5e3Sopenharmony_ci//         %x2 - actualArgv
734514f5e3Sopenharmony_ci//         %x3 - func
744514f5e3Sopenharmony_ci//         %x4  - new target
754514f5e3Sopenharmony_ci//         %x5  - this
764514f5e3Sopenharmony_ci//         %x6  - arg0
774514f5e3Sopenharmony_ci//         %x7  - arg1
784514f5e3Sopenharmony_ci//
794514f5e3Sopenharmony_ci// * The OptimizedJSFunctionArgsConfig Frame's structure is illustrated as the following:
804514f5e3Sopenharmony_ci//          +--------------------------+
814514f5e3Sopenharmony_ci//          |         arg[N-1]         |
824514f5e3Sopenharmony_ci//          +--------------------------+
834514f5e3Sopenharmony_ci//          |         . . . .          |
844514f5e3Sopenharmony_ci//          +--------------------------+
854514f5e3Sopenharmony_ci//          |         arg[0]           |
864514f5e3Sopenharmony_ci//          +--------------------------+
874514f5e3Sopenharmony_ci//          |         argC             |
884514f5e3Sopenharmony_ci//  sp ---> +--------------------------+ -----------------
894514f5e3Sopenharmony_ci//          |                          |                 ^
904514f5e3Sopenharmony_ci//          |        prevFP            |                 |
914514f5e3Sopenharmony_ci//          |--------------------------|    OptimizedJSFunctionArgsConfigFrame
924514f5e3Sopenharmony_ci//          |       frameType          |                 |
934514f5e3Sopenharmony_ci//          |                          |                 V
944514f5e3Sopenharmony_ci//          +--------------------------+ -----------------
954514f5e3Sopenharmony_civoid OptimizedFastCall::OptimizedFastCallAndPushArgv(ExtendedAssembler *assembler)
964514f5e3Sopenharmony_ci{
974514f5e3Sopenharmony_ci    __ BindAssemblerStub(RTSTUB_ID(OptimizedFastCallAndPushArgv));
984514f5e3Sopenharmony_ci    Register glue(X0);
994514f5e3Sopenharmony_ci    Register actualNumArgs(X1);
1004514f5e3Sopenharmony_ci    Register actualArgv(X2);
1014514f5e3Sopenharmony_ci    Register jsfunc(X3);
1024514f5e3Sopenharmony_ci    Register codeAddr(X4);
1034514f5e3Sopenharmony_ci    Register sp(SP);
1044514f5e3Sopenharmony_ci    Register currentSp = __ AvailableRegister1();
1054514f5e3Sopenharmony_ci    Register op = __ AvailableRegister1();
1064514f5e3Sopenharmony_ci    Label call;
1074514f5e3Sopenharmony_ci    Label arg4;
1084514f5e3Sopenharmony_ci    Label arg5;
1094514f5e3Sopenharmony_ci    Label arg6;
1104514f5e3Sopenharmony_ci    Label argc;
1114514f5e3Sopenharmony_ci    Label checkExpectedArgs;
1124514f5e3Sopenharmony_ci    Label pushUndefined;
1134514f5e3Sopenharmony_ci
1144514f5e3Sopenharmony_ci    // construct frame
1154514f5e3Sopenharmony_ci    OptimizedCall::PushOptimizedArgsConfigFrame(assembler);
1164514f5e3Sopenharmony_ci
1174514f5e3Sopenharmony_ci    __ Mov(__ AvailableRegister3(), Register(X1));
1184514f5e3Sopenharmony_ci    __ Add(__ AvailableRegister4(), sp, Immediate(4 * FRAME_SLOT_SIZE)); // 4 skip fp lr type x19
1194514f5e3Sopenharmony_ci    Register actualNumArgsReg = __ AvailableRegister3();
1204514f5e3Sopenharmony_ci    Register argV = __ AvailableRegister4();
1214514f5e3Sopenharmony_ci
1224514f5e3Sopenharmony_ci    Register method = __ AvailableRegister1();
1234514f5e3Sopenharmony_ci    Register expectedNumArgs = __ AvailableRegister2();
1244514f5e3Sopenharmony_ci    __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
1254514f5e3Sopenharmony_ci    __ Ldr(expectedNumArgs, MemoryOperand(method, Method::CALL_FIELD_OFFSET));
1264514f5e3Sopenharmony_ci    __ Lsr(expectedNumArgs, expectedNumArgs, MethodLiteral::NumArgsBits::START_BIT);
1274514f5e3Sopenharmony_ci    __ And(expectedNumArgs, expectedNumArgs,
1284514f5e3Sopenharmony_ci        LogicalImmediate::Create(
1294514f5e3Sopenharmony_ci            MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegXSize));
1304514f5e3Sopenharmony_ci    __ Add(expectedNumArgs, expectedNumArgs, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
1314514f5e3Sopenharmony_ci
1324514f5e3Sopenharmony_ci    Label arg7;
1334514f5e3Sopenharmony_ci    Label arg8;
1344514f5e3Sopenharmony_ci    __ Mov(Register(X1), Register(X3)); // func move to argc
1354514f5e3Sopenharmony_ci    __ Mov(Register(X2), Register(X5)); // this move to func
1364514f5e3Sopenharmony_ci    jsfunc = Register(X1);
1374514f5e3Sopenharmony_ci
1384514f5e3Sopenharmony_ci    __ Cmp(actualNumArgsReg, Immediate(3)); // 3: 3 args
1394514f5e3Sopenharmony_ci    __ B(Condition::NE, &arg4);
1404514f5e3Sopenharmony_ci    __ Mov(Register(X3), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1414514f5e3Sopenharmony_ci    __ Mov(Register(X4), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1424514f5e3Sopenharmony_ci    __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1434514f5e3Sopenharmony_ci    __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1444514f5e3Sopenharmony_ci    __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1454514f5e3Sopenharmony_ci    __ B(&checkExpectedArgs);
1464514f5e3Sopenharmony_ci
1474514f5e3Sopenharmony_ci    __ Bind(&arg4);
1484514f5e3Sopenharmony_ci    {
1494514f5e3Sopenharmony_ci        __ Mov(Register(X3), Register(X6));
1504514f5e3Sopenharmony_ci        __ Cmp(actualNumArgsReg, Immediate(4)); // 4: 4 args
1514514f5e3Sopenharmony_ci        __ B(Condition::NE, &arg5);
1524514f5e3Sopenharmony_ci        __ Mov(Register(X4), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1534514f5e3Sopenharmony_ci        __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1544514f5e3Sopenharmony_ci        __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1554514f5e3Sopenharmony_ci        __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1564514f5e3Sopenharmony_ci        __ B(&checkExpectedArgs);
1574514f5e3Sopenharmony_ci    }
1584514f5e3Sopenharmony_ci
1594514f5e3Sopenharmony_ci    __ Bind(&arg5);
1604514f5e3Sopenharmony_ci    {
1614514f5e3Sopenharmony_ci        __ Mov(Register(X4), Register(X7));
1624514f5e3Sopenharmony_ci        __ Cmp(actualNumArgsReg, Immediate(5)); // 5: 5 args
1634514f5e3Sopenharmony_ci        __ B(Condition::NE, &arg6);
1644514f5e3Sopenharmony_ci        __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1654514f5e3Sopenharmony_ci        __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1664514f5e3Sopenharmony_ci        __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1674514f5e3Sopenharmony_ci        __ B(&checkExpectedArgs);
1684514f5e3Sopenharmony_ci    }
1694514f5e3Sopenharmony_ci
1704514f5e3Sopenharmony_ci    __ Bind(&arg6);
1714514f5e3Sopenharmony_ci    {
1724514f5e3Sopenharmony_ci        __ Ldr(op, MemoryOperand(argV, 0));
1734514f5e3Sopenharmony_ci        __ Mov(Register(X5), op);
1744514f5e3Sopenharmony_ci        __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
1754514f5e3Sopenharmony_ci        __ Cmp(actualNumArgsReg, Immediate(6)); // 6: 6 args
1764514f5e3Sopenharmony_ci        __ B(Condition::NE, &arg7);
1774514f5e3Sopenharmony_ci        __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1784514f5e3Sopenharmony_ci        __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1794514f5e3Sopenharmony_ci        __ B(&checkExpectedArgs);
1804514f5e3Sopenharmony_ci    }
1814514f5e3Sopenharmony_ci
1824514f5e3Sopenharmony_ci    __ Bind(&arg7);
1834514f5e3Sopenharmony_ci    {
1844514f5e3Sopenharmony_ci        __ Ldr(op, MemoryOperand(argV, 0));
1854514f5e3Sopenharmony_ci        __ Mov(Register(X6), op);
1864514f5e3Sopenharmony_ci        __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
1874514f5e3Sopenharmony_ci        __ Cmp(actualNumArgsReg, Immediate(7)); // 7: 7 args
1884514f5e3Sopenharmony_ci        __ B(Condition::NE, &arg8);
1894514f5e3Sopenharmony_ci        __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1904514f5e3Sopenharmony_ci        __ B(&checkExpectedArgs);
1914514f5e3Sopenharmony_ci    }
1924514f5e3Sopenharmony_ci
1934514f5e3Sopenharmony_ci    __ Bind(&arg8);
1944514f5e3Sopenharmony_ci    {
1954514f5e3Sopenharmony_ci        __ Ldr(op, MemoryOperand(argV, 0));
1964514f5e3Sopenharmony_ci        __ Mov(Register(X7), op);
1974514f5e3Sopenharmony_ci        __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
1984514f5e3Sopenharmony_ci        __ Cmp(actualNumArgsReg, Immediate(8)); // 8: 8 args
1994514f5e3Sopenharmony_ci        __ B(Condition::NE, &argc);
2004514f5e3Sopenharmony_ci        __ B(&checkExpectedArgs);
2014514f5e3Sopenharmony_ci    }
2024514f5e3Sopenharmony_ci
2034514f5e3Sopenharmony_ci    __ Bind(&argc);
2044514f5e3Sopenharmony_ci    {
2054514f5e3Sopenharmony_ci        TempRegister1Scope scope1(assembler);
2064514f5e3Sopenharmony_ci        TempRegister2Scope scope2(assembler);
2074514f5e3Sopenharmony_ci        Register tmp = __ TempRegister1();
2084514f5e3Sopenharmony_ci        Register undefinedValue = __ TempRegister2();
2094514f5e3Sopenharmony_ci
2104514f5e3Sopenharmony_ci        __ Cmp(expectedNumArgs, actualNumArgsReg);
2114514f5e3Sopenharmony_ci        __ B(Condition::GT, &pushUndefined);
2124514f5e3Sopenharmony_ci        __ Sub(expectedNumArgs, expectedNumArgs, Immediate(8)); // 8 : register save 8 arg
2134514f5e3Sopenharmony_ci        __ Sub(actualNumArgsReg, actualNumArgsReg, Immediate(8)); // 8 : register save 8 arg
2144514f5e3Sopenharmony_ci        OptimizedCall::IncreaseStackForArguments(assembler, actualNumArgsReg, currentSp);
2154514f5e3Sopenharmony_ci        PushArgsWithArgv(assembler, glue, actualNumArgsReg, argV, undefinedValue, currentSp, nullptr, nullptr);
2164514f5e3Sopenharmony_ci        __ B(&call);
2174514f5e3Sopenharmony_ci
2184514f5e3Sopenharmony_ci        __ Bind(&pushUndefined);
2194514f5e3Sopenharmony_ci        __ Sub(expectedNumArgs, expectedNumArgs, Immediate(8)); // 8 : register save 8 arg
2204514f5e3Sopenharmony_ci        __ Sub(actualNumArgsReg, actualNumArgsReg, Immediate(8)); // 8 : register save 8 arg
2214514f5e3Sopenharmony_ci        OptimizedCall::IncreaseStackForArguments(assembler, expectedNumArgs, currentSp);
2224514f5e3Sopenharmony_ci        __ Sub(tmp, expectedNumArgs, actualNumArgsReg);
2234514f5e3Sopenharmony_ci        PushUndefinedWithArgc(assembler, glue, tmp, undefinedValue, currentSp, nullptr, nullptr);
2244514f5e3Sopenharmony_ci        PushArgsWithArgv(assembler, glue, actualNumArgsReg, argV, undefinedValue, currentSp, nullptr, nullptr);
2254514f5e3Sopenharmony_ci        __ B(&call);
2264514f5e3Sopenharmony_ci    }
2274514f5e3Sopenharmony_ci
2284514f5e3Sopenharmony_ci    __ Bind(&checkExpectedArgs);
2294514f5e3Sopenharmony_ci    {
2304514f5e3Sopenharmony_ci        __ Cmp(expectedNumArgs, Immediate(8)); // 8 : register save 8 arg
2314514f5e3Sopenharmony_ci        __ B(Condition::LS, &call);
2324514f5e3Sopenharmony_ci        __ Sub(expectedNumArgs, expectedNumArgs, Immediate(8)); // 8 : register save 8 arg
2334514f5e3Sopenharmony_ci        OptimizedCall::IncreaseStackForArguments(assembler, expectedNumArgs, currentSp);
2344514f5e3Sopenharmony_ci        TempRegister2Scope scope2(assembler);
2354514f5e3Sopenharmony_ci        Register undefinedValue = __ TempRegister2();
2364514f5e3Sopenharmony_ci        PushUndefinedWithArgc(assembler, glue, expectedNumArgs, undefinedValue, currentSp, nullptr, nullptr);
2374514f5e3Sopenharmony_ci        __ B(&call);
2384514f5e3Sopenharmony_ci    }
2394514f5e3Sopenharmony_ci    __ Bind(&call);
2404514f5e3Sopenharmony_ci    TempRegister1Scope scope1(assembler);
2414514f5e3Sopenharmony_ci    Register method1 = __ TempRegister1();
2424514f5e3Sopenharmony_ci    __ Ldr(method1, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
2434514f5e3Sopenharmony_ci    __ Ldr(X11, MemoryOperand(jsfunc, JSFunction::CODE_ENTRY_OFFSET));
2444514f5e3Sopenharmony_ci    __ Blr(X11);
2454514f5e3Sopenharmony_ci
2464514f5e3Sopenharmony_ci    __ Mov(Register(SP), Register(FP));
2474514f5e3Sopenharmony_ci    __ RestoreFpAndLr();
2484514f5e3Sopenharmony_ci    __ Ret();
2494514f5e3Sopenharmony_ci}
2504514f5e3Sopenharmony_ci
2514514f5e3Sopenharmony_ci// * uint64_t JSFastCallWithArgV(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
2524514f5e3Sopenharmony_ci//                                JSTaggedType this, argV)
2534514f5e3Sopenharmony_ci// * cc calling convention call js function()
2544514f5e3Sopenharmony_ci// * arguments:
2554514f5e3Sopenharmony_ci//              %x0 - glue
2564514f5e3Sopenharmony_ci//              %x1 - call-target
2574514f5e3Sopenharmony_ci//              %x2 - this
2584514f5e3Sopenharmony_ci//              %x3 - artual argc
2594514f5e3Sopenharmony_ci//              %x4 - argv
2604514f5e3Sopenharmony_civoid OptimizedFastCall::JSFastCallWithArgV(ExtendedAssembler *assembler)
2614514f5e3Sopenharmony_ci{
2624514f5e3Sopenharmony_ci    __ BindAssemblerStub(RTSTUB_ID(JSFastCallWithArgV));
2634514f5e3Sopenharmony_ci    Register sp(SP);
2644514f5e3Sopenharmony_ci    Register glue(X0);
2654514f5e3Sopenharmony_ci    Register actualNumArgs(X3);
2664514f5e3Sopenharmony_ci    Register jsfunc(X1);
2674514f5e3Sopenharmony_ci    Register thisObj(X2);
2684514f5e3Sopenharmony_ci    Register currentSp = __ AvailableRegister1();
2694514f5e3Sopenharmony_ci    Register callsiteSp = __ AvailableRegister2();
2704514f5e3Sopenharmony_ci    Label call;
2714514f5e3Sopenharmony_ci    __ Mov(callsiteSp, sp);
2724514f5e3Sopenharmony_ci    OptimizedCall::PushOptimizedUnfoldArgVFrame(assembler, callsiteSp);
2734514f5e3Sopenharmony_ci    TempRegister2Scope scope2(assembler);
2744514f5e3Sopenharmony_ci    Register op = __ TempRegister2();
2754514f5e3Sopenharmony_ci    Register argC = __ AvailableRegister3();
2764514f5e3Sopenharmony_ci    Register argV = __ AvailableRegister4();
2774514f5e3Sopenharmony_ci    __ Mov(argC, actualNumArgs);
2784514f5e3Sopenharmony_ci    __ Mov(argV, Register(X4));
2794514f5e3Sopenharmony_ci
2804514f5e3Sopenharmony_ci    __ Cmp(argC, Immediate(0));
2814514f5e3Sopenharmony_ci    __ B(Condition::EQ, &call);
2824514f5e3Sopenharmony_ci    __ Ldr(op, MemoryOperand(argV, 0));
2834514f5e3Sopenharmony_ci    __ Mov(Register(X3), op); // first arg
2844514f5e3Sopenharmony_ci    __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
2854514f5e3Sopenharmony_ci    __ Sub(argC, argC, Immediate(1));
2864514f5e3Sopenharmony_ci
2874514f5e3Sopenharmony_ci    __ Cmp(argC, Immediate(0));
2884514f5e3Sopenharmony_ci    __ B(Condition::EQ, &call);
2894514f5e3Sopenharmony_ci    __ Ldr(op, MemoryOperand(argV, 0));
2904514f5e3Sopenharmony_ci    __ Mov(Register(X4), op); // second arg
2914514f5e3Sopenharmony_ci    __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
2924514f5e3Sopenharmony_ci    __ Sub(argC, argC, Immediate(1));
2934514f5e3Sopenharmony_ci
2944514f5e3Sopenharmony_ci    __ Cmp(argC, Immediate(0));
2954514f5e3Sopenharmony_ci    __ B(Condition::EQ, &call);
2964514f5e3Sopenharmony_ci    __ Ldr(op, MemoryOperand(argV, 0));
2974514f5e3Sopenharmony_ci    __ Mov(Register(X5), op); // third arg
2984514f5e3Sopenharmony_ci    __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
2994514f5e3Sopenharmony_ci    __ Sub(argC, argC, Immediate(1));
3004514f5e3Sopenharmony_ci
3014514f5e3Sopenharmony_ci    __ Cmp(argC, Immediate(0));
3024514f5e3Sopenharmony_ci    __ B(Condition::EQ, &call);
3034514f5e3Sopenharmony_ci    __ Ldr(op, MemoryOperand(argV, 0));
3044514f5e3Sopenharmony_ci    __ Mov(Register(X6), op);
3054514f5e3Sopenharmony_ci    __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
3064514f5e3Sopenharmony_ci    __ Sub(argC, argC, Immediate(1));
3074514f5e3Sopenharmony_ci
3084514f5e3Sopenharmony_ci    __ Cmp(argC, Immediate(0));
3094514f5e3Sopenharmony_ci    __ B(Condition::EQ, &call);
3104514f5e3Sopenharmony_ci    __ Ldr(op, MemoryOperand(argV, 0));
3114514f5e3Sopenharmony_ci    __ Mov(Register(X7), op);
3124514f5e3Sopenharmony_ci    __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
3134514f5e3Sopenharmony_ci    __ Sub(argC, argC, Immediate(1));
3144514f5e3Sopenharmony_ci
3154514f5e3Sopenharmony_ci    __ Cmp(argC, Immediate(0));
3164514f5e3Sopenharmony_ci    __ B(Condition::EQ, &call);
3174514f5e3Sopenharmony_ci    OptimizedCall::IncreaseStackForArguments(assembler, argC, currentSp);
3184514f5e3Sopenharmony_ci    PushArgsWithArgv(assembler, glue, argC, argV, op, currentSp, nullptr, nullptr);
3194514f5e3Sopenharmony_ci
3204514f5e3Sopenharmony_ci    __ Bind(&call);
3214514f5e3Sopenharmony_ci    TempRegister1Scope scope1(assembler);
3224514f5e3Sopenharmony_ci    Register method = __ TempRegister1();
3234514f5e3Sopenharmony_ci    __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET));
3244514f5e3Sopenharmony_ci    __ Ldr(X11, MemoryOperand(jsfunc, JSFunctionBase::CODE_ENTRY_OFFSET));
3254514f5e3Sopenharmony_ci    __ Blr(X11);
3264514f5e3Sopenharmony_ci
3274514f5e3Sopenharmony_ci    __ Mov(Register(SP), Register(FP));
3284514f5e3Sopenharmony_ci    __ RestoreFpAndLr();
3294514f5e3Sopenharmony_ci    __ Ret();
3304514f5e3Sopenharmony_ci}
3314514f5e3Sopenharmony_ci
3324514f5e3Sopenharmony_ci// * Arguments:
3334514f5e3Sopenharmony_ci//        %x0 - glue
3344514f5e3Sopenharmony_ci//        %x1 - func
3354514f5e3Sopenharmony_ci//        %x2 - this
3364514f5e3Sopenharmony_ci//        %x3 - actualNumArgs
3374514f5e3Sopenharmony_ci//        %x4 -  argv
3384514f5e3Sopenharmony_ci//        %x5 -  expectedNumArgs
3394514f5e3Sopenharmony_civoid OptimizedFastCall::JSFastCallWithArgVAndPushArgv(ExtendedAssembler *assembler)
3404514f5e3Sopenharmony_ci{
3414514f5e3Sopenharmony_ci    __ BindAssemblerStub(RTSTUB_ID(JSFastCallWithArgVAndPushArgv));
3424514f5e3Sopenharmony_ci    Register sp(SP);
3434514f5e3Sopenharmony_ci    Register glue(X0);
3444514f5e3Sopenharmony_ci    Register jsfunc(X1);
3454514f5e3Sopenharmony_ci    Register thisObj(X2);
3464514f5e3Sopenharmony_ci    Register currentSp = __ AvailableRegister1();
3474514f5e3Sopenharmony_ci    Register op = __ AvailableRegister1();
3484514f5e3Sopenharmony_ci    Register callsiteSp = __ AvailableRegister2();
3494514f5e3Sopenharmony_ci    Label call;
3504514f5e3Sopenharmony_ci    Label arg1;
3514514f5e3Sopenharmony_ci    Label arg2;
3524514f5e3Sopenharmony_ci    Label arg3;
3534514f5e3Sopenharmony_ci    Label arg4;
3544514f5e3Sopenharmony_ci    Label arg5;
3554514f5e3Sopenharmony_ci    Label argc;
3564514f5e3Sopenharmony_ci    Label checkExpectedArgs;
3574514f5e3Sopenharmony_ci    Label pushUndefined;
3584514f5e3Sopenharmony_ci    __ Mov(callsiteSp, sp);
3594514f5e3Sopenharmony_ci    OptimizedCall::PushOptimizedUnfoldArgVFrame(assembler, callsiteSp);
3604514f5e3Sopenharmony_ci    Register actualNumArgsReg = __ AvailableRegister3();
3614514f5e3Sopenharmony_ci    Register argV = __ AvailableRegister4();
3624514f5e3Sopenharmony_ci    Register expectedNumArgs = __ AvailableRegister2();
3634514f5e3Sopenharmony_ci    __ Mov(actualNumArgsReg, Register(X3));
3644514f5e3Sopenharmony_ci    __ Mov(argV, Register(X4));
3654514f5e3Sopenharmony_ci    __ Mov(expectedNumArgs, Register(X5));
3664514f5e3Sopenharmony_ci
3674514f5e3Sopenharmony_ci    __ Cmp(actualNumArgsReg, Immediate(0));
3684514f5e3Sopenharmony_ci    __ B(Condition::NE, &arg1);
3694514f5e3Sopenharmony_ci    __ Mov(Register(X3), Immediate(JSTaggedValue::VALUE_UNDEFINED));
3704514f5e3Sopenharmony_ci    __ Mov(Register(X4), Immediate(JSTaggedValue::VALUE_UNDEFINED));
3714514f5e3Sopenharmony_ci    __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED));
3724514f5e3Sopenharmony_ci    __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
3734514f5e3Sopenharmony_ci    __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
3744514f5e3Sopenharmony_ci    __ B(&checkExpectedArgs);
3754514f5e3Sopenharmony_ci
3764514f5e3Sopenharmony_ci    __ Bind(&arg1);
3774514f5e3Sopenharmony_ci    {
3784514f5e3Sopenharmony_ci        __ Ldr(op, MemoryOperand(argV, 0));
3794514f5e3Sopenharmony_ci        __ Mov(Register(X3), op);
3804514f5e3Sopenharmony_ci        __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
3814514f5e3Sopenharmony_ci        __ Cmp(actualNumArgsReg, Immediate(1));
3824514f5e3Sopenharmony_ci        __ B(Condition::NE, &arg2);
3834514f5e3Sopenharmony_ci        __ Mov(Register(X4), Immediate(JSTaggedValue::VALUE_UNDEFINED));
3844514f5e3Sopenharmony_ci        __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED));
3854514f5e3Sopenharmony_ci        __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
3864514f5e3Sopenharmony_ci        __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
3874514f5e3Sopenharmony_ci        __ B(&checkExpectedArgs);
3884514f5e3Sopenharmony_ci    }
3894514f5e3Sopenharmony_ci
3904514f5e3Sopenharmony_ci    __ Bind(&arg2);
3914514f5e3Sopenharmony_ci    {
3924514f5e3Sopenharmony_ci        __ Ldr(op, MemoryOperand(argV, 0));
3934514f5e3Sopenharmony_ci        __ Mov(Register(X4), op);
3944514f5e3Sopenharmony_ci        __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
3954514f5e3Sopenharmony_ci        __ Cmp(actualNumArgsReg, Immediate(2)); // 2: 2 args
3964514f5e3Sopenharmony_ci        __ B(Condition::NE, &arg3);
3974514f5e3Sopenharmony_ci        __ Mov(Register(X5), Immediate(JSTaggedValue::VALUE_UNDEFINED));
3984514f5e3Sopenharmony_ci        __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
3994514f5e3Sopenharmony_ci        __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
4004514f5e3Sopenharmony_ci        __ B(&checkExpectedArgs);
4014514f5e3Sopenharmony_ci    }
4024514f5e3Sopenharmony_ci
4034514f5e3Sopenharmony_ci    __ Bind(&arg3);
4044514f5e3Sopenharmony_ci    {
4054514f5e3Sopenharmony_ci        __ Ldr(op, MemoryOperand(argV, 0));
4064514f5e3Sopenharmony_ci        __ Mov(Register(X5), op);
4074514f5e3Sopenharmony_ci        __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
4084514f5e3Sopenharmony_ci        __ Cmp(actualNumArgsReg, Immediate(3)); // 3: 3 args
4094514f5e3Sopenharmony_ci        __ B(Condition::NE, &arg4);
4104514f5e3Sopenharmony_ci        __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
4114514f5e3Sopenharmony_ci        __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
4124514f5e3Sopenharmony_ci        __ B(&checkExpectedArgs);
4134514f5e3Sopenharmony_ci    }
4144514f5e3Sopenharmony_ci
4154514f5e3Sopenharmony_ci    __ Bind(&arg4);
4164514f5e3Sopenharmony_ci    {
4174514f5e3Sopenharmony_ci        __ Ldr(op, MemoryOperand(argV, 0));
4184514f5e3Sopenharmony_ci        __ Mov(Register(X6), op);
4194514f5e3Sopenharmony_ci        __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
4204514f5e3Sopenharmony_ci        __ Cmp(actualNumArgsReg, Immediate(4)); // 4: 4 args
4214514f5e3Sopenharmony_ci        __ B(Condition::NE, &arg5);
4224514f5e3Sopenharmony_ci        __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
4234514f5e3Sopenharmony_ci        __ B(&checkExpectedArgs);
4244514f5e3Sopenharmony_ci    }
4254514f5e3Sopenharmony_ci
4264514f5e3Sopenharmony_ci    __ Bind(&arg5);
4274514f5e3Sopenharmony_ci    {
4284514f5e3Sopenharmony_ci        __ Ldr(op, MemoryOperand(argV, 0));
4294514f5e3Sopenharmony_ci        __ Mov(Register(X7), op);
4304514f5e3Sopenharmony_ci        __ Add(argV, argV, Immediate(FRAME_SLOT_SIZE));
4314514f5e3Sopenharmony_ci        __ Cmp(actualNumArgsReg, Immediate(5)); // 5: 5 args
4324514f5e3Sopenharmony_ci        __ B(Condition::NE, &argc);
4334514f5e3Sopenharmony_ci        __ B(&checkExpectedArgs);
4344514f5e3Sopenharmony_ci    }
4354514f5e3Sopenharmony_ci
4364514f5e3Sopenharmony_ci    __ Bind(&argc);
4374514f5e3Sopenharmony_ci    {
4384514f5e3Sopenharmony_ci        TempRegister1Scope scope1(assembler);
4394514f5e3Sopenharmony_ci        TempRegister2Scope scope2(assembler);
4404514f5e3Sopenharmony_ci        Register tmp = __ TempRegister1();
4414514f5e3Sopenharmony_ci        Register undefinedValue = __ TempRegister2();
4424514f5e3Sopenharmony_ci
4434514f5e3Sopenharmony_ci        __ Cmp(expectedNumArgs, actualNumArgsReg);
4444514f5e3Sopenharmony_ci        __ B(Condition::GT, &pushUndefined);
4454514f5e3Sopenharmony_ci        __ Sub(expectedNumArgs, expectedNumArgs, Immediate(5)); // 5 : register save 5 arg
4464514f5e3Sopenharmony_ci        __ Sub(actualNumArgsReg, actualNumArgsReg, Immediate(5)); // 5 : register save 5 arg
4474514f5e3Sopenharmony_ci        OptimizedCall::IncreaseStackForArguments(assembler, actualNumArgsReg, currentSp);
4484514f5e3Sopenharmony_ci        PushArgsWithArgv(assembler, glue, actualNumArgsReg, argV, undefinedValue, currentSp, nullptr, nullptr);
4494514f5e3Sopenharmony_ci        __ B(&call);
4504514f5e3Sopenharmony_ci
4514514f5e3Sopenharmony_ci        __ Bind(&pushUndefined);
4524514f5e3Sopenharmony_ci        __ Sub(expectedNumArgs, expectedNumArgs, Immediate(5)); // 5 : register save 5 arg
4534514f5e3Sopenharmony_ci        __ Sub(actualNumArgsReg, actualNumArgsReg, Immediate(5)); // 5 : register save 5 arg
4544514f5e3Sopenharmony_ci        OptimizedCall::IncreaseStackForArguments(assembler, expectedNumArgs, currentSp);
4554514f5e3Sopenharmony_ci        __ Sub(tmp, expectedNumArgs, actualNumArgsReg);
4564514f5e3Sopenharmony_ci        PushUndefinedWithArgc(assembler, glue, tmp, undefinedValue, currentSp, nullptr, nullptr);
4574514f5e3Sopenharmony_ci        PushArgsWithArgv(assembler, glue, actualNumArgsReg, argV, undefinedValue, currentSp, nullptr, nullptr);
4584514f5e3Sopenharmony_ci        __ B(&call);
4594514f5e3Sopenharmony_ci    }
4604514f5e3Sopenharmony_ci
4614514f5e3Sopenharmony_ci    __ Bind(&checkExpectedArgs);
4624514f5e3Sopenharmony_ci    {
4634514f5e3Sopenharmony_ci        __ Cmp(expectedNumArgs, Immediate(5)); // 5 : register save 5 arg
4644514f5e3Sopenharmony_ci        __ B(Condition::LS, &call);
4654514f5e3Sopenharmony_ci        __ Sub(expectedNumArgs, expectedNumArgs, Immediate(5)); // 5 : register save 5 arg
4664514f5e3Sopenharmony_ci        OptimizedCall::IncreaseStackForArguments(assembler, expectedNumArgs, currentSp);
4674514f5e3Sopenharmony_ci        TempRegister2Scope scope2(assembler);
4684514f5e3Sopenharmony_ci        Register undefinedValue = __ TempRegister2();
4694514f5e3Sopenharmony_ci        PushUndefinedWithArgc(assembler, glue, expectedNumArgs, undefinedValue, currentSp, nullptr, nullptr);
4704514f5e3Sopenharmony_ci        __ B(&call);
4714514f5e3Sopenharmony_ci    }
4724514f5e3Sopenharmony_ci
4734514f5e3Sopenharmony_ci    __ Bind(&call);
4744514f5e3Sopenharmony_ci    TempRegister1Scope scope1(assembler);
4754514f5e3Sopenharmony_ci    Register method = __ TempRegister1();
4764514f5e3Sopenharmony_ci    __ Ldr(method, MemoryOperand(X1, JSFunction::METHOD_OFFSET));
4774514f5e3Sopenharmony_ci    __ Ldr(X11, MemoryOperand(X1, JSFunction::CODE_ENTRY_OFFSET));
4784514f5e3Sopenharmony_ci    __ Blr(X11);
4794514f5e3Sopenharmony_ci
4804514f5e3Sopenharmony_ci    __ Mov(Register(SP), Register(FP));
4814514f5e3Sopenharmony_ci    __ RestoreFpAndLr();
4824514f5e3Sopenharmony_ci    __ Ret();
4834514f5e3Sopenharmony_ci}
4844514f5e3Sopenharmony_ci#undef __
4854514f5e3Sopenharmony_ci}  // panda::ecmascript::aarch64