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