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