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 24namespace panda::ecmascript { 25#ifdef JIT_ENABLE_CODE_SIGN 26using namespace OHOS::Security::CodeSign; 27#endif 28enum 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 38class GCStackMapRegisters { 39public: 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 54static 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 74static 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 95enum 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. 104enum 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 115class Label { 116public: 117 Label() = default; 118 119 ~Label() = default; 120 121 bool IsBound() const 122 { 123 return pos_ > 0; 124 } 125 126 bool IsLinked() const 127 { 128 return pos_ < 0; 129 } 130 131 bool IsLinkedNear() const 132 { 133 return nearPos_ > 0; 134 } 135 136 uint32_t GetPos() const 137 { 138 return static_cast<uint32_t>(pos_ - 1); 139 } 140 141 uint32_t GetLinkedPos() const 142 { 143 ASSERT(!IsBound()); 144 return static_cast<uint32_t>(-pos_ - 1); 145 } 146 147 void BindTo(int32_t pos) 148 { 149 // +1 skip offset 0 150 pos_ = pos + 1; 151 } 152 153 void LinkTo(int32_t pos) 154 { 155 // +1 skip offset 0 156 pos_ = - (pos + 1); 157 } 158 159 void UnlinkNearPos() 160 { 161 nearPos_ = 0; 162 } 163 164 void LinkNearPos(uint32_t pos) 165 { 166 // +1 skip offset 0 167 nearPos_ = pos + 1; 168 } 169 170 uint32_t GetLinkedNearPos() const 171 { 172 ASSERT(!IsBound()); 173 return static_cast<uint32_t>(nearPos_ - 1); 174 } 175 176private: 177 int32_t pos_ = 0; 178 uint32_t nearPos_ = 0; 179}; 180 181class Assembler { 182public: 183 explicit Assembler(Chunk *chunk) 184 : buffer_(chunk) {} 185 ~Assembler() = default; 186 187 void EmitU8(uint8_t v) 188 { 189 buffer_.EmitChar(v); 190 } 191 192 void EmitI8(int8_t v) 193 { 194 buffer_.EmitChar(static_cast<uint8_t>(v)); 195 } 196 197 void EmitU16(uint16_t v) 198 { 199 buffer_.EmitU16(v); 200 } 201 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 216 void EmitI32(int32_t v) 217 { 218 buffer_.EmitU32(static_cast<uint32_t>(v)); 219 } 220 221 void EmitU64(uint64_t v) 222 { 223 buffer_.EmitU64(v); 224 } 225 226 void PutI8(size_t offset, int8_t data) 227 { 228 buffer_.PutU8(offset, static_cast<int8_t>(data)); 229 } 230 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 245 uint32_t GetU32(size_t offset) const 246 { 247 return buffer_.GetU32(offset); 248 } 249 250 int8_t GetI8(size_t offset) const 251 { 252 return static_cast<int8_t>(buffer_.GetU8(offset)); 253 } 254 255 uint8_t GetU8(size_t offset) const 256 { 257 return buffer_.GetU8(offset); 258 } 259 260 size_t GetCurrentPosition() const 261 { 262 return buffer_.GetSize(); 263 } 264 265 uint8_t *GetBegin() const 266 { 267 return buffer_.GetBegin(); 268 } 269 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 276 static bool InRange8(int32_t x) 277 { 278 // 8: range8 279 return InRangeN(x, 8); 280 } 281 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 300 void SetDoCodeSign() 301 { 302 doCodeSign = true; 303 } 304 305private: 306 DynChunk buffer_; 307 bool doCodeSign = false; 308}; 309} // panda::ecmascript 310#endif // ECMASCRIPT_COMPILER_ASSEMBLER_H 311