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