• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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