• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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