1 /** 2 * Copyright (c) 2024 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 16 #ifndef LIBABCKIT_SRC_IR_BUILDER_DYNAMIC_BYTECODE_INST_H 17 #define LIBABCKIT_SRC_IR_BUILDER_DYNAMIC_BYTECODE_INST_H 18 19 #include <cstdint> 20 #include <cstddef> 21 #include <type_traits> 22 #include <memory> 23 #include <array> 24 #include "libabckit/src/macros.h" 25 26 #include "static_core/libpandabase/utils/bit_helpers.h" 27 #include "static_core/libpandabase/os/mem.h" 28 #include "static_core/libpandabase/os/filesystem.h" 29 #include "static_core/libpandabase/utils/span.h" 30 #include "static_core/libpandabase/utils/utf.h" 31 32 #include <iostream> 33 34 namespace libabckit { 35 36 using Index = uint16_t; 37 38 class EntityId { 39 public: EntityId(uint32_t offset)40 explicit constexpr EntityId(uint32_t offset) : offset_(offset) {} 41 GetOffset()42 uint32_t GetOffset() const 43 { 44 return offset_; 45 } 46 GetSize()47 static constexpr size_t GetSize() 48 { 49 return sizeof(uint32_t); 50 } 51 52 friend bool operator<(const EntityId &l, const EntityId &r) 53 { 54 return l.offset_ < r.offset_; 55 } 56 57 friend bool operator==(const EntityId &l, const EntityId &r) 58 { 59 return l.offset_ == r.offset_; 60 } 61 62 friend std::ostream &operator<<(std::ostream &stream, const EntityId &id) 63 { 64 return stream << id.offset_; 65 } 66 67 private: 68 uint32_t offset_ {0}; 69 }; 70 71 class BytecodeId { 72 public: BytecodeId(uint32_t id)73 constexpr explicit BytecodeId(uint32_t id) : id_(id) {} 74 75 constexpr BytecodeId() = default; 76 77 ~BytecodeId() = default; 78 79 DEFAULT_COPY_SEMANTIC(BytecodeId); 80 NO_MOVE_SEMANTIC(BytecodeId); 81 AsIndex()82 Index AsIndex() const 83 { 84 ASSERT(id_ < std::numeric_limits<uint16_t>::max()); 85 return id_; 86 } 87 AsFileId()88 EntityId AsFileId() const 89 { 90 return EntityId(id_); 91 } 92 AsRawValue()93 uint32_t AsRawValue() const 94 { 95 return id_; 96 } 97 IsValid()98 bool IsValid() const 99 { 100 return id_ != INVALID; 101 } 102 103 bool operator==(BytecodeId id) const noexcept 104 { 105 return id_ == id.id_; 106 } 107 108 friend std::ostream &operator<<(std::ostream &stream, BytecodeId id) 109 { 110 return stream << id.id_; 111 } 112 113 private: 114 static constexpr size_t INVALID = std::numeric_limits<uint32_t>::max(); 115 116 uint32_t id_ {INVALID}; 117 }; 118 119 class BytecodeInstBase { 120 public: 121 BytecodeInstBase() = default; BytecodeInstBase(const uint8_t * pc)122 explicit BytecodeInstBase(const uint8_t *pc) : pc_ {pc} {} 123 DEFAULT_COPY_SEMANTIC(BytecodeInstBase); 124 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(BytecodeInstBase); 125 virtual ~BytecodeInstBase() = default; 126 127 protected: GetPointer(int32_t offset)128 const uint8_t *GetPointer(int32_t offset) const 129 { 130 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 131 return pc_ + offset; 132 } 133 GetAddress()134 const uint8_t *GetAddress() const 135 { 136 return pc_; 137 } 138 GetAddress()139 const uint8_t *GetAddress() volatile const 140 { 141 return pc_; 142 } 143 144 template <class T> Read(size_t offset)145 T Read(size_t offset) const 146 { 147 using UnalignedType __attribute__((aligned(1))) = const T; 148 return *reinterpret_cast<UnalignedType *>(GetPointer(offset)); 149 } 150 Write(uint32_t value,uint32_t offset,uint32_t width)151 void Write(uint32_t value, uint32_t offset, uint32_t width) 152 { 153 auto *dst = const_cast<uint8_t *>(GetPointer(offset)); 154 if (memcpy_s(dst, width, &value, width) != 0) { 155 std::cerr << "Cannot write value : " << value << "at the dst offset : " << offset << std::endl; 156 } 157 } 158 159 private: 160 const uint8_t *pc_ {nullptr}; 161 }; 162 163 // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions, hicpp-special-member-functions) 164 class BytecodeInst : public BytecodeInstBase { 165 using Base = BytecodeInstBase; 166 167 public: 168 #include <generated/bytecode_inst_enum_gen.h> 169 170 BytecodeInst() = default; 171 DEFAULT_COPY_SEMANTIC(BytecodeInst); 172 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(BytecodeInst); 173 ~BytecodeInst() override = default; 174 BytecodeInst(const uint8_t * pc)175 explicit BytecodeInst(const uint8_t *pc) : Base {pc} {} 176 177 template <Format FORMAT, size_t IDX = 0, bool IS_SIGNED = false> 178 auto GetImm() const; 179 180 BytecodeId GetId(size_t idx = 0) const; 181 182 uint16_t GetVReg(size_t idx = 0) const; 183 184 BytecodeInst::Opcode GetOpcode() const; 185 GetPrimaryOpcode()186 uint8_t GetPrimaryOpcode() const 187 { 188 return ReadByte(0); 189 } 190 191 uint8_t GetSecondaryOpcode() const; 192 JumpTo(int32_t offset)193 auto JumpTo(int32_t offset) const 194 { 195 return BytecodeInst(Base::GetPointer(offset)); 196 } 197 198 template <Format FORMAT> GetNext()199 BytecodeInst GetNext() const 200 { 201 return JumpTo(Size(FORMAT)); 202 } 203 GetNext()204 BytecodeInst GetNext() const 205 { 206 return JumpTo(GetSize()); 207 } 208 GetAddress()209 const uint8_t *GetAddress() const 210 { 211 return Base::GetAddress(); 212 } 213 GetAddress()214 const uint8_t *GetAddress() volatile const 215 { 216 return Base::GetAddress(); 217 } 218 ReadByte(size_t offset)219 uint8_t ReadByte(size_t offset) const 220 { 221 return Base::template Read<uint8_t>(offset); 222 } 223 224 template <class R, class S> 225 auto ReadHelper(size_t byteoffset, size_t bytecount, size_t offset, size_t width) const; 226 227 template <size_t OFFSET, size_t WIDTH, bool IS_SIGNED = false> 228 auto Read() const; 229 230 template <bool IS_SIGNED = false> 231 auto Read64(size_t offset, size_t width) const; 232 233 size_t GetSize() const; 234 235 Format GetFormat() const; 236 237 bool HasFlag(Flags flag) const; 238 239 bool IsThrow(Exceptions exception) const; 240 IsTerminator()241 bool IsTerminator() const 242 { 243 return HasFlag(Flags::RETURN) || HasFlag(Flags::JUMP) || IsThrow(Exceptions::X_THROW); 244 } 245 IsSuspend()246 bool IsSuspend() const 247 { 248 return HasFlag(Flags::SUSPEND); 249 } 250 251 static constexpr bool HasId(Format format, size_t idx); 252 253 static constexpr bool HasVReg(Format format, size_t idx); 254 255 static constexpr bool HasImm(Format format, size_t idx); 256 257 static constexpr Format GetFormat(Opcode opcode); 258 259 static constexpr size_t Size(Format format); 260 }; 261 262 std::ostream &operator<<(std::ostream &os, const BytecodeInst &inst); 263 264 } // namespace libabckit 265 266 #endif // LIBABCKIT_SRC_IR_BUILDER_DYNAMIC_BYTECODE_INST_H 267