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 #ifndef ECMASCRIPT_COMPILER_ASSEMBLER_H
16 #define ECMASCRIPT_COMPILER_ASSEMBLER_H
17
18 #include "ecmascript/mem/dyn_chunk.h"
19
20 namespace panda::ecmascript {
21 enum class Triple {
22 TRIPLE_AMD64,
23 TRIPLE_AARCH64,
24 TRIPLE_ARM32,
25 };
26
27 #define TARGET_X64 "x86_64-unknown-linux-gnu"
28 #define TARGET_AARCH64 "aarch64-unknown-linux-gnu"
29 #define TARGET_ARM32 "arm-unknown-linux-gnu"
30
31 class GCStackMapRegisters {
32 public:
33 #if defined(PANDA_TARGET_AMD64)
34 static constexpr int SP = 7; /* x7 */
35 static constexpr int FP = 6; /* x6 */
36 #elif defined(PANDA_TARGET_ARM64)
37 static constexpr int SP = 31; /* x31 */
38 static constexpr int FP = 29; /* x29 */
39 #elif defined(PANDA_TARGET_ARM32)
40 static constexpr int SP = 13; /* x13 */
41 static constexpr int FP = 11; /* x11 */
42 #else
43 static constexpr int SP = -1;
44 static constexpr int FP = -1;
45 #endif
46
GetFpRegByTriple(Triple triple)47 static int GetFpRegByTriple(Triple triple)
48 {
49 int fp = -1;
50 switch (triple) {
51 case Triple::TRIPLE_AMD64:
52 fp = 6; /* x6 */
53 break;
54 case Triple::TRIPLE_ARM32:
55 fp = 11; /* x11 */
56 break;
57 case Triple::TRIPLE_AARCH64:
58 fp = 29; /* x29 */
59 break;
60 default:
61 UNREACHABLE();
62 break;
63 }
64 return fp;
65 }
66
GetSpRegByTriple(Triple triple)67 static int GetSpRegByTriple(Triple triple)
68 {
69 int sp = -1;
70 switch (triple) {
71 case Triple::TRIPLE_AMD64:
72 sp = 7; /* x7 */
73 break;
74 case Triple::TRIPLE_ARM32:
75 sp = 13; /* x13 */
76 break;
77 case Triple::TRIPLE_AARCH64:
78 sp = 31; /* x31 */
79 break;
80 default:
81 UNREACHABLE();
82 break;
83 }
84 return sp;
85 }
86 };
87
88 enum Distance {
89 Near,
90 Far
91 };
92
93 // When run from cpp to assembly code, there are some insts before the assembly frame is ready.
94 // When return from assembly code to cpp, there are some insts after the assembly frame is broken.
95 // And here are the numbers of insts. Only AsmInterpreterEntryFrame is dealt here, and there is no need
96 // for OptimizedEntryFrame because insts for OptimizedEntryFrame are negligible.
97 enum FrameCompletionPos : uint64_t {
98 // X64
99 X64CppToAsmInterp = 28,
100 X64AsmInterpToCpp = 9,
101 X64EntryFrameDuration = 70,
102 // ARM64
103 ARM64CppToAsmInterp = 56,
104 ARM64AsmInterpToCpp = 40,
105 ARM64EntryFrameDuration = 116,
106 };
107
108 class Label {
109 public:
IsBound()110 bool IsBound() const
111 {
112 return pos_ > 0;
113 }
114
IsLinked()115 bool IsLinked() const
116 {
117 return pos_ < 0;
118 }
119
IsLinkedNear()120 bool IsLinkedNear() const
121 {
122 return nearPos_ > 0;
123 }
124
GetPos()125 uint32_t GetPos() const
126 {
127 return static_cast<uint32_t>(pos_ - 1);
128 }
129
GetLinkedPos()130 uint32_t GetLinkedPos() const
131 {
132 ASSERT(!IsBound());
133 return static_cast<uint32_t>(-pos_ - 1);
134 }
135
BindTo(int32_t pos)136 void BindTo(int32_t pos)
137 {
138 // +1 skip offset 0
139 pos_ = pos + 1;
140 }
141
LinkTo(int32_t pos)142 void LinkTo(int32_t pos)
143 {
144 // +1 skip offset 0
145 pos_ = - (pos + 1);
146 }
147
UnlinkNearPos()148 void UnlinkNearPos()
149 {
150 nearPos_ = 0;
151 }
152
LinkNearPos(uint32_t pos)153 void LinkNearPos(uint32_t pos)
154 {
155 // +1 skip offset 0
156 nearPos_ = pos + 1;
157 }
158
GetLinkedNearPos()159 uint32_t GetLinkedNearPos() const
160 {
161 ASSERT(!IsBound());
162 return static_cast<uint32_t>(nearPos_ - 1);
163 }
164
165 private:
166 int32_t pos_ = 0;
167 uint32_t nearPos_ = 0;
168 };
169
170 class Assembler {
171 public:
Assembler(Chunk * chunk)172 explicit Assembler(Chunk *chunk)
173 : buffer_(chunk) {}
174 ~Assembler() = default;
175
EmitU8(uint8_t v)176 void EmitU8(uint8_t v)
177 {
178 buffer_.EmitChar(v);
179 }
180
EmitI8(int8_t v)181 void EmitI8(int8_t v)
182 {
183 buffer_.EmitChar(static_cast<uint8_t>(v));
184 }
185
EmitU16(uint16_t v)186 void EmitU16(uint16_t v)
187 {
188 buffer_.EmitU16(v);
189 }
190
EmitU32(uint32_t v)191 void EmitU32(uint32_t v)
192 {
193 buffer_.EmitU32(v);
194 }
195
EmitI32(int32_t v)196 void EmitI32(int32_t v)
197 {
198 buffer_.EmitU32(static_cast<uint32_t>(v));
199 }
200
EmitU64(uint64_t v)201 void EmitU64(uint64_t v)
202 {
203 buffer_.EmitU64(v);
204 }
205
PutI8(size_t offset,int8_t data)206 void PutI8(size_t offset, int8_t data)
207 {
208 buffer_.PutU8(offset, static_cast<int8_t>(data));
209 }
210
PutI32(size_t offset,int32_t data)211 void PutI32(size_t offset, int32_t data)
212 {
213 buffer_.PutU32(offset, static_cast<int32_t>(data));
214 }
215
GetU32(size_t offset)216 uint32_t GetU32(size_t offset) const
217 {
218 return buffer_.GetU32(offset);
219 }
220
GetI8(size_t offset)221 int8_t GetI8(size_t offset) const
222 {
223 return static_cast<int8_t>(buffer_.GetU8(offset));
224 }
225
GetU8(size_t offset)226 uint8_t GetU8(size_t offset) const
227 {
228 return buffer_.GetU8(offset);
229 }
230
GetCurrentPosition()231 size_t GetCurrentPosition() const
232 {
233 return buffer_.GetSize();
234 }
235
GetBegin()236 uint8_t *GetBegin() const
237 {
238 return buffer_.GetBegin();
239 }
240
InRangeN(int32_t x,uint32_t n)241 static bool InRangeN(int32_t x, uint32_t n)
242 {
243 int32_t limit = 1 << (n - 1);
244 return (x >= -limit) && (x < limit);
245 }
246
InRange8(int32_t x)247 static bool InRange8(int32_t x)
248 {
249 // 8: range8
250 return InRangeN(x, 8);
251 }
252
GetFrameCompletionPos(uint64_t & headerSize,uint64_t & tailSize,uint64_t & entryDuration)253 static void GetFrameCompletionPos(uint64_t &headerSize, uint64_t &tailSize, uint64_t &entryDuration)
254 {
255 #if defined(PANDA_TARGET_AMD64)
256 headerSize = FrameCompletionPos::X64CppToAsmInterp;
257 tailSize = FrameCompletionPos::X64AsmInterpToCpp;
258 entryDuration = FrameCompletionPos::X64EntryFrameDuration;
259 #elif defined(PANDA_TARGET_ARM64)
260 headerSize = FrameCompletionPos::ARM64CppToAsmInterp;
261 tailSize = FrameCompletionPos::ARM64AsmInterpToCpp;
262 entryDuration = FrameCompletionPos::ARM64EntryFrameDuration;
263 #else
264 headerSize = 0;
265 tailSize = 0;
266 entryDuration = 0;
267 LOG_ECMA(FATAL) << "Assembler does not currently support other platforms, please run on x64 and arm64";
268 #endif
269 }
270 private:
271 DynChunk buffer_;
272 };
273 } // panda::ecmascript
274 #endif // ECMASCRIPT_COMPILER_ASSEMBLER_H
275