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