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