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 
23 namespace panda::ecmascript::aarch64 {
24 using namespace panda::ecmascript::kungfu;
25 // ExtendAssembler implements frequently-used assembler macros.
26 class ExtendedAssembler : public AssemblerAarch64 {
27 public:
28     static constexpr int FRAME_SLOT_SIZE = 8;
29     static constexpr int PAIR_SLOT_SIZE = 16;
ExtendedAssembler(Chunk *chunk, AssemblerModule *module)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 
TempRegister1()48     Register TempRegister1()
49     {
50         if (temp1InUse_) {
51             LOG_COMPILER(FATAL) << "temp register1 inuse.";
52             UNREACHABLE();
53         }
54         temp1InUse_ = true;
55         return X9;
56     }
TempRegister2()57     Register TempRegister2()
58     {
59         if (temp2InUse_) {
60             LOG_COMPILER(FATAL) << "temp register2 inuse.";
61             UNREACHABLE();
62         }
63         temp2InUse_ = true;
64         return X10;
65     }
AvailableRegister1() const66     Register AvailableRegister1() const
67     {
68         // X11 is neither callee saved reegister nor argument register
69         return X11;
70     }
AvailableRegister2() const71     Register AvailableRegister2() const
72     {
73         // X12 is neither callee saved reegister nor argument register
74         return X12;
75     }
AvailableRegister3() const76     Register AvailableRegister3() const
77     {
78         // X13 is neither callee saved reegister nor argument register
79         return X13;
80     }
AvailableRegister4() const81     Register AvailableRegister4() const
82     {
83         // X14 is neither callee saved reegister nor argument register
84         return X14;
85     }
CallDispatcherArgument(kungfu::CallDispatchInputs index)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     }
GlueRegister()95     Register GlueRegister()
96     {
97         return isGhcCallingConv_ ? X19 : X0;
98     }
99 
FromInterpreterHandler() const100     bool FromInterpreterHandler() const
101     {
102         return isGhcCallingConv_;
103     }
104 private:
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 
118 class TempRegister1Scope {
119 public:
TempRegister1Scope(ExtendedAssembler *assembler)120     explicit TempRegister1Scope(ExtendedAssembler *assembler) : assembler_(assembler) {}
~TempRegister1Scope()121     ~TempRegister1Scope()
122     {
123         assembler_->temp1InUse_ = false;
124     }
125 
126     NO_COPY_SEMANTIC(TempRegister1Scope);
127     NO_MOVE_SEMANTIC(TempRegister1Scope);
128 private:
129     ExtendedAssembler *assembler_;
130 };
131 
132 class TempRegister2Scope {
133 public:
TempRegister2Scope(ExtendedAssembler *assembler)134     explicit TempRegister2Scope(ExtendedAssembler *assembler) : assembler_(assembler) {}
~TempRegister2Scope()135     ~TempRegister2Scope()
136     {
137         assembler_->temp2InUse_ = false;
138     }
139 
140     NO_COPY_SEMANTIC(TempRegister2Scope);
141     NO_MOVE_SEMANTIC(TempRegister2Scope);
142 private:
143     ExtendedAssembler *assembler_;
144 };
145 }  // panda::ecmascript::aarch64
146 #endif  // ECMASCRIPT_COMPILER_AARCH64_EXTEND_ASSEMBLER_H