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/ecma_runtime_call_info.h"
22#include "ecmascript/frames.h"
23#include "ecmascript/js_function.h"
24#include "ecmascript/mem/machine_code.h"
25#include "ecmascript/method.h"
26#include "ecmascript/js_thread.h"
27#include "ecmascript/js_generator_object.h"
28#include "ecmascript/message_string.h"
29#include "ecmascript/runtime_call_id.h"
30
31namespace panda::ecmascript::aarch64 {
32using Label = panda::ecmascript::Label;
33#define __ assembler->
34
35// Generate code for entering asm interpreter
36// c++ calling convention
37// Input: glue           - %X0
38//        callTarget     - %X1
39//        method         - %X2
40//        callField      - %X3
41//        argc           - %X4
42//        argv           - %X5(<callTarget, newTarget, this> are at the beginning of argv)
43void AsmInterpreterCall::AsmInterpreterEntry(ExtendedAssembler *assembler)
44{
45    __ BindAssemblerStub(RTSTUB_ID(AsmInterpreterEntry));
46    Label target;
47    size_t begin = __ GetCurrentPosition();
48    PushAsmInterpEntryFrame(assembler);
49    __ Bl(&target);
50    PopAsmInterpEntryFrame(assembler);
51    size_t end = __ GetCurrentPosition();
52    if ((end - begin) != FrameCompletionPos::ARM64EntryFrameDuration) {
53        LOG_COMPILER(FATAL) << (end - begin) << " != " << FrameCompletionPos::ARM64EntryFrameDuration
54                            << "This frame has been modified, and the offset EntryFrameDuration should be updated too.";
55    }
56    __ Ret();
57
58    __ Bind(&target);
59    {
60        AsmInterpEntryDispatch(assembler);
61    }
62}
63
64// Input: glue           - %X0
65//        callTarget     - %X1
66//        method         - %X2
67//        callField      - %X3
68//        argc           - %X4
69//        argv           - %X5(<callTarget, newTarget, this> are at the beginning of argv)
70void AsmInterpreterCall::AsmInterpEntryDispatch(ExtendedAssembler *assembler)
71{
72    Label notJSFunction;
73    Label callNativeEntry;
74    Label callJSFunctionEntry;
75    Label notCallable;
76    Register glueRegister(X0);
77    Register argcRegister(X4, W);
78    Register argvRegister(X5);
79    Register callTargetRegister(X1);
80    Register callFieldRegister(X3);
81    Register bitFieldRegister(X16);
82    Register tempRegister(X17); // can not be used to store any variable
83    Register functionTypeRegister(X18, W);
84    __ Ldr(tempRegister, MemoryOperand(callTargetRegister, TaggedObject::HCLASS_OFFSET));
85    __ Ldr(bitFieldRegister, MemoryOperand(tempRegister, JSHClass::BIT_FIELD_OFFSET));
86    __ And(functionTypeRegister, bitFieldRegister.W(), LogicalImmediate::Create(0xFF, RegWSize));
87    __ Mov(tempRegister.W(), Immediate(static_cast<int64_t>(JSType::JS_FUNCTION_FIRST)));
88    __ Cmp(functionTypeRegister, tempRegister.W());
89    __ B(Condition::LO, &notJSFunction);
90    __ Mov(tempRegister.W(), Immediate(static_cast<int64_t>(JSType::JS_FUNCTION_LAST)));
91    __ Cmp(functionTypeRegister, tempRegister.W());
92    __ B(Condition::LS, &callJSFunctionEntry);
93    __ Bind(&notJSFunction);
94    {
95        __ Tst(bitFieldRegister,
96            LogicalImmediate::Create(static_cast<int64_t>(1ULL << JSHClass::CallableBit::START_BIT), RegXSize));
97        __ B(Condition::EQ, &notCallable);
98        // fall through
99    }
100    __ Bind(&callNativeEntry);
101    CallNativeEntry(assembler);
102    __ Bind(&callJSFunctionEntry);
103    {
104        __ Tbnz(callFieldRegister, MethodLiteral::IsNativeBit::START_BIT, &callNativeEntry);
105        // fast path
106        __ Add(argvRegister, argvRegister, Immediate(NUM_MANDATORY_JSFUNC_ARGS * JSTaggedValue::TaggedTypeSize()));
107        JSCallCommonEntry(assembler, JSCallMode::CALL_ENTRY, FrameTransitionType::OTHER_TO_BASELINE_CHECK);
108    }
109    __ Bind(&notCallable);
110    {
111        Register runtimeId(X11);
112        Register trampoline(X12);
113        __ Mov(runtimeId, Immediate(kungfu::RuntimeStubCSigns::ID_ThrowNotCallableException));
114        // 3 : 3 means *8
115        __ Add(trampoline, glueRegister, Operand(runtimeId, LSL, 3));
116        __ Ldr(trampoline, MemoryOperand(trampoline, JSThread::GlueData::GetRTStubEntriesOffset(false)));
117        __ Blr(trampoline);
118        __ Ret();
119    }
120}
121
122void AsmInterpreterCall::JSCallCommonEntry(ExtendedAssembler *assembler,
123    JSCallMode mode, FrameTransitionType type)
124{
125    Label stackOverflow;
126    Register glueRegister = __ GlueRegister();
127    Register fpRegister = __ AvailableRegister1();
128    Register currentSlotRegister = __ AvailableRegister3();
129    Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
130    Register argcRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARGC);
131    if (!kungfu::AssemblerModule::IsJumpToCallCommonEntry(mode) || type == FrameTransitionType::BASELINE_TO_OTHER ||
132        type == FrameTransitionType::BASELINE_TO_BASELINE_CHECK) {
133        __ PushFpAndLr();
134    }
135    // save fp
136    __ Mov(fpRegister, Register(SP));
137    __ Mov(currentSlotRegister, Register(SP));
138
139    {
140        // Reserve enough sp space to prevent stack parameters from being covered by cpu profiler.
141        [[maybe_unused]] TempRegister1Scope scope(assembler);
142        Register tempRegister = __ TempRegister1();
143        __ Ldr(tempRegister, MemoryOperand(glueRegister, JSThread::GlueData::GetStackLimitOffset(false)));
144        __ Mov(Register(SP), tempRegister);
145    }
146
147    Register declaredNumArgsRegister = __ AvailableRegister2();
148    GetDeclaredNumArgsFromCallField(assembler, callFieldRegister, declaredNumArgsRegister);
149
150    Label slowPathEntry;
151    Label fastPathEntry;
152    Label pushCallThis;
153    auto argc = kungfu::AssemblerModule::GetArgcFromJSCallMode(mode);
154    if (argc >= 0) {
155        __ Cmp(declaredNumArgsRegister, Immediate(argc));
156    } else {
157        __ Cmp(declaredNumArgsRegister, argcRegister);
158    }
159    __ B(Condition::NE, &slowPathEntry);
160    __ Bind(&fastPathEntry);
161    JSCallCommonFastPath(assembler, mode, &pushCallThis, &stackOverflow);
162    __ Bind(&pushCallThis);
163    PushCallThis(assembler, mode, &stackOverflow, type);
164    __ Bind(&slowPathEntry);
165    JSCallCommonSlowPath(assembler, mode, &fastPathEntry, &pushCallThis, &stackOverflow);
166
167    __ Bind(&stackOverflow);
168    if (kungfu::AssemblerModule::IsJumpToCallCommonEntry(mode)) {
169        __ Mov(Register(SP), fpRegister);
170        [[maybe_unused]] TempRegister1Scope scope(assembler);
171        Register temp = __ TempRegister1();
172        // only glue and acc are useful in exception handler
173        if (glueRegister.GetId() != X19) {
174            __ Mov(Register(X19), glueRegister);
175        }
176        Register acc(X23);
177        __ Mov(acc, Immediate(JSTaggedValue::VALUE_EXCEPTION));
178        Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
179        Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
180        // Reload pc to make sure stack trace is right
181        __ Mov(temp, callTargetRegister);
182        __ Ldr(Register(X20), MemoryOperand(methodRegister, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
183        // Reload constpool and profileInfo to make sure gc map work normally
184        __ Ldr(Register(X22), MemoryOperand(temp, JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET));
185        __ Ldr(Register(X22), MemoryOperand(Register(X22), ProfileTypeInfoCell::VALUE_OFFSET));
186        __ Ldr(Register(X21), MemoryOperand(methodRegister, Method::CONSTANT_POOL_OFFSET));
187
188        __ Mov(temp, kungfu::BytecodeStubCSigns::ID_ThrowStackOverflowException);
189        __ Add(temp, glueRegister, Operand(temp, UXTW, 3));  // 3: bc * 8
190        __ Ldr(temp, MemoryOperand(temp, JSThread::GlueData::GetBCStubEntriesOffset(false)));
191        __ Br(temp);
192    } else {
193        [[maybe_unused]] TempRegister1Scope scope(assembler);
194        Register temp = __ TempRegister1();
195        ThrowStackOverflowExceptionAndReturn(assembler, glueRegister, fpRegister, temp);
196    }
197}
198
199void AsmInterpreterCall::JSCallCommonFastPath(ExtendedAssembler *assembler, JSCallMode mode, Label *pushCallThis,
200    Label *stackOverflow)
201{
202    Register glueRegister = __ GlueRegister();
203    auto argc = kungfu::AssemblerModule::GetArgcFromJSCallMode(mode);
204    Register currentSlotRegister = __ AvailableRegister3();
205    // call range
206    if (argc < 0) {
207        Register numRegister = __ AvailableRegister2();
208        Register argcRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARGC);
209        Register argvRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARGV);
210        __ Mov(numRegister, argcRegister);
211        [[maybe_unused]] TempRegister1Scope scope(assembler);
212        Register opRegister = __ TempRegister1();
213        PushArgsWithArgv(assembler, glueRegister, numRegister, argvRegister, opRegister,
214                         currentSlotRegister, pushCallThis, stackOverflow);
215    } else if (argc > 0) {
216        if (argc > 2) { // 2: call arg2
217            Register arg2 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG2);
218            __ Str(arg2, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
219        }
220        if (argc > 1) {
221            Register arg1 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
222            __ Str(arg1, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
223        }
224        if (argc > 0) {
225            Register arg0 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
226            __ Str(arg0, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
227        }
228    }
229}
230
231void AsmInterpreterCall::JSCallCommonSlowPath(ExtendedAssembler *assembler, JSCallMode mode,
232                                              Label *fastPathEntry, Label *pushCallThis, Label *stackOverflow)
233{
234    Register glueRegister = __ GlueRegister();
235    Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
236    Register argcRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARGC);
237    Register argvRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARGV);
238    Register currentSlotRegister = __ AvailableRegister3();
239    Register arg0 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
240    Register arg1 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
241    Label noExtraEntry;
242    Label pushArgsEntry;
243
244    auto argc = kungfu::AssemblerModule::GetArgcFromJSCallMode(mode);
245    Register declaredNumArgsRegister = __ AvailableRegister2();
246    __ Tbz(callFieldRegister, MethodLiteral::HaveExtraBit::START_BIT, &noExtraEntry);
247    // extra entry
248    {
249        [[maybe_unused]] TempRegister1Scope scope1(assembler);
250        Register tempArgcRegister = __ TempRegister1();
251        if (argc >= 0) {
252            __ PushArgc(argc, tempArgcRegister, currentSlotRegister);
253        } else {
254            __ PushArgc(argcRegister, tempArgcRegister, currentSlotRegister);
255        }
256        // fall through
257    }
258    __ Bind(&noExtraEntry);
259    {
260        if (argc == 0) {
261            {
262                [[maybe_unused]] TempRegister1Scope scope(assembler);
263                Register tempRegister = __ TempRegister1();
264                PushUndefinedWithArgc(assembler, glueRegister, declaredNumArgsRegister, tempRegister,
265                                      currentSlotRegister, nullptr, stackOverflow);
266            }
267            __ B(fastPathEntry);
268            return;
269        }
270        [[maybe_unused]] TempRegister1Scope scope1(assembler);
271        Register diffRegister = __ TempRegister1();
272        if (argc >= 0) {
273            __ Sub(diffRegister.W(), declaredNumArgsRegister.W(), Immediate(argc));
274        } else {
275            __ Sub(diffRegister.W(), declaredNumArgsRegister.W(), argcRegister.W());
276        }
277        [[maybe_unused]] TempRegister2Scope scope2(assembler);
278        Register tempRegister = __ TempRegister2();
279        PushUndefinedWithArgc(assembler, glueRegister, diffRegister, tempRegister,
280                              currentSlotRegister, &pushArgsEntry, stackOverflow);
281        __ B(fastPathEntry);
282    }
283    // declare < actual
284    __ Bind(&pushArgsEntry);
285    {
286        __ Tbnz(callFieldRegister, MethodLiteral::HaveExtraBit::START_BIT, fastPathEntry);
287        // no extra branch
288        // arg1, declare must be 0
289        if (argc == 1) {
290            __ B(pushCallThis);
291            return;
292        }
293        __ Cmp(declaredNumArgsRegister, Immediate(0));
294        __ B(Condition::EQ, pushCallThis);
295        // call range
296        if (argc < 0) {
297            [[maybe_unused]] TempRegister1Scope scope(assembler);
298            Register opRegister = __ TempRegister1();
299            PushArgsWithArgv(assembler, glueRegister, declaredNumArgsRegister,
300                             argvRegister, opRegister,
301                             currentSlotRegister, nullptr, stackOverflow);
302        } else if (argc > 0) {
303            Label pushArgs0;
304            if (argc > 2) {  // 2: call arg2
305                // decalare is 2 or 1 now
306                __ Cmp(declaredNumArgsRegister, Immediate(1));
307                __ B(Condition::EQ, &pushArgs0);
308                __ Str(arg1, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
309            }
310            if (argc > 1) {
311                __ Bind(&pushArgs0);
312                // decalare is is 1 now
313                __ Str(arg0, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
314            }
315        }
316        __ B(pushCallThis);
317    }
318}
319
320Register AsmInterpreterCall::GetThisRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister)
321{
322    switch (mode) {
323        case JSCallMode::CALL_GETTER:
324        case JSCallMode::CALL_THIS_ARG0:
325            return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
326        case JSCallMode::CALL_SETTER:
327        case JSCallMode::CALL_THIS_ARG1:
328            return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
329        case JSCallMode::CALL_THIS_ARG2:
330        case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
331        case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
332        case JSCallMode::SUPER_CALL_WITH_ARGV:
333        case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
334        case JSCallMode::CALL_THIS_WITH_ARGV:
335        case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
336            return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG2);
337        case JSCallMode::CALL_THIS_ARG3:
338        case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
339            return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG3);
340        case JSCallMode::CALL_FROM_AOT:
341        case JSCallMode::CALL_ENTRY: {
342            Register argvRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
343            __ Ldur(defaultRegister, MemoryOperand(argvRegister, -FRAME_SLOT_SIZE));
344            return defaultRegister;
345        }
346        default:
347            LOG_ECMA(FATAL) << "this branch is unreachable";
348            UNREACHABLE();
349    }
350    return INVALID_REG;
351}
352
353Register AsmInterpreterCall::GetNewTargetRegsiter(ExtendedAssembler *assembler, JSCallMode mode,
354    Register defaultRegister)
355{
356    switch (mode) {
357        case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
358        case JSCallMode::CALL_THIS_WITH_ARGV:
359            return __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
360        case JSCallMode::SUPER_CALL_WITH_ARGV:
361        case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
362            return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG3);
363        case JSCallMode::CALL_FROM_AOT:
364        case JSCallMode::CALL_ENTRY: {
365            Register argvRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
366            // 2: new Target index
367            __ Ldur(defaultRegister, MemoryOperand(argvRegister, -2 * FRAME_SLOT_SIZE));
368            return defaultRegister;
369        }
370        default:
371            LOG_ECMA(FATAL) << "this branch is unreachable";
372            UNREACHABLE();
373    }
374    return INVALID_REG;
375}
376
377// void PushCallArgsxAndDispatch(uintptr_t glue, uintptr_t sp, uint64_t callTarget, uintptr_t method,
378//     uint64_t callField, ...)
379// GHC calling convention
380// Input1: for callarg0/1/2/3        Input2: for callrange
381// X19 - glue                        // X19 - glue
382// FP  - sp                          // FP  - sp
383// X20 - callTarget                  // X20 - callTarget
384// X21 - method                      // X21 - method
385// X22 - callField                   // X22 - callField
386// X23 - arg0                        // X23 - actualArgc
387// X24 - arg1                        // X24 - argv
388// X25 - arg2
389void AsmInterpreterCall::PushCallThisRangeAndDispatch(ExtendedAssembler *assembler)
390{
391    __ BindAssemblerStub(RTSTUB_ID(PushCallThisRangeAndDispatch));
392    JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_WITH_ARGV, FrameTransitionType::OTHER_TO_OTHER);
393}
394
395void AsmInterpreterCall::PushCallRangeAndDispatch(ExtendedAssembler *assembler)
396{
397    __ BindAssemblerStub(RTSTUB_ID(PushCallRangeAndDispatch));
398    JSCallCommonEntry(assembler, JSCallMode::CALL_WITH_ARGV, FrameTransitionType::OTHER_TO_OTHER);
399}
400
401void AsmInterpreterCall::PushCallNewAndDispatch(ExtendedAssembler *assembler)
402{
403    __ BindAssemblerStub(RTSTUB_ID(PushCallNewAndDispatch));
404    JSCallCommonEntry(assembler, JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV, FrameTransitionType::OTHER_TO_OTHER);
405}
406
407void AsmInterpreterCall::PushSuperCallAndDispatch(ExtendedAssembler *assembler)
408{
409    __ BindAssemblerStub(RTSTUB_ID(PushSuperCallAndDispatch));
410    JSCallCommonEntry(assembler, JSCallMode::SUPER_CALL_WITH_ARGV, FrameTransitionType::OTHER_TO_OTHER);
411}
412
413void AsmInterpreterCall::PushCallArgs3AndDispatch(ExtendedAssembler *assembler)
414{
415    __ BindAssemblerStub(RTSTUB_ID(PushCallArgs3AndDispatch));
416    JSCallCommonEntry(assembler, JSCallMode::CALL_ARG3, FrameTransitionType::OTHER_TO_OTHER);
417}
418
419void AsmInterpreterCall::PushCallArgs2AndDispatch(ExtendedAssembler *assembler)
420{
421    __ BindAssemblerStub(RTSTUB_ID(PushCallArgs2AndDispatch));
422    JSCallCommonEntry(assembler, JSCallMode::CALL_ARG2, FrameTransitionType::OTHER_TO_OTHER);
423}
424
425void AsmInterpreterCall::PushCallArg1AndDispatch(ExtendedAssembler *assembler)
426{
427    __ BindAssemblerStub(RTSTUB_ID(PushCallArg1AndDispatch));
428    JSCallCommonEntry(assembler, JSCallMode::CALL_ARG1, FrameTransitionType::OTHER_TO_OTHER);
429}
430
431void AsmInterpreterCall::PushCallArg0AndDispatch(ExtendedAssembler *assembler)
432{
433    __ BindAssemblerStub(RTSTUB_ID(PushCallArg0AndDispatch));
434    JSCallCommonEntry(assembler, JSCallMode::CALL_ARG0, FrameTransitionType::OTHER_TO_OTHER);
435}
436
437void AsmInterpreterCall::PushCallThisArg0AndDispatch(ExtendedAssembler *assembler)
438{
439    __ BindAssemblerStub(RTSTUB_ID(PushCallThisArg0AndDispatch));
440    JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG0, FrameTransitionType::OTHER_TO_OTHER);
441}
442
443void AsmInterpreterCall::PushCallThisArg1AndDispatch(ExtendedAssembler *assembler)
444{
445    __ BindAssemblerStub(RTSTUB_ID(PushCallThisArg1AndDispatch));
446    JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG1, FrameTransitionType::OTHER_TO_OTHER);
447}
448
449void AsmInterpreterCall::PushCallThisArgs2AndDispatch(ExtendedAssembler *assembler)
450{
451    __ BindAssemblerStub(RTSTUB_ID(PushCallThisArgs2AndDispatch));
452    JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG2, FrameTransitionType::OTHER_TO_OTHER);
453}
454
455void AsmInterpreterCall::PushCallThisArgs3AndDispatch(ExtendedAssembler *assembler)
456{
457    __ BindAssemblerStub(RTSTUB_ID(PushCallThisArgs3AndDispatch));
458    JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG3, FrameTransitionType::OTHER_TO_OTHER);
459}
460
461// uint64_t PushCallRangeAndDispatchNative(uintptr_t glue, uint32_t argc, JSTaggedType calltarget, uintptr_t argv[])
462// c++ calling convention call js function
463// Input: X0 - glue
464//        X1 - nativeCode
465//        X2 - callTarget
466//        X3 - thisValue
467//        X4  - argc
468//        X5  - argV (...)
469void AsmInterpreterCall::PushCallRangeAndDispatchNative(ExtendedAssembler *assembler)
470{
471    __ BindAssemblerStub(RTSTUB_ID(PushCallRangeAndDispatchNative));
472    CallNativeWithArgv(assembler, false);
473}
474
475void AsmInterpreterCall::PushCallNewAndDispatchNative(ExtendedAssembler *assembler)
476{
477    __ BindAssemblerStub(RTSTUB_ID(PushCallNewAndDispatchNative));
478    CallNativeWithArgv(assembler, true);
479}
480
481void AsmInterpreterCall::PushNewTargetAndDispatchNative(ExtendedAssembler *assembler)
482{
483    __ BindAssemblerStub(RTSTUB_ID(PushNewTargetAndDispatchNative));
484    CallNativeWithArgv(assembler, true, true);
485}
486
487void AsmInterpreterCall::CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew, bool hasNewTarget)
488{
489    Register glue(X0);
490    Register nativeCode(X1);
491    Register callTarget(X2);
492    Register thisObj(X3);
493    Register argc(X4);
494    Register argv(X5);
495    Register newTarget(X6);
496    Register opArgc(X8);
497    Register opArgv(X9);
498    Register temp(X10);
499    Register currentSlotRegister(X11);
500    Register spRegister(SP);
501
502    Label pushThis;
503    Label stackOverflow;
504    bool isFrameComplete = PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_FRAME_WITH_ARGV, temp, argc);
505
506    __ Mov(currentSlotRegister, spRegister);
507    // Reserve enough sp space to prevent stack parameters from being covered by cpu profiler.
508    __ Ldr(temp, MemoryOperand(glue, JSThread::GlueData::GetStackLimitOffset(false)));
509    __ Mov(Register(SP), temp);
510
511    __ Mov(opArgc, argc);
512    __ Mov(opArgv, argv);
513    PushArgsWithArgv(assembler, glue, opArgc, opArgv, temp, currentSlotRegister, &pushThis, &stackOverflow);
514
515    __ Bind(&pushThis);
516    // newTarget
517    if (callNew) {
518        if (hasNewTarget) {
519            // 16: this & newTarget
520            __ Stp(newTarget, thisObj, MemoryOperand(currentSlotRegister, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
521        } else {
522            // 16: this & newTarget
523            __ Stp(callTarget, thisObj, MemoryOperand(currentSlotRegister, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
524        }
525    } else {
526        __ Mov(temp, Immediate(JSTaggedValue::VALUE_UNDEFINED));
527        // 16: this & newTarget
528        __ Stp(temp, thisObj, MemoryOperand(currentSlotRegister, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
529    }
530    // callTarget
531    __ Str(callTarget, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
532    __ Add(temp, currentSlotRegister, Immediate(QUINTUPLE_SLOT_SIZE));
533    if (!isFrameComplete) {
534        __ Add(Register(FP), temp, Operand(argc, LSL, 3));  // 3: argc * 8
535    }
536
537    __ Add(temp, argc, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
538    // 2: thread & argc
539    __ Stp(glue, temp, MemoryOperand(currentSlotRegister, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
540    __ Add(Register(X0), currentSlotRegister, Immediate(0));
541
542    __ Align16(currentSlotRegister);
543    __ Mov(spRegister, currentSlotRegister);
544
545    CallNativeInternal(assembler, nativeCode);
546    __ Ret();
547
548    __ Bind(&stackOverflow);
549    {
550        // use builtin_with_argv_frame to mark gc map
551        Register frameType(X11);
552        __ Ldr(temp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
553        __ Mov(spRegister, temp);
554        __ Mov(frameType, Immediate(static_cast<int32_t>(FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME)));
555        // 2: frame type and argc
556        __ Stp(Register(Zero), frameType, MemoryOperand(Register(SP), -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
557        __ Mov(temp, Immediate(JSTaggedValue::VALUE_UNDEFINED));
558        // 2: fill this&newtgt slots
559        __ Stp(temp, temp, MemoryOperand(spRegister, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
560        // 2: fill func&align slots
561        __ Stp(Register(Zero), temp, MemoryOperand(spRegister, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
562        __ Mov(temp, spRegister);
563        // 6:frame type, argc, this, newTarget, func and align
564        // +----------------------------------------------------------------+ <---- fp = sp + 6 * frame_slot_size
565        // |     FrameType =  BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME |
566        // +----------------------------------------------------------------+
567        // |                           argc = 0                             |
568        // |----------------------------------------------------------------|
569        // |                       this = undefined                         |
570        // |----------------------------------------------------------------|
571        // |                      newTarget = undefine                      |
572        // |----------------------------------------------------------------|
573        // |                       function = undefined                     |
574        // |----------------------------------------------------------------|
575        // |                               align                            |
576        // +----------------------------------------------------------------+  <---- sp
577        __ Add(Register(FP), temp, Immediate(FRAME_SLOT_SIZE * 6));
578
579        Register runtimeId(X11);
580        Register trampoline(X12);
581        __ Mov(runtimeId, Immediate(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException));
582        // 3 : 3 means *8
583        __ Add(trampoline, glue, Operand(runtimeId, LSL, 3));
584        __ Ldr(trampoline, MemoryOperand(trampoline, JSThread::GlueData::GetRTStubEntriesOffset(false)));
585        __ Blr(trampoline);
586
587        // resume rsp
588        __ Mov(Register(SP), Register(FP));
589        __ RestoreFpAndLr();
590        __ Ret();
591    }
592}
593
594// uint64_t PushCallArgsAndDispatchNative(uintptr_t codeAddress, uintptr_t glue, uint32_t argc, ...)
595// webkit_jscc calling convention call runtime_id's runtion function(c-abi)
596// Input: X0 - codeAddress
597// stack layout: sp + N*8 argvN
598//               ........
599//               sp + 24: argv1
600//               sp + 16: argv0
601//               sp + 8:  actualArgc
602//               sp:      thread
603// construct Native Leave Frame
604//               +--------------------------+
605//               |     argV[N - 1]          |
606//               |--------------------------|
607//               |       . . . .            |
608//               |--------------------------+
609//               |     argV[2]=this         |
610//               +--------------------------+
611//               |     argV[1]=new-target   |
612//               +--------------------------+
613//               |     argV[0]=call-target  |
614//               +--------------------------+ ---------
615//               |       argc               |         ^
616//               |--------------------------|         |
617//               |       thread             |         |
618//               |--------------------------|         |
619//               |       returnAddr         |     BuiltinFrame
620//               |--------------------------|         |
621//               |       callsiteFp         |         |
622//               |--------------------------|         |
623//               |       frameType          |         v
624//               +--------------------------+ ---------
625
626void AsmInterpreterCall::PushCallArgsAndDispatchNative(ExtendedAssembler *assembler)
627{
628    __ BindAssemblerStub(RTSTUB_ID(PushCallArgsAndDispatchNative));
629
630    Register nativeCode(X0);
631    Register glue(X1);
632    Register argv(X5);
633    Register temp(X6);
634    Register sp(SP);
635    Register nativeCodeTemp(X2);
636
637    __ Mov(nativeCodeTemp, nativeCode);
638
639    __ Ldr(glue, MemoryOperand(sp, 0));
640    __ Add(Register(X0), sp, Immediate(0));
641    PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_FRAME, temp, argv);
642
643    CallNativeInternal(assembler, nativeCodeTemp);
644    __ Ret();
645}
646
647bool AsmInterpreterCall::PushBuiltinFrame(ExtendedAssembler *assembler, Register glue,
648    FrameType type, Register op, Register next)
649{
650    Register sp(SP);
651    __ PushFpAndLr();
652    __ Mov(op, sp);
653    __ Str(op, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
654    __ Mov(op, Immediate(static_cast<int32_t>(type)));
655    if (type == FrameType::BUILTIN_FRAME) {
656        // push stack args
657        __ Add(next, sp, Immediate(BuiltinFrame::GetStackArgsToFpDelta(false)));
658        // 2: -2 * FRAME_SLOT_SIZE means type & next
659        __ Stp(next, op, MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
660        // 2: 2 * FRAME_SLOT_SIZE means skip next and frame type
661        __ Add(Register(FP), sp, Immediate(2 * FRAME_SLOT_SIZE));
662        return true;
663    } else if (type == FrameType::BUILTIN_ENTRY_FRAME) {
664        // 2: -2 * FRAME_SLOT_SIZE means type & next
665        __ Stp(next, op, MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
666        // 2: 2 * FRAME_SLOT_SIZE means skip next and frame type
667        __ Add(Register(FP), sp, Immediate(2 * FRAME_SLOT_SIZE));
668        return true;
669    } else if (type == FrameType::BUILTIN_FRAME_WITH_ARGV) {
670        // this frame push stack args must before update FP, otherwise cpu profiler maybe visit incomplete stack
671        // BuiltinWithArgvFrame layout please see frames.h
672        // 2: -2 * FRAME_SLOT_SIZE means type & next
673        __ Stp(next, op, MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
674        return false;
675    } else {
676        LOG_ECMA(FATAL) << "this branch is unreachable";
677        UNREACHABLE();
678    }
679}
680
681void AsmInterpreterCall::CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode)
682{
683    __ Blr(nativeCode);
684    // resume rsp
685    __ Mov(Register(SP), Register(FP));
686    __ RestoreFpAndLr();
687}
688
689// ResumeRspAndDispatch(uintptr_t glue, uintptr_t sp, uintptr_t pc, uintptr_t constantPool,
690//     uint64_t profileTypeInfo, uint64_t acc, uint32_t hotnessCounter, size_t jumpSize)
691// GHC calling convention
692// X19 - glue
693// FP  - sp
694// X20 - pc
695// X21 - constantPool
696// X22 - profileTypeInfo
697// X23 - acc
698// X24 - hotnessCounter
699// X25 - jumpSizeAfterCall
700void AsmInterpreterCall::ResumeRspAndDispatch(ExtendedAssembler *assembler)
701{
702    __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndDispatch));
703
704    Register glueRegister = __ GlueRegister();
705    Register sp(FP);
706    Register rsp(SP);
707    Register pc(X20);
708    Register jumpSizeRegister(X25);
709
710    Register ret(X23);
711    Register opcode(X6, W);
712    Register temp(X7);
713    Register bcStub(X7);
714    Register fp(X8);
715
716    int64_t fpOffset = static_cast<int64_t>(AsmInterpretedFrame::GetFpOffset(false))
717        - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
718    int64_t spOffset = static_cast<int64_t>(AsmInterpretedFrame::GetBaseOffset(false))
719        - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
720    int64_t thisOffset = static_cast<int64_t>(AsmInterpretedFrame::GetThisOffset(false))
721        - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
722    ASSERT(fpOffset < 0);
723    ASSERT(spOffset < 0);
724
725    Label newObjectRangeReturn;
726    Label dispatch;
727    __ Ldur(fp, MemoryOperand(sp, fpOffset));  // store fp for temporary
728    __ Cmp(jumpSizeRegister, Immediate(0));
729    __ B(Condition::LE, &newObjectRangeReturn);
730    __ Ldur(sp, MemoryOperand(sp, spOffset));  // update sp
731
732    __ Add(pc, pc, Operand(jumpSizeRegister, LSL, 0));
733    __ Ldrb(opcode, MemoryOperand(pc, 0));
734    __ Bind(&dispatch);
735    {
736        __ Mov(rsp, fp);  // resume rsp
737        __ Add(bcStub, glueRegister, Operand(opcode, UXTW, FRAME_SLOT_SIZE_LOG2));
738        __ Ldr(bcStub, MemoryOperand(bcStub, JSThread::GlueData::GetBCStubEntriesOffset(false)));
739        __ Br(bcStub);
740    }
741
742    Label getThis;
743    Label notUndefined;
744    __ Bind(&newObjectRangeReturn);
745    {
746        __ Cmp(ret, Immediate(JSTaggedValue::VALUE_UNDEFINED));
747        __ B(Condition::NE, &notUndefined);
748        ASSERT(thisOffset < 0);
749        __ Bind(&getThis);
750        __ Ldur(ret, MemoryOperand(sp, thisOffset));  // update acc
751        __ Ldur(sp, MemoryOperand(sp, spOffset));  // update sp
752        __ Mov(rsp, fp);  // resume rsp
753        __ Sub(pc, pc, jumpSizeRegister); // sub negative jmupSize
754        __ Ldrb(opcode, MemoryOperand(pc, 0));
755        __ Add(bcStub, glueRegister, Operand(opcode, UXTW, FRAME_SLOT_SIZE_LOG2));
756        __ Ldr(bcStub, MemoryOperand(bcStub, JSThread::GlueData::GetBCStubEntriesOffset(false)));
757        __ Br(bcStub);
758    }
759    __ Bind(&notUndefined);
760    {
761        Label notEcmaObject;
762        __ Mov(temp, Immediate(JSTaggedValue::TAG_HEAPOBJECT_MASK));
763        __ And(temp, temp, ret);
764        __ Cmp(temp, Immediate(0));
765        __ B(Condition::NE, &notEcmaObject);
766        // acc is heap object
767        __ Ldr(temp, MemoryOperand(ret, TaggedObject::HCLASS_OFFSET));
768        __ Ldr(temp, MemoryOperand(temp, JSHClass::BIT_FIELD_OFFSET));
769        __ And(temp.W(), temp.W(), LogicalImmediate::Create(0xFF, RegWSize));
770        __ Cmp(temp.W(), Immediate(static_cast<int64_t>(JSType::ECMA_OBJECT_LAST)));
771        __ B(Condition::HI, &notEcmaObject);
772        __ Cmp(temp.W(), Immediate(static_cast<int64_t>(JSType::ECMA_OBJECT_FIRST)));
773        __ B(Condition::LO, &notEcmaObject);
774        // acc is ecma object
775        __ Ldur(sp, MemoryOperand(sp, spOffset));  // update sp
776        __ Sub(pc, pc, jumpSizeRegister); // sub negative jmupSize
777        __ Ldrb(opcode, MemoryOperand(pc, 0));
778        __ B(&dispatch);
779
780        __ Bind(&notEcmaObject);
781        {
782            int64_t constructorOffset = static_cast<int64_t>(AsmInterpretedFrame::GetFunctionOffset(false))
783                - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
784            ASSERT(constructorOffset < 0);
785            __ Ldur(temp, MemoryOperand(sp, constructorOffset));  // load constructor
786            __ Ldr(temp, MemoryOperand(temp, JSFunctionBase::METHOD_OFFSET));
787            __ Ldr(temp, MemoryOperand(temp, Method::EXTRA_LITERAL_INFO_OFFSET));
788            __ Lsr(temp.W(), temp.W(), MethodLiteral::FunctionKindBits::START_BIT);
789            __ And(temp.W(), temp.W(),
790                LogicalImmediate::Create((1LU << MethodLiteral::FunctionKindBits::SIZE) - 1, RegWSize));
791            __ Cmp(temp.W(), Immediate(static_cast<int64_t>(FunctionKind::CLASS_CONSTRUCTOR)));
792            __ B(Condition::LS, &getThis);  // constructor is base
793            // exception branch
794            {
795                __ Mov(opcode, kungfu::BytecodeStubCSigns::ID_NewObjectRangeThrowException);
796                __ Ldur(sp, MemoryOperand(sp, spOffset));  // update sp
797                __ B(&dispatch);
798            }
799        }
800    }
801}
802
803// ResumeRspAndReturn(uintptr_t acc)
804// GHC calling convention
805// X19 - acc
806// FP - prevSp
807// X20 - sp
808void AsmInterpreterCall::ResumeRspAndReturn(ExtendedAssembler *assembler)
809{
810    __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndReturn));
811    Register rsp(SP);
812    Register currentSp(X20);
813
814    [[maybe_unused]] TempRegister1Scope scope1(assembler);
815    Register fpRegister = __ TempRegister1();
816    int64_t offset = static_cast<int64_t>(AsmInterpretedFrame::GetFpOffset(false))
817        - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
818    ASSERT(offset < 0);
819    __ Ldur(fpRegister, MemoryOperand(currentSp, offset));
820    __ Mov(rsp, fpRegister);
821
822    // return
823    {
824        __ RestoreFpAndLr();
825        __ Mov(Register(X0), Register(X19));
826        __ Ret();
827    }
828}
829
830// ResumeRspAndReturnBaseline(uintptr_t acc)
831// GHC calling convention
832// X19 - acc
833// FP - prevSp
834// X20 - sp
835// X21 - jumpSizeAfterCall
836void AsmInterpreterCall::ResumeRspAndReturnBaseline(ExtendedAssembler *assembler)
837{
838    __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndReturnBaseline));
839    Register rsp(SP);
840    Register currentSp(X20);
841
842    [[maybe_unused]] TempRegister1Scope scope1(assembler);
843    Register fpRegister = __ TempRegister1();
844    int64_t fpOffset = static_cast<int64_t>(AsmInterpretedFrame::GetFpOffset(false)) -
845        static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
846    ASSERT(fpOffset < 0);
847    __ Ldur(fpRegister, MemoryOperand(currentSp, fpOffset));
848    __ Mov(rsp, fpRegister);
849    __ RestoreFpAndLr();
850    __ Mov(Register(X0), Register(X19));
851
852    // Check and set result
853    Register ret = X0;
854    Register jumpSizeRegister = X21;
855    Label getThis;
856    Label notUndefined;
857    Label normalReturn;
858    Label newObjectRangeReturn;
859    __ Cmp(jumpSizeRegister, Immediate(0));
860    __ B(Condition::GT, &normalReturn);
861
862    __ Bind(&newObjectRangeReturn);
863    {
864        __ Cmp(ret, Immediate(JSTaggedValue::VALUE_UNDEFINED));
865        __ B(Condition::NE, &notUndefined);
866
867        __ Bind(&getThis);
868        int64_t thisOffset = static_cast<int64_t>(AsmInterpretedFrame::GetThisOffset(false)) -
869            static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
870        ASSERT(thisOffset < 0);
871        __ Ldur(ret, MemoryOperand(currentSp, thisOffset));  // update result
872        __ B(&normalReturn);
873
874        __ Bind(&notUndefined);
875        {
876            Register temp = X19;
877            Label notEcmaObject;
878            __ Mov(temp, Immediate(JSTaggedValue::TAG_HEAPOBJECT_MASK));
879            __ And(temp, temp, ret);
880            __ Cmp(temp, Immediate(0));
881            __ B(Condition::NE, &notEcmaObject);
882            // acc is heap object
883            __ Ldr(temp, MemoryOperand(ret, TaggedObject::HCLASS_OFFSET));
884            __ Ldr(temp, MemoryOperand(temp, JSHClass::BIT_FIELD_OFFSET));
885            __ And(temp.W(), temp.W(), LogicalImmediate::Create(0xFF, RegWSize));
886            __ Cmp(temp.W(), Immediate(static_cast<int64_t>(JSType::ECMA_OBJECT_LAST)));
887            __ B(Condition::HI, &notEcmaObject);
888            __ Cmp(temp.W(), Immediate(static_cast<int64_t>(JSType::ECMA_OBJECT_FIRST)));
889            __ B(Condition::LO, &notEcmaObject);
890            // acc is ecma object
891            __ B(&normalReturn);
892
893            __ Bind(&notEcmaObject);
894            {
895                int64_t funcOffset = static_cast<int64_t>(AsmInterpretedFrame::GetFunctionOffset(false)) -
896                    static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
897                ASSERT(funcOffset < 0);
898                __ Ldur(temp, MemoryOperand(currentSp, funcOffset));  // load constructor
899                __ Ldr(temp, MemoryOperand(temp, JSFunctionBase::METHOD_OFFSET));
900                __ Ldr(temp, MemoryOperand(temp, Method::EXTRA_LITERAL_INFO_OFFSET));
901                __ Lsr(temp.W(), temp.W(), MethodLiteral::FunctionKindBits::START_BIT);
902                __ And(temp.W(), temp.W(),
903                       LogicalImmediate::Create((1LU << MethodLiteral::FunctionKindBits::SIZE) - 1, RegWSize));
904                __ Cmp(temp.W(), Immediate(static_cast<int64_t>(FunctionKind::CLASS_CONSTRUCTOR)));
905                __ B(Condition::LS, &getThis);  // constructor is base
906                // fall through
907            }
908        }
909    }
910    __ Bind(&normalReturn);
911    __ Ret();
912}
913
914// ResumeCaughtFrameAndDispatch(uintptr_t glue, uintptr_t sp, uintptr_t pc, uintptr_t constantPool,
915//     uint64_t profileTypeInfo, uint64_t acc, uint32_t hotnessCounter)
916// GHC calling convention
917// X19 - glue
918// FP  - sp
919// X20 - pc
920// X21 - constantPool
921// X22 - profileTypeInfo
922// X23 - acc
923// X24 - hotnessCounter
924void AsmInterpreterCall::ResumeCaughtFrameAndDispatch(ExtendedAssembler *assembler)
925{
926    __ BindAssemblerStub(RTSTUB_ID(ResumeCaughtFrameAndDispatch));
927
928    Register glue(X19);
929    Register pc(X20);
930    Register fp(X5);
931    Register opcode(X6, W);
932    Register bcStub(X7);
933
934    Label dispatch;
935    __ Ldr(fp, MemoryOperand(glue, JSThread::GlueData::GetLastFpOffset(false)));
936    __ Cmp(fp, Immediate(0));
937    __ B(Condition::EQ, &dispatch);
938    // up frame
939    __ Mov(Register(SP), fp);
940    // fall through
941    __ Bind(&dispatch);
942    {
943        __ Ldrb(opcode, MemoryOperand(pc, 0));
944        __ Add(bcStub, glue, Operand(opcode, UXTW, FRAME_SLOT_SIZE_LOG2));
945        __ Ldr(bcStub, MemoryOperand(bcStub, JSThread::GlueData::GetBCStubEntriesOffset(false)));
946        __ Br(bcStub);
947    }
948}
949
950// ResumeUncaughtFrameAndReturn(uintptr_t glue)
951// GHC calling convention
952// X19 - glue
953// FP - sp
954// X20 - acc
955void AsmInterpreterCall::ResumeUncaughtFrameAndReturn(ExtendedAssembler *assembler)
956{
957    __ BindAssemblerStub(RTSTUB_ID(ResumeUncaughtFrameAndReturn));
958
959    Register glue(X19);
960    Register fp(X5);
961    Register acc(X20);
962    Register cppRet(X0);
963
964    __ Ldr(fp, MemoryOperand(glue, JSThread::GlueData::GetLastFpOffset(false)));
965    __ Mov(Register(SP), fp);
966    // this method will return to Execute(cpp calling convention), and the return value should be put into X0.
967    __ Mov(cppRet, acc);
968    __ RestoreFpAndLr();
969    __ Ret();
970}
971
972// ResumeRspAndRollback(uintptr_t glue, uintptr_t sp, uintptr_t pc, uintptr_t constantPool,
973//     uint64_t profileTypeInfo, uint64_t acc, uint32_t hotnessCounter, size_t jumpSize)
974// GHC calling convention
975// X19 - glue
976// FP  - sp
977// X20 - pc
978// X21 - constantPool
979// X22 - profileTypeInfo
980// X23 - acc
981// X24 - hotnessCounter
982// X25 - jumpSizeAfterCall
983void AsmInterpreterCall::ResumeRspAndRollback(ExtendedAssembler *assembler)
984{
985    __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndRollback));
986
987    Register glueRegister = __ GlueRegister();
988    Register sp(FP);
989    Register rsp(SP);
990    Register pc(X20);
991    Register jumpSizeRegister(X25);
992
993    Register ret(X23);
994    Register opcode(X6, W);
995    Register bcStub(X7);
996    Register fp(X8);
997
998    int64_t fpOffset = static_cast<int64_t>(AsmInterpretedFrame::GetFpOffset(false))
999        - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
1000    int64_t spOffset = static_cast<int64_t>(AsmInterpretedFrame::GetBaseOffset(false))
1001        - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
1002    int64_t funcOffset = static_cast<int64_t>(AsmInterpretedFrame::GetFunctionOffset(false))
1003        - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
1004    ASSERT(fpOffset < 0);
1005    ASSERT(spOffset < 0);
1006    ASSERT(funcOffset < 0);
1007
1008    __ Ldur(fp, MemoryOperand(sp, fpOffset));  // store fp for temporary
1009    __ Ldur(ret, MemoryOperand(sp, funcOffset)); // restore acc
1010    __ Ldur(sp, MemoryOperand(sp, spOffset));  // update sp
1011
1012    __ Add(pc, pc, Operand(jumpSizeRegister, LSL, 0));
1013    __ Ldrb(opcode, MemoryOperand(pc, 0));
1014
1015    __ Mov(rsp, fp);  // resume rsp
1016    __ Add(bcStub, glueRegister, Operand(opcode, UXTW, FRAME_SLOT_SIZE_LOG2));
1017    __ Ldr(bcStub, MemoryOperand(bcStub, JSThread::GlueData::GetBCStubEntriesOffset(false)));
1018    __ Br(bcStub);
1019}
1020
1021// c++ calling convention
1022// X0 - glue
1023// X1 - callTarget
1024// X2 - method
1025// X3 - callField
1026// X4 - receiver
1027// X5 - value
1028void AsmInterpreterCall::CallGetter(ExtendedAssembler *assembler)
1029{
1030    __ BindAssemblerStub(RTSTUB_ID(CallGetter));
1031    Label target;
1032
1033    PushAsmInterpBridgeFrame(assembler);
1034    __ Bl(&target);
1035    PopAsmInterpBridgeFrame(assembler);
1036    __ Ret();
1037    __ Bind(&target);
1038    {
1039        JSCallCommonEntry(assembler, JSCallMode::CALL_GETTER, FrameTransitionType::OTHER_TO_OTHER);
1040    }
1041}
1042
1043void AsmInterpreterCall::CallSetter(ExtendedAssembler *assembler)
1044{
1045    __ BindAssemblerStub(RTSTUB_ID(CallSetter));
1046    Label target;
1047    PushAsmInterpBridgeFrame(assembler);
1048    __ Bl(&target);
1049    PopAsmInterpBridgeFrame(assembler);
1050    __ Ret();
1051    __ Bind(&target);
1052    {
1053        JSCallCommonEntry(assembler, JSCallMode::CALL_SETTER, FrameTransitionType::OTHER_TO_OTHER);
1054    }
1055}
1056
1057void AsmInterpreterCall::CallContainersArgs2(ExtendedAssembler *assembler)
1058{
1059    __ BindAssemblerStub(RTSTUB_ID(CallContainersArgs2));
1060    Label target;
1061    PushAsmInterpBridgeFrame(assembler);
1062    __ Bl(&target);
1063    PopAsmInterpBridgeFrame(assembler);
1064    __ Ret();
1065    __ Bind(&target);
1066    {
1067        JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG2_WITH_RETURN,
1068                          FrameTransitionType::OTHER_TO_OTHER);
1069    }
1070}
1071
1072void AsmInterpreterCall::CallContainersArgs3(ExtendedAssembler *assembler)
1073{
1074    __ BindAssemblerStub(RTSTUB_ID(CallContainersArgs3));
1075    Label target;
1076    PushAsmInterpBridgeFrame(assembler);
1077    __ Bl(&target);
1078    PopAsmInterpBridgeFrame(assembler);
1079    __ Ret();
1080    __ Bind(&target);
1081    {
1082        JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG3_WITH_RETURN,
1083                          FrameTransitionType::OTHER_TO_OTHER);
1084    }
1085}
1086
1087// c++ calling convention
1088// X0 - glue
1089// X1 - callTarget
1090// X2 - method
1091// X3 - callField
1092// X4 - arg0(argc)
1093// X5 - arg1(arglist)
1094// X6 - arg3(argthis)
1095void AsmInterpreterCall::CallReturnWithArgv(ExtendedAssembler *assembler)
1096{
1097    __ BindAssemblerStub(RTSTUB_ID(CallReturnWithArgv));
1098    Label target;
1099    PushAsmInterpBridgeFrame(assembler);
1100    __ Bl(&target);
1101    PopAsmInterpBridgeFrame(assembler);
1102    __ Ret();
1103    __ Bind(&target);
1104    {
1105        JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARGV_WITH_RETURN,
1106                          FrameTransitionType::OTHER_TO_OTHER);
1107    }
1108}
1109
1110// preserve all the general registers, except x15 and callee saved registers/
1111// and call x15
1112void AsmInterpreterCall::PreserveMostCall(ExtendedAssembler* assembler)
1113{
1114    // * layout as the following:
1115    //               +--------------------------+ ---------
1116    //               |       . . . . .          |         ^
1117    // callerSP ---> |--------------------------|         |
1118    //               |       returnAddr         |         |
1119    //               |--------------------------|   OptimizedFrame
1120    //               |       callsiteFp         |         |
1121    //       fp ---> |--------------------------|         |
1122    //               |     OPTIMIZED_FRAME      |         v
1123    //               +--------------------------+ ---------
1124    //               |           x0             |
1125    //               +--------------------------+
1126    //               |           x1             |
1127    //               +--------------------------+
1128    //               |           r2             |
1129    //               +--------------------------+
1130    //               |           x3             |
1131    //               +--------------------------+
1132    //               |           x4             |
1133    //               +--------------------------+
1134    //               |           x5             |
1135    //               +--------------------------+
1136    //               |           x6             |
1137    //               +--------------------------+
1138    //               |           x7             |
1139    //               +--------------------------+
1140    //               |           x8             |
1141    //               +--------------------------+
1142    //               |           x9             |
1143    //               +--------------------------+
1144    //               |           x10            |
1145    //               +--------------------------+
1146    //               |           x11            |
1147    //               +--------------------------+
1148    //               |           x12            |
1149    //               +--------------------------+
1150    //               |           x13            |
1151    //               +--------------------------+
1152    //               |           x14            |
1153    //               +--------------------------+
1154    //               |           x16            |
1155    //               +--------------------------+
1156    //               |           x17            |
1157    //               +--------------------------+
1158    //               |           x18            |
1159    //               +--------------------------+
1160    //               |         align            |
1161    // calleeSP ---> +--------------------------+
1162    {
1163        // prologue to save fp, frametype, and update fp.
1164        __ Stp(X29, X30, MemoryOperand(SP, -DOUBLE_SLOT_SIZE, PREINDEX));
1165        // Zero register means OPTIMIZED_FRAME
1166        __ Stp(X0, Zero, MemoryOperand(SP, -DOUBLE_SLOT_SIZE, PREINDEX));
1167        __ Add(FP, SP, Immediate(DOUBLE_SLOT_SIZE));
1168    }
1169    int32_t PreserveRegPairIndex = 9;
1170    // x0~x14,x16,x17,x18 should be preserved,
1171    // other general registers are callee saved register, callee will save them.
1172    __ Sub(SP, SP, Immediate(DOUBLE_SLOT_SIZE * PreserveRegPairIndex));
1173    __ Stp(X1, X2, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1174    __ Stp(X3, X4, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1175    __ Stp(X5, X6, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1176    __ Stp(X7, X8, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1177    __ Stp(X9, X10, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1178    __ Stp(X11, X12, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1179    __ Stp(X13, X14, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1180    __ Stp(X16, X17, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1181    __ Str(X18, MemoryOperand(SP, FRAME_SLOT_SIZE));
1182    __ Blr(X15);
1183    __ Ldr(X18, MemoryOperand(SP, FRAME_SLOT_SIZE));
1184    __ Ldp(X16, X17, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1185    __ Ldp(X13, X14, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1186    __ Ldp(X11, X12, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1187    __ Ldp(X9, X10, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1188    __ Ldp(X7, X8, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1189    __ Ldp(X5, X6, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1190    __ Ldp(X3, X4, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1191    __ Ldp(X1, X2, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1192    __ Ldr(X0, MemoryOperand(SP, DOUBLE_SLOT_SIZE * PreserveRegPairIndex));
1193    {
1194        // epilogue to restore sp, fp, lr.
1195        // Skip x0 slot and frametype slot
1196        __ Add(SP, SP, Immediate(DOUBLE_SLOT_SIZE * PreserveRegPairIndex +
1197            FRAME_SLOT_SIZE + FRAME_SLOT_SIZE));
1198        __ Ldp(FP, X30, MemoryOperand(SP, DOUBLE_SLOT_SIZE, AddrMode::POSTINDEX));
1199        __ Ret();
1200    }
1201}
1202
1203// ASMFastWriteBarrier(GateRef glue, GateRef obj, GateRef offset, GateRef value)
1204// c calling convention, but preserve all general registers except %x15
1205// %x0 - glue
1206// %x1 - obj
1207// %x2 - offset
1208// %x3 - value
1209void AsmInterpreterCall::ASMFastWriteBarrier(ExtendedAssembler* assembler)
1210{
1211    // valid region flag are as follows, assume it will be ALWAYS VALID.
1212    // Judge the region of value with:
1213    //                          "young"            "sweepable share"  "readonly share"
1214    // region flag:         0x08, 0x09, [0x0A, 0x11], [0x12, 0x15],     0x16
1215    // value is share:                                [0x12,            0x16] =>  valueMaybeSweepableShare
1216    // readonly share:                                                  0x16  =>  return
1217    // sweepable share:                               [0x12, 0x15]            =>  needShareBarrier
1218    // value is not share:  0x08, 0x09, [0x0A, 0x11],                         =>  valueNotShare
1219    // value is young :           0x09                                        =>  needCallNotShare
1220    // value is not young : 0x08,       [0x0A, 0x11],                         =>  checkMark
1221    ASSERT(GENERAL_YOUNG_BEGIN <= IN_YOUNG_SPACE && IN_YOUNG_SPACE < SHARED_SPACE_BEGIN &&
1222        SHARED_SPACE_BEGIN <= SHARED_SWEEPABLE_SPACE_BEGIN && SHARED_SWEEPABLE_SPACE_END < IN_SHARED_READ_ONLY_SPACE &&
1223        IN_SHARED_READ_ONLY_SPACE == HEAP_SPACE_END);
1224    __ BindAssemblerStub(RTSTUB_ID(ASMFastWriteBarrier));
1225    Label needCall;
1226    Label checkMark;
1227    Label needCallNotShare;
1228    Label needShareBarrier;
1229    Label valueNotShare;
1230    Label valueMaybeSweepableShare;
1231    {
1232        // int8_t *valueRegion = value & (~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK))
1233        // int8_t valueFlag = *valueRegion
1234        // if (valueFlag >= SHARED_SWEEPABLE_SPACE_BEGIN){
1235        //    goto valueMaybeSweepableShare
1236        // }
1237
1238        __ And(X15, X3, LogicalImmediate::Create(~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK), RegXSize));
1239        // X15 is the region address of value.
1240        __ Ldrb(Register(X15, W), MemoryOperand(X15, 0));
1241        // X15 is the flag load from region of value.
1242        __ Cmp(Register(X15, W), Immediate(SHARED_SWEEPABLE_SPACE_BEGIN));
1243        __ B(GE, &valueMaybeSweepableShare);
1244        // if value may be SweepableShare, goto valueMaybeSweepableShare
1245    }
1246    __ Bind(&valueNotShare);
1247    {
1248        // valueNotShare:
1249        // if (valueFlag != IN_YOUNG_SPACE){
1250        //      goto checkMark
1251        // }
1252        // int8_t *objRegion = obj & (~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK))
1253        // int8_t objFlag = *objRegion
1254        // if (objFlag != IN_YOUNG_SPACE){
1255        //    goto needCallNotShare
1256        // }
1257
1258        __ Cmp(Register(X15, W), Immediate(RegionSpaceFlag::IN_YOUNG_SPACE));
1259        __ B(NE, &checkMark);
1260        // if value is not in young, goto checkMark
1261
1262        __ And(X15, X1, LogicalImmediate::Create(~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK), RegXSize));
1263        // X15 is the region address of obj.
1264        __ Ldrb(Register(X15, W), MemoryOperand(X15, 0));
1265        // X15 is the flag load from region of obj.
1266        __ Cmp(Register(X15, W), Immediate(RegionSpaceFlag::IN_YOUNG_SPACE));
1267        __ B(NE, &needCallNotShare);
1268        // if obj is not in young, goto needCallNotShare
1269    }
1270
1271    __ Bind(&checkMark);
1272    {
1273        // checkMark:
1274        // int8_t GCStateBitField = *(glue+GCStateBitFieldOffset)
1275        // if (GCStateBitField & JSThread::CONCURRENT_MARKING_BITFIELD_MASK != 0) {
1276        //    goto needCallNotShare
1277        // }
1278        // return
1279
1280        __ Mov(X15, JSThread::GlueData::GetGCStateBitFieldOffset(false));
1281        __ Ldrb(Register(X15, W), MemoryOperand(X0, Register(X15), UXTX));
1282        __ Tst(Register(X15, W), LogicalImmediate::Create(JSThread::CONCURRENT_MARKING_BITFIELD_MASK, RegWSize));
1283        __ B(NE, &needCallNotShare);
1284        // if GCState is not READY_TO_MARK, go to needCallNotShare.
1285        __ Ret();
1286    }
1287
1288    __ Bind(&valueMaybeSweepableShare);
1289    {
1290        // valueMaybeSweepableShare:
1291        // if (valueFlag != IN_SHARED_READ_ONLY_SPACE){
1292        //    goto needShareBarrier
1293        // }
1294        // return
1295        __ Cmp(Register(X15, W), Immediate(RegionSpaceFlag::IN_SHARED_READ_ONLY_SPACE));
1296        __ B(NE, &needShareBarrier);
1297        __ Ret();
1298    }
1299
1300    __ Bind(&needCallNotShare);
1301    {
1302        int32_t NonSValueBarrier = static_cast<int32_t>(JSThread::GlueData::GetCOStubEntriesOffset(false)) +
1303            kungfu::CommonStubCSigns::SetNonSValueWithBarrier * FRAME_SLOT_SIZE;
1304        __ Mov(X15, NonSValueBarrier);
1305    }
1306    __ Bind(&needCall);
1307    {
1308        __ Ldr(X15, MemoryOperand(X0, Register(X15), UXTX));
1309        PreserveMostCall(assembler);
1310    }
1311    __ Bind(&needShareBarrier);
1312    {
1313        ASMFastSharedWriteBarrier(assembler, needCall);
1314    }
1315}
1316
1317// ASMWriteBarrierWithEden(GateRef glue, GateRef obj, GateRef offset, GateRef value)
1318// c calling convention, but preserve all general registers except %x15
1319// %x0 - glue
1320// %x1 - obj
1321// %x2 - offset
1322// %x3 - value
1323void AsmInterpreterCall::ASMWriteBarrierWithEden(ExtendedAssembler* assembler)
1324{
1325    __ BindAssemblerStub(RTSTUB_ID(ASMWriteBarrierWithEden));
1326    // Just for compitability, not a fast implement, should be refactored when enable EdenBarrier.
1327    int32_t EdenBarrierOffset = static_cast<int32_t>(JSThread::GlueData::GetCOStubEntriesOffset(false)) +
1328    kungfu::CommonStubCSigns::SetValueWithEdenBarrier * FRAME_SLOT_SIZE;
1329    __ Mov(X15, EdenBarrierOffset);
1330    __ Ldr(X15, MemoryOperand(X0, Register(X15), UXTX));
1331    PreserveMostCall(assembler);
1332}
1333
1334// %x0 - glue
1335// %x1 - obj
1336// %x2 - offset
1337// %x3 - value
1338void AsmInterpreterCall::ASMFastSharedWriteBarrier(ExtendedAssembler* assembler, Label& needCall)
1339{
1340    Label checkBarrierForSharedValue;
1341    Label restoreScratchRegister;
1342    Label callSharedBarrier;
1343    {
1344        // int8_t *objRegion = obj & (~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK))
1345        // int8_t objFlag = *objRegion
1346        // if (objFlag >= SHARED_SPACE_BEGIN){
1347        //    // share to share, just check the barrier
1348        //    goto checkBarrierForSharedValue
1349        // }
1350        __ And(X15, X1, LogicalImmediate::Create(~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK), RegXSize));
1351        __ Ldrb(Register(X15, W), MemoryOperand(X15, 0));
1352        // X15 is the flag load from region of obj.
1353        __ Cmp(Register(X15, W), Immediate(RegionSpaceFlag::SHARED_SPACE_BEGIN));
1354        __ B(GE, &checkBarrierForSharedValue);  // if objflag >= SHARED_SPACE_BEGIN  => checkBarrierForSharedValue
1355    }
1356    {
1357        // int8_t *objRegion = obj & (~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK))
1358        // int8_t *localToShareSet = *(objRegion + LocalToShareSetOffset)
1359        // if (localToShareSet == 0){
1360        //    goto callSharedBarrier
1361        // }
1362        __ And(X15, X1, LogicalImmediate::Create(~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK), RegXSize));
1363        __ Ldr(X15, MemoryOperand(X15, Region::PackedData::GetLocalToShareSetOffset(false)));
1364        // X15 is localToShareSet for obj region.
1365        __ Cbz({X15, X}, &callSharedBarrier);   // if localToShareSet == 0  => callSharedBarrier
1366    }
1367    {
1368        // X16, X17 will be used as scratch register, spill them.
1369        // the caller will call this function with inline asm, it will not save any registers except x15.
1370        // So we need spill and restore x16, x17 when we need them as scratch register.
1371        {
1372            __ Stp(X16, X17, MemoryOperand(SP, -DOUBLE_SLOT_SIZE, PREINDEX));
1373        }
1374        // int64_t objOffset = obj & DEFAULT_REGION_MASK
1375        // int64_t slotOffset = objOffset + offset
1376        __ And(X16, X1, LogicalImmediate::Create(DEFAULT_REGION_MASK, RegXSize));
1377        __ Add(X16, X16, Operand(Register(X2)));
1378
1379        // the logic to get mask in stub_builder.cpp
1380        //               [63-------------------------35][34------------------------8][7---3][2-0]
1381        // bitOffset:                                       bbbbbbbbbbbbbbbbbbbbbbbb  bbbcc  ccc
1382        // bitPerWordMask:                                                               11  111
1383        // indexInWord = And bitoffset bitPerWordMask
1384        // indexInWord:                                                                  cc  ccc
1385        // mask = 1 << indexInWord
1386
1387        // the logic to test bit set value here:
1388        //               [63-------------------------35][34------------------------8][7---3][2-0]
1389        // slotOffset:    aaaaaaaaaaaaaaaaaaaaaaaaaaaaa  bbbbbbbbbbbbbbbbbbbbbbbbbbb  ccccc  ddd
1390        // Ubfm X16 slotOffset 3 7
1391        // indexInWord:                                                                  cc  ccc
1392        __ Ubfm(X17, X16, TAGGED_TYPE_SIZE_LOG, TAGGED_TYPE_SIZE_LOG + GCBitset::BIT_PER_WORD_LOG2 - 1);
1393
1394        // the logic to get byteIndex in stub_builder.cpp
1395        //               [63-------------------------35][34------------------------8][7---3][2-0]
1396        // slotOffset:    aaaaaaaaaaaaaaaaaaaaaaaaaaaaa  bbbbbbbbbbbbbbbbbbbbbbbbbbb  ccccc  ddd
1397        // 1. bitOffsetPtr = LSR TAGGED_TYPE_SIZE_LOG(3) slotOffset
1398        // bitOffsetPtr:     aaaaaaaaaaaaaaaaaaaaaaaaaa  aaabbbbbbbbbbbbbbbbbbbbbbbb  bbbcc  ccc
1399        // 2. bitOffset = TruncPtrToInt32 bitOffsetPtr
1400        // bitOffset:                                       bbbbbbbbbbbbbbbbbbbbbbbb  bbbcc  ccc
1401        // 3. index = LSR BIT_PER_WORD_LOG2(5) bitOffset
1402        // index:                                                bbbbbbbbbbbbbbbbbbb  bbbbb  bbb
1403        // 4. byteIndex = Mul index BYTE_PER_WORD(4)
1404        // byteIndex:                                          bbbbbbbbbbbbbbbbbbbbb  bbbbb  b00
1405
1406        // the logic to get byteIndex here:
1407        //               [63-------------------------35][34------------------------8][7---3][2-0]
1408        // slotOffset:    aaaaaaaaaaaaaaaaaaaaaaaaaaaaa  bbbbbbbbbbbbbbbbbbbbbbbbbbb  ccccc  ddd
1409        // Ubfm X16 slotOffset 8 34
1410        // index:                                                bbbbbbbbbbbbbbbbbbb  bbbbb  bbb
1411        __ Ubfm(X16, X16, TAGGED_TYPE_SIZE_LOG + GCBitset::BIT_PER_WORD_LOG2,
1412                sizeof(uint32_t) * GCBitset::BIT_PER_BYTE + TAGGED_TYPE_SIZE_LOG - 1);
1413        __ Add(X15, X15, Operand(Register(X16), LSL, GCBitset::BYTE_PER_WORD_LOG2));
1414        __ Add(X15, X15, Immediate(RememberedSet::GCBITSET_DATA_OFFSET));
1415        // X15 is the address of bitset value. X15 = X15 + X16 << BYTE_PER_WORD_LOG2 + GCBITSET_DATA_OFFSET
1416
1417        // mask = 1 << indexInWord
1418        __ Mov(Register(X16, W), 1);
1419        __ Lsl(Register(X17, W), Register(X16, W), Register(X17, W)); // X17 is the mask
1420
1421        __ Ldr(Register(X16, W), MemoryOperand(X15, 0)); // x16: oldsetValue
1422        __ Tst(Register(X16, W), Register(X17, W));
1423        __ B(NE, &restoreScratchRegister);
1424        __ Orr(Register(X16, W), Register(X16, W), Register(X17, W));
1425        __ Str(Register(X16, W), MemoryOperand(X15, 0));
1426    }
1427    __ Bind(&restoreScratchRegister);
1428    {
1429        __ Ldp(X16, X17, MemoryOperand(SP, DOUBLE_SLOT_SIZE, POSTINDEX));
1430    }
1431    __ Bind(&checkBarrierForSharedValue);
1432    {
1433        // checkBarrierForSharedValue:
1434        // int8_t GCStateBitField = *(glue+SharedGCStateBitFieldOffset)
1435        // if (GCStateBitField & JSThread::SHARED_CONCURRENT_MARKING_BITFIELD_MASK != 0) {
1436        //    goto callSharedBarrier
1437        // }
1438        // return
1439        __ Mov(X15, JSThread::GlueData::GetSharedGCStateBitFieldOffset(false));
1440        __ Ldrb(Register(X15, W), MemoryOperand(X0, Register(X15), UXTX));
1441        static_assert(JSThread::SHARED_CONCURRENT_MARKING_BITFIELD_MASK == 1 && "Tbnz can't handle other bit mask");
1442        __ Tbnz(Register(X15, W), 0, &callSharedBarrier);
1443        // if GCState is not READY_TO_MARK, go to needCallNotShare.
1444        __ Ret();
1445    }
1446
1447    __ Bind(&callSharedBarrier);
1448    {
1449        int32_t SValueBarrierOffset = static_cast<int32_t>(JSThread::GlueData::GetCOStubEntriesOffset(false)) +
1450            kungfu::CommonStubCSigns::SetSValueWithBarrier * FRAME_SLOT_SIZE;
1451        __ Mov(X15, SValueBarrierOffset);
1452        __ B(&needCall);
1453    }
1454}
1455
1456// Generate code for generator re-entering asm interpreter
1457// c++ calling convention
1458// Input: %X0 - glue
1459//        %X1 - context(GeneratorContext)
1460void AsmInterpreterCall::GeneratorReEnterAsmInterp(ExtendedAssembler *assembler)
1461{
1462    __ BindAssemblerStub(RTSTUB_ID(GeneratorReEnterAsmInterp));
1463    Label target;
1464    size_t begin = __ GetCurrentPosition();
1465    PushAsmInterpEntryFrame(assembler);
1466    __ Bl(&target);
1467    PopAsmInterpEntryFrame(assembler);
1468    size_t end = __ GetCurrentPosition();
1469    if ((end - begin) != FrameCompletionPos::ARM64EntryFrameDuration) {
1470        LOG_COMPILER(FATAL) << (end - begin) << " != " << FrameCompletionPos::ARM64EntryFrameDuration
1471                            << "This frame has been modified, and the offset EntryFrameDuration should be updated too.";
1472    }
1473    __ Ret();
1474    __ Bind(&target);
1475    {
1476        GeneratorReEnterAsmInterpDispatch(assembler);
1477    }
1478}
1479
1480void AsmInterpreterCall::GeneratorReEnterAsmInterpDispatch(ExtendedAssembler *assembler)
1481{
1482    Label pushFrameState;
1483    Label stackOverflow;
1484    Register glue = __ GlueRegister();
1485    Register contextRegister(X1);
1486    Register spRegister(SP);
1487    Register pc(X8);
1488    Register prevSpRegister(FP);
1489    Register callTarget(X4);
1490    Register method(X5);
1491    Register temp(X6); // can not be used to store any variable
1492    Register currentSlotRegister(X7);
1493    Register fpRegister(X9);
1494    Register thisRegister(X25);
1495    Register nRegsRegister(X26, W);
1496    Register regsArrayRegister(X27);
1497    Register newSp(X28);
1498    __ Ldr(callTarget, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_METHOD_OFFSET));
1499    __ Ldr(method, MemoryOperand(callTarget, JSFunctionBase::METHOD_OFFSET));
1500    __ PushFpAndLr();
1501    // save fp
1502    __ Mov(fpRegister, spRegister);
1503    __ Mov(currentSlotRegister, spRegister);
1504    // Reserve enough sp space to prevent stack parameters from being covered by cpu profiler.
1505    __ Ldr(temp, MemoryOperand(glue, JSThread::GlueData::GetStackLimitOffset(false)));
1506    __ Mov(Register(SP), temp);
1507    // push context regs
1508    __ Ldr(nRegsRegister, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_NREGS_OFFSET));
1509    __ Ldr(thisRegister, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_THIS_OFFSET));
1510    __ Ldr(regsArrayRegister, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_REGS_ARRAY_OFFSET));
1511    __ Add(regsArrayRegister, regsArrayRegister, Immediate(TaggedArray::DATA_OFFSET));
1512    PushArgsWithArgv(assembler, glue, nRegsRegister, regsArrayRegister, temp,
1513                     currentSlotRegister, &pushFrameState, &stackOverflow);
1514
1515    __ Bind(&pushFrameState);
1516    __ Mov(newSp, currentSlotRegister);
1517    // push frame state
1518    PushGeneratorFrameState(assembler, prevSpRegister, fpRegister, currentSlotRegister, callTarget, thisRegister,
1519                            method, contextRegister, pc, temp);
1520    __ Align16(currentSlotRegister);
1521    __ Mov(Register(SP), currentSlotRegister);
1522    // call bc stub
1523    CallBCStub(assembler, newSp, glue, callTarget, method, pc, temp);
1524
1525    __ Bind(&stackOverflow);
1526    {
1527        ThrowStackOverflowExceptionAndReturn(assembler, glue, fpRegister, temp);
1528    }
1529}
1530
1531void AsmInterpreterCall::PushCallThis(ExtendedAssembler *assembler,
1532    JSCallMode mode, Label *stackOverflow, FrameTransitionType type)
1533{
1534    Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
1535    Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
1536    Register thisRegister = __ AvailableRegister2();
1537    Register currentSlotRegister = __ AvailableRegister3();
1538
1539    Label pushVregs;
1540    Label pushNewTarget;
1541    Label pushCallTarget;
1542    bool haveThis = kungfu::AssemblerModule::JSModeHaveThisArg(mode);
1543    bool haveNewTarget = kungfu::AssemblerModule::JSModeHaveNewTargetArg(mode);
1544    if (!haveThis) {
1545        __ Mov(thisRegister, Immediate(JSTaggedValue::VALUE_UNDEFINED));  // default this: undefined
1546    } else {
1547        Register thisArgRegister = GetThisRegsiter(assembler, mode, thisRegister);
1548        if (thisRegister.GetId() != thisArgRegister.GetId()) {
1549            __ Mov(thisRegister, thisArgRegister);
1550        }
1551    }
1552    __ Tst(callFieldRegister, LogicalImmediate::Create(CALL_TYPE_MASK, RegXSize));
1553    __ B(Condition::EQ, &pushVregs);
1554    __ Tbz(callFieldRegister, MethodLiteral::HaveThisBit::START_BIT, &pushNewTarget);
1555    if (!haveThis) {
1556        [[maybe_unused]] TempRegister1Scope scope1(assembler);
1557        Register tempRegister = __ TempRegister1();
1558        __ Mov(tempRegister, Immediate(JSTaggedValue::VALUE_UNDEFINED));
1559        __ Str(tempRegister, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1560    } else {
1561        __ Str(thisRegister, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1562    }
1563    __ Bind(&pushNewTarget);
1564    {
1565        __ Tbz(callFieldRegister, MethodLiteral::HaveNewTargetBit::START_BIT, &pushCallTarget);
1566        if (!haveNewTarget) {
1567            [[maybe_unused]] TempRegister1Scope scope1(assembler);
1568            Register newTarget = __ TempRegister1();
1569            __ Mov(newTarget, Immediate(JSTaggedValue::VALUE_UNDEFINED));
1570            __ Str(newTarget, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1571        } else {
1572            [[maybe_unused]] TempRegister1Scope scope1(assembler);
1573            Register defaultRegister = __ TempRegister1();
1574            Register newTargetRegister = GetNewTargetRegsiter(assembler, mode, defaultRegister);
1575            __ Str(newTargetRegister, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1576        }
1577    }
1578    __ Bind(&pushCallTarget);
1579    {
1580        __ Tbz(callFieldRegister, MethodLiteral::HaveFuncBit::START_BIT, &pushVregs);
1581        __ Str(callTargetRegister, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1582    }
1583    __ Bind(&pushVregs);
1584    {
1585        PushVregs(assembler, stackOverflow, type);
1586    }
1587}
1588
1589void AsmInterpreterCall::PushVregs(ExtendedAssembler *assembler,
1590    Label *stackOverflow, FrameTransitionType type)
1591{
1592    Register glue = __ GlueRegister();
1593    Register prevSpRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::SP);
1594    Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
1595    Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
1596    Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
1597    Register fpRegister = __ AvailableRegister1();
1598    Register thisRegister = __ AvailableRegister2();
1599    Register currentSlotRegister = __ AvailableRegister3();
1600
1601    Label pushFrameStateAndCall;
1602    [[maybe_unused]] TempRegister1Scope scope1(assembler);
1603    Register tempRegister = __ TempRegister1();
1604    // args register can be reused now.
1605    Register newSpRegister = __ AvailableRegister4();
1606    Register numVregsRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
1607    GetNumVregsFromCallField(assembler, callFieldRegister, numVregsRegister);
1608    PushUndefinedWithArgc(assembler, glue, numVregsRegister, tempRegister, currentSlotRegister, &pushFrameStateAndCall,
1609        stackOverflow);
1610    // fall through
1611    __ Bind(&pushFrameStateAndCall);
1612    {
1613        __ Mov(newSpRegister, currentSlotRegister);
1614
1615        [[maybe_unused]] TempRegister2Scope scope2(assembler);
1616        Register pcRegister = __ TempRegister2();
1617        PushFrameState(assembler, prevSpRegister, fpRegister, currentSlotRegister, callTargetRegister, thisRegister,
1618            methodRegister, pcRegister, tempRegister);
1619
1620        __ Align16(currentSlotRegister);
1621        __ Mov(Register(SP), currentSlotRegister);
1622        if (type == FrameTransitionType::OTHER_TO_BASELINE_CHECK ||
1623            type == FrameTransitionType::BASELINE_TO_BASELINE_CHECK) {
1624            // check baselinecode, temp modify TOOD: need to check
1625            Label baselineCodeUndefined;
1626            __ Ldr(tempRegister, MemoryOperand(callTargetRegister, JSFunction::BASELINECODE_OFFSET));
1627            __ Cmp(tempRegister, Immediate(JSTaggedValue::VALUE_UNDEFINED));
1628            __ B(Condition::EQ, &baselineCodeUndefined);
1629
1630            // check is compiling
1631            __ Cmp(tempRegister, Immediate(JSTaggedValue::VALUE_HOLE));
1632            __ B(Condition::EQ, &baselineCodeUndefined);
1633
1634            __ Ldr(tempRegister, MemoryOperand(tempRegister, MachineCode::FUNCADDR_OFFSET));
1635            if (glue != X19) {
1636                __ Mov(X19, glue);
1637            }
1638            if (methodRegister != X21) {
1639                __ Mov(X21, methodRegister);
1640            }
1641            __ Mov(currentSlotRegister, Immediate(BASELINEJIT_PC_FLAG));
1642            // -3: frame type, prevSp, pc
1643            __ Stur(currentSlotRegister, MemoryOperand(newSpRegister, -3 * FRAME_SLOT_SIZE));
1644            __ Mov(Register(X29), newSpRegister);
1645            __ Br(tempRegister);
1646            __ Bind(&baselineCodeUndefined);
1647        }
1648        DispatchCall(assembler, pcRegister, newSpRegister);
1649    }
1650}
1651
1652// Input: X19 - glue
1653//        FP - sp
1654//        X20 - callTarget
1655//        X21 - method
1656void AsmInterpreterCall::DispatchCall(ExtendedAssembler *assembler, Register pcRegister,
1657    Register newSpRegister, Register accRegister)
1658{
1659    Register glueRegister = __ GlueRegister();
1660    Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
1661    Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
1662
1663    if (glueRegister.GetId() != X19) {
1664        __ Mov(Register(X19), glueRegister);
1665    }
1666    __ Ldrh(Register(X24, W), MemoryOperand(methodRegister, Method::LITERAL_INFO_OFFSET));
1667    if (accRegister == INVALID_REG) {
1668        __ Mov(Register(X23), Immediate(JSTaggedValue::VALUE_HOLE));
1669    } else {
1670        ASSERT(accRegister == Register(X23));
1671    }
1672    __ Ldr(Register(X22), MemoryOperand(callTargetRegister, JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET));
1673    __ Ldr(Register(X22), MemoryOperand(Register(X22), ProfileTypeInfoCell::VALUE_OFFSET));
1674    __ Ldr(Register(X21), MemoryOperand(methodRegister, Method::CONSTANT_POOL_OFFSET));
1675    __ Mov(Register(X20), pcRegister);
1676    __ Mov(Register(FP), newSpRegister);
1677
1678    Register bcIndexRegister = __ AvailableRegister1();
1679    Register tempRegister = __ AvailableRegister2();
1680    __ Ldrb(bcIndexRegister.W(), MemoryOperand(pcRegister, 0));
1681    __ Add(tempRegister, glueRegister, Operand(bcIndexRegister.W(), UXTW, FRAME_SLOT_SIZE_LOG2));
1682    __ Ldr(tempRegister, MemoryOperand(tempRegister, JSThread::GlueData::GetBCStubEntriesOffset(false)));
1683    __ Br(tempRegister);
1684}
1685
1686void AsmInterpreterCall::PushFrameState(ExtendedAssembler *assembler, Register prevSp, Register fp,
1687    Register currentSlot, Register callTarget, Register thisObj, Register method, Register pc, Register op)
1688{
1689    __ Mov(op, Immediate(static_cast<int32_t>(FrameType::ASM_INTERPRETER_FRAME)));
1690    __ Stp(prevSp, op, MemoryOperand(currentSlot, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX)); // -2: frame type & prevSp
1691    __ Ldr(pc, MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
1692    __ Stp(fp, pc, MemoryOperand(currentSlot, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX)); // -2: pc & fp
1693    __ Ldr(op, MemoryOperand(callTarget, JSFunction::LEXICAL_ENV_OFFSET));
1694    __ Stp(op, Register(Zero), MemoryOperand(currentSlot,
1695                                             -2 * FRAME_SLOT_SIZE, // -2: jumpSizeAfterCall & env
1696                                             AddrMode::PREINDEX));
1697    __ Mov(op, Immediate(JSTaggedValue::VALUE_HOLE));
1698    __ Stp(thisObj, op, MemoryOperand(currentSlot, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));    // -2: acc & this
1699    __ Str(callTarget, MemoryOperand(currentSlot, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));         // -1: callTarget
1700}
1701
1702void AsmInterpreterCall::GetNumVregsFromCallField(ExtendedAssembler *assembler, Register callField, Register numVregs)
1703{
1704    __ Mov(numVregs, callField);
1705    __ Lsr(numVregs, numVregs, MethodLiteral::NumVregsBits::START_BIT);
1706    __ And(numVregs.W(), numVregs.W(), LogicalImmediate::Create(
1707        MethodLiteral::NumVregsBits::Mask() >> MethodLiteral::NumVregsBits::START_BIT, RegWSize));
1708}
1709
1710void AsmInterpreterCall::GetDeclaredNumArgsFromCallField(ExtendedAssembler *assembler, Register callField,
1711    Register declaredNumArgs)
1712{
1713    __ Mov(declaredNumArgs, callField);
1714    __ Lsr(declaredNumArgs, declaredNumArgs, MethodLiteral::NumArgsBits::START_BIT);
1715    __ And(declaredNumArgs.W(), declaredNumArgs.W(), LogicalImmediate::Create(
1716        MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegWSize));
1717}
1718
1719void AsmInterpreterCall::PushAsmInterpEntryFrame(ExtendedAssembler *assembler)
1720{
1721    Register glue = __ GlueRegister();
1722    Register fp(X29);
1723    Register sp(SP);
1724
1725    size_t begin = __ GetCurrentPosition();
1726    if (!assembler->FromInterpreterHandler()) {
1727        __ CalleeSave();
1728    }
1729
1730    [[maybe_unused]] TempRegister1Scope scope1(assembler);
1731    Register prevFrameRegister = __ TempRegister1();
1732    [[maybe_unused]] TempRegister2Scope scope2(assembler);
1733    Register frameTypeRegister = __ TempRegister2();
1734
1735    __ PushFpAndLr();
1736
1737    // prev managed fp is leave frame or nullptr(the first frame)
1738    __ Ldr(prevFrameRegister, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
1739    __ Mov(frameTypeRegister, Immediate(static_cast<int64_t>(FrameType::ASM_INTERPRETER_ENTRY_FRAME)));
1740    // 2 : prevSp & frame type
1741    __ Stp(prevFrameRegister, frameTypeRegister, MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1742    // 2 : pc & glue
1743    __ Stp(glue, Register(Zero), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));  // pc
1744    if (!assembler->FromInterpreterHandler()) {
1745        size_t end = __ GetCurrentPosition();
1746        if ((end - begin) != FrameCompletionPos::ARM64CppToAsmInterp) {
1747            LOG_COMPILER(FATAL) << (end - begin) << " != " << FrameCompletionPos::ARM64CppToAsmInterp
1748                                << "This frame has been modified, and the offset CppToAsmInterp should be updated too.";
1749        }
1750    }
1751    __ Add(fp, sp, Immediate(4 * FRAME_SLOT_SIZE));  // 4: 32 means skip frame type, prevSp, pc and glue
1752}
1753
1754void AsmInterpreterCall::PopAsmInterpEntryFrame(ExtendedAssembler *assembler)
1755{
1756    Register sp(SP);
1757
1758    [[maybe_unused]] TempRegister1Scope scope1(assembler);
1759    Register prevFrameRegister = __ TempRegister1();
1760    [[maybe_unused]] TempRegister2Scope scope2(assembler);
1761    Register glue = __ TempRegister2();
1762    // 2: glue & pc
1763    __ Ldp(glue, Register(Zero), MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
1764    // 2: skip frame type & prev
1765    __ Ldp(prevFrameRegister, Register(Zero), MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
1766    __ Str(prevFrameRegister, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
1767    size_t begin = __ GetCurrentPosition();
1768    __ RestoreFpAndLr();
1769    if (!assembler->FromInterpreterHandler()) {
1770        __ CalleeRestore();
1771        size_t end = __ GetCurrentPosition();
1772        if ((end - begin) != FrameCompletionPos::ARM64AsmInterpToCpp) {
1773            LOG_COMPILER(FATAL) << (end - begin) << " != " << FrameCompletionPos::ARM64AsmInterpToCpp
1774                                << "This frame has been modified, and the offset AsmInterpToCpp should be updated too.";
1775        }
1776    }
1777}
1778
1779void AsmInterpreterCall::PushGeneratorFrameState(ExtendedAssembler *assembler, Register &prevSpRegister,
1780    Register &fpRegister, Register &currentSlotRegister, Register &callTargetRegister, Register &thisRegister,
1781    Register &methodRegister, Register &contextRegister, Register &pcRegister, Register &operatorRegister)
1782{
1783    __ Mov(operatorRegister, Immediate(static_cast<int64_t>(FrameType::ASM_INTERPRETER_FRAME)));
1784    __ Stp(prevSpRegister, operatorRegister,
1785        MemoryOperand(currentSlotRegister, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));  // 2 : frameType and prevSp
1786    __ Ldr(pcRegister, MemoryOperand(methodRegister, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
1787    // offset need 8 align, GENERATOR_NREGS_OFFSET instead of GENERATOR_BC_OFFSET_OFFSET
1788    __ Ldr(operatorRegister, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_NREGS_OFFSET));
1789    // 32: get high 32bit
1790    __ Lsr(operatorRegister, operatorRegister, 32);
1791    __ Add(pcRegister, operatorRegister, pcRegister);
1792    // 2 : pc and fp
1793    __ Stp(fpRegister, pcRegister, MemoryOperand(currentSlotRegister, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1794    // jumpSizeAfterCall
1795    __ Str(Register(Zero), MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1796    __ Ldr(operatorRegister, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_LEXICALENV_OFFSET));
1797    // env
1798    __ Str(operatorRegister, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1799    __ Ldr(operatorRegister, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_ACC_OFFSET));
1800    // acc
1801    __ Str(operatorRegister, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1802    __ Stp(callTargetRegister, thisRegister,
1803        MemoryOperand(currentSlotRegister, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));  // 2 : acc and callTarget
1804}
1805
1806void AsmInterpreterCall::CallBCStub(ExtendedAssembler *assembler, Register &newSp, Register &glue,
1807    Register &callTarget, Register &method, Register &pc, Register &temp)
1808{
1809    // prepare call entry
1810    __ Mov(Register(X19), glue);    // X19 - glue
1811    __ Mov(Register(FP), newSp);    // FP - sp
1812    __ Mov(Register(X20), pc);      // X20 - pc
1813    __ Ldr(Register(X21), MemoryOperand(method, Method::CONSTANT_POOL_OFFSET));   // X21 - constantpool
1814    __ Ldr(Register(X22), MemoryOperand(callTarget, JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET));
1815    __ Ldr(Register(X22), MemoryOperand(Register(X22), ProfileTypeInfoCell::VALUE_OFFSET));  // X22 - profileTypeInfo
1816    __ Mov(Register(X23), Immediate(JSTaggedValue::Hole().GetRawData()));                   // X23 - acc
1817    __ Ldr(Register(X24), MemoryOperand(method, Method::LITERAL_INFO_OFFSET)); // X24 - hotnessCounter
1818
1819    // call the first bytecode handler
1820    __ Ldrb(temp.W(), MemoryOperand(pc, 0));
1821    // 3 : 3 means *8
1822    __ Add(temp, glue, Operand(temp.W(), UXTW, FRAME_SLOT_SIZE_LOG2));
1823    __ Ldr(temp, MemoryOperand(temp, JSThread::GlueData::GetBCStubEntriesOffset(false)));
1824    __ Br(temp);
1825}
1826
1827void AsmInterpreterCall::CallNativeEntry(ExtendedAssembler *assembler)
1828{
1829    Label callFastBuiltin;
1830    Label callNativeBuiltin;
1831    Register glue(X0);
1832    Register argv(X5);
1833    Register method(X2);
1834    Register function(X1);
1835    Register nativeCode(X7);
1836    Register temp(X9);
1837    Register callFieldRegister(X3);
1838    // get native pointer
1839    __ Ldr(nativeCode, MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
1840    __ Tbnz(callFieldRegister, MethodLiteral::IsFastBuiltinBit::START_BIT, &callFastBuiltin);
1841
1842    __ Bind(&callNativeBuiltin);
1843    Register sp(SP);
1844    // 2: function & align
1845    __ Stp(function, Register(Zero), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1846    // 2: skip argc & thread
1847    __ Sub(sp, sp, Immediate(2 * FRAME_SLOT_SIZE));
1848    PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_ENTRY_FRAME, temp, argv);
1849    __ Mov(temp, argv);
1850    __ Sub(Register(X0), temp, Immediate(2 * FRAME_SLOT_SIZE));  // 2: skip argc & thread
1851    CallNativeInternal(assembler, nativeCode);
1852
1853    // 4: skip function
1854    __ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
1855    __ Ret();
1856
1857    __ Bind(&callFastBuiltin);
1858    CallFastBuiltin(assembler, &callNativeBuiltin);
1859}
1860
1861void AsmInterpreterCall::CallFastBuiltin(ExtendedAssembler *assembler, Label *callNativeBuiltin)
1862{
1863    Label lCall1;
1864    Label lCall2;
1865    Label lCall3;
1866    Label callEntry;
1867    Register sp(SP);
1868    Register glue(X0);
1869    Register function(X1);
1870    Register method(X2);
1871    Register argc(X4);
1872    Register argv(X5);
1873    Register nativeCode(X7);
1874
1875    Register builtinId = __ AvailableRegister1();
1876    Register temp = __ AvailableRegister2();
1877    // get builtinid
1878    __ Ldr(builtinId, MemoryOperand(method, Method::EXTRA_LITERAL_INFO_OFFSET));  // get extra literal
1879    __ And(builtinId.W(), builtinId.W(), LogicalImmediate::Create(0xff, RegWSize));
1880    __ Cmp(builtinId.W(), Immediate(kungfu::BuiltinsStubCSigns::BUILTINS_CONSTRUCTOR_STUB_FIRST));
1881    __ B(Condition::GE, callNativeBuiltin);
1882
1883    __ Cmp(argc, Immediate(3)); // 3: number of args
1884    __ B(Condition::HI, callNativeBuiltin);
1885
1886    // get builtin func addr
1887    __ Add(builtinId, glue, Operand(builtinId.W(), UXTW, FRAME_SLOT_SIZE_LOG2));
1888    __ Ldr(builtinId, MemoryOperand(builtinId, JSThread::GlueData::GetBuiltinsStubEntriesOffset(false)));
1889    // create frame
1890    PushAsmBridgeFrame(assembler);
1891    __ Mov(temp, function);
1892    __ Mov(X1, nativeCode);
1893    __ Mov(X2, temp);
1894    __ Mov(temp, argv);
1895    __ Mov(X5, argc);
1896    __ Ldr(X3, MemoryOperand(temp, FRAME_SLOT_SIZE));
1897    __ Ldr(X4, MemoryOperand(temp, DOUBLE_SLOT_SIZE));
1898
1899    __ Cmp(Register(X5), Immediate(0));
1900    __ B(Condition::NE, &lCall1);
1901    __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1902    __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1903    __ Stp(Register(X7), Register(X7), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
1904    __ B(&callEntry);
1905
1906    __ Bind(&lCall1);
1907    {
1908        __ Cmp(Register(X5), Immediate(1));
1909        __ B(Condition::NE, &lCall2);
1910        __ Ldr(Register(X6), MemoryOperand(temp, TRIPLE_SLOT_SIZE));
1911        __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));  // reset x7
1912        __ Stp(Register(X7), Register(X7), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
1913        __ B(&callEntry);
1914    }
1915
1916    __ Bind(&lCall2);
1917    {
1918        __ Cmp(Register(X5), Immediate(2)); // 2: number of args
1919        __ B(Condition::NE, &lCall3);
1920        __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1921        __ Stp(Register(X7), Register(X7), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
1922        __ Ldp(Register(X6), Register(X7), MemoryOperand(temp, TRIPLE_SLOT_SIZE));
1923        __ B(&callEntry);
1924    }
1925
1926    __ Bind(&lCall3);
1927    {
1928        __ Ldr(Register(X7), MemoryOperand(temp, QUINTUPLE_SLOT_SIZE));
1929        __ Stp(Register(X7), Register(X7), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
1930        __ Ldp(Register(X6), Register(X7), MemoryOperand(temp, TRIPLE_SLOT_SIZE));  // get arg0 arg1
1931        __ B(&callEntry);
1932    }
1933
1934    __ Bind(&callEntry);
1935    {
1936        __ Blr(builtinId);
1937        __ Add(sp, sp, Immediate(DOUBLE_SLOT_SIZE));
1938    }
1939    PopAsmBridgeFrame(assembler);
1940    __ Ret();
1941}
1942
1943void AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(ExtendedAssembler *assembler, Register glue,
1944    Register fp, Register op)
1945{
1946    if (fp != Register(SP)) {
1947        __ Mov(Register(SP), fp);
1948    }
1949    __ Mov(op, Immediate(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException));
1950    // 3 : 3 means *8
1951    __ Add(op, glue, Operand(op, LSL, 3));
1952    __ Ldr(op, MemoryOperand(op, JSThread::GlueData::GetRTStubEntriesOffset(false)));
1953    if (glue.GetId() != X0) {
1954        __ Mov(Register(X0), glue);
1955    }
1956    __ Blr(op);
1957    __ RestoreFpAndLr();
1958    __ Ret();
1959}
1960#undef __
1961}  // panda::ecmascript::aarch64