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