1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef ECMASCRIPT_COMPILER_AARCH64_EXTEND_ASSEMBLER_H
17#define ECMASCRIPT_COMPILER_AARCH64_EXTEND_ASSEMBLER_H
18
19#include "ecmascript/compiler/assembler/aarch64/assembler_aarch64.h"
20#include "ecmascript/compiler/assembler_module.h"
21#include "ecmascript/compiler/bc_call_signature.h"
22
23namespace panda::ecmascript::aarch64 {
24using namespace panda::ecmascript::kungfu;
25// ExtendAssembler implements frequently-used assembler macros.
26class ExtendedAssembler : public AssemblerAarch64 {
27public:
28    static constexpr int FRAME_SLOT_SIZE = 8;
29    static constexpr int PAIR_SLOT_SIZE = 16;
30    ExtendedAssembler(Chunk *chunk, AssemblerModule *module)
31        : AssemblerAarch64(chunk), module_(module)
32    {
33    }
34    void BindAssemblerStub(int id);
35    void CalleeSave();
36    void CalleeRestore();
37    void CallAssemblerStub(int id, bool isTail = false);
38    void PushFpAndLr();
39    void SaveFpAndLr();
40    void RestoreFpAndLr();
41    void PushLrAndFp();
42    void SaveLrAndFp();
43    void RestoreLrAndFp();
44    void PushArgc(int32_t argc, Register op, Register fp);
45    void PushArgc(Register argc, Register op, Register fp);
46    void Align16(Register fp);
47
48    Register TempRegister1()
49    {
50        if (temp1InUse_) {
51            LOG_COMPILER(FATAL) << "temp register1 inuse.";
52            UNREACHABLE();
53        }
54        temp1InUse_ = true;
55        return X9;
56    }
57    Register TempRegister2()
58    {
59        if (temp2InUse_) {
60            LOG_COMPILER(FATAL) << "temp register2 inuse.";
61            UNREACHABLE();
62        }
63        temp2InUse_ = true;
64        return X10;
65    }
66    Register AvailableRegister1() const
67    {
68        // X11 is neither callee saved reegister nor argument register
69        return X11;
70    }
71    Register AvailableRegister2() const
72    {
73        // X12 is neither callee saved reegister nor argument register
74        return X12;
75    }
76    Register AvailableRegister3() const
77    {
78        // X13 is neither callee saved reegister nor argument register
79        return X13;
80    }
81    Register AvailableRegister4() const
82    {
83        // X14 is neither callee saved reegister nor argument register
84        return X14;
85    }
86    Register CallDispatcherArgument(kungfu::CallDispatchInputs index)
87    {
88        size_t i = static_cast<size_t>(index);
89        Register ret = isGhcCallingConv_ ? ghcJSCallDispacherArgs_[i] : cppJSCallDispacherArgs_[i];
90        if (ret.GetId() == INVALID_REG) {
91            LOG_COMPILER(FATAL) << "arm64 invalid call argument:" << i;
92        }
93        return ret;
94    }
95    Register GlueRegister()
96    {
97        return isGhcCallingConv_ ? X19 : X0;
98    }
99
100    bool FromInterpreterHandler() const
101    {
102        return isGhcCallingConv_;
103    }
104private:
105    AssemblerModule *module_ {nullptr};
106    bool isGhcCallingConv_ {false};
107    bool temp1InUse_ {false};
108    bool temp2InUse_ {false};
109    friend class TempRegister1Scope;
110    friend class TempRegister2Scope;
111
112    static constexpr size_t JS_CALL_DISPATCHER_ARGS_COUNT =
113        static_cast<size_t>(kungfu::CallDispatchInputs::NUM_OF_INPUTS);
114    static Register ghcJSCallDispacherArgs_[JS_CALL_DISPATCHER_ARGS_COUNT];
115    static Register cppJSCallDispacherArgs_[JS_CALL_DISPATCHER_ARGS_COUNT];
116};
117
118class TempRegister1Scope {
119public:
120    explicit TempRegister1Scope(ExtendedAssembler *assembler) : assembler_(assembler) {}
121    ~TempRegister1Scope()
122    {
123        assembler_->temp1InUse_ = false;
124    }
125
126    NO_COPY_SEMANTIC(TempRegister1Scope);
127    NO_MOVE_SEMANTIC(TempRegister1Scope);
128private:
129    ExtendedAssembler *assembler_;
130};
131
132class TempRegister2Scope {
133public:
134    explicit TempRegister2Scope(ExtendedAssembler *assembler) : assembler_(assembler) {}
135    ~TempRegister2Scope()
136    {
137        assembler_->temp2InUse_ = false;
138    }
139
140    NO_COPY_SEMANTIC(TempRegister2Scope);
141    NO_MOVE_SEMANTIC(TempRegister2Scope);
142private:
143    ExtendedAssembler *assembler_;
144};
145}  // panda::ecmascript::aarch64
146#endif  // ECMASCRIPT_COMPILER_AARCH64_EXTEND_ASSEMBLER_H