/src/WasmEdge/include/ast/instruction.h
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: 2019-2024 Second State INC |
3 | | |
4 | | //===-- wasmedge/ast/instruction.h - Instruction class definition ---------===// |
5 | | // |
6 | | // Part of the WasmEdge Project. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | /// |
10 | | /// \file |
11 | | /// This file contains the declaration of the Instruction node class. |
12 | | /// |
13 | | //===----------------------------------------------------------------------===// |
14 | | #pragma once |
15 | | |
16 | | #include "common/enum_ast.hpp" |
17 | | #include "common/span.h" |
18 | | #include "common/types.h" |
19 | | |
20 | | #include <algorithm> |
21 | | #include <vector> |
22 | | |
23 | | namespace WasmEdge { |
24 | | namespace AST { |
25 | | |
26 | | /// Instruction node class. |
27 | | class Instruction { |
28 | | public: |
29 | | struct JumpDescriptor { |
30 | | uint32_t TargetIndex; |
31 | | uint32_t StackEraseBegin; |
32 | | uint32_t StackEraseEnd; |
33 | | int32_t PCOffset; |
34 | | }; |
35 | | struct BrCastDescriptor { |
36 | | struct JumpDescriptor Jump; |
37 | | ValType RType1, RType2; |
38 | | }; |
39 | | struct CatchDescriptor { |
40 | | bool IsAll : 1; |
41 | | bool IsRef : 1; |
42 | | uint32_t TagIndex; |
43 | | uint32_t LabelIndex; |
44 | | struct JumpDescriptor Jump; |
45 | | }; |
46 | | struct TryDescriptor { |
47 | | BlockType ResType; |
48 | | uint32_t BlockParamNum; |
49 | | uint32_t JumpEnd; |
50 | | std::vector<CatchDescriptor> Catch; |
51 | | }; |
52 | | |
53 | | public: |
54 | | /// Constructor assigns the OpCode and the Offset. |
55 | | Instruction(OpCode Byte, uint32_t Off = 0) noexcept |
56 | 8.24M | : Offset(Off), Code(Byte) { |
57 | 8.24M | #if defined(__x86_64__) || defined(__aarch64__) || \ |
58 | 8.24M | (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__) |
59 | 8.24M | Data.Num = static_cast<uint128_t>(0); |
60 | | #else |
61 | | Data.Num.Low = static_cast<uint64_t>(0); |
62 | | Data.Num.High = static_cast<uint64_t>(0); |
63 | | #endif |
64 | 8.24M | Flags.IsAllocLabelList = false; |
65 | 8.24M | Flags.IsAllocValTypeList = false; |
66 | 8.24M | Flags.IsAllocBrCast = false; |
67 | 8.24M | Flags.IsAllocTryCatch = false; |
68 | 8.24M | } |
69 | | |
70 | | /// Copy constructor. |
71 | | Instruction(const Instruction &Instr) noexcept |
72 | 2.58M | : Data(Instr.Data), Offset(Instr.Offset), Code(Instr.Code), |
73 | 2.58M | Flags(Instr.Flags) { |
74 | 2.58M | if (Flags.IsAllocLabelList) { |
75 | 2.63k | Data.BrTable.LabelList = new JumpDescriptor[Data.BrTable.LabelListSize]; |
76 | 2.63k | std::copy_n(Instr.Data.BrTable.LabelList, Data.BrTable.LabelListSize, |
77 | 2.63k | Data.BrTable.LabelList); |
78 | 2.57M | } else if (Flags.IsAllocValTypeList) { |
79 | 663 | Data.SelectT.ValTypeList = new ValType[Data.SelectT.ValTypeListSize]; |
80 | 663 | std::copy_n(Instr.Data.SelectT.ValTypeList, Data.SelectT.ValTypeListSize, |
81 | 663 | Data.SelectT.ValTypeList); |
82 | 2.57M | } else if (Flags.IsAllocBrCast) { |
83 | 301 | Data.BrCast = new BrCastDescriptor(*Instr.Data.BrCast); |
84 | 2.57M | } else if (Flags.IsAllocTryCatch) { |
85 | 1.66k | Data.TryCatch = new TryDescriptor(*Instr.Data.TryCatch); |
86 | 1.66k | } |
87 | 2.58M | } |
88 | | |
89 | | /// Move constructor. |
90 | | Instruction(Instruction &&Instr) noexcept |
91 | 12.1M | : Data(Instr.Data), Offset(Instr.Offset), Code(Instr.Code), |
92 | 12.1M | Flags(Instr.Flags) { |
93 | 12.1M | Instr.Flags.IsAllocLabelList = false; |
94 | 12.1M | Instr.Flags.IsAllocValTypeList = false; |
95 | 12.1M | Instr.Flags.IsAllocBrCast = false; |
96 | 12.1M | Instr.Flags.IsAllocTryCatch = false; |
97 | 12.1M | } |
98 | | |
99 | | /// Destructor. |
100 | 22.9M | ~Instruction() { reset(); } |
101 | | |
102 | | /// Copy assignment. |
103 | 0 | Instruction &operator=(const Instruction &Instr) { |
104 | 0 | if (this != &Instr) { |
105 | 0 | Instruction Tmp(Instr); |
106 | 0 | Tmp.swap(*this); |
107 | 0 | } |
108 | 0 | return *this; |
109 | 0 | } |
110 | | |
111 | | /// Getter of OpCode. |
112 | 13.1M | OpCode getOpCode() const noexcept { return Code; } |
113 | | |
114 | | /// Getter of Offset. |
115 | 1.80k | uint32_t getOffset() const noexcept { return Offset; } |
116 | | |
117 | | /// Getter and setter of block type. |
118 | 17.0k | const BlockType &getBlockType() const noexcept { return Data.Blocks.ResType; } |
119 | 271k | BlockType &getBlockType() noexcept { return Data.Blocks.ResType; } |
120 | | |
121 | | /// Getter and setter of jump count to End instruction. |
122 | 10.3k | uint32_t getJumpEnd() const noexcept { return Data.Blocks.JumpEnd; } |
123 | 30.9k | void setJumpEnd(const uint32_t Cnt) noexcept { Data.Blocks.JumpEnd = Cnt; } |
124 | | |
125 | | /// Getter and setter of jump count to Else instruction. |
126 | 20.2k | uint32_t getJumpElse() const noexcept { return Data.Blocks.JumpElse; } |
127 | 11.4k | void setJumpElse(const uint32_t Cnt) noexcept { Data.Blocks.JumpElse = Cnt; } |
128 | | |
129 | | /// Getter and setter of value type. |
130 | 24.3k | const ValType &getValType() const noexcept { return Data.VType; } |
131 | 14.5k | void setValType(const ValType &VType) noexcept { Data.VType = VType; } |
132 | | |
133 | | /// Getter and setter of label list. |
134 | 9.18k | void setLabelListSize(uint32_t Size) { |
135 | 9.18k | reset(); |
136 | 9.18k | if (Size > 0) { |
137 | 9.18k | Data.BrTable.LabelListSize = Size; |
138 | 9.18k | Data.BrTable.LabelList = new JumpDescriptor[Size]; |
139 | 9.18k | Flags.IsAllocLabelList = true; |
140 | 9.18k | } |
141 | 9.18k | } |
142 | 984 | Span<const JumpDescriptor> getLabelList() const noexcept { |
143 | 984 | return Span<const JumpDescriptor>( |
144 | 984 | Data.BrTable.LabelList, |
145 | 984 | Flags.IsAllocLabelList ? Data.BrTable.LabelListSize : 0); |
146 | 984 | } |
147 | 86.0k | Span<JumpDescriptor> getLabelList() noexcept { |
148 | 86.0k | return Span<JumpDescriptor>( |
149 | 86.0k | Data.BrTable.LabelList, |
150 | 86.0k | Flags.IsAllocLabelList ? Data.BrTable.LabelListSize : 0); |
151 | 86.0k | } |
152 | | |
153 | | /// Getter and setter of expression end for End instruction. |
154 | 0 | bool isExprLast() const noexcept { return Data.EndFlags.IsExprLast; } |
155 | 59.4k | void setExprLast(bool Last = true) noexcept { |
156 | 59.4k | Data.EndFlags.IsExprLast = Last; |
157 | 59.4k | } |
158 | | |
159 | | /// Getter and setter of try block end for End instruction. |
160 | 0 | bool isTryBlockLast() const noexcept { return Data.EndFlags.IsTryBlockLast; } |
161 | 30.5k | void setTryBlockLast(bool Last = true) noexcept { |
162 | 30.5k | Data.EndFlags.IsTryBlockLast = Last; |
163 | 30.5k | } |
164 | | |
165 | | /// Getter and setter of Jump for Br* instruction. |
166 | 4.97k | const JumpDescriptor &getJump() const noexcept { return Data.Jump; } |
167 | 17.7k | JumpDescriptor &getJump() noexcept { return Data.Jump; } |
168 | | |
169 | | /// Getter and setter of selecting value types list. |
170 | 2.21k | void setValTypeListSize(uint32_t Size) { |
171 | 2.21k | reset(); |
172 | 2.21k | if (Size > 0) { |
173 | 1.76k | Data.SelectT.ValTypeListSize = Size; |
174 | 1.76k | Data.SelectT.ValTypeList = new ValType[Size]; |
175 | 1.76k | Flags.IsAllocValTypeList = true; |
176 | 1.76k | } |
177 | 2.21k | } |
178 | 1.19k | Span<const ValType> getValTypeList() const noexcept { |
179 | 1.19k | return Span<const ValType>(Data.SelectT.ValTypeList, |
180 | 1.19k | Data.SelectT.ValTypeListSize); |
181 | 1.19k | } |
182 | 3.33k | Span<ValType> getValTypeList() noexcept { |
183 | 3.33k | return Span<ValType>(Data.SelectT.ValTypeList, |
184 | 3.33k | Data.SelectT.ValTypeListSize); |
185 | 3.33k | } |
186 | | |
187 | | /// Getter and setter of target index. |
188 | 196k | uint32_t getTargetIndex() const noexcept { return Data.Indices.TargetIdx; } |
189 | 296k | uint32_t &getTargetIndex() noexcept { return Data.Indices.TargetIdx; } |
190 | | |
191 | | /// Getter and setter of source index. |
192 | 4.69k | uint32_t getSourceIndex() const noexcept { return Data.Indices.SourceIdx; } |
193 | 33.6k | uint32_t &getSourceIndex() noexcept { return Data.Indices.SourceIdx; } |
194 | | |
195 | | /// Getter and setter of stack offset. |
196 | 0 | uint32_t getStackOffset() const noexcept { return Data.Indices.StackOffset; } |
197 | 25.6k | uint32_t &getStackOffset() noexcept { return Data.Indices.StackOffset; } |
198 | | |
199 | | /// Getter and setter of memory alignment. |
200 | 118k | uint32_t getMemoryAlign() const noexcept { return Data.Memories.MemAlign; } |
201 | 470k | uint32_t &getMemoryAlign() noexcept { return Data.Memories.MemAlign; } |
202 | | |
203 | | /// Getter of memory offset. |
204 | 22.9k | uint32_t getMemoryOffset() const noexcept { return Data.Memories.MemOffset; } |
205 | 156k | uint32_t &getMemoryOffset() noexcept { return Data.Memories.MemOffset; } |
206 | | |
207 | | /// Getter of memory lane. |
208 | 16.2k | uint8_t getMemoryLane() const noexcept { return Data.Memories.MemLane; } |
209 | 48.7k | uint8_t &getMemoryLane() noexcept { return Data.Memories.MemLane; } |
210 | | |
211 | | /// Getter and setter of the constant value. |
212 | 707k | ValVariant getNum() const noexcept { |
213 | 707k | #if defined(__x86_64__) || defined(__aarch64__) || \ |
214 | 707k | (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__) |
215 | 707k | return ValVariant(Data.Num); |
216 | | #else |
217 | | uint128_t N{Data.Num.High, Data.Num.Low}; |
218 | | return ValVariant(N); |
219 | | #endif |
220 | 707k | } |
221 | 2.25M | void setNum(ValVariant N) noexcept { |
222 | 2.25M | #if defined(__x86_64__) || defined(__aarch64__) || \ |
223 | 2.25M | (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__) |
224 | 2.25M | Data.Num = N.get<uint128_t>(); |
225 | | #else |
226 | | uint128_t V = N.get<uint128_t>(); |
227 | | Data.Num.Low = V.low(); |
228 | | Data.Num.High = V.high(); |
229 | | #endif |
230 | 2.25M | } |
231 | | |
232 | | /// Getter and setter of BrCast info for Br_cast instructions. |
233 | 1.36k | void setBrCast(uint32_t LabelIdx) { |
234 | 1.36k | reset(); |
235 | 1.36k | Data.BrCast = new BrCastDescriptor(); |
236 | 1.36k | Data.BrCast->Jump.TargetIndex = LabelIdx; |
237 | 1.36k | Flags.IsAllocBrCast = true; |
238 | 1.36k | } |
239 | 84 | const BrCastDescriptor &getBrCast() const noexcept { return *Data.BrCast; } |
240 | 2.74k | BrCastDescriptor &getBrCast() noexcept { return *Data.BrCast; } |
241 | | |
242 | | /// Getter and setter of try block info for try_table instruction. |
243 | 2.79k | void setTryCatch() { |
244 | 2.79k | reset(); |
245 | 2.79k | Data.TryCatch = new TryDescriptor(); |
246 | 2.79k | Flags.IsAllocTryCatch = true; |
247 | 2.79k | } |
248 | 132 | const TryDescriptor &getTryCatch() const noexcept { return *Data.TryCatch; } |
249 | 30.9k | TryDescriptor &getTryCatch() noexcept { return *Data.TryCatch; } |
250 | | |
251 | | private: |
252 | | /// Release allocated resources. |
253 | 22.9M | void reset() noexcept { |
254 | 22.9M | if (Flags.IsAllocLabelList) { |
255 | 11.8k | Data.BrTable.LabelListSize = 0; |
256 | 11.8k | delete[] Data.BrTable.LabelList; |
257 | 22.9M | } else if (Flags.IsAllocValTypeList) { |
258 | 2.42k | Data.SelectT.ValTypeListSize = 0; |
259 | 2.42k | delete[] Data.SelectT.ValTypeList; |
260 | 22.9M | } else if (Flags.IsAllocBrCast) { |
261 | 1.66k | delete Data.BrCast; |
262 | 22.9M | } else if (Flags.IsAllocTryCatch) { |
263 | 4.46k | delete Data.TryCatch; |
264 | 4.46k | } |
265 | 22.9M | Flags.IsAllocLabelList = false; |
266 | 22.9M | Flags.IsAllocValTypeList = false; |
267 | 22.9M | Flags.IsAllocBrCast = false; |
268 | 22.9M | Flags.IsAllocTryCatch = false; |
269 | 22.9M | } |
270 | | |
271 | | /// Swap function. |
272 | 0 | void swap(Instruction &Instr) noexcept { |
273 | 0 | std::swap(Data, Instr.Data); |
274 | 0 | std::swap(Offset, Instr.Offset); |
275 | 0 | std::swap(Code, Instr.Code); |
276 | 0 | std::swap(Flags, Instr.Flags); |
277 | 0 | } |
278 | | |
279 | | /// \name Data of instructions. |
280 | | /// @{ |
281 | | union Inner { |
282 | | // Type 1: BlockType, JumpEnd, and JumpElse. |
283 | | struct { |
284 | | uint32_t JumpEnd; |
285 | | uint32_t JumpElse; |
286 | | BlockType ResType; |
287 | | } Blocks; |
288 | | // Type 2: TargetIdx, SourceIdx and StackOffset. |
289 | | struct { |
290 | | uint32_t TargetIdx; |
291 | | uint32_t SourceIdx; |
292 | | uint32_t StackOffset; |
293 | | } Indices; |
294 | | // Type 3: Jump. |
295 | | JumpDescriptor Jump; |
296 | | // Type 4: LabelList. |
297 | | struct { |
298 | | uint32_t LabelListSize; |
299 | | JumpDescriptor *LabelList; |
300 | | } BrTable; |
301 | | // Type 5: ValType. |
302 | | ValType VType; |
303 | | // Type 6: ValTypeList. |
304 | | struct { |
305 | | uint32_t ValTypeListSize; |
306 | | ValType *ValTypeList; |
307 | | } SelectT; |
308 | | // Type 7: TargetIdx, MemAlign, MemOffset, and MemLane. |
309 | | struct { |
310 | | uint32_t TargetIdx; |
311 | | uint32_t MemAlign; |
312 | | uint32_t MemOffset; |
313 | | uint8_t MemLane; |
314 | | } Memories; |
315 | | // Type 8: Num. |
316 | | #if defined(__x86_64__) || defined(__aarch64__) || \ |
317 | | (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__) |
318 | | uint128_t Num; |
319 | | #else |
320 | | struct { |
321 | | uint64_t Low; |
322 | | uint64_t High; |
323 | | } Num; |
324 | | #endif |
325 | | // Type 9: End flags. |
326 | | struct { |
327 | | bool IsExprLast : 1; |
328 | | bool IsTryBlockLast : 1; |
329 | | } EndFlags; |
330 | | // Type 10: TypeCastBranch. |
331 | | BrCastDescriptor *BrCast; |
332 | | // Type 11: Try Block. |
333 | | TryDescriptor *TryCatch; |
334 | | } Data; |
335 | | uint32_t Offset = 0; |
336 | | OpCode Code = OpCode::End; |
337 | | struct { |
338 | | bool IsAllocLabelList : 1; |
339 | | bool IsAllocValTypeList : 1; |
340 | | bool IsAllocBrCast : 1; |
341 | | bool IsAllocTryCatch : 1; |
342 | | } Flags; |
343 | | /// @} |
344 | | }; |
345 | | |
346 | | // Type aliasing |
347 | | using InstrVec = std::vector<Instruction>; |
348 | | using InstrView = Span<const Instruction>; |
349 | | |
350 | | } // namespace AST |
351 | | } // namespace WasmEdge |