/src/WasmEdge/lib/validator/formchecker.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | #include "validator/formchecker.h" |
5 | | |
6 | | #include "common/errinfo.h" |
7 | | |
8 | | #include <algorithm> |
9 | | #include <array> |
10 | | #include <cstdint> |
11 | | #include <tuple> |
12 | | |
13 | | using namespace std::literals; |
14 | | |
15 | | namespace WasmEdge { |
16 | | namespace Validator { |
17 | | |
18 | | namespace { |
19 | | |
20 | | // Helper function for printing an error log for an index out of range. |
21 | | auto logOutOfRange(ErrCode Code, ErrInfo::IndexCategory Cate, uint32_t Idx, |
22 | 1.17k | uint32_t Bound) { |
23 | 1.17k | spdlog::error(Code); |
24 | 1.17k | spdlog::error(ErrInfo::InfoForbidIndex(Cate, Idx, Bound)); |
25 | 1.17k | return Unexpect(Code); |
26 | 1.17k | } |
27 | | |
28 | | // Helper function for packing TypeCode to address type. |
29 | 59.6k | AddressType convTypeCodeToAddrType(const TypeCode TC) noexcept { |
30 | 59.6k | switch (TC) { |
31 | 58.7k | case TypeCode::I32: |
32 | 58.7k | return AddressType::I32; |
33 | 913 | case TypeCode::I64: |
34 | 913 | return AddressType::I64; |
35 | 0 | default: |
36 | 0 | assumingUnreachable(); |
37 | 59.6k | } |
38 | 59.6k | }; |
39 | | |
40 | | } // namespace |
41 | | |
42 | 38.6k | void FormChecker::reset(bool CleanGlobal) { |
43 | 38.6k | ValStack.clear(); |
44 | 38.6k | CtrlStack.clear(); |
45 | 38.6k | Locals.clear(); |
46 | 38.6k | Returns.clear(); |
47 | | |
48 | 38.6k | if (CleanGlobal) { |
49 | 13.9k | Types.clear(); |
50 | 13.9k | Funcs.clear(); |
51 | 13.9k | Tables.clear(); |
52 | 13.9k | Mems.clear(); |
53 | 13.9k | Globals.clear(); |
54 | 13.9k | Datas.clear(); |
55 | 13.9k | Elems.clear(); |
56 | 13.9k | Refs.clear(); |
57 | 13.9k | Tags.clear(); |
58 | 13.9k | NumImportFuncs = 0; |
59 | 13.9k | NumImportGlobals = 0; |
60 | 13.9k | } |
61 | 38.6k | } |
62 | | |
63 | | Expect<void> FormChecker::validate(AST::InstrView Instrs, |
64 | 24.6k | Span<const ValType> RetVals) { |
65 | 53.6k | for (const ValType &Val : RetVals) { |
66 | 53.6k | Returns.push_back(Val); |
67 | 53.6k | } |
68 | 24.6k | return checkExpr(Instrs); |
69 | 24.6k | } |
70 | | |
71 | 506M | Expect<void> FormChecker::validate(const ValType &VT) const noexcept { |
72 | | // The value type should be validated for the type index case. |
73 | 506M | if (VT.isRefType() && VT.getHeapTypeCode() == TypeCode::TypeIndex) { |
74 | 457M | if (VT.getTypeIndex() >= Types.size()) { |
75 | 127 | spdlog::error(ErrCode::Value::InvalidFuncTypeIdx); |
76 | 127 | spdlog::error(ErrInfo::InfoForbidIndex( |
77 | 127 | ErrInfo::IndexCategory::FunctionType, VT.getTypeIndex(), |
78 | 127 | static_cast<uint32_t>(Types.size()))); |
79 | 127 | return Unexpect(ErrCode::Value::InvalidFuncTypeIdx); |
80 | 127 | } |
81 | 457M | } |
82 | 506M | return {}; |
83 | 506M | } |
84 | | |
85 | 34.5k | void FormChecker::addType(const AST::SubType &Type) { Types.push_back(&Type); } |
86 | | |
87 | 29.4k | void FormChecker::addFunc(const uint32_t TypeIdx, const bool IsImport) { |
88 | 29.4k | if (Types.size() > TypeIdx) { |
89 | 29.4k | Funcs.emplace_back(TypeIdx); |
90 | 29.4k | } |
91 | 29.4k | if (IsImport) { |
92 | 1.12k | NumImportFuncs++; |
93 | 1.12k | } |
94 | 29.4k | } |
95 | | |
96 | 5.47k | void FormChecker::addTable(const AST::TableType &Tab) { |
97 | 5.47k | Tables.emplace_back( |
98 | 5.47k | ValTypeFromAddressType(Tab.getLimit().getAddrType()).getCode(), |
99 | 5.47k | Tab.getRefType()); |
100 | 5.47k | } |
101 | | |
102 | 5.31k | void FormChecker::addMemory(const AST::MemoryType &Mem) { |
103 | 5.31k | Mems.push_back( |
104 | 5.31k | ValTypeFromAddressType(Mem.getLimit().getAddrType()).getCode()); |
105 | 5.31k | } |
106 | | |
107 | 2.63k | void FormChecker::addGlobal(const AST::GlobalType &Glob, const bool IsImport) { |
108 | | // The global type is confirmed in the loading phase. |
109 | 2.63k | Globals.emplace_back(Glob.getValType(), Glob.getValMut()); |
110 | 2.63k | if (IsImport) { |
111 | 795 | NumImportGlobals++; |
112 | 795 | } |
113 | 2.63k | } |
114 | | |
115 | 2.44k | void FormChecker::addData(const AST::DataSegment &) { |
116 | 2.44k | Datas.emplace_back(static_cast<uint32_t>(Datas.size())); |
117 | 2.44k | } |
118 | | |
119 | 1.15k | void FormChecker::addElem(const AST::ElementSegment &Elem) { |
120 | 1.15k | Elems.emplace_back(Elem.getRefType()); |
121 | 1.15k | } |
122 | | |
123 | 12.3k | void FormChecker::addRef(const uint32_t FuncIdx) { Refs.emplace(FuncIdx); } |
124 | | |
125 | 506M | void FormChecker::addLocal(const ValType &V, bool Initialized) { |
126 | 506M | Locals.emplace_back(V); |
127 | 506M | if (Initialized || V.isDefaultable()) { |
128 | 504M | LocalInits.push_back(static_cast<uint32_t>(Locals.size() - 1)); |
129 | 504M | Locals.back().IsInit = true; |
130 | 504M | } |
131 | 506M | } |
132 | | |
133 | 3.67k | void FormChecker::addTag(const uint32_t TypeIdx) { Tags.push_back(TypeIdx); } |
134 | | |
135 | 3.66k | ValType FormChecker::VTypeToAST(const VType &V) { |
136 | 3.66k | if (!V) { |
137 | 2 | return TypeCode::I32; |
138 | 2 | } |
139 | 3.65k | return *V; |
140 | 3.66k | } |
141 | | |
142 | 24.6k | Expect<void> FormChecker::checkExpr(AST::InstrView Instrs) { |
143 | 24.6k | if (Instrs.size() > 0) { |
144 | | // Push ctrl frame ([] -> [Returns]) |
145 | 24.6k | pushCtrl({}, Returns, &*Instrs.rbegin()); |
146 | 24.6k | return checkInstrs(Instrs); |
147 | 24.6k | } |
148 | 0 | return {}; |
149 | 24.6k | } |
150 | | |
151 | 24.6k | Expect<void> FormChecker::checkInstrs(AST::InstrView Instrs) { |
152 | | // Validate instructions |
153 | 2.26M | for (auto &Instr : Instrs) { |
154 | 2.26M | EXPECTED_TRY(checkInstr(Instr).map_error([&Instr](auto E) { |
155 | 2.26M | spdlog::error( |
156 | 2.26M | ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); |
157 | 2.26M | return E; |
158 | 2.26M | })); |
159 | 2.26M | } |
160 | 20.4k | return {}; |
161 | 24.6k | } |
162 | | |
163 | 2.26M | Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { |
164 | | // Note: The instructions and their immediates have passed proposal |
165 | | // configuration checking in the loader phase. |
166 | | |
167 | | // Helper lambda for checking whether the table index is valid. |
168 | 2.26M | auto checkTableIdx = [this](const uint32_t Idx) -> Expect<void> { |
169 | 3.68k | if (unlikely(Idx >= Tables.size())) { |
170 | 113 | return logOutOfRange(ErrCode::Value::InvalidTableIdx, |
171 | 113 | ErrInfo::IndexCategory::Table, Idx, |
172 | 113 | static_cast<uint32_t>(Tables.size())); |
173 | 113 | } |
174 | 3.56k | return {}; |
175 | 3.68k | }; |
176 | | |
177 | | // Helper lambda for checking whether the memory index is valid. |
178 | 2.26M | auto checkMemIdx = [this](const uint32_t Idx) -> Expect<void> { |
179 | 70.6k | if (unlikely(Idx >= Mems.size())) { |
180 | 353 | return logOutOfRange(ErrCode::Value::InvalidMemoryIdx, |
181 | 353 | ErrInfo::IndexCategory::Memory, Idx, |
182 | 353 | static_cast<uint32_t>(Mems.size())); |
183 | 353 | } |
184 | 70.3k | return {}; |
185 | 70.6k | }; |
186 | | |
187 | | // Helper lambda for checking whether the data index is valid. |
188 | 2.26M | auto checkDataIdx = [this](const uint32_t Idx) -> Expect<void> { |
189 | 297 | if (unlikely(Idx >= Datas.size())) { |
190 | 51 | return logOutOfRange(ErrCode::Value::InvalidDataIdx, |
191 | 51 | ErrInfo::IndexCategory::Data, Idx, |
192 | 51 | static_cast<uint32_t>(Datas.size())); |
193 | 51 | } |
194 | 246 | return {}; |
195 | 297 | }; |
196 | | |
197 | | // Helper lambda for checking whether the element index is valid. |
198 | 2.26M | auto checkElemIdx = [this](const uint32_t Idx) -> Expect<void> { |
199 | 2.08k | if (unlikely(Idx >= Elems.size())) { |
200 | 38 | return logOutOfRange(ErrCode::Value::InvalidElemIdx, |
201 | 38 | ErrInfo::IndexCategory::Element, Idx, |
202 | 38 | static_cast<uint32_t>(Elems.size())); |
203 | 38 | } |
204 | 2.05k | return {}; |
205 | 2.08k | }; |
206 | | |
207 | | // Helper lambda for checking whether the tag index is valid. |
208 | 2.26M | auto checkTagIdx = [this](const uint32_t Idx) -> Expect<void> { |
209 | 495 | if (unlikely(Idx >= Tags.size())) { |
210 | 67 | return logOutOfRange(ErrCode::Value::InvalidTagIdx, |
211 | 67 | ErrInfo::IndexCategory::Tag, Idx, |
212 | 67 | static_cast<uint32_t>(Tags.size())); |
213 | 67 | } |
214 | 428 | return {}; |
215 | 495 | }; |
216 | | |
217 | | // Helper lambda for checking the defined type. |
218 | 2.26M | auto checkDefinedType = |
219 | 2.26M | [this](uint32_t TIdx, TypeCode TC) -> Expect<const AST::CompositeType *> { |
220 | 12.4k | if (TIdx >= Types.size()) { |
221 | 133 | return logOutOfRange(ErrCode::Value::InvalidFuncTypeIdx, |
222 | 133 | ErrInfo::IndexCategory::FunctionType, TIdx, |
223 | 133 | static_cast<uint32_t>(Types.size())); |
224 | 133 | } |
225 | 12.2k | const auto &CType = Types[TIdx]->getCompositeType(); |
226 | 12.2k | if (CType.getContentTypeCode() == TC) { |
227 | 12.2k | return &CType; |
228 | 12.2k | } else { |
229 | 37 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
230 | 37 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
231 | 37 | } |
232 | 12.2k | }; |
233 | | |
234 | | // Helper lambda for checking and resolving the block type. |
235 | 2.26M | auto checkBlockType = [this, checkDefinedType](std::vector<ValType> &Buffer, |
236 | 2.26M | const BlockType &BType) |
237 | 2.26M | -> Expect<std::pair<Span<const ValType>, Span<const ValType>>> { |
238 | 15.5k | using ReturnType = std::pair<Span<const ValType>, Span<const ValType>>; |
239 | 15.5k | if (BType.isEmpty()) { |
240 | | // Empty case. t2* = none |
241 | 5.80k | return ReturnType{{}, {}}; |
242 | 9.78k | } else if (BType.isValType()) { |
243 | | // ValType case. t2* = valtype |
244 | 3.53k | EXPECTED_TRY(validate(BType.getValType())); |
245 | 3.53k | Buffer[0] = BType.getValType(); |
246 | 3.53k | return ReturnType{{}, Buffer}; |
247 | 6.24k | } else { |
248 | | // Type index case. t2* = functype.returns. |
249 | 6.24k | EXPECTED_TRY(auto CompType, |
250 | 6.22k | checkDefinedType(BType.getTypeIndex(), TypeCode::Func)); |
251 | 6.22k | const auto &FType = CompType->getFuncType(); |
252 | 6.22k | return ReturnType{FType.getParamTypes(), FType.getReturnTypes()}; |
253 | 6.24k | } |
254 | 15.5k | }; |
255 | | |
256 | | // Helper lambda for checking control stack depth and return index. |
257 | 2.26M | auto checkCtrlStackDepth = [this](uint32_t N) -> Expect<uint32_t> { |
258 | | // Check the control stack for at least N + 1 frames. |
259 | 53.8k | if (N >= CtrlStack.size()) { |
260 | | // Branch out of the stack. |
261 | 145 | return logOutOfRange(ErrCode::Value::InvalidLabelIdx, |
262 | 145 | ErrInfo::IndexCategory::Label, N, |
263 | 145 | static_cast<uint32_t>(CtrlStack.size())); |
264 | 145 | } |
265 | | // Return the index of the N-th element from the end. |
266 | 53.7k | return static_cast<uint32_t>(CtrlStack.size()) - UINT32_C(1) - N; |
267 | 53.8k | }; |
268 | | |
269 | | // Helper lambda for checking lane index and performing transformation. |
270 | 2.26M | auto checkLaneAndTrans = [this, |
271 | 2.26M | &Instr](uint32_t N, Span<const ValType> Take, |
272 | 2.26M | Span<const ValType> Put) -> Expect<void> { |
273 | 10.1k | if (Instr.getMemoryLane() >= N) { |
274 | 43 | return logOutOfRange(ErrCode::Value::InvalidLaneIdx, |
275 | 43 | ErrInfo::IndexCategory::Lane, Instr.getMemoryLane(), |
276 | 43 | N); |
277 | 43 | } |
278 | 10.0k | return StackTrans(Take, Put); |
279 | 10.1k | }; |
280 | | |
281 | | // Helper lambda for checking memory alignment and performing transformation. |
282 | 2.26M | auto checkMemArgAndTrans = [this, checkMemIdx, |
283 | 2.26M | &Instr](uint32_t N, Span<const ValType> Take, |
284 | 2.26M | Span<const ValType> Put, |
285 | 2.26M | bool CheckLane = false) -> Expect<void> { |
286 | | // The first arg is always `addr_type`, representing the memory offset. |
287 | | // This helper will automatically add the first arg, therefore the caller |
288 | | // should set the input type list without the memory offset arg. |
289 | | |
290 | | // Check the memory index and get the address type. |
291 | 58.4k | EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex())); |
292 | | // Check the alignment. |
293 | 58.2k | auto IsAtomic = Instr.getOpCode() >= OpCode::Memory__atomic__notify && |
294 | 341 | Instr.getOpCode() <= OpCode::I64__atomic__rmw32__cmpxchg_u; |
295 | 58.2k | if (Instr.getMemoryAlign() > 31 || |
296 | 58.1k | (!IsAtomic && (1UL << Instr.getMemoryAlign()) > (N >> 3UL))) { |
297 | | // 2 ^ align must be <= N / 8. |
298 | 110 | spdlog::error(ErrCode::Value::AlignmentTooLarge); |
299 | 110 | spdlog::error(ErrInfo::InfoMismatch(static_cast<uint8_t>(N >> 3), |
300 | 110 | Instr.getMemoryAlign())); |
301 | 110 | return Unexpect(ErrCode::Value::AlignmentTooLarge); |
302 | 110 | } |
303 | 58.1k | if (IsAtomic && (1UL << Instr.getMemoryAlign()) != (N >> 3UL)) { |
304 | | // 2 ^ align must be == N / 8. |
305 | 46 | spdlog::error(ErrCode::Value::InvalidAlignment); |
306 | 46 | spdlog::error(ErrInfo::InfoMismatch(static_cast<uint8_t>(N >> 3), |
307 | 46 | Instr.getMemoryAlign())); |
308 | 46 | return Unexpect(ErrCode::Value::InvalidAlignment); |
309 | 46 | } |
310 | | // Check the memory offset validation. |
311 | 58.0k | auto ATCode = Mems[Instr.getTargetIndex()]; |
312 | 58.0k | if (Instr.getMemoryOffset() > |
313 | 58.0k | getMaxAddress(convTypeCodeToAddrType(ATCode))) { |
314 | 17 | spdlog::error(ErrCode::Value::InvalidOffset); |
315 | 17 | return Unexpect(ErrCode::Value::InvalidOffset); |
316 | 17 | } |
317 | | // Check the memory lane if needed. |
318 | 58.0k | if (CheckLane && Instr.getMemoryLane() >= 128 / N) { |
319 | 16 | return logOutOfRange(ErrCode::Value::InvalidLaneIdx, |
320 | 16 | ErrInfo::IndexCategory::Lane, Instr.getMemoryLane(), |
321 | 16 | 128 / N); |
322 | 16 | } |
323 | | // Perform the stack change. Additionally pop the first arg (address type). |
324 | 58.0k | EXPECTED_TRY(popTypes(Take)); |
325 | 58.0k | EXPECTED_TRY(popType(ATCode)); |
326 | 57.9k | pushTypes(Put); |
327 | 57.9k | return {}; |
328 | 58.0k | }; |
329 | | |
330 | | // Helper lambda for checking value type matching. |
331 | 2.26M | auto checkTypesMatching = [this](Span<const ValType> Exp, |
332 | 2.26M | Span<const ValType> Got) -> Expect<void> { |
333 | 4.80k | if (!AST::TypeMatcher::matchTypes(Types, Exp, Got)) { |
334 | 88 | std::vector<ValType> ExpV(Exp.begin(), Exp.end()), |
335 | 88 | GotV(Got.begin(), Got.end()); |
336 | 88 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
337 | 88 | spdlog::error(ErrInfo::InfoMismatch(ExpV, GotV)); |
338 | 88 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
339 | 88 | } |
340 | 4.71k | return {}; |
341 | 4.80k | }; |
342 | | |
343 | | // Helper lambda for recording jump data. |
344 | 2.26M | auto recordJump = [this, &Instr](AST::Instruction::JumpDescriptor &Jump, |
345 | 2.26M | uint32_t Arity, uint32_t D) -> void { |
346 | 53.5k | const uint32_t Remain = |
347 | 53.5k | static_cast<uint32_t>(ValStack.size() - CtrlStack[D].Height); |
348 | 53.5k | Jump.StackEraseBegin = Remain + Arity; |
349 | 53.5k | Jump.StackEraseEnd = Arity; |
350 | 53.5k | Jump.PCOffset = static_cast<int32_t>(CtrlStack[D].Jump - &Instr); |
351 | 53.5k | }; |
352 | | |
353 | | // Helper lambda for unpacking a value type. |
354 | 2.26M | auto unpackType = [](const ValType &T) -> ValType { |
355 | 1.63k | if (T.isPackType()) { |
356 | 767 | return ValType(TypeCode::I32); |
357 | 767 | } |
358 | 867 | return T; |
359 | 1.63k | }; |
360 | | |
361 | | // Helper lambda for downcasting into the top heap type. |
362 | 2.26M | auto toTopHeapType = [this](const ValType &T) -> ValType { |
363 | 930 | assuming(T.isRefType()); |
364 | 930 | return AST::TypeMatcher::getTopHeapType( |
365 | 930 | T.isAbsHeapType() |
366 | 930 | ? T.getHeapTypeCode() |
367 | 930 | : Types[T.getTypeIndex()]->getCompositeType().expand()); |
368 | 930 | }; |
369 | | |
370 | 2.26M | switch (Instr.getOpCode()) { |
371 | | // Control instructions. |
372 | 316k | case OpCode::Unreachable: |
373 | 316k | return unreachable(); |
374 | 113k | case OpCode::Nop: |
375 | 113k | return {}; |
376 | | |
377 | 6.60k | case OpCode::Block: |
378 | 9.82k | case OpCode::Loop: |
379 | 14.6k | case OpCode::If: |
380 | 15.5k | case OpCode::Try_table: { |
381 | | // Get blocktype [t1*] -> [t2*] and check valtype first. |
382 | 15.5k | std::vector<ValType> Buffer(1); |
383 | 15.5k | const auto &BType = (Instr.getOpCode() == OpCode::Try_table) |
384 | 15.5k | ? Instr.getTryCatch().ResType |
385 | 15.5k | : Instr.getBlockType(); |
386 | 15.5k | EXPECTED_TRY(auto T1T2, checkBlockType(Buffer, BType)); |
387 | 15.5k | auto [T1, T2] = T1T2; |
388 | | // For the if instruction, pop I32 first. |
389 | 15.5k | if (Instr.getOpCode() == OpCode::If) { |
390 | 4.78k | EXPECTED_TRY(popType(TypeCode::I32)); |
391 | 4.78k | } |
392 | | // Pop and check [t1*] |
393 | 15.5k | EXPECTED_TRY(popTypes(T1)); |
394 | | // For the try_table instruction, validate the handlers. |
395 | 15.5k | if (Instr.getOpCode() == OpCode::Try_table) { |
396 | 968 | const auto &TryDesc = Instr.getTryCatch(); |
397 | 968 | const_cast<AST::Instruction::TryDescriptor &>(TryDesc).BlockParamNum = |
398 | 968 | static_cast<uint32_t>(T1.size()); |
399 | | // Validate catch clause. |
400 | 2.71k | for (const auto &C : TryDesc.Catch) { |
401 | 2.71k | if (!C.IsAll) { |
402 | | // Check tag index. |
403 | 387 | EXPECTED_TRY(checkTagIdx(C.TagIndex)); |
404 | | // Result types of tag indices are checked in the tag section. |
405 | 387 | } |
406 | 5.38k | EXPECTED_TRY(auto D, checkCtrlStackDepth(C.LabelIndex)); |
407 | 5.38k | pushCtrl({}, getLabelTypes(CtrlStack[D]), &Instr + TryDesc.JumpEnd, |
408 | 5.38k | Instr.getOpCode()); |
409 | 5.38k | std::vector<ValType> NTypes; |
410 | 5.38k | if (!C.IsAll) { |
411 | | // The type is checked as a function type. |
412 | 372 | NTypes = Types[Tags[C.TagIndex]] |
413 | 372 | ->getCompositeType() |
414 | 372 | .getFuncType() |
415 | 372 | .getParamTypes(); |
416 | 372 | } |
417 | 5.38k | if (C.IsRef) { |
418 | 25 | NTypes.emplace_back(ValType(TypeCode::Ref, TypeCode::ExnRef)); |
419 | 25 | } |
420 | 5.38k | pushTypes(NTypes); |
421 | 5.38k | EXPECTED_TRY(popCtrl()); |
422 | 2.67k | recordJump(const_cast<AST::Instruction::JumpDescriptor &>(C.Jump), |
423 | 2.67k | static_cast<uint32_t>(NTypes.size()), D); |
424 | 2.67k | } |
425 | 968 | } |
426 | | // Push ctrl frame ([t1*], [t2*]) |
427 | 15.5k | const AST::Instruction *From = nullptr; |
428 | 15.5k | if (Instr.getOpCode() == OpCode::Loop) { |
429 | 3.21k | From = &Instr; |
430 | 12.2k | } else if (Instr.getOpCode() == OpCode::Try_table) { |
431 | 931 | From = &Instr + Instr.getTryCatch().JumpEnd; |
432 | 11.3k | } else { |
433 | 11.3k | From = &Instr + Instr.getJumpEnd(); |
434 | 11.3k | } |
435 | 15.5k | pushCtrl(T1, T2, From, Instr.getOpCode()); |
436 | 15.5k | if (Instr.getOpCode() == OpCode::If && |
437 | 4.77k | Instr.getJumpElse() == Instr.getJumpEnd()) { |
438 | | // No else case in if-else statement. |
439 | 2.89k | EXPECTED_TRY(checkTypesMatching(T2, T1)); |
440 | 2.89k | } |
441 | 15.4k | return {}; |
442 | 15.5k | } |
443 | | |
444 | 1.80k | case OpCode::Else: { |
445 | 1.80k | EXPECTED_TRY(auto Ctrl, popCtrl()); |
446 | 1.80k | pushCtrl(Ctrl.StartTypes, Ctrl.EndTypes, Ctrl.Jump, Instr.getOpCode()); |
447 | 1.80k | return {}; |
448 | 1.80k | } |
449 | | |
450 | 108 | case OpCode::Throw: { |
451 | 108 | EXPECTED_TRY(checkTagIdx(Instr.getTargetIndex())); |
452 | 100 | EXPECTED_TRY(auto CompType, checkDefinedType(Tags[Instr.getTargetIndex()], |
453 | 100 | TypeCode::Func)); |
454 | 100 | std::vector<ValType> Input = CompType->getFuncType().getParamTypes(); |
455 | 100 | EXPECTED_TRY(popTypes(Input)); |
456 | 44 | return unreachable(); |
457 | 100 | } |
458 | | |
459 | 1.35k | case OpCode::Throw_ref: |
460 | 1.35k | EXPECTED_TRY(popType(TypeCode::ExnRef)); |
461 | 1.33k | return unreachable(); |
462 | | |
463 | 34.9k | case OpCode::End: { |
464 | 34.9k | EXPECTED_TRY(auto Ctrl, popCtrl()); |
465 | 34.5k | pushTypes(Ctrl.EndTypes); |
466 | 34.5k | return {}; |
467 | 34.9k | } |
468 | | |
469 | 5.85k | case OpCode::Br: { |
470 | 5.85k | EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex)); |
471 | | // D is the last D element of control stack. |
472 | 5.83k | const auto NTypes = getLabelTypes(CtrlStack[D]); |
473 | 5.83k | EXPECTED_TRY(popTypes(NTypes)); |
474 | 5.83k | recordJump(const_cast<AST::Instruction &>(Instr).getJump(), |
475 | 5.83k | static_cast<uint32_t>(NTypes.size()), D); |
476 | 5.83k | return unreachable(); |
477 | 5.83k | } |
478 | 2.31k | case OpCode::Br_if: { |
479 | 2.31k | EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex)); |
480 | | // D is the last D element of control stack. |
481 | 2.29k | EXPECTED_TRY(popType(TypeCode::I32)); |
482 | 2.27k | const auto NTypes = getLabelTypes(CtrlStack[D]); |
483 | 2.27k | EXPECTED_TRY(popTypes(NTypes)); |
484 | 2.27k | recordJump(const_cast<AST::Instruction &>(Instr).getJump(), |
485 | 2.27k | static_cast<uint32_t>(NTypes.size()), D); |
486 | 2.27k | pushTypes(NTypes); |
487 | 2.27k | return {}; |
488 | 2.27k | } |
489 | 2.32k | case OpCode::Br_table: { |
490 | 2.32k | EXPECTED_TRY(popType(TypeCode::I32)); |
491 | 2.31k | auto LabelTable = const_cast<AST::Instruction &>(Instr).getLabelList(); |
492 | 2.31k | const auto LabelTableSize = static_cast<uint32_t>(LabelTable.size() - 1); |
493 | 2.31k | EXPECTED_TRY(auto M, |
494 | 2.29k | checkCtrlStackDepth(LabelTable[LabelTableSize].TargetIndex)); |
495 | | // M is the M-th element from the end of the control stack. |
496 | 2.29k | auto MTypes = getLabelTypes(CtrlStack[M]); |
497 | 40.8k | for (uint32_t LabelIdx = 0; LabelIdx < LabelTableSize; ++LabelIdx) { |
498 | 38.6k | const uint32_t L = LabelTable[LabelIdx].TargetIndex; |
499 | 38.6k | EXPECTED_TRY(auto N, checkCtrlStackDepth(L)); |
500 | | // N is the N-th element from the end of the control stack. |
501 | 38.5k | const auto NTypes = getLabelTypes(CtrlStack[N]); |
502 | 38.5k | if (MTypes.size() != NTypes.size()) { |
503 | 6 | return checkTypesMatching(MTypes, NTypes); |
504 | 6 | } |
505 | | // Push the popped types. |
506 | 38.5k | std::vector<VType> TypeBuf(NTypes.size()); |
507 | 49.2k | for (uint32_t IdxN = static_cast<uint32_t>(NTypes.size()); IdxN >= 1; |
508 | 38.5k | --IdxN) { |
509 | 10.7k | const uint32_t Idx = IdxN - 1; |
510 | | // Check whether `unreachableVType` occurred when an `unreachable` |
511 | | // instruction appeared before the `br_table` instruction. |
512 | 10.7k | const bool IsBottom = ValStack.size() == CtrlStack.back().Height || |
513 | 8.91k | ValStack.back() == unreachableVType(); |
514 | | // Cannot use popTypes() here because we need the popped value. |
515 | 10.7k | EXPECTED_TRY(auto Type, popType(NTypes[Idx])); |
516 | 10.7k | TypeBuf[Idx] = IsBottom ? unreachableVType() : Type; |
517 | 10.7k | } |
518 | 38.5k | recordJump(LabelTable[LabelIdx], static_cast<uint32_t>(NTypes.size()), N); |
519 | 38.5k | pushTypes(TypeBuf); |
520 | 38.5k | } |
521 | 2.24k | const auto NTypes = getLabelTypes(CtrlStack[M]); |
522 | 2.24k | EXPECTED_TRY(popTypes(NTypes)); |
523 | 2.24k | recordJump(LabelTable[LabelTableSize], static_cast<uint32_t>(NTypes.size()), |
524 | 2.24k | M); |
525 | 2.24k | return unreachable(); |
526 | 2.24k | } |
527 | | |
528 | 1.66k | case OpCode::Br_on_null: { |
529 | | // D is the last D element of control stack. |
530 | 1.66k | EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex)); |
531 | 1.64k | const auto NTypes = getLabelTypes(CtrlStack[D]); |
532 | 1.64k | EXPECTED_TRY(auto ResT, popType()); |
533 | 1.64k | if (ResT.has_value() && !ResT->isRefType()) { |
534 | 10 | spdlog::error(ErrCode::Value::InvalidBrRefType); |
535 | 10 | return Unexpect(ErrCode::ErrCode::Value::InvalidBrRefType); |
536 | 10 | } |
537 | 1.63k | EXPECTED_TRY(popTypes(NTypes)); |
538 | 1.62k | recordJump(const_cast<AST::Instruction &>(Instr).getJump(), |
539 | 1.62k | static_cast<uint32_t>(NTypes.size()), D); |
540 | 1.62k | pushTypes(NTypes); |
541 | 1.62k | if (ResT.has_value()) { |
542 | 768 | pushType(ResT->toNonNullableRef()); |
543 | 857 | } else { |
544 | 857 | pushType(unreachableVType()); |
545 | 857 | } |
546 | 1.62k | return {}; |
547 | 1.63k | } |
548 | | |
549 | 254 | case OpCode::Br_on_non_null: { |
550 | 254 | EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex)); |
551 | | // Get the result type of the label. (Should be [t* rt].) |
552 | 244 | auto LabelTypes = getLabelTypes(CtrlStack[D]); |
553 | 244 | std::vector<ValType> NTypes(LabelTypes.begin(), LabelTypes.end()); |
554 | 244 | if (unlikely(NTypes.empty())) { |
555 | 5 | spdlog::error(ErrCode::Value::InvalidBrRefType); |
556 | 5 | return Unexpect(ErrCode::Value::InvalidBrRefType); |
557 | 5 | } |
558 | | // Pop types [t* (ref.null rt)]. |
559 | 239 | ValType &RT = NTypes.back(); |
560 | 239 | if (!RT.isRefType()) { |
561 | 5 | spdlog::error(ErrCode::Value::InvalidBrRefType); |
562 | 5 | return Unexpect(ErrCode::Value::InvalidBrRefType); |
563 | 5 | } |
564 | 234 | RT.toNullableRef(); |
565 | 234 | EXPECTED_TRY(popTypes(NTypes)); |
566 | 231 | recordJump(const_cast<AST::Instruction &>(Instr).getJump(), |
567 | 231 | static_cast<uint32_t>(NTypes.size()), D); |
568 | | // Push types [t*]. |
569 | 231 | NTypes.pop_back(); |
570 | 231 | pushTypes(NTypes); |
571 | 231 | return {}; |
572 | 234 | } |
573 | | |
574 | 5.14k | case OpCode::Return: |
575 | 5.14k | EXPECTED_TRY(popTypes(Returns)); |
576 | 5.13k | return unreachable(); |
577 | | |
578 | 7.40k | case OpCode::Call: { |
579 | 7.40k | auto N = Instr.getTargetIndex(); |
580 | 7.40k | if (unlikely(N >= Funcs.size())) { |
581 | 40 | return logOutOfRange(ErrCode::Value::InvalidFuncIdx, |
582 | 40 | ErrInfo::IndexCategory::Function, N, |
583 | 40 | static_cast<uint32_t>(Funcs.size())); |
584 | 40 | } |
585 | | // Because functions were validated when added, Type[Funcs[N]] must be a |
586 | | // function type. |
587 | 7.36k | auto &FuncType = Types[Funcs[N]]->getCompositeType().getFuncType(); |
588 | 7.36k | return StackTrans(FuncType.getParamTypes(), FuncType.getReturnTypes()); |
589 | 7.40k | } |
590 | 1.26k | case OpCode::Call_indirect: { |
591 | 1.26k | auto N = Instr.getTargetIndex(); |
592 | 1.26k | auto T = Instr.getSourceIndex(); |
593 | | // Check source table index. |
594 | 1.26k | EXPECTED_TRY(checkTableIdx(T)); |
595 | 1.23k | if (!AST::TypeMatcher::matchType(Types, TypeCode::FuncRef, |
596 | 1.23k | Tables[T].second)) { |
597 | 4 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
598 | 4 | spdlog::error(ErrInfo::InfoMismatch(TypeCode::FuncRef, Tables[T].second)); |
599 | 4 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
600 | 4 | } |
601 | | // Check target function type index. |
602 | 2.46k | EXPECTED_TRY(auto CompType, checkDefinedType(N, TypeCode::Func)); |
603 | 2.46k | EXPECTED_TRY(popType(Tables[T].first)); |
604 | 1.22k | const auto &FType = CompType->getFuncType(); |
605 | 1.22k | return StackTrans(FType.getParamTypes(), FType.getReturnTypes()); |
606 | 2.46k | } |
607 | 712 | case OpCode::Return_call: { |
608 | 712 | auto N = Instr.getTargetIndex(); |
609 | 712 | if (unlikely(N >= Funcs.size())) { |
610 | | // Call function index out of range |
611 | 36 | spdlog::error(ErrCode::Value::InvalidFuncIdx); |
612 | 36 | spdlog::error( |
613 | 36 | ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::Function, N, |
614 | 36 | static_cast<uint32_t>(Funcs.size()))); |
615 | 36 | return Unexpect(ErrCode::Value::InvalidFuncIdx); |
616 | 36 | } |
617 | | // Because functions were validated when added, Type[Funcs[N]] must be a |
618 | | // function type. |
619 | 676 | auto &FType = Types[Funcs[N]]->getCompositeType().getFuncType(); |
620 | 676 | EXPECTED_TRY(checkTypesMatching(Returns, FType.getReturnTypes())); |
621 | 662 | EXPECTED_TRY(popTypes(FType.getParamTypes())); |
622 | 658 | return unreachable(); |
623 | 662 | } |
624 | 326 | case OpCode::Return_call_indirect: { |
625 | 326 | auto N = Instr.getTargetIndex(); |
626 | 326 | auto T = Instr.getSourceIndex(); |
627 | | // Check source table index. |
628 | 326 | EXPECTED_TRY(checkTableIdx(T)); |
629 | 313 | if (!AST::TypeMatcher::matchType(Types, TypeCode::FuncRef, |
630 | 313 | Tables[T].second)) { |
631 | 3 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
632 | 3 | spdlog::error(ErrInfo::InfoMismatch(TypeCode::FuncRef, Tables[T].second)); |
633 | 3 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
634 | 3 | } |
635 | | // Check target function type index. |
636 | 615 | EXPECTED_TRY(auto CompType, checkDefinedType(N, TypeCode::Func)); |
637 | 615 | const auto &FType = CompType->getFuncType(); |
638 | 615 | EXPECTED_TRY(checkTypesMatching(Returns, FType.getReturnTypes())); |
639 | 302 | EXPECTED_TRY(popType(Tables[T].first)); |
640 | 299 | EXPECTED_TRY(popTypes(FType.getParamTypes())); |
641 | 296 | return unreachable(); |
642 | 299 | } |
643 | 600 | case OpCode::Call_ref: { |
644 | 600 | EXPECTED_TRY(auto CompType, |
645 | 578 | checkDefinedType(Instr.getTargetIndex(), TypeCode::Func)); |
646 | 578 | const auto &FType = CompType->getFuncType(); |
647 | 578 | std::vector<ValType> Input = FType.getParamTypes(); |
648 | 578 | Input.push_back(ValType(TypeCode::RefNull, Instr.getTargetIndex())); |
649 | 578 | return StackTrans(Input, FType.getReturnTypes()); |
650 | 600 | } |
651 | 939 | case OpCode::Return_call_ref: { |
652 | 939 | EXPECTED_TRY(auto CompType, |
653 | 924 | checkDefinedType(Instr.getTargetIndex(), TypeCode::Func)); |
654 | 924 | const auto &FType = CompType->getFuncType(); |
655 | 924 | EXPECTED_TRY(checkTypesMatching(Returns, FType.getReturnTypes())); |
656 | 894 | EXPECTED_TRY(popType(ValType(TypeCode::RefNull, Instr.getTargetIndex()))); |
657 | 887 | EXPECTED_TRY(popTypes(FType.getParamTypes())); |
658 | 885 | return unreachable(); |
659 | 887 | } |
660 | | |
661 | | // Reference Instructions. |
662 | 11.7k | case OpCode::Ref__null: { |
663 | 11.7k | EXPECTED_TRY(validate(Instr.getValType())); |
664 | 11.6k | return StackTrans({}, {Instr.getValType()}); |
665 | 11.7k | } |
666 | 4.20k | case OpCode::Ref__is_null: { |
667 | 4.20k | EXPECTED_TRY(auto Type, popType()); |
668 | 4.20k | if (Type.has_value() && !Type->isRefType()) { |
669 | 14 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
670 | 14 | spdlog::error(ErrInfo::InfoMismatch(TypeCode::FuncRef, VTypeToAST(Type))); |
671 | 14 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
672 | 14 | } |
673 | 4.18k | return StackTrans({}, {ValType(TypeCode::I32)}); |
674 | 4.20k | } |
675 | 2.19k | case OpCode::Ref__func: { |
676 | 2.19k | auto FuncIdx = Instr.getTargetIndex(); |
677 | 2.19k | if (Refs.find(FuncIdx) == Refs.cend()) { |
678 | | // Undeclared function reference. |
679 | 67 | spdlog::error(ErrCode::Value::InvalidRefIdx); |
680 | 67 | return Unexpect(ErrCode::Value::InvalidRefIdx); |
681 | 67 | } |
682 | 2.12k | assuming(FuncIdx < Funcs.size()); |
683 | 2.12k | auto TypeIdx = Funcs[FuncIdx]; |
684 | 2.12k | assuming(TypeIdx < Types.size()); |
685 | 2.12k | return StackTrans({}, {ValType(TypeCode::Ref, TypeIdx)}); |
686 | 2.12k | } |
687 | 1.47k | case OpCode::Ref__eq: |
688 | 1.47k | return StackTrans({ValType(TypeCode::RefNull, TypeCode::EqRef), |
689 | 1.47k | ValType(TypeCode::RefNull, TypeCode::EqRef)}, |
690 | 1.47k | {ValType(TypeCode::I32)}); |
691 | 2.50k | case OpCode::Ref__as_non_null: { |
692 | 2.50k | EXPECTED_TRY(auto Type, popType()); |
693 | 2.49k | if (Type == unreachableVType()) { |
694 | 1.39k | pushType(unreachableVType()); |
695 | 1.39k | return {}; |
696 | 1.39k | } |
697 | 1.09k | if (!Type->isRefType()) { |
698 | 13 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
699 | 13 | spdlog::error(ErrInfo::InfoMismatch( |
700 | 13 | ValType(TypeCode::RefNull, TypeCode::FuncRef), VTypeToAST(Type))); |
701 | 13 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
702 | 13 | } |
703 | 1.08k | return StackTrans({}, {Type->toNonNullableRef()}); |
704 | 1.09k | } |
705 | | |
706 | 364 | case OpCode::Struct__new: |
707 | 1.11k | case OpCode::Struct__new_default: { |
708 | 1.11k | EXPECTED_TRY(auto CompType, |
709 | 1.07k | checkDefinedType(Instr.getTargetIndex(), TypeCode::Struct)); |
710 | 1.07k | std::vector<ValType> Fields; |
711 | 1.07k | if (Instr.getOpCode() == OpCode::Struct__new) { |
712 | 345 | Fields.reserve(CompType->getFieldTypes().size()); |
713 | 345 | } |
714 | 7.85k | for (auto &FType : CompType->getFieldTypes()) { |
715 | 7.85k | if (Instr.getOpCode() == OpCode::Struct__new) { |
716 | 170 | Fields.emplace_back(unpackType(FType.getStorageType())); |
717 | 7.68k | } else if (!FType.getStorageType().isDefaultable()) { |
718 | 1 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
719 | 1 | spdlog::error(" Value type should be defaultable."sv); |
720 | 1 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
721 | 1 | } |
722 | 7.85k | } |
723 | 1.07k | return StackTrans(Fields, {ValType(TypeCode::Ref, Instr.getTargetIndex())}); |
724 | 1.07k | } |
725 | 8 | case OpCode::Struct__get: |
726 | 22 | case OpCode::Struct__get_s: |
727 | 29 | case OpCode::Struct__get_u: { |
728 | 29 | EXPECTED_TRY(auto CompType, |
729 | 19 | checkDefinedType(Instr.getTargetIndex(), TypeCode::Struct)); |
730 | 19 | if (Instr.getSourceIndex() >= CompType->getFieldTypes().size()) { |
731 | 3 | return logOutOfRange( |
732 | 3 | ErrCode::Value::InvalidFieldIdx, ErrInfo::IndexCategory::Field, |
733 | 3 | Instr.getSourceIndex(), |
734 | 3 | static_cast<uint32_t>(CompType->getFieldTypes().size())); |
735 | 3 | } |
736 | 16 | const auto &FType = CompType->getFieldTypes()[Instr.getSourceIndex()]; |
737 | 16 | if (unlikely(Instr.getOpCode() == OpCode::Struct__get && |
738 | 16 | FType.getStorageType().isPackType())) { |
739 | | // For a packed type, the `_s` or `_u` in the instruction is required. |
740 | 2 | spdlog::error(ErrCode::Value::InvalidPackedField); |
741 | 2 | return Unexpect(ErrCode::Value::InvalidPackedField); |
742 | 14 | } else if (unlikely(Instr.getOpCode() != OpCode::Struct__get && |
743 | 14 | !FType.getStorageType().isPackType())) { |
744 | | // The `_s` or `_u` in instruction only accepts packed field. |
745 | 4 | spdlog::error(ErrCode::Value::InvalidUnpackedField); |
746 | 4 | return Unexpect(ErrCode::Value::InvalidUnpackedField); |
747 | 4 | } |
748 | 10 | return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex())}, |
749 | 10 | {unpackType(FType.getStorageType())}); |
750 | 16 | } |
751 | 41 | case OpCode::Struct__set: { |
752 | 41 | EXPECTED_TRY(auto CompType, |
753 | 37 | checkDefinedType(Instr.getTargetIndex(), TypeCode::Struct)); |
754 | 37 | if (Instr.getSourceIndex() >= CompType->getFieldTypes().size()) { |
755 | 2 | return logOutOfRange( |
756 | 2 | ErrCode::Value::InvalidFieldIdx, ErrInfo::IndexCategory::Field, |
757 | 2 | Instr.getSourceIndex(), |
758 | 2 | static_cast<uint32_t>(CompType->getFieldTypes().size())); |
759 | 2 | } |
760 | 35 | const auto &FType = CompType->getFieldTypes()[Instr.getSourceIndex()]; |
761 | 35 | if (FType.getValMut() != ValMut::Var) { |
762 | 2 | spdlog::error(ErrCode::Value::ImmutableField); |
763 | 2 | return Unexpect(ErrCode::Value::ImmutableField); |
764 | 2 | } |
765 | 33 | return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()), |
766 | 33 | unpackType(FType.getStorageType())}, |
767 | 33 | {}); |
768 | 35 | } |
769 | 334 | case OpCode::Array__new: |
770 | 541 | case OpCode::Array__new_default: |
771 | 1.02k | case OpCode::Array__new_fixed: { |
772 | 1.02k | EXPECTED_TRY(auto CompType, |
773 | 1.00k | checkDefinedType(Instr.getTargetIndex(), TypeCode::Array)); |
774 | 1.00k | const auto &SType = CompType->getFieldTypes()[0].getStorageType(); |
775 | 1.00k | if (Instr.getOpCode() == OpCode::Array__new) { |
776 | 324 | return StackTrans({unpackType(SType), ValType(TypeCode::I32)}, |
777 | 324 | {ValType(TypeCode::Ref, Instr.getTargetIndex())}); |
778 | 681 | } else if (Instr.getOpCode() == OpCode::Array__new_default) { |
779 | 201 | if (!SType.isDefaultable()) { |
780 | 1 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
781 | 1 | spdlog::error(" Value type should be defaultable."sv); |
782 | 1 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
783 | 1 | } |
784 | 200 | return StackTrans({ValType(TypeCode::I32)}, |
785 | 200 | {ValType(TypeCode::Ref, Instr.getTargetIndex())}); |
786 | 480 | } else { |
787 | | // One pop past the frame height already decides underflow or polymorphic. |
788 | 480 | const auto ElemType = unpackType(SType); |
789 | 480 | const auto Count = |
790 | 480 | std::min<size_t>(Instr.getSourceIndex(), |
791 | 480 | ValStack.size() - CtrlStack.back().Height + 1); |
792 | 975 | for (size_t I = 0; I < Count; ++I) { |
793 | 515 | EXPECTED_TRY(popType(ElemType)); |
794 | 515 | } |
795 | 460 | return StackTrans({}, {ValType(TypeCode::Ref, Instr.getTargetIndex())}); |
796 | 480 | } |
797 | 1.00k | } |
798 | 38 | case OpCode::Array__new_data: |
799 | 51 | case OpCode::Array__init_data: { |
800 | 51 | EXPECTED_TRY(auto CompType, |
801 | 44 | checkDefinedType(Instr.getTargetIndex(), TypeCode::Array)); |
802 | 44 | const auto &FType = CompType->getFieldTypes()[0]; |
803 | 44 | if (Instr.getOpCode() == OpCode::Array__init_data && |
804 | 9 | FType.getValMut() != ValMut::Var) { |
805 | 3 | spdlog::error(ErrCode::Value::ImmutableArray); |
806 | 3 | return Unexpect(ErrCode::Value::ImmutableArray); |
807 | 3 | } |
808 | 41 | if (!unpackType(FType.getStorageType()).isNumType()) { |
809 | 3 | spdlog::error(ErrCode::Value::ArrayTypesNumtypeRequired); |
810 | 3 | return Unexpect(ErrCode::Value::ArrayTypesNumtypeRequired); |
811 | 3 | } |
812 | 38 | EXPECTED_TRY(checkDataIdx(Instr.getSourceIndex())); |
813 | 2 | if (Instr.getOpCode() == OpCode::Array__new_data) { |
814 | 1 | return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)}, |
815 | 1 | {ValType(TypeCode::Ref, Instr.getTargetIndex())}); |
816 | 1 | } else { |
817 | 1 | return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()), |
818 | 1 | ValType(TypeCode::I32), ValType(TypeCode::I32), |
819 | 1 | ValType(TypeCode::I32)}, |
820 | 1 | {}); |
821 | 1 | } |
822 | 2 | } |
823 | 7 | case OpCode::Array__new_elem: |
824 | 18 | case OpCode::Array__init_elem: { |
825 | 18 | EXPECTED_TRY(auto CompType, |
826 | 12 | checkDefinedType(Instr.getTargetIndex(), TypeCode::Array)); |
827 | 12 | const auto &FType = CompType->getFieldTypes()[0]; |
828 | 12 | if (Instr.getOpCode() == OpCode::Array__init_elem && |
829 | 8 | FType.getValMut() != ValMut::Var) { |
830 | 3 | spdlog::error(ErrCode::Value::ImmutableArray); |
831 | 3 | return Unexpect(ErrCode::Value::ImmutableArray); |
832 | 3 | } |
833 | 9 | if (!FType.getStorageType().isRefType()) { |
834 | 2 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
835 | 2 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
836 | 2 | } |
837 | 7 | EXPECTED_TRY(checkElemIdx(Instr.getSourceIndex())); |
838 | 2 | if (!AST::TypeMatcher::matchType(Types, FType.getStorageType(), |
839 | 2 | Elems[Instr.getSourceIndex()])) { |
840 | 1 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
841 | 1 | spdlog::error(ErrInfo::InfoMismatch(FType.getStorageType(), |
842 | 1 | Elems[Instr.getSourceIndex()])); |
843 | 1 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
844 | 1 | } |
845 | 1 | if (Instr.getOpCode() == OpCode::Array__new_elem) { |
846 | 0 | return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)}, |
847 | 0 | {ValType(TypeCode::Ref, Instr.getTargetIndex())}); |
848 | 1 | } else { |
849 | 1 | return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()), |
850 | 1 | ValType(TypeCode::I32), ValType(TypeCode::I32), |
851 | 1 | ValType(TypeCode::I32)}, |
852 | 1 | {}); |
853 | 1 | } |
854 | 1 | } |
855 | 215 | case OpCode::Array__get: |
856 | 385 | case OpCode::Array__get_s: |
857 | 463 | case OpCode::Array__get_u: { |
858 | 463 | EXPECTED_TRY(auto CompType, |
859 | 450 | checkDefinedType(Instr.getTargetIndex(), TypeCode::Array)); |
860 | 450 | const auto &FType = CompType->getFieldTypes()[0]; |
861 | 450 | if (unlikely(Instr.getOpCode() == OpCode::Array__get && |
862 | 450 | FType.getStorageType().isPackType())) { |
863 | | // For a packed type, the `_s` or `_u` in the instruction is required. |
864 | 2 | spdlog::error(ErrCode::Value::InvalidPackedArray); |
865 | 2 | return Unexpect(ErrCode::Value::InvalidPackedArray); |
866 | 448 | } else if (unlikely(Instr.getOpCode() != OpCode::Array__get && |
867 | 448 | !FType.getStorageType().isPackType())) { |
868 | | // The `_s` or `_u` in instruction only accepts packed array. |
869 | 4 | spdlog::error(ErrCode::Value::InvalidUnpackedArray); |
870 | 4 | return Unexpect(ErrCode::Value::InvalidUnpackedArray); |
871 | 4 | } |
872 | 444 | return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()), |
873 | 444 | ValType(TypeCode::I32)}, |
874 | 444 | {unpackType(FType.getStorageType())}); |
875 | 450 | } |
876 | 90 | case OpCode::Array__set: |
877 | 142 | case OpCode::Array__fill: { |
878 | 142 | EXPECTED_TRY(auto CompType, |
879 | 135 | checkDefinedType(Instr.getTargetIndex(), TypeCode::Array)); |
880 | 135 | const auto &FType = CompType->getFieldTypes()[0]; |
881 | 135 | if (FType.getValMut() != ValMut::Var) { |
882 | 3 | spdlog::error(ErrCode::Value::ImmutableArray); |
883 | 3 | return Unexpect(ErrCode::Value::ImmutableArray); |
884 | 3 | } |
885 | 132 | std::vector<ValType> Fields = { |
886 | 132 | ValType(TypeCode::RefNull, Instr.getTargetIndex()), |
887 | 132 | ValType(TypeCode::I32), unpackType(FType.getStorageType())}; |
888 | 132 | if (Instr.getOpCode() == OpCode::Array__fill) { |
889 | 46 | Fields.emplace_back(ValType(TypeCode::I32)); |
890 | 46 | } |
891 | 132 | return StackTrans(Fields, {}); |
892 | 135 | } |
893 | 323 | case OpCode::Array__len: |
894 | 323 | return StackTrans({ValType(TypeCode::ArrayRef)}, {ValType(TypeCode::I32)}); |
895 | 85 | case OpCode::Array__copy: { |
896 | 85 | EXPECTED_TRY(auto CompType, |
897 | 82 | checkDefinedType(Instr.getTargetIndex(), TypeCode::Array)); |
898 | 82 | const auto &DstFType = CompType->getFieldTypes()[0]; |
899 | 82 | if (DstFType.getValMut() != ValMut::Var) { |
900 | 3 | spdlog::error(ErrCode::Value::ImmutableArray); |
901 | 3 | return Unexpect(ErrCode::Value::ImmutableArray); |
902 | 3 | } |
903 | 153 | EXPECTED_TRY(auto Src, |
904 | 153 | checkDefinedType(Instr.getSourceIndex(), TypeCode::Array)); |
905 | 153 | const auto &SrcFType = Src->getFieldTypes()[0]; |
906 | 153 | if (!AST::TypeMatcher::matchType(Types, DstFType.getStorageType(), |
907 | 74 | SrcFType.getStorageType())) { |
908 | 2 | spdlog::error(ErrCode::Value::ArrayTypesMismatch); |
909 | 2 | spdlog::error(ErrInfo::InfoMismatch(DstFType.getStorageType(), |
910 | 2 | SrcFType.getStorageType())); |
911 | 2 | return Unexpect(ErrCode::Value::ArrayTypesMismatch); |
912 | 2 | } |
913 | 72 | return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()), |
914 | 72 | ValType(TypeCode::I32), |
915 | 72 | ValType(TypeCode::RefNull, Instr.getSourceIndex()), |
916 | 72 | ValType(TypeCode::I32), ValType(TypeCode::I32)}, |
917 | 72 | {}); |
918 | 153 | } |
919 | | |
920 | 320 | case OpCode::Ref__test: |
921 | 491 | case OpCode::Ref__test_null: |
922 | 868 | case OpCode::Ref__cast: |
923 | 1.15k | case OpCode::Ref__cast_null: { |
924 | 1.15k | EXPECTED_TRY(validate(Instr.getValType())); |
925 | 2.28k | EXPECTED_TRY(auto Type, popType()); |
926 | 2.28k | if (Type.has_value() && !Type->isRefType()) { |
927 | | // The trap occurs when the actual type is not a reference type. |
928 | 4 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
929 | 4 | spdlog::error( |
930 | 4 | ErrInfo::InfoMismatch(Instr.getValType(), VTypeToAST(Type))); |
931 | 4 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
932 | 4 | } |
933 | | // When Type is nullopt (unreachable/bottom type), the bottom type matches |
934 | | // any target type, so skip the type matching check. |
935 | 1.13k | if (Type.has_value() && |
936 | 930 | !AST::TypeMatcher::matchType(Types, toTopHeapType(*Type), |
937 | 930 | Instr.getValType())) { |
938 | 17 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
939 | 17 | spdlog::error(ErrInfo::InfoMismatch(*Type, Instr.getValType())); |
940 | 17 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
941 | 17 | } |
942 | 1.12k | if (Instr.getOpCode() == OpCode::Ref__test || |
943 | 804 | Instr.getOpCode() == OpCode::Ref__test_null) { |
944 | 481 | return StackTrans({}, {ValType(TypeCode::I32)}); |
945 | 640 | } else { |
946 | 640 | return StackTrans({}, {Instr.getValType()}); |
947 | 640 | } |
948 | 1.12k | } |
949 | 112 | case OpCode::Br_on_cast: |
950 | 190 | case OpCode::Br_on_cast_fail: { |
951 | | // The reference types should be valid. |
952 | 190 | auto &RT1 = Instr.getBrCast().RType1; |
953 | 190 | auto &RT2 = Instr.getBrCast().RType2; |
954 | 190 | EXPECTED_TRY(validate(RT1)); |
955 | 185 | EXPECTED_TRY(validate(RT2)); |
956 | | // The reference type RT2 should match RT1. |
957 | 181 | if (unlikely(!AST::TypeMatcher::matchType(Types, RT1, RT2))) { |
958 | 8 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
959 | 8 | spdlog::error(ErrInfo::InfoMismatch(RT1, RT2)); |
960 | 8 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
961 | 8 | } |
962 | 340 | EXPECTED_TRY(auto D, |
963 | 340 | checkCtrlStackDepth(Instr.getBrCast().Jump.TargetIndex)); |
964 | | // Get the result type of the label. (Should be [t* rt'].) |
965 | 340 | auto LabelTypes = getLabelTypes(CtrlStack[D]); |
966 | 340 | std::vector<ValType> NTypes(LabelTypes.begin(), LabelTypes.end()); |
967 | 340 | if (unlikely(NTypes.empty())) { |
968 | 3 | spdlog::error(ErrCode::Value::InvalidBrRefType); |
969 | 3 | return Unexpect(ErrCode::Value::InvalidBrRefType); |
970 | 3 | } |
971 | | // Get the type difference between rt1 \ rt2. (rt1' = rt1 \ rt2) |
972 | 164 | ValType RT1P = RT2.isNullableRefType() ? RT1.getNonNullableRef() : RT1; |
973 | | // For br_on_cast, rt2 must match rt'. |
974 | | // For Br_on_cast_fail, rt1' must match rt'. |
975 | 164 | ValType &RTP = NTypes.back(); |
976 | 164 | const ValType &RTRHS = Instr.getOpCode() == OpCode::Br_on_cast ? RT2 : RT1P; |
977 | 164 | if (unlikely(!AST::TypeMatcher::matchType(Types, RTP, RTRHS))) { |
978 | 4 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
979 | 4 | spdlog::error(ErrInfo::InfoMismatch(RTP, RTRHS)); |
980 | 4 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
981 | 4 | } |
982 | | // Pop types [t* rt1]. |
983 | 160 | RTP = RT1; |
984 | 160 | EXPECTED_TRY(popTypes(NTypes)); |
985 | 156 | recordJump(const_cast<AST::Instruction &>(Instr).getBrCast().Jump, |
986 | 156 | static_cast<uint32_t>(NTypes.size()), D); |
987 | | // For br_on_cast, push types [t* rt1']. |
988 | | // For Br_on_cast_fail, push types [t* rt2]. |
989 | 156 | RTP = Instr.getOpCode() == OpCode::Br_on_cast ? RT1P : RT2; |
990 | 156 | pushTypes(NTypes); |
991 | 156 | return {}; |
992 | 160 | } |
993 | 175 | case OpCode::Any__convert_extern: { |
994 | 175 | EXPECTED_TRY(auto Type, popType(TypeCode::ExternRef)); |
995 | 162 | return StackTrans({}, {ValType(Type->getCode(), TypeCode::AnyRef)}); |
996 | 175 | } |
997 | 222 | case OpCode::Extern__convert_any: { |
998 | 222 | EXPECTED_TRY(auto Type, popType(TypeCode::AnyRef)); |
999 | 216 | return StackTrans({}, {ValType(Type->getCode(), TypeCode::ExternRef)}); |
1000 | 222 | } |
1001 | 303 | case OpCode::Ref__i31: |
1002 | 303 | return StackTrans({ValType(TypeCode::I32)}, |
1003 | 303 | {ValType(TypeCode::Ref, TypeCode::I31Ref)}); |
1004 | 172 | case OpCode::I31__get_s: |
1005 | 306 | case OpCode::I31__get_u: |
1006 | 306 | return StackTrans({ValType(TypeCode::RefNull, TypeCode::I31Ref)}, |
1007 | 306 | {ValType(TypeCode::I32)}); |
1008 | | |
1009 | | // Parametric Instructions. |
1010 | 10.7k | case OpCode::Drop: |
1011 | 10.7k | return StackPopAny(); |
1012 | 4.99k | case OpCode::Select: { |
1013 | | // Pop I32. |
1014 | 4.99k | EXPECTED_TRY(popType(TypeCode::I32)); |
1015 | | // Pop T1 and T2. |
1016 | 9.96k | EXPECTED_TRY(VType T1, popType()); |
1017 | 9.96k | EXPECTED_TRY(VType T2, popType()); |
1018 | | // T1 and T2 should be number type. |
1019 | 4.97k | if (T1.has_value() && !T1->isNumType()) { |
1020 | 5 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
1021 | 5 | spdlog::error(ErrInfo::InfoMismatch(TypeCode::I32, VTypeToAST(T1))); |
1022 | 5 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
1023 | 5 | } |
1024 | 4.96k | if (T2.has_value() && !T2->isNumType()) { |
1025 | 6 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
1026 | 6 | spdlog::error(ErrInfo::InfoMismatch(VTypeToAST(T1), VTypeToAST(T2))); |
1027 | 6 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
1028 | 6 | } |
1029 | | // Error if t1 != t2 && t1 =/= Unknown && t2 =/= Unknown |
1030 | 4.96k | if (T1 != T2 && T1 != unreachableVType() && T2 != unreachableVType()) { |
1031 | 6 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
1032 | 6 | spdlog::error(ErrInfo::InfoMismatch(VTypeToAST(T1), VTypeToAST(T2))); |
1033 | 6 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
1034 | 6 | } |
1035 | | // Push value. |
1036 | 4.95k | if (T1 == unreachableVType()) { |
1037 | 3.04k | pushType(T2); |
1038 | 3.04k | } else { |
1039 | 1.91k | pushType(T1); |
1040 | 1.91k | } |
1041 | 4.95k | return {}; |
1042 | 4.96k | } |
1043 | 677 | case OpCode::Select_t: { |
1044 | | // Note: There may be multiple values choice in the future. |
1045 | 677 | if (Instr.getValTypeList().size() != 1) { |
1046 | 19 | spdlog::error(ErrCode::Value::InvalidResultArity); |
1047 | 19 | return Unexpect(ErrCode::Value::InvalidResultArity); |
1048 | 19 | } |
1049 | 658 | ValType ExpT = Instr.getValTypeList()[0]; |
1050 | 658 | EXPECTED_TRY(validate(ExpT)); |
1051 | 652 | EXPECTED_TRY(popTypes({ExpT, ExpT, ValType(TypeCode::I32)})); |
1052 | 648 | pushType(ExpT); |
1053 | 648 | return {}; |
1054 | 652 | } |
1055 | | |
1056 | | // Variable Instructions. |
1057 | 18.5k | case OpCode::Local__get: |
1058 | 25.2k | case OpCode::Local__set: |
1059 | 30.7k | case OpCode::Local__tee: { |
1060 | 30.7k | if (Instr.getTargetIndex() >= Locals.size()) { |
1061 | 83 | return logOutOfRange( |
1062 | 83 | ErrCode::Value::InvalidLocalIdx, ErrInfo::IndexCategory::Local, |
1063 | 83 | Instr.getTargetIndex(), static_cast<uint32_t>(Locals.size())); |
1064 | 83 | } |
1065 | 30.6k | auto &TExpect = Locals[Instr.getTargetIndex()]; |
1066 | 30.6k | const_cast<AST::Instruction &>(Instr).getStackOffset() = |
1067 | 30.6k | static_cast<uint32_t>(ValStack.size() + |
1068 | 30.6k | (Locals.size() - Instr.getTargetIndex())); |
1069 | 30.6k | if (Instr.getOpCode() == OpCode::Local__get) { |
1070 | 18.5k | if (!TExpect.IsInit) { |
1071 | 3 | spdlog::error(ErrCode::Value::InvalidUninitLocal); |
1072 | 3 | return Unexpect(ErrCode::Value::InvalidUninitLocal); |
1073 | 3 | } |
1074 | 18.5k | return StackTrans({}, {TExpect.VType}); |
1075 | 18.5k | } else if (Instr.getOpCode() == OpCode::Local__set) { |
1076 | 6.64k | if (!TExpect.IsInit) { |
1077 | 62 | TExpect.IsInit = true; |
1078 | 62 | LocalInits.push_back(Instr.getTargetIndex()); |
1079 | 62 | } |
1080 | 6.64k | return StackTrans({TExpect.VType}, {}); |
1081 | 6.64k | } else if (Instr.getOpCode() == OpCode::Local__tee) { |
1082 | 5.51k | if (!TExpect.IsInit) { |
1083 | 100 | TExpect.IsInit = true; |
1084 | 100 | LocalInits.push_back(Instr.getTargetIndex()); |
1085 | 100 | } |
1086 | 5.51k | return StackTrans({TExpect.VType}, {TExpect.VType}); |
1087 | 5.51k | } else { |
1088 | 0 | assumingUnreachable(); |
1089 | 0 | } |
1090 | 30.6k | } |
1091 | 10.8k | case OpCode::Global__set: |
1092 | | // Global case, check mutation. |
1093 | 10.8k | if (Instr.getTargetIndex() < Globals.size() && |
1094 | 10.8k | Globals[Instr.getTargetIndex()].second != ValMut::Var) { |
1095 | | // Global is immutable |
1096 | 2 | spdlog::error(ErrCode::Value::ImmutableGlobal); |
1097 | 2 | return Unexpect(ErrCode::Value::ImmutableGlobal); |
1098 | 2 | } |
1099 | 10.8k | [[fallthrough]]; |
1100 | 23.6k | case OpCode::Global__get: { |
1101 | 23.6k | if (Instr.getTargetIndex() >= Globals.size()) { |
1102 | 89 | return logOutOfRange( |
1103 | 89 | ErrCode::Value::InvalidGlobalIdx, ErrInfo::IndexCategory::Global, |
1104 | 89 | Instr.getTargetIndex(), static_cast<uint32_t>(Globals.size())); |
1105 | 89 | } |
1106 | 23.5k | ValType ExpT = Globals[Instr.getTargetIndex()].first; |
1107 | 23.5k | if (Instr.getOpCode() == OpCode::Global__set) { |
1108 | 10.8k | return StackTrans({ExpT}, {}); |
1109 | 12.7k | } else { |
1110 | 12.7k | return StackTrans({}, {ExpT}); |
1111 | 12.7k | } |
1112 | 23.5k | } |
1113 | | |
1114 | | // Table Instructions. |
1115 | 227 | case OpCode::Table__get: |
1116 | 227 | EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex())); |
1117 | 210 | return StackTrans({ValType(Tables[Instr.getTargetIndex()].first)}, |
1118 | 210 | {Tables[Instr.getTargetIndex()].second}); |
1119 | 450 | case OpCode::Table__set: |
1120 | 450 | EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex())); |
1121 | 430 | return StackTrans({ValType(Tables[Instr.getTargetIndex()].first), |
1122 | 430 | Tables[Instr.getTargetIndex()].second}, |
1123 | 430 | {}); |
1124 | 80 | case OpCode::Table__init: |
1125 | 80 | EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex())); |
1126 | 75 | EXPECTED_TRY(checkElemIdx(Instr.getSourceIndex())); |
1127 | | // Check whether the reference types match. |
1128 | 69 | if (!AST::TypeMatcher::matchType(Types, |
1129 | 69 | Tables[Instr.getTargetIndex()].second, |
1130 | 69 | Elems[Instr.getSourceIndex()])) { |
1131 | 2 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
1132 | 2 | spdlog::error(ErrInfo::InfoMismatch(Tables[Instr.getTargetIndex()].second, |
1133 | 2 | Elems[Instr.getSourceIndex()])); |
1134 | 2 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
1135 | 2 | } |
1136 | 67 | return StackTrans({ValType(Tables[Instr.getTargetIndex()].first), |
1137 | 67 | ValType(TypeCode::I32), ValType(TypeCode::I32)}, |
1138 | 67 | {}); |
1139 | 2.00k | case OpCode::Elem__drop: |
1140 | 2.00k | EXPECTED_TRY(checkElemIdx(Instr.getTargetIndex())); |
1141 | 1.98k | return {}; |
1142 | 294 | case OpCode::Table__copy: { |
1143 | 294 | EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex())); |
1144 | 288 | EXPECTED_TRY(checkTableIdx(Instr.getSourceIndex())); |
1145 | | // Check whether the reference types match. |
1146 | 283 | if (!AST::TypeMatcher::matchType(Types, |
1147 | 283 | Tables[Instr.getTargetIndex()].second, |
1148 | 283 | Tables[Instr.getSourceIndex()].second)) { |
1149 | 2 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
1150 | 2 | spdlog::error( |
1151 | 2 | ErrInfo::InfoMismatch(Tables[Instr.getTargetIndex()].second, |
1152 | 2 | Tables[Instr.getSourceIndex()].second)); |
1153 | 2 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
1154 | 2 | } |
1155 | 281 | auto ATDst = Tables[Instr.getTargetIndex()].first; |
1156 | 281 | auto ATSrc = Tables[Instr.getSourceIndex()].first; |
1157 | 281 | auto ATMin = convTypeCodeToAddrType(ATDst) <= convTypeCodeToAddrType(ATSrc) |
1158 | 281 | ? ATDst |
1159 | 281 | : ATSrc; |
1160 | 281 | return StackTrans({ValType(ATDst), ValType(ATSrc), ValType(ATMin)}, {}); |
1161 | 283 | } |
1162 | 209 | case OpCode::Table__grow: |
1163 | 209 | EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex())); |
1164 | 202 | return StackTrans({Tables[Instr.getTargetIndex()].second, |
1165 | 202 | ValType(Tables[Instr.getTargetIndex()].first)}, |
1166 | 202 | {ValType(Tables[Instr.getTargetIndex()].first)}); |
1167 | 459 | case OpCode::Table__size: |
1168 | 459 | EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex())); |
1169 | 456 | return StackTrans({}, {ValType(Tables[Instr.getTargetIndex()].first)}); |
1170 | 81 | case OpCode::Table__fill: |
1171 | 81 | EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex())); |
1172 | 76 | return StackTrans({ValType(Tables[Instr.getTargetIndex()].first), |
1173 | 76 | Tables[Instr.getTargetIndex()].second, |
1174 | 76 | ValType(Tables[Instr.getTargetIndex()].first)}, |
1175 | 76 | {}); |
1176 | | |
1177 | | // Memory Instructions. |
1178 | 4.78k | case OpCode::I32__load: |
1179 | 4.78k | return checkMemArgAndTrans(32, {}, {ValType(TypeCode::I32)}); |
1180 | 3.67k | case OpCode::I64__load: |
1181 | 3.67k | return checkMemArgAndTrans(64, {}, {ValType(TypeCode::I64)}); |
1182 | 866 | case OpCode::F32__load: |
1183 | 866 | return checkMemArgAndTrans(32, {}, {ValType(TypeCode::F32)}); |
1184 | 1.16k | case OpCode::F64__load: |
1185 | 1.16k | return checkMemArgAndTrans(64, {}, {ValType(TypeCode::F64)}); |
1186 | 1.79k | case OpCode::I32__load8_s: |
1187 | 3.33k | case OpCode::I32__load8_u: |
1188 | 3.33k | return checkMemArgAndTrans(8, {}, {ValType(TypeCode::I32)}); |
1189 | 1.35k | case OpCode::I32__load16_s: |
1190 | 3.73k | case OpCode::I32__load16_u: |
1191 | 3.73k | return checkMemArgAndTrans(16, {}, {ValType(TypeCode::I32)}); |
1192 | 1.88k | case OpCode::I64__load8_s: |
1193 | 3.01k | case OpCode::I64__load8_u: |
1194 | 3.01k | return checkMemArgAndTrans(8, {}, {ValType(TypeCode::I64)}); |
1195 | 1.39k | case OpCode::I64__load16_s: |
1196 | 3.40k | case OpCode::I64__load16_u: |
1197 | 3.40k | return checkMemArgAndTrans(16, {}, {ValType(TypeCode::I64)}); |
1198 | 1.18k | case OpCode::I64__load32_s: |
1199 | 2.63k | case OpCode::I64__load32_u: |
1200 | 2.63k | return checkMemArgAndTrans(32, {}, {ValType(TypeCode::I64)}); |
1201 | 833 | case OpCode::I32__store: |
1202 | 833 | return checkMemArgAndTrans(32, {ValType(TypeCode::I32)}, {}); |
1203 | 2.61k | case OpCode::I64__store: |
1204 | 2.61k | return checkMemArgAndTrans(64, {ValType(TypeCode::I64)}, {}); |
1205 | 820 | case OpCode::F32__store: |
1206 | 820 | return checkMemArgAndTrans(32, {ValType(TypeCode::F32)}, {}); |
1207 | 313 | case OpCode::F64__store: |
1208 | 313 | return checkMemArgAndTrans(64, {ValType(TypeCode::F64)}, {}); |
1209 | 1.37k | case OpCode::I32__store8: |
1210 | 1.37k | return checkMemArgAndTrans(8, {ValType(TypeCode::I32)}, {}); |
1211 | 1.09k | case OpCode::I32__store16: |
1212 | 1.09k | return checkMemArgAndTrans(16, {ValType(TypeCode::I32)}, {}); |
1213 | 997 | case OpCode::I64__store8: |
1214 | 997 | return checkMemArgAndTrans(8, {ValType(TypeCode::I64)}, {}); |
1215 | 890 | case OpCode::I64__store16: |
1216 | 890 | return checkMemArgAndTrans(16, {ValType(TypeCode::I64)}, {}); |
1217 | 564 | case OpCode::I64__store32: |
1218 | 564 | return checkMemArgAndTrans(32, {ValType(TypeCode::I64)}, {}); |
1219 | 3.36k | case OpCode::Memory__size: |
1220 | 3.36k | EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex())); |
1221 | 3.33k | return StackTrans({}, {ValType(Mems[Instr.getTargetIndex()])}); |
1222 | 6.38k | case OpCode::Memory__grow: |
1223 | 6.38k | EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex())); |
1224 | 6.32k | return StackTrans({ValType(Mems[Instr.getTargetIndex()])}, |
1225 | 6.32k | {ValType(Mems[Instr.getTargetIndex()])}); |
1226 | 72 | case OpCode::Memory__init: |
1227 | 72 | EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex())); |
1228 | 69 | EXPECTED_TRY(checkDataIdx(Instr.getSourceIndex())); |
1229 | 62 | return StackTrans({ValType(Mems[Instr.getTargetIndex()]), |
1230 | 62 | ValType(TypeCode::I32), ValType(TypeCode::I32)}, |
1231 | 62 | {}); |
1232 | 190 | case OpCode::Data__drop: |
1233 | 190 | EXPECTED_TRY(checkDataIdx(Instr.getTargetIndex())); |
1234 | 182 | return {}; |
1235 | 543 | case OpCode::Memory__copy: { |
1236 | 543 | EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex())); |
1237 | 536 | EXPECTED_TRY(checkMemIdx(Instr.getSourceIndex())); |
1238 | 533 | auto ATDst = Mems[Instr.getTargetIndex()]; |
1239 | 533 | auto ATSrc = Mems[Instr.getSourceIndex()]; |
1240 | 533 | auto ATMin = convTypeCodeToAddrType(ATDst) <= convTypeCodeToAddrType(ATSrc) |
1241 | 533 | ? ATDst |
1242 | 533 | : ATSrc; |
1243 | 533 | return StackTrans({ValType(ATDst), ValType(ATSrc), ValType(ATMin)}, {}); |
1244 | 536 | } |
1245 | 1.30k | case OpCode::Memory__fill: |
1246 | 1.30k | EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex())); |
1247 | 1.30k | return StackTrans({ValType(Mems[Instr.getTargetIndex()]), |
1248 | 1.30k | ValType(TypeCode::I32), |
1249 | 1.30k | ValType(Mems[Instr.getTargetIndex()])}, |
1250 | 1.30k | {}); |
1251 | | |
1252 | | // Const Instructions. |
1253 | 801k | case OpCode::I32__const: |
1254 | 801k | return StackTrans({}, {ValType(TypeCode::I32)}); |
1255 | 111k | case OpCode::I64__const: |
1256 | 111k | return StackTrans({}, {ValType(TypeCode::I64)}); |
1257 | 25.9k | case OpCode::F32__const: |
1258 | 25.9k | return StackTrans({}, {ValType(TypeCode::F32)}); |
1259 | 12.0k | case OpCode::F64__const: |
1260 | 12.0k | return StackTrans({}, {ValType(TypeCode::F64)}); |
1261 | | |
1262 | | // Unary Numeric Instructions. |
1263 | 12.1k | case OpCode::I32__eqz: |
1264 | 12.1k | return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)}); |
1265 | 3.24k | case OpCode::I64__eqz: |
1266 | 3.24k | return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I32)}); |
1267 | 4.60k | case OpCode::I32__clz: |
1268 | 9.13k | case OpCode::I32__ctz: |
1269 | 35.9k | case OpCode::I32__popcnt: |
1270 | 35.9k | return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)}); |
1271 | 2.31k | case OpCode::I64__clz: |
1272 | 4.83k | case OpCode::I64__ctz: |
1273 | 8.63k | case OpCode::I64__popcnt: |
1274 | 8.63k | return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I64)}); |
1275 | 2.12k | case OpCode::F32__abs: |
1276 | 4.74k | case OpCode::F32__neg: |
1277 | 9.71k | case OpCode::F32__ceil: |
1278 | 11.8k | case OpCode::F32__floor: |
1279 | 15.1k | case OpCode::F32__trunc: |
1280 | 17.2k | case OpCode::F32__nearest: |
1281 | 21.1k | case OpCode::F32__sqrt: |
1282 | 21.1k | return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::F32)}); |
1283 | 1.99k | case OpCode::F64__abs: |
1284 | 3.99k | case OpCode::F64__neg: |
1285 | 9.05k | case OpCode::F64__ceil: |
1286 | 10.2k | case OpCode::F64__floor: |
1287 | 11.8k | case OpCode::F64__trunc: |
1288 | 12.7k | case OpCode::F64__nearest: |
1289 | 15.7k | case OpCode::F64__sqrt: |
1290 | 15.7k | return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::F64)}); |
1291 | 969 | case OpCode::I32__wrap_i64: |
1292 | 969 | return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I32)}); |
1293 | 2.12k | case OpCode::I32__trunc_f32_s: |
1294 | 3.35k | case OpCode::I32__trunc_f32_u: |
1295 | 3.35k | return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)}); |
1296 | 1.65k | case OpCode::I32__trunc_f64_s: |
1297 | 3.16k | case OpCode::I32__trunc_f64_u: |
1298 | 3.16k | return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I32)}); |
1299 | 3.56k | case OpCode::I64__extend_i32_s: |
1300 | 5.83k | case OpCode::I64__extend_i32_u: |
1301 | 5.83k | return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I64)}); |
1302 | 1.09k | case OpCode::I64__trunc_f32_s: |
1303 | 3.54k | case OpCode::I64__trunc_f32_u: |
1304 | 3.54k | return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I64)}); |
1305 | 1.19k | case OpCode::I64__trunc_f64_s: |
1306 | 3.70k | case OpCode::I64__trunc_f64_u: |
1307 | 3.70k | return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)}); |
1308 | 2.80k | case OpCode::F32__convert_i32_s: |
1309 | 4.50k | case OpCode::F32__convert_i32_u: |
1310 | 4.50k | return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F32)}); |
1311 | 2.90k | case OpCode::F32__convert_i64_s: |
1312 | 5.36k | case OpCode::F32__convert_i64_u: |
1313 | 5.36k | return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F32)}); |
1314 | 797 | case OpCode::F32__demote_f64: |
1315 | 797 | return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::F32)}); |
1316 | 2.72k | case OpCode::F64__convert_i32_s: |
1317 | 5.76k | case OpCode::F64__convert_i32_u: |
1318 | 5.76k | return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F64)}); |
1319 | 8.49k | case OpCode::F64__convert_i64_s: |
1320 | 9.08k | case OpCode::F64__convert_i64_u: |
1321 | 9.08k | return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F64)}); |
1322 | 558 | case OpCode::F64__promote_f32: |
1323 | 558 | return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::F64)}); |
1324 | 2.34k | case OpCode::I32__reinterpret_f32: |
1325 | 2.34k | return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)}); |
1326 | 3.01k | case OpCode::I64__reinterpret_f64: |
1327 | 3.01k | return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)}); |
1328 | 6.66k | case OpCode::F32__reinterpret_i32: |
1329 | 6.66k | return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F32)}); |
1330 | 2.54k | case OpCode::F64__reinterpret_i64: |
1331 | 2.54k | return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F64)}); |
1332 | 5.13k | case OpCode::I32__extend8_s: |
1333 | 11.4k | case OpCode::I32__extend16_s: |
1334 | 11.4k | return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)}); |
1335 | 1.52k | case OpCode::I64__extend8_s: |
1336 | 2.86k | case OpCode::I64__extend16_s: |
1337 | 4.03k | case OpCode::I64__extend32_s: |
1338 | 4.03k | return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I64)}); |
1339 | 763 | case OpCode::I32__trunc_sat_f32_s: |
1340 | 1.29k | case OpCode::I32__trunc_sat_f32_u: |
1341 | 1.29k | return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)}); |
1342 | 931 | case OpCode::I32__trunc_sat_f64_s: |
1343 | 1.90k | case OpCode::I32__trunc_sat_f64_u: |
1344 | 1.90k | return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I32)}); |
1345 | 1.04k | case OpCode::I64__trunc_sat_f32_s: |
1346 | 1.77k | case OpCode::I64__trunc_sat_f32_u: |
1347 | 1.77k | return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I64)}); |
1348 | 534 | case OpCode::I64__trunc_sat_f64_s: |
1349 | 1.19k | case OpCode::I64__trunc_sat_f64_u: |
1350 | 1.19k | return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)}); |
1351 | | |
1352 | | // Binary Numeric Instructions. |
1353 | 2.02k | case OpCode::I32__eq: |
1354 | 3.96k | case OpCode::I32__ne: |
1355 | 10.7k | case OpCode::I32__lt_s: |
1356 | 19.8k | case OpCode::I32__lt_u: |
1357 | 23.1k | case OpCode::I32__gt_s: |
1358 | 32.5k | case OpCode::I32__gt_u: |
1359 | 35.8k | case OpCode::I32__le_s: |
1360 | 37.6k | case OpCode::I32__le_u: |
1361 | 40.7k | case OpCode::I32__ge_s: |
1362 | 43.0k | case OpCode::I32__ge_u: |
1363 | 43.0k | return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)}, |
1364 | 43.0k | {ValType(TypeCode::I32)}); |
1365 | 603 | case OpCode::I64__eq: |
1366 | 1.45k | case OpCode::I64__ne: |
1367 | 2.94k | case OpCode::I64__lt_s: |
1368 | 3.72k | case OpCode::I64__lt_u: |
1369 | 5.06k | case OpCode::I64__gt_s: |
1370 | 5.38k | case OpCode::I64__gt_u: |
1371 | 7.00k | case OpCode::I64__le_s: |
1372 | 9.57k | case OpCode::I64__le_u: |
1373 | 10.1k | case OpCode::I64__ge_s: |
1374 | 11.5k | case OpCode::I64__ge_u: |
1375 | 11.5k | return StackTrans({ValType(TypeCode::I64), ValType(TypeCode::I64)}, |
1376 | 11.5k | {ValType(TypeCode::I32)}); |
1377 | 935 | case OpCode::F32__eq: |
1378 | 1.50k | case OpCode::F32__ne: |
1379 | 2.58k | case OpCode::F32__lt: |
1380 | 3.05k | case OpCode::F32__gt: |
1381 | 3.94k | case OpCode::F32__le: |
1382 | 5.17k | case OpCode::F32__ge: |
1383 | 5.17k | return StackTrans({ValType(TypeCode::F32), ValType(TypeCode::F32)}, |
1384 | 5.17k | {ValType(TypeCode::I32)}); |
1385 | 1.53k | case OpCode::F64__eq: |
1386 | 2.12k | case OpCode::F64__ne: |
1387 | 2.85k | case OpCode::F64__lt: |
1388 | 3.99k | case OpCode::F64__gt: |
1389 | 4.56k | case OpCode::F64__le: |
1390 | 5.49k | case OpCode::F64__ge: |
1391 | 5.49k | return StackTrans({ValType(TypeCode::F64), ValType(TypeCode::F64)}, |
1392 | 5.49k | {ValType(TypeCode::I32)}); |
1393 | 2.46k | case OpCode::I32__add: |
1394 | 6.74k | case OpCode::I32__sub: |
1395 | 8.32k | case OpCode::I32__mul: |
1396 | 11.4k | case OpCode::I32__div_s: |
1397 | 17.9k | case OpCode::I32__div_u: |
1398 | 20.5k | case OpCode::I32__rem_s: |
1399 | 23.7k | case OpCode::I32__rem_u: |
1400 | 25.4k | case OpCode::I32__and: |
1401 | 28.4k | case OpCode::I32__or: |
1402 | 36.8k | case OpCode::I32__xor: |
1403 | 40.8k | case OpCode::I32__shl: |
1404 | 45.3k | case OpCode::I32__shr_s: |
1405 | 52.0k | case OpCode::I32__shr_u: |
1406 | 56.2k | case OpCode::I32__rotl: |
1407 | 59.8k | case OpCode::I32__rotr: |
1408 | 59.8k | return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)}, |
1409 | 59.8k | {ValType(TypeCode::I32)}); |
1410 | 1.76k | case OpCode::I64__add: |
1411 | 4.12k | case OpCode::I64__sub: |
1412 | 6.27k | case OpCode::I64__mul: |
1413 | 7.67k | case OpCode::I64__div_s: |
1414 | 11.1k | case OpCode::I64__div_u: |
1415 | 12.6k | case OpCode::I64__rem_s: |
1416 | 14.3k | case OpCode::I64__rem_u: |
1417 | 16.5k | case OpCode::I64__and: |
1418 | 17.8k | case OpCode::I64__or: |
1419 | 23.2k | case OpCode::I64__xor: |
1420 | 24.4k | case OpCode::I64__shl: |
1421 | 26.1k | case OpCode::I64__shr_s: |
1422 | 27.2k | case OpCode::I64__shr_u: |
1423 | 30.3k | case OpCode::I64__rotl: |
1424 | 33.8k | case OpCode::I64__rotr: |
1425 | 33.8k | return StackTrans({ValType(TypeCode::I64), ValType(TypeCode::I64)}, |
1426 | 33.8k | {ValType(TypeCode::I64)}); |
1427 | 885 | case OpCode::F32__add: |
1428 | 3.30k | case OpCode::F32__sub: |
1429 | 4.72k | case OpCode::F32__mul: |
1430 | 5.57k | case OpCode::F32__div: |
1431 | 6.62k | case OpCode::F32__min: |
1432 | 8.18k | case OpCode::F32__max: |
1433 | 9.74k | case OpCode::F32__copysign: |
1434 | 9.74k | return StackTrans({ValType(TypeCode::F32), ValType(TypeCode::F32)}, |
1435 | 9.74k | {ValType(TypeCode::F32)}); |
1436 | 898 | case OpCode::F64__add: |
1437 | 3.22k | case OpCode::F64__sub: |
1438 | 4.30k | case OpCode::F64__mul: |
1439 | 5.74k | case OpCode::F64__div: |
1440 | 6.78k | case OpCode::F64__min: |
1441 | 9.12k | case OpCode::F64__max: |
1442 | 11.1k | case OpCode::F64__copysign: |
1443 | 11.1k | return StackTrans({ValType(TypeCode::F64), ValType(TypeCode::F64)}, |
1444 | 11.1k | {ValType(TypeCode::F64)}); |
1445 | | |
1446 | | // SIMD Memory Instruction. |
1447 | 8.99k | case OpCode::V128__load: |
1448 | 8.99k | return checkMemArgAndTrans(128, {}, {ValType(TypeCode::V128)}); |
1449 | 1.03k | case OpCode::V128__load8x8_s: |
1450 | 1.26k | case OpCode::V128__load8x8_u: |
1451 | 2.02k | case OpCode::V128__load16x4_s: |
1452 | 3.75k | case OpCode::V128__load16x4_u: |
1453 | 4.34k | case OpCode::V128__load32x2_s: |
1454 | 4.73k | case OpCode::V128__load32x2_u: |
1455 | 5.27k | case OpCode::V128__load64_splat: |
1456 | 5.55k | case OpCode::V128__load64_zero: |
1457 | 5.55k | return checkMemArgAndTrans(64, {}, {ValType(TypeCode::V128)}); |
1458 | 558 | case OpCode::V128__load8_splat: |
1459 | 558 | return checkMemArgAndTrans(8, {}, {ValType(TypeCode::V128)}); |
1460 | 748 | case OpCode::V128__load16_splat: |
1461 | 748 | return checkMemArgAndTrans(16, {}, {ValType(TypeCode::V128)}); |
1462 | 554 | case OpCode::V128__load32_splat: |
1463 | 906 | case OpCode::V128__load32_zero: |
1464 | 906 | return checkMemArgAndTrans(32, {}, {ValType(TypeCode::V128)}); |
1465 | 799 | case OpCode::V128__store: |
1466 | 799 | return checkMemArgAndTrans(128, {ValType(TypeCode::V128)}, {}); |
1467 | 280 | case OpCode::V128__load8_lane: |
1468 | 280 | return checkMemArgAndTrans(8, {ValType(TypeCode::V128)}, |
1469 | 280 | {ValType(TypeCode::V128)}, true); |
1470 | 1.24k | case OpCode::V128__load16_lane: |
1471 | 1.24k | return checkMemArgAndTrans(16, {ValType(TypeCode::V128)}, |
1472 | 1.24k | {ValType(TypeCode::V128)}, true); |
1473 | 258 | case OpCode::V128__load32_lane: |
1474 | 258 | return checkMemArgAndTrans(32, {ValType(TypeCode::V128)}, |
1475 | 258 | {ValType(TypeCode::V128)}, true); |
1476 | 463 | case OpCode::V128__load64_lane: |
1477 | 463 | return checkMemArgAndTrans(64, {ValType(TypeCode::V128)}, |
1478 | 463 | {ValType(TypeCode::V128)}, true); |
1479 | 656 | case OpCode::V128__store8_lane: |
1480 | 656 | return checkMemArgAndTrans(8, {ValType(TypeCode::V128)}, {}, true); |
1481 | 209 | case OpCode::V128__store16_lane: |
1482 | 209 | return checkMemArgAndTrans(16, {ValType(TypeCode::V128)}, {}, true); |
1483 | 934 | case OpCode::V128__store32_lane: |
1484 | 934 | return checkMemArgAndTrans(32, {ValType(TypeCode::V128)}, {}, true); |
1485 | 401 | case OpCode::V128__store64_lane: |
1486 | 401 | return checkMemArgAndTrans(64, {ValType(TypeCode::V128)}, {}, true); |
1487 | | |
1488 | | // SIMD Const Instruction. |
1489 | 1.86k | case OpCode::V128__const: |
1490 | 1.86k | return StackTrans({}, {ValType(TypeCode::V128)}); |
1491 | | |
1492 | | // SIMD Shuffle Instruction. |
1493 | 317 | case OpCode::I8x16__shuffle: { |
1494 | | // Check that all lane indices are less than 32 by masking. |
1495 | 317 | const uint128_t Mask = (uint128_t(0xe0e0e0e0e0e0e0e0U) << 64U) | |
1496 | 317 | uint128_t(0xe0e0e0e0e0e0e0e0U); |
1497 | 317 | const uint128_t Result = Instr.getNum().get<uint128_t>() & Mask; |
1498 | 317 | if (Result) { |
1499 | 6 | spdlog::error(ErrCode::Value::InvalidLaneIdx); |
1500 | 6 | return Unexpect(ErrCode::Value::InvalidLaneIdx); |
1501 | 6 | } |
1502 | 311 | return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)}, |
1503 | 311 | {ValType(TypeCode::V128)}); |
1504 | 317 | } |
1505 | | |
1506 | | // SIMD Lane Instructions. |
1507 | 1.10k | case OpCode::I8x16__extract_lane_s: |
1508 | 1.34k | case OpCode::I8x16__extract_lane_u: |
1509 | 1.34k | return checkLaneAndTrans(16, {ValType(TypeCode::V128)}, |
1510 | 1.34k | {ValType(TypeCode::I32)}); |
1511 | 1.11k | case OpCode::I8x16__replace_lane: |
1512 | 1.11k | return checkLaneAndTrans(16, |
1513 | 1.11k | {ValType(TypeCode::V128), ValType(TypeCode::I32)}, |
1514 | 1.11k | {ValType(TypeCode::V128)}); |
1515 | 1.12k | case OpCode::I16x8__extract_lane_s: |
1516 | 1.97k | case OpCode::I16x8__extract_lane_u: |
1517 | 1.97k | return checkLaneAndTrans(8, {ValType(TypeCode::V128)}, |
1518 | 1.97k | {ValType(TypeCode::I32)}); |
1519 | 666 | case OpCode::I16x8__replace_lane: |
1520 | 666 | return checkLaneAndTrans(8, |
1521 | 666 | {ValType(TypeCode::V128), ValType(TypeCode::I32)}, |
1522 | 666 | {ValType(TypeCode::V128)}); |
1523 | 1.68k | case OpCode::I32x4__extract_lane: |
1524 | 1.68k | return checkLaneAndTrans(4, {ValType(TypeCode::V128)}, |
1525 | 1.68k | {ValType(TypeCode::I32)}); |
1526 | 607 | case OpCode::I32x4__replace_lane: |
1527 | 607 | return checkLaneAndTrans(4, |
1528 | 607 | {ValType(TypeCode::V128), ValType(TypeCode::I32)}, |
1529 | 607 | {ValType(TypeCode::V128)}); |
1530 | 389 | case OpCode::I64x2__extract_lane: |
1531 | 389 | return checkLaneAndTrans(2, {ValType(TypeCode::V128)}, |
1532 | 389 | {ValType(TypeCode::I64)}); |
1533 | 914 | case OpCode::I64x2__replace_lane: |
1534 | 914 | return checkLaneAndTrans(2, |
1535 | 914 | {ValType(TypeCode::V128), ValType(TypeCode::I64)}, |
1536 | 914 | {ValType(TypeCode::V128)}); |
1537 | 459 | case OpCode::F32x4__extract_lane: |
1538 | 459 | return checkLaneAndTrans(4, {ValType(TypeCode::V128)}, |
1539 | 459 | {ValType(TypeCode::F32)}); |
1540 | 224 | case OpCode::F32x4__replace_lane: |
1541 | 224 | return checkLaneAndTrans(4, |
1542 | 224 | {ValType(TypeCode::V128), ValType(TypeCode::F32)}, |
1543 | 224 | {ValType(TypeCode::V128)}); |
1544 | 525 | case OpCode::F64x2__extract_lane: |
1545 | 525 | return checkLaneAndTrans(2, {ValType(TypeCode::V128)}, |
1546 | 525 | {ValType(TypeCode::F64)}); |
1547 | 214 | case OpCode::F64x2__replace_lane: |
1548 | 214 | return checkLaneAndTrans(2, |
1549 | 214 | {ValType(TypeCode::V128), ValType(TypeCode::F64)}, |
1550 | 214 | {ValType(TypeCode::V128)}); |
1551 | | |
1552 | | // SIMD Numeric Instructions. |
1553 | 54.2k | case OpCode::I8x16__splat: |
1554 | 66.4k | case OpCode::I16x8__splat: |
1555 | 68.9k | case OpCode::I32x4__splat: |
1556 | 68.9k | return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::V128)}); |
1557 | 1.23k | case OpCode::I64x2__splat: |
1558 | 1.23k | return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::V128)}); |
1559 | 570 | case OpCode::F32x4__splat: |
1560 | 570 | return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::V128)}); |
1561 | 800 | case OpCode::F64x2__splat: |
1562 | 800 | return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::V128)}); |
1563 | 885 | case OpCode::V128__not: |
1564 | 3.52k | case OpCode::I8x16__abs: |
1565 | 7.38k | case OpCode::I8x16__neg: |
1566 | 8.44k | case OpCode::I8x16__popcnt: |
1567 | 9.56k | case OpCode::I16x8__abs: |
1568 | 10.6k | case OpCode::I16x8__neg: |
1569 | 12.4k | case OpCode::I16x8__extend_low_i8x16_s: |
1570 | 12.8k | case OpCode::I16x8__extend_high_i8x16_s: |
1571 | 13.8k | case OpCode::I16x8__extend_low_i8x16_u: |
1572 | 13.9k | case OpCode::I16x8__extend_high_i8x16_u: |
1573 | 15.2k | case OpCode::I16x8__extadd_pairwise_i8x16_s: |
1574 | 17.0k | case OpCode::I16x8__extadd_pairwise_i8x16_u: |
1575 | 18.1k | case OpCode::I32x4__abs: |
1576 | 18.7k | case OpCode::I32x4__neg: |
1577 | 20.4k | case OpCode::I32x4__extend_low_i16x8_s: |
1578 | 21.3k | case OpCode::I32x4__extend_high_i16x8_s: |
1579 | 24.5k | case OpCode::I32x4__extend_low_i16x8_u: |
1580 | 25.2k | case OpCode::I32x4__extend_high_i16x8_u: |
1581 | 27.2k | case OpCode::I32x4__extadd_pairwise_i16x8_s: |
1582 | 29.4k | case OpCode::I32x4__extadd_pairwise_i16x8_u: |
1583 | 31.0k | case OpCode::I64x2__abs: |
1584 | 32.4k | case OpCode::I64x2__neg: |
1585 | 33.4k | case OpCode::I64x2__extend_low_i32x4_s: |
1586 | 34.9k | case OpCode::I64x2__extend_high_i32x4_s: |
1587 | 35.4k | case OpCode::I64x2__extend_low_i32x4_u: |
1588 | 36.9k | case OpCode::I64x2__extend_high_i32x4_u: |
1589 | 37.2k | case OpCode::F32x4__abs: |
1590 | 39.1k | case OpCode::F32x4__neg: |
1591 | 39.6k | case OpCode::F32x4__sqrt: |
1592 | 40.3k | case OpCode::F64x2__abs: |
1593 | 41.7k | case OpCode::F64x2__neg: |
1594 | 42.0k | case OpCode::F64x2__sqrt: |
1595 | 42.9k | case OpCode::I32x4__trunc_sat_f32x4_s: |
1596 | 48.8k | case OpCode::I32x4__trunc_sat_f32x4_u: |
1597 | 49.4k | case OpCode::F32x4__convert_i32x4_s: |
1598 | 50.6k | case OpCode::F32x4__convert_i32x4_u: |
1599 | 51.9k | case OpCode::I32x4__trunc_sat_f64x2_s_zero: |
1600 | 55.2k | case OpCode::I32x4__trunc_sat_f64x2_u_zero: |
1601 | 56.5k | case OpCode::F64x2__convert_low_i32x4_s: |
1602 | 58.6k | case OpCode::F64x2__convert_low_i32x4_u: |
1603 | 60.1k | case OpCode::F32x4__demote_f64x2_zero: |
1604 | 61.7k | case OpCode::F64x2__promote_low_f32x4: |
1605 | 63.4k | case OpCode::F32x4__ceil: |
1606 | 66.9k | case OpCode::F32x4__floor: |
1607 | 69.9k | case OpCode::F32x4__trunc: |
1608 | 70.9k | case OpCode::F32x4__nearest: |
1609 | 72.4k | case OpCode::F64x2__ceil: |
1610 | 74.2k | case OpCode::F64x2__floor: |
1611 | 75.3k | case OpCode::F64x2__trunc: |
1612 | 76.1k | case OpCode::F64x2__nearest: |
1613 | 76.1k | return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::V128)}); |
1614 | 855 | case OpCode::I8x16__swizzle: |
1615 | 1.63k | case OpCode::I8x16__eq: |
1616 | 2.27k | case OpCode::I8x16__ne: |
1617 | 2.92k | case OpCode::I8x16__lt_s: |
1618 | 3.40k | case OpCode::I8x16__lt_u: |
1619 | 4.81k | case OpCode::I8x16__gt_s: |
1620 | 5.24k | case OpCode::I8x16__gt_u: |
1621 | 5.70k | case OpCode::I8x16__le_s: |
1622 | 6.18k | case OpCode::I8x16__le_u: |
1623 | 7.35k | case OpCode::I8x16__ge_s: |
1624 | 7.81k | case OpCode::I8x16__ge_u: |
1625 | 8.31k | case OpCode::I16x8__eq: |
1626 | 9.18k | case OpCode::I16x8__ne: |
1627 | 9.86k | case OpCode::I16x8__lt_s: |
1628 | 11.4k | case OpCode::I16x8__lt_u: |
1629 | 12.6k | case OpCode::I16x8__gt_s: |
1630 | 14.0k | case OpCode::I16x8__gt_u: |
1631 | 14.7k | case OpCode::I16x8__le_s: |
1632 | 15.4k | case OpCode::I16x8__le_u: |
1633 | 16.2k | case OpCode::I16x8__ge_s: |
1634 | 17.0k | case OpCode::I16x8__ge_u: |
1635 | 17.5k | case OpCode::I32x4__eq: |
1636 | 18.0k | case OpCode::I32x4__ne: |
1637 | 19.0k | case OpCode::I32x4__lt_s: |
1638 | 19.4k | case OpCode::I32x4__lt_u: |
1639 | 19.9k | case OpCode::I32x4__gt_s: |
1640 | 20.8k | case OpCode::I32x4__gt_u: |
1641 | 22.5k | case OpCode::I32x4__le_s: |
1642 | 23.1k | case OpCode::I32x4__le_u: |
1643 | 23.4k | case OpCode::I32x4__ge_s: |
1644 | 24.2k | case OpCode::I32x4__ge_u: |
1645 | 24.5k | case OpCode::I64x2__eq: |
1646 | 25.1k | case OpCode::I64x2__ne: |
1647 | 25.8k | case OpCode::I64x2__lt_s: |
1648 | 26.1k | case OpCode::I64x2__gt_s: |
1649 | 26.4k | case OpCode::I64x2__le_s: |
1650 | 27.4k | case OpCode::I64x2__ge_s: |
1651 | 29.8k | case OpCode::F32x4__eq: |
1652 | 30.1k | case OpCode::F32x4__ne: |
1653 | 31.0k | case OpCode::F32x4__lt: |
1654 | 31.4k | case OpCode::F32x4__gt: |
1655 | 32.4k | case OpCode::F32x4__le: |
1656 | 32.8k | case OpCode::F32x4__ge: |
1657 | 34.4k | case OpCode::F64x2__eq: |
1658 | 34.8k | case OpCode::F64x2__ne: |
1659 | 35.4k | case OpCode::F64x2__lt: |
1660 | 37.2k | case OpCode::F64x2__gt: |
1661 | 37.7k | case OpCode::F64x2__le: |
1662 | 38.6k | case OpCode::F64x2__ge: |
1663 | 39.0k | case OpCode::V128__and: |
1664 | 39.4k | case OpCode::V128__andnot: |
1665 | 40.0k | case OpCode::V128__or: |
1666 | 41.2k | case OpCode::V128__xor: |
1667 | 42.0k | case OpCode::I8x16__narrow_i16x8_s: |
1668 | 42.7k | case OpCode::I8x16__narrow_i16x8_u: |
1669 | 43.2k | case OpCode::I8x16__add: |
1670 | 44.3k | case OpCode::I8x16__add_sat_s: |
1671 | 44.8k | case OpCode::I8x16__add_sat_u: |
1672 | 45.8k | case OpCode::I8x16__sub: |
1673 | 46.8k | case OpCode::I8x16__sub_sat_s: |
1674 | 47.3k | case OpCode::I8x16__sub_sat_u: |
1675 | 47.7k | case OpCode::I8x16__min_s: |
1676 | 49.0k | case OpCode::I8x16__min_u: |
1677 | 49.9k | case OpCode::I8x16__max_s: |
1678 | 50.6k | case OpCode::I8x16__max_u: |
1679 | 51.3k | case OpCode::I8x16__avgr_u: |
1680 | 51.8k | case OpCode::I16x8__narrow_i32x4_s: |
1681 | 53.5k | case OpCode::I16x8__narrow_i32x4_u: |
1682 | 54.3k | case OpCode::I16x8__add: |
1683 | 54.6k | case OpCode::I16x8__add_sat_s: |
1684 | 55.6k | case OpCode::I16x8__add_sat_u: |
1685 | 56.2k | case OpCode::I16x8__sub: |
1686 | 56.8k | case OpCode::I16x8__sub_sat_s: |
1687 | 57.3k | case OpCode::I16x8__sub_sat_u: |
1688 | 58.0k | case OpCode::I16x8__mul: |
1689 | 58.7k | case OpCode::I16x8__min_s: |
1690 | 59.2k | case OpCode::I16x8__min_u: |
1691 | 59.7k | case OpCode::I16x8__max_s: |
1692 | 61.0k | case OpCode::I16x8__max_u: |
1693 | 61.3k | case OpCode::I16x8__avgr_u: |
1694 | 61.7k | case OpCode::I16x8__extmul_low_i8x16_s: |
1695 | 62.5k | case OpCode::I16x8__extmul_high_i8x16_s: |
1696 | 62.8k | case OpCode::I16x8__extmul_low_i8x16_u: |
1697 | 63.7k | case OpCode::I16x8__extmul_high_i8x16_u: |
1698 | 64.4k | case OpCode::I16x8__q15mulr_sat_s: |
1699 | 64.9k | case OpCode::I32x4__add: |
1700 | 65.1k | case OpCode::I32x4__sub: |
1701 | 65.4k | case OpCode::I32x4__mul: |
1702 | 66.0k | case OpCode::I32x4__min_s: |
1703 | 66.4k | case OpCode::I32x4__min_u: |
1704 | 66.7k | case OpCode::I32x4__max_s: |
1705 | 67.1k | case OpCode::I32x4__max_u: |
1706 | 67.5k | case OpCode::I32x4__extmul_low_i16x8_s: |
1707 | 67.9k | case OpCode::I32x4__extmul_high_i16x8_s: |
1708 | 68.4k | case OpCode::I32x4__extmul_low_i16x8_u: |
1709 | 68.8k | case OpCode::I32x4__extmul_high_i16x8_u: |
1710 | 69.4k | case OpCode::I64x2__add: |
1711 | 69.9k | case OpCode::I64x2__sub: |
1712 | 70.6k | case OpCode::I64x2__mul: |
1713 | 70.8k | case OpCode::I64x2__extmul_low_i32x4_s: |
1714 | 71.8k | case OpCode::I64x2__extmul_high_i32x4_s: |
1715 | 72.4k | case OpCode::I64x2__extmul_low_i32x4_u: |
1716 | 73.3k | case OpCode::I64x2__extmul_high_i32x4_u: |
1717 | 75.1k | case OpCode::F32x4__add: |
1718 | 76.0k | case OpCode::F32x4__sub: |
1719 | 76.8k | case OpCode::F32x4__mul: |
1720 | 77.2k | case OpCode::F32x4__div: |
1721 | 77.7k | case OpCode::F32x4__min: |
1722 | 78.3k | case OpCode::F32x4__max: |
1723 | 80.2k | case OpCode::F32x4__pmin: |
1724 | 80.7k | case OpCode::F32x4__pmax: |
1725 | 80.9k | case OpCode::F64x2__add: |
1726 | 82.0k | case OpCode::F64x2__sub: |
1727 | 82.4k | case OpCode::F64x2__mul: |
1728 | 82.8k | case OpCode::F64x2__div: |
1729 | 83.2k | case OpCode::F64x2__min: |
1730 | 83.6k | case OpCode::F64x2__max: |
1731 | 84.3k | case OpCode::F64x2__pmin: |
1732 | 84.8k | case OpCode::F64x2__pmax: |
1733 | 85.3k | case OpCode::I32x4__dot_i16x8_s: |
1734 | 85.3k | return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)}, |
1735 | 85.3k | {ValType(TypeCode::V128)}); |
1736 | 280 | case OpCode::V128__bitselect: |
1737 | 280 | return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128), |
1738 | 280 | ValType(TypeCode::V128)}, |
1739 | 280 | {ValType(TypeCode::V128)}); |
1740 | 358 | case OpCode::V128__any_true: |
1741 | 958 | case OpCode::I8x16__all_true: |
1742 | 2.14k | case OpCode::I8x16__bitmask: |
1743 | 2.66k | case OpCode::I16x8__all_true: |
1744 | 3.13k | case OpCode::I16x8__bitmask: |
1745 | 3.95k | case OpCode::I32x4__all_true: |
1746 | 5.52k | case OpCode::I32x4__bitmask: |
1747 | 6.38k | case OpCode::I64x2__all_true: |
1748 | 6.89k | case OpCode::I64x2__bitmask: |
1749 | 6.89k | return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::I32)}); |
1750 | 633 | case OpCode::I8x16__shl: |
1751 | 2.40k | case OpCode::I8x16__shr_s: |
1752 | 3.09k | case OpCode::I8x16__shr_u: |
1753 | 3.28k | case OpCode::I16x8__shl: |
1754 | 3.86k | case OpCode::I16x8__shr_s: |
1755 | 4.13k | case OpCode::I16x8__shr_u: |
1756 | 5.77k | case OpCode::I32x4__shl: |
1757 | 6.14k | case OpCode::I32x4__shr_s: |
1758 | 7.07k | case OpCode::I32x4__shr_u: |
1759 | 7.43k | case OpCode::I64x2__shl: |
1760 | 8.63k | case OpCode::I64x2__shr_s: |
1761 | 8.79k | case OpCode::I64x2__shr_u: |
1762 | 8.79k | return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::I32)}, |
1763 | 8.79k | {ValType(TypeCode::V128)}); |
1764 | | |
1765 | 171 | case OpCode::I8x16__relaxed_swizzle: |
1766 | 171 | return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)}, |
1767 | 171 | {ValType(TypeCode::V128)}); |
1768 | 145 | case OpCode::I32x4__relaxed_trunc_f32x4_s: |
1769 | 352 | case OpCode::I32x4__relaxed_trunc_f32x4_u: |
1770 | 575 | case OpCode::I32x4__relaxed_trunc_f64x2_s_zero: |
1771 | 793 | case OpCode::I32x4__relaxed_trunc_f64x2_u_zero: |
1772 | 793 | return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::V128)}); |
1773 | 73 | case OpCode::F32x4__relaxed_madd: |
1774 | 585 | case OpCode::F32x4__relaxed_nmadd: |
1775 | 748 | case OpCode::F64x2__relaxed_madd: |
1776 | 887 | case OpCode::F64x2__relaxed_nmadd: |
1777 | 1.33k | case OpCode::I8x16__relaxed_laneselect: |
1778 | 1.48k | case OpCode::I16x8__relaxed_laneselect: |
1779 | 1.67k | case OpCode::I32x4__relaxed_laneselect: |
1780 | 1.89k | case OpCode::I64x2__relaxed_laneselect: |
1781 | 1.89k | return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128), |
1782 | 1.89k | ValType(TypeCode::V128)}, |
1783 | 1.89k | {ValType(TypeCode::V128)}); |
1784 | 259 | case OpCode::F32x4__relaxed_min: |
1785 | 439 | case OpCode::F32x4__relaxed_max: |
1786 | 549 | case OpCode::F64x2__relaxed_min: |
1787 | 756 | case OpCode::F64x2__relaxed_max: |
1788 | 869 | case OpCode::I16x8__relaxed_q15mulr_s: |
1789 | 1.12k | case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s: |
1790 | 1.12k | return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)}, |
1791 | 1.12k | {ValType(TypeCode::V128)}); |
1792 | 221 | case OpCode::I32x4__relaxed_dot_i8x16_i7x16_add_s: |
1793 | 221 | return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128), |
1794 | 221 | ValType(TypeCode::V128)}, |
1795 | 221 | {ValType(TypeCode::V128)}); |
1796 | | |
1797 | 465 | case OpCode::Atomic__fence: |
1798 | 465 | return {}; |
1799 | | |
1800 | 196 | case OpCode::Memory__atomic__notify: |
1801 | 196 | return checkMemArgAndTrans(32, {ValType(TypeCode::I32)}, |
1802 | 196 | {ValType(TypeCode::I32)}); |
1803 | 57 | case OpCode::Memory__atomic__wait32: |
1804 | 57 | return checkMemArgAndTrans(32, |
1805 | 57 | {ValType(TypeCode::I32), ValType(TypeCode::I64)}, |
1806 | 57 | {ValType(TypeCode::I32)}); |
1807 | 98 | case OpCode::Memory__atomic__wait64: |
1808 | 98 | return checkMemArgAndTrans(64, |
1809 | 98 | {ValType(TypeCode::I64), ValType(TypeCode::I64)}, |
1810 | 98 | {ValType(TypeCode::I32)}); |
1811 | | |
1812 | 0 | case OpCode::I32__atomic__load: |
1813 | 0 | return checkMemArgAndTrans(32, {}, {ValType(TypeCode::I32)}); |
1814 | 0 | case OpCode::I64__atomic__load: |
1815 | 0 | return checkMemArgAndTrans(64, {}, {ValType(TypeCode::I64)}); |
1816 | 0 | case OpCode::I32__atomic__load8_u: |
1817 | 0 | return checkMemArgAndTrans(8, {}, {ValType(TypeCode::I32)}); |
1818 | 0 | case OpCode::I32__atomic__load16_u: |
1819 | 0 | return checkMemArgAndTrans(16, {}, {ValType(TypeCode::I32)}); |
1820 | 0 | case OpCode::I64__atomic__load8_u: |
1821 | 0 | return checkMemArgAndTrans(8, {}, {ValType(TypeCode::I64)}); |
1822 | 0 | case OpCode::I64__atomic__load16_u: |
1823 | 0 | return checkMemArgAndTrans(16, {}, {ValType(TypeCode::I64)}); |
1824 | 0 | case OpCode::I64__atomic__load32_u: |
1825 | 0 | return checkMemArgAndTrans(32, {}, {ValType(TypeCode::I64)}); |
1826 | 0 | case OpCode::I32__atomic__store: |
1827 | 0 | return checkMemArgAndTrans(32, {ValType(TypeCode::I32)}, {}); |
1828 | 0 | case OpCode::I64__atomic__store: |
1829 | 0 | return checkMemArgAndTrans(64, {ValType(TypeCode::I64)}, {}); |
1830 | 0 | case OpCode::I32__atomic__store8: |
1831 | 0 | return checkMemArgAndTrans(8, {ValType(TypeCode::I32)}, {}); |
1832 | 0 | case OpCode::I32__atomic__store16: |
1833 | 0 | return checkMemArgAndTrans(16, {ValType(TypeCode::I32)}, {}); |
1834 | 0 | case OpCode::I64__atomic__store8: |
1835 | 0 | return checkMemArgAndTrans(8, {ValType(TypeCode::I64)}, {}); |
1836 | 0 | case OpCode::I64__atomic__store16: |
1837 | 0 | return checkMemArgAndTrans(16, {ValType(TypeCode::I64)}, {}); |
1838 | 0 | case OpCode::I64__atomic__store32: |
1839 | 0 | return checkMemArgAndTrans(32, {ValType(TypeCode::I64)}, {}); |
1840 | 0 | case OpCode::I32__atomic__rmw__add: |
1841 | 0 | return checkMemArgAndTrans(32, {ValType(TypeCode::I32)}, |
1842 | 0 | {ValType(TypeCode::I32)}); |
1843 | 0 | case OpCode::I64__atomic__rmw__add: |
1844 | 0 | return checkMemArgAndTrans(64, {ValType(TypeCode::I64)}, |
1845 | 0 | {ValType(TypeCode::I64)}); |
1846 | 0 | case OpCode::I32__atomic__rmw8__add_u: |
1847 | 0 | return checkMemArgAndTrans(8, {ValType(TypeCode::I32)}, |
1848 | 0 | {ValType(TypeCode::I32)}); |
1849 | 0 | case OpCode::I32__atomic__rmw16__add_u: |
1850 | 0 | return checkMemArgAndTrans(16, {ValType(TypeCode::I32)}, |
1851 | 0 | {ValType(TypeCode::I32)}); |
1852 | 0 | case OpCode::I64__atomic__rmw8__add_u: |
1853 | 0 | return checkMemArgAndTrans(8, {ValType(TypeCode::I64)}, |
1854 | 0 | {ValType(TypeCode::I64)}); |
1855 | 0 | case OpCode::I64__atomic__rmw16__add_u: |
1856 | 0 | return checkMemArgAndTrans(16, {ValType(TypeCode::I64)}, |
1857 | 0 | {ValType(TypeCode::I64)}); |
1858 | 0 | case OpCode::I64__atomic__rmw32__add_u: |
1859 | 0 | return checkMemArgAndTrans(32, {ValType(TypeCode::I64)}, |
1860 | 0 | {ValType(TypeCode::I64)}); |
1861 | 0 | case OpCode::I32__atomic__rmw__sub: |
1862 | 0 | return checkMemArgAndTrans(32, {ValType(TypeCode::I32)}, |
1863 | 0 | {ValType(TypeCode::I32)}); |
1864 | 0 | case OpCode::I64__atomic__rmw__sub: |
1865 | 0 | return checkMemArgAndTrans(64, {ValType(TypeCode::I64)}, |
1866 | 0 | {ValType(TypeCode::I64)}); |
1867 | 0 | case OpCode::I32__atomic__rmw8__sub_u: |
1868 | 0 | return checkMemArgAndTrans(8, {ValType(TypeCode::I32)}, |
1869 | 0 | {ValType(TypeCode::I32)}); |
1870 | 0 | case OpCode::I32__atomic__rmw16__sub_u: |
1871 | 0 | return checkMemArgAndTrans(16, {ValType(TypeCode::I32)}, |
1872 | 0 | {ValType(TypeCode::I32)}); |
1873 | 0 | case OpCode::I64__atomic__rmw8__sub_u: |
1874 | 0 | return checkMemArgAndTrans(8, {ValType(TypeCode::I64)}, |
1875 | 0 | {ValType(TypeCode::I64)}); |
1876 | 0 | case OpCode::I64__atomic__rmw16__sub_u: |
1877 | 0 | return checkMemArgAndTrans(16, {ValType(TypeCode::I64)}, |
1878 | 0 | {ValType(TypeCode::I64)}); |
1879 | 0 | case OpCode::I64__atomic__rmw32__sub_u: |
1880 | 0 | return checkMemArgAndTrans(32, {ValType(TypeCode::I64)}, |
1881 | 0 | {ValType(TypeCode::I64)}); |
1882 | 0 | case OpCode::I32__atomic__rmw__and: |
1883 | 0 | return checkMemArgAndTrans(32, {ValType(TypeCode::I32)}, |
1884 | 0 | {ValType(TypeCode::I32)}); |
1885 | 0 | case OpCode::I64__atomic__rmw__and: |
1886 | 0 | return checkMemArgAndTrans(64, {ValType(TypeCode::I64)}, |
1887 | 0 | {ValType(TypeCode::I64)}); |
1888 | 0 | case OpCode::I32__atomic__rmw8__and_u: |
1889 | 0 | return checkMemArgAndTrans(8, {ValType(TypeCode::I32)}, |
1890 | 0 | {ValType(TypeCode::I32)}); |
1891 | 0 | case OpCode::I32__atomic__rmw16__and_u: |
1892 | 0 | return checkMemArgAndTrans(16, {ValType(TypeCode::I32)}, |
1893 | 0 | {ValType(TypeCode::I32)}); |
1894 | 0 | case OpCode::I64__atomic__rmw8__and_u: |
1895 | 0 | return checkMemArgAndTrans(8, {ValType(TypeCode::I64)}, |
1896 | 0 | {ValType(TypeCode::I64)}); |
1897 | 0 | case OpCode::I64__atomic__rmw16__and_u: |
1898 | 0 | return checkMemArgAndTrans(16, {ValType(TypeCode::I64)}, |
1899 | 0 | {ValType(TypeCode::I64)}); |
1900 | 0 | case OpCode::I64__atomic__rmw32__and_u: |
1901 | 0 | return checkMemArgAndTrans(32, {ValType(TypeCode::I64)}, |
1902 | 0 | {ValType(TypeCode::I64)}); |
1903 | 0 | case OpCode::I32__atomic__rmw__or: |
1904 | 0 | return checkMemArgAndTrans(32, {ValType(TypeCode::I32)}, |
1905 | 0 | {ValType(TypeCode::I32)}); |
1906 | 0 | case OpCode::I64__atomic__rmw__or: |
1907 | 0 | return checkMemArgAndTrans(64, {ValType(TypeCode::I64)}, |
1908 | 0 | {ValType(TypeCode::I64)}); |
1909 | 0 | case OpCode::I32__atomic__rmw8__or_u: |
1910 | 0 | return checkMemArgAndTrans(8, {ValType(TypeCode::I32)}, |
1911 | 0 | {ValType(TypeCode::I32)}); |
1912 | 0 | case OpCode::I32__atomic__rmw16__or_u: |
1913 | 0 | return checkMemArgAndTrans(16, {ValType(TypeCode::I32)}, |
1914 | 0 | {ValType(TypeCode::I32)}); |
1915 | 0 | case OpCode::I64__atomic__rmw8__or_u: |
1916 | 0 | return checkMemArgAndTrans(8, {ValType(TypeCode::I64)}, |
1917 | 0 | {ValType(TypeCode::I64)}); |
1918 | 0 | case OpCode::I64__atomic__rmw16__or_u: |
1919 | 0 | return checkMemArgAndTrans(16, {ValType(TypeCode::I64)}, |
1920 | 0 | {ValType(TypeCode::I64)}); |
1921 | 0 | case OpCode::I64__atomic__rmw32__or_u: |
1922 | 0 | return checkMemArgAndTrans(32, {ValType(TypeCode::I64)}, |
1923 | 0 | {ValType(TypeCode::I64)}); |
1924 | 0 | case OpCode::I32__atomic__rmw__xor: |
1925 | 0 | return checkMemArgAndTrans(32, {ValType(TypeCode::I32)}, |
1926 | 0 | {ValType(TypeCode::I32)}); |
1927 | 0 | case OpCode::I64__atomic__rmw__xor: |
1928 | 0 | return checkMemArgAndTrans(64, {ValType(TypeCode::I64)}, |
1929 | 0 | {ValType(TypeCode::I64)}); |
1930 | 0 | case OpCode::I32__atomic__rmw8__xor_u: |
1931 | 0 | return checkMemArgAndTrans(8, {ValType(TypeCode::I32)}, |
1932 | 0 | {ValType(TypeCode::I32)}); |
1933 | 0 | case OpCode::I32__atomic__rmw16__xor_u: |
1934 | 0 | return checkMemArgAndTrans(16, {ValType(TypeCode::I32)}, |
1935 | 0 | {ValType(TypeCode::I32)}); |
1936 | 0 | case OpCode::I64__atomic__rmw8__xor_u: |
1937 | 0 | return checkMemArgAndTrans(8, {ValType(TypeCode::I64)}, |
1938 | 0 | {ValType(TypeCode::I64)}); |
1939 | 0 | case OpCode::I64__atomic__rmw16__xor_u: |
1940 | 0 | return checkMemArgAndTrans(16, {ValType(TypeCode::I64)}, |
1941 | 0 | {ValType(TypeCode::I64)}); |
1942 | 0 | case OpCode::I64__atomic__rmw32__xor_u: |
1943 | 0 | return checkMemArgAndTrans(32, {ValType(TypeCode::I64)}, |
1944 | 0 | {ValType(TypeCode::I64)}); |
1945 | 0 | case OpCode::I32__atomic__rmw__xchg: |
1946 | 0 | return checkMemArgAndTrans(32, {ValType(TypeCode::I32)}, |
1947 | 0 | {ValType(TypeCode::I32)}); |
1948 | 0 | case OpCode::I64__atomic__rmw__xchg: |
1949 | 0 | return checkMemArgAndTrans(64, {ValType(TypeCode::I64)}, |
1950 | 0 | {ValType(TypeCode::I64)}); |
1951 | 0 | case OpCode::I32__atomic__rmw8__xchg_u: |
1952 | 0 | return checkMemArgAndTrans(8, {ValType(TypeCode::I32)}, |
1953 | 0 | {ValType(TypeCode::I32)}); |
1954 | 0 | case OpCode::I32__atomic__rmw16__xchg_u: |
1955 | 0 | return checkMemArgAndTrans(16, {ValType(TypeCode::I32)}, |
1956 | 0 | {ValType(TypeCode::I32)}); |
1957 | 0 | case OpCode::I64__atomic__rmw8__xchg_u: |
1958 | 0 | return checkMemArgAndTrans(8, {ValType(TypeCode::I64)}, |
1959 | 0 | {ValType(TypeCode::I64)}); |
1960 | 0 | case OpCode::I64__atomic__rmw16__xchg_u: |
1961 | 0 | return checkMemArgAndTrans(16, {ValType(TypeCode::I64)}, |
1962 | 0 | {ValType(TypeCode::I64)}); |
1963 | 0 | case OpCode::I64__atomic__rmw32__xchg_u: |
1964 | 0 | return checkMemArgAndTrans(32, {ValType(TypeCode::I64)}, |
1965 | 0 | {ValType(TypeCode::I64)}); |
1966 | 0 | case OpCode::I32__atomic__rmw__cmpxchg: |
1967 | 0 | return checkMemArgAndTrans(32, |
1968 | 0 | {ValType(TypeCode::I32), ValType(TypeCode::I32)}, |
1969 | 0 | {ValType(TypeCode::I32)}); |
1970 | 0 | case OpCode::I64__atomic__rmw__cmpxchg: |
1971 | 0 | return checkMemArgAndTrans(64, |
1972 | 0 | {ValType(TypeCode::I64), ValType(TypeCode::I64)}, |
1973 | 0 | {ValType(TypeCode::I64)}); |
1974 | 0 | case OpCode::I32__atomic__rmw8__cmpxchg_u: |
1975 | 0 | return checkMemArgAndTrans(8, |
1976 | 0 | {ValType(TypeCode::I32), ValType(TypeCode::I32)}, |
1977 | 0 | {ValType(TypeCode::I32)}); |
1978 | 0 | case OpCode::I32__atomic__rmw16__cmpxchg_u: |
1979 | 0 | return checkMemArgAndTrans(16, |
1980 | 0 | {ValType(TypeCode::I32), ValType(TypeCode::I32)}, |
1981 | 0 | {ValType(TypeCode::I32)}); |
1982 | 0 | case OpCode::I64__atomic__rmw8__cmpxchg_u: |
1983 | 0 | return checkMemArgAndTrans(8, |
1984 | 0 | {ValType(TypeCode::I64), ValType(TypeCode::I64)}, |
1985 | 0 | {ValType(TypeCode::I64)}); |
1986 | 0 | case OpCode::I64__atomic__rmw16__cmpxchg_u: |
1987 | 0 | return checkMemArgAndTrans(16, |
1988 | 0 | {ValType(TypeCode::I64), ValType(TypeCode::I64)}, |
1989 | 0 | {ValType(TypeCode::I64)}); |
1990 | 0 | case OpCode::I64__atomic__rmw32__cmpxchg_u: |
1991 | 0 | return checkMemArgAndTrans(32, |
1992 | 0 | {ValType(TypeCode::I64), ValType(TypeCode::I64)}, |
1993 | 0 | {ValType(TypeCode::I64)}); |
1994 | | |
1995 | | // Wide-arithmetic instructions. |
1996 | 0 | case OpCode::I64__add128: |
1997 | 0 | case OpCode::I64__sub128: |
1998 | 0 | return StackTrans({ValType(TypeCode::I64), ValType(TypeCode::I64), |
1999 | 0 | ValType(TypeCode::I64), ValType(TypeCode::I64)}, |
2000 | 0 | {ValType(TypeCode::I64), ValType(TypeCode::I64)}); |
2001 | 0 | case OpCode::I64__mul_wide_s: |
2002 | 0 | case OpCode::I64__mul_wide_u: |
2003 | 0 | return StackTrans({ValType(TypeCode::I64), ValType(TypeCode::I64)}, |
2004 | 0 | {ValType(TypeCode::I64), ValType(TypeCode::I64)}); |
2005 | | |
2006 | 0 | default: |
2007 | 0 | assumingUnreachable(); |
2008 | 2.26M | } |
2009 | 2.26M | } |
2010 | | |
2011 | 1.79M | void FormChecker::pushType(VType V) { ValStack.emplace_back(V); } |
2012 | | |
2013 | 38.5k | void FormChecker::pushTypes(Span<const VType> Input) { |
2014 | 38.5k | for (auto Val : Input) { |
2015 | 10.7k | pushType(Val); |
2016 | 10.7k | } |
2017 | 38.5k | } |
2018 | | |
2019 | 1.82M | void FormChecker::pushTypes(Span<const ValType> Input) { |
2020 | 1.82M | for (auto Val : Input) { |
2021 | 1.77M | pushType(Val); |
2022 | 1.77M | } |
2023 | 1.82M | } |
2024 | | |
2025 | 2.13M | Expect<VType> FormChecker::popType() { |
2026 | 2.13M | if (ValStack.size() == CtrlStack.back().Height) { |
2027 | 403k | if (CtrlStack.back().IsUnreachable) { |
2028 | 402k | return unreachableVType(); |
2029 | 402k | } |
2030 | | // Value stack underflow |
2031 | 396 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
2032 | 396 | spdlog::error(" Value stack underflow."sv); |
2033 | 396 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
2034 | 403k | } |
2035 | 1.73M | auto T = std::move(ValStack.back()); |
2036 | 1.73M | ValStack.pop_back(); |
2037 | 1.73M | return T; |
2038 | 2.13M | } |
2039 | | |
2040 | 1.21M | Expect<VType> FormChecker::popType(ValType E) { |
2041 | 1.21M | EXPECTED_TRY(auto Type, popType()); |
2042 | 1.21M | if (Type == unreachableVType()) { |
2043 | 400k | return E; |
2044 | 400k | } |
2045 | | |
2046 | 812k | if (!AST::TypeMatcher::matchType(Types, E, *Type)) { |
2047 | | // The expected value on the value stack does not match. |
2048 | 1.80k | spdlog::error(ErrCode::Value::TypeCheckFailed); |
2049 | 1.80k | spdlog::error(ErrInfo::InfoMismatch(VTypeToAST(E), VTypeToAST(Type))); |
2050 | 1.80k | return Unexpect(ErrCode::Value::TypeCheckFailed); |
2051 | 1.80k | } |
2052 | 810k | return Type; |
2053 | 812k | } |
2054 | | |
2055 | 1.81M | Expect<void> FormChecker::popTypes(Span<const ValType> Input) { |
2056 | 2.93M | for (auto Val = Input.rbegin(); Val != Input.rend(); ++Val) { |
2057 | 1.12M | EXPECTED_TRY(popType(*Val)); |
2058 | 1.12M | } |
2059 | 1.80M | return {}; |
2060 | 1.81M | } |
2061 | | |
2062 | | void FormChecker::pushCtrl(Span<const ValType> In, Span<const ValType> Out, |
2063 | 44.6k | const AST::Instruction *Jump, OpCode Code) { |
2064 | 44.6k | CtrlStack.emplace_back(In, Out, Jump, ValStack.size(), LocalInits.size(), |
2065 | 44.6k | Code); |
2066 | 44.6k | pushTypes(In); |
2067 | 44.6k | } |
2068 | | |
2069 | 39.4k | Expect<FormChecker::CtrlFrame> FormChecker::popCtrl() { |
2070 | 39.4k | if (CtrlStack.empty()) { |
2071 | | // Ctrl stack is empty when popping. |
2072 | 0 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
2073 | 0 | spdlog::error(" Control stack underflow."sv); |
2074 | 0 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
2075 | 0 | } |
2076 | 39.4k | EXPECTED_TRY(popTypes(CtrlStack.back().EndTypes)); |
2077 | 39.2k | if (ValStack.size() != CtrlStack.back().Height) { |
2078 | | // Value stack size does not match. |
2079 | 254 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
2080 | 254 | spdlog::error(" Value stack underflow."sv); |
2081 | 254 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
2082 | 254 | } |
2083 | | // When popping a frame, reset the locals initialized during this frame. |
2084 | 39.1k | for (size_t I = CtrlStack.back().InitedLocal; I < LocalInits.size(); I++) { |
2085 | 138 | Locals[LocalInits[I]].IsInit = false; |
2086 | 138 | } |
2087 | 38.9k | LocalInits.erase(LocalInits.begin() + |
2088 | 38.9k | static_cast<uint32_t>(CtrlStack.back().InitedLocal), |
2089 | 38.9k | LocalInits.end()); |
2090 | 38.9k | auto Head = std::move(CtrlStack.back()); |
2091 | 38.9k | CtrlStack.pop_back(); |
2092 | 38.9k | return Head; |
2093 | 39.2k | } |
2094 | | |
2095 | | Span<const ValType> |
2096 | 55.9k | FormChecker::getLabelTypes(const FormChecker::CtrlFrame &F) { |
2097 | 55.9k | if (F.Code == OpCode::Loop) { |
2098 | 8.77k | return F.StartTypes; |
2099 | 8.77k | } |
2100 | 47.1k | return F.EndTypes; |
2101 | 55.9k | } |
2102 | | |
2103 | 333k | Expect<void> FormChecker::unreachable() { |
2104 | 1.22M | while (ValStack.size() > CtrlStack.back().Height) { |
2105 | 891k | EXPECTED_TRY(popType()); |
2106 | 891k | } |
2107 | 333k | CtrlStack.back().IsUnreachable = true; |
2108 | 333k | return {}; |
2109 | 333k | } |
2110 | | |
2111 | | Expect<void> FormChecker::StackTrans(Span<const ValType> Take, |
2112 | 1.67M | Span<const ValType> Put) { |
2113 | 1.67M | EXPECTED_TRY(popTypes(Take)); |
2114 | 1.67M | pushTypes(Put); |
2115 | 1.67M | return {}; |
2116 | 1.67M | } |
2117 | | |
2118 | 10.7k | Expect<void> FormChecker::StackPopAny() { |
2119 | 10.7k | EXPECTED_TRY(popType()); |
2120 | 10.7k | return {}; |
2121 | 10.7k | } |
2122 | | |
2123 | | } // namespace Validator |
2124 | | } // namespace WasmEdge |