/src/WasmEdge/include/executor/executor.h
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | //===-- wasmedge/executor/executor.h - Executor class definition ----------===// |
5 | | // |
6 | | // Part of the WasmEdge Project. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | /// |
10 | | /// \file |
11 | | /// This file contains the declaration of the Executor class, which instantiates |
12 | | /// and runs Wasm modules. |
13 | | /// |
14 | | //===----------------------------------------------------------------------===// |
15 | | #pragma once |
16 | | |
17 | | #include "ast/component/component.h" |
18 | | #include "ast/module.h" |
19 | | #include "common/async.h" |
20 | | #include "common/configure.h" |
21 | | #include "common/defines.h" |
22 | | #include "common/errcode.h" |
23 | | #include "common/statistics.h" |
24 | | #include "common/types.h" |
25 | | #include "runtime/callingframe.h" |
26 | | #include "runtime/instance/component/component.h" |
27 | | #include "runtime/instance/module.h" |
28 | | #include "runtime/stackmgr.h" |
29 | | #include "runtime/storemgr.h" |
30 | | |
31 | | #include <atomic> |
32 | | #include <csignal> |
33 | | #include <cstdint> |
34 | | #include <functional> |
35 | | #include <memory> |
36 | | #include <mutex> |
37 | | #include <optional> |
38 | | #include <shared_mutex> |
39 | | #include <string_view> |
40 | | #include <type_traits> |
41 | | #include <utility> |
42 | | #include <vector> |
43 | | |
44 | | namespace WasmEdge { |
45 | | namespace Executor { |
46 | | |
47 | | namespace { |
48 | | |
49 | | // Template return type aliasing |
50 | | /// Accept unsigned integer types. (uint32_t, uint64_t) |
51 | | template <typename T> |
52 | | using TypeU = typename std::enable_if_t<IsWasmUnsignV<T>, Expect<void>>; |
53 | | /// Accept integer types. (uint32_t, int32_t, uint64_t, int64_t) |
54 | | template <typename T> |
55 | | using TypeI = typename std::enable_if_t<IsWasmIntV<T>, Expect<void>>; |
56 | | /// Accept floating types. (float, double) |
57 | | template <typename T> |
58 | | using TypeF = typename std::enable_if_t<IsWasmFloatV<T>, Expect<void>>; |
59 | | /// Accept all num types. (uint32_t, int32_t, uint64_t, int64_t, float, double) |
60 | | template <typename T> |
61 | | using TypeT = typename std::enable_if_t<IsWasmNumV<T>, Expect<void>>; |
62 | | /// Accept Wasm built-in num types. (uint32_t, uint64_t, float, double) |
63 | | template <typename T> |
64 | | using TypeN = typename std::enable_if_t<IsWasmNativeNumV<T>, Expect<void>>; |
65 | | |
66 | | /// Accept (unsigned integer types, unsigned integer types). |
67 | | template <typename T1, typename T2> |
68 | | using TypeUU = typename std::enable_if_t<IsWasmUnsignV<T1> && IsWasmUnsignV<T2>, |
69 | | Expect<void>>; |
70 | | /// Accept (integer types, unsigned integer types). |
71 | | template <typename T1, typename T2> |
72 | | using TypeIU = typename std::enable_if_t<IsWasmIntV<T1> && IsWasmUnsignV<T2>, |
73 | | Expect<void>>; |
74 | | /// Accept (floating types, floating types). |
75 | | template <typename T1, typename T2> |
76 | | using TypeFF = typename std::enable_if_t<IsWasmFloatV<T1> && IsWasmFloatV<T2>, |
77 | | Expect<void>>; |
78 | | /// Accept (integer types, floating types). |
79 | | template <typename T1, typename T2> |
80 | | using TypeIF = |
81 | | typename std::enable_if_t<IsWasmIntV<T1> && IsWasmFloatV<T2>, Expect<void>>; |
82 | | /// Accept (floating types, integer types). |
83 | | template <typename T1, typename T2> |
84 | | using TypeFI = |
85 | | typename std::enable_if_t<IsWasmFloatV<T1> && IsWasmIntV<T2>, Expect<void>>; |
86 | | /// Accept (Wasm built-in num types, Wasm built-in num types). |
87 | | template <typename T1, typename T2> |
88 | | using TypeNN = |
89 | | typename std::enable_if_t<IsWasmNativeNumV<T1> && IsWasmNativeNumV<T2> && |
90 | | sizeof(T1) == sizeof(T2), |
91 | | Expect<void>>; |
92 | | |
93 | | } // namespace |
94 | | |
95 | | /// Helper class for handling the pre- and post-host functions. |
96 | | class HostFuncHandler { |
97 | | public: |
98 | 0 | void setPreHost(void *HostData, std::function<void(void *)> HostFunc) { |
99 | 0 | std::unique_lock Lock(Mutex); |
100 | 0 | PreHostData = HostData; |
101 | 0 | PreHostFunc = HostFunc; |
102 | 0 | } |
103 | 0 | void setPostHost(void *HostData, std::function<void(void *)> HostFunc) { |
104 | 0 | std::unique_lock Lock(Mutex); |
105 | 0 | PostHostData = HostData; |
106 | 0 | PostHostFunc = HostFunc; |
107 | 0 | } |
108 | 0 | void invokePreHostFunc() { |
109 | 0 | std::function<void(void *)> FuncSnapshot; |
110 | 0 | void *DataSnapshot = nullptr; |
111 | 0 | { |
112 | 0 | std::shared_lock Lock(Mutex); |
113 | 0 | FuncSnapshot = PreHostFunc; |
114 | 0 | DataSnapshot = PreHostData; |
115 | 0 | } |
116 | 0 | if (FuncSnapshot.operator bool()) { |
117 | 0 | FuncSnapshot(DataSnapshot); |
118 | 0 | } |
119 | 0 | } |
120 | 0 | void invokePostHostFunc() { |
121 | 0 | std::function<void(void *)> FuncSnapshot; |
122 | 0 | void *DataSnapshot = nullptr; |
123 | 0 | { |
124 | 0 | std::shared_lock Lock(Mutex); |
125 | 0 | FuncSnapshot = PostHostFunc; |
126 | 0 | DataSnapshot = PostHostData; |
127 | 0 | } |
128 | 0 | if (FuncSnapshot.operator bool()) { |
129 | 0 | FuncSnapshot(DataSnapshot); |
130 | 0 | } |
131 | 0 | } |
132 | | |
133 | | private: |
134 | | void *PreHostData = nullptr; |
135 | | void *PostHostData = nullptr; |
136 | | std::function<void(void *)> PreHostFunc = {}; |
137 | | std::function<void(void *)> PostHostFunc = {}; |
138 | | mutable std::shared_mutex Mutex; |
139 | | }; |
140 | | |
141 | | /// Executor flow control class. |
142 | | class Executor { |
143 | | public: |
144 | | Executor(const Configure &Conf, Statistics::Statistics *S = nullptr) noexcept |
145 | 0 | : Conf(Conf) { |
146 | 0 | if (Conf.getStatisticsConfigure().isInstructionCounting() || |
147 | 0 | Conf.getStatisticsConfigure().isCostMeasuring() || |
148 | 0 | Conf.getStatisticsConfigure().isTimeMeasuring()) { |
149 | 0 | Stat = S; |
150 | 0 | } else { |
151 | 0 | Stat = nullptr; |
152 | 0 | } |
153 | 0 | if (Stat) { |
154 | 0 | Stat->setCostLimit(Conf.getStatisticsConfigure().getCostLimit()); |
155 | 0 | } |
156 | 0 | } |
157 | | |
158 | | /// Getter for configuration. |
159 | 0 | const Configure &getConfigure() const { return Conf; } |
160 | | |
161 | | /// Instantiate a WASM Module as an anonymous module instance. |
162 | | Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>> |
163 | | instantiateModule(Runtime::StoreManager &StoreMgr, const AST::Module &Mod); |
164 | | |
165 | | /// Instantiate and register a WASM module as a named module instance. |
166 | | Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>> |
167 | | registerModule(Runtime::StoreManager &StoreMgr, const AST::Module &Mod, |
168 | | std::string_view Name); |
169 | | |
170 | | /// Register an instantiated module as a named module instance. |
171 | | Expect<void> registerModule(Runtime::StoreManager &StoreMgr, |
172 | | const Runtime::Instance::ModuleInstance &ModInst); |
173 | | |
174 | | /// Register an instantiated module under the given alias name. |
175 | | Expect<void> registerModule(Runtime::StoreManager &StoreMgr, |
176 | | const Runtime::Instance::ModuleInstance &ModInst, |
177 | | std::string_view Name); |
178 | | |
179 | | /// Instantiate a Component as an anonymous component instance. |
180 | | Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>> |
181 | | instantiateComponent(Runtime::StoreManager &StoreMgr, |
182 | | const AST::Component::Component &Comp); |
183 | | |
184 | | /// Instantiate and register a Component as a named component instance. |
185 | | Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>> |
186 | | registerComponent(Runtime::StoreManager &StoreMgr, |
187 | | const AST::Component::Component &Comp, |
188 | | std::string_view Name); |
189 | | |
190 | | /// Register an instantiated component into a named component instance. |
191 | | Expect<void> |
192 | | registerComponent(Runtime::StoreManager &StoreMgr, |
193 | | const Runtime::Instance::ComponentInstance &CompInst); |
194 | | |
195 | | /// Register a host function which will be invoked before calling a |
196 | | /// host function. |
197 | | Expect<void> registerPreHostFunction(void *HostData, |
198 | | std::function<void(void *)> HostFunc); |
199 | | |
200 | | /// Register a host function which will be invoked after calling a |
201 | | /// host function. |
202 | | Expect<void> registerPostHostFunction(void *HostData, |
203 | | std::function<void(void *)> HostFunc); |
204 | | |
205 | | /// Register a callback for lazy function compilation |
206 | | void registerLazyCompilationCallback( |
207 | | std::function<Expect<void>(const Runtime::Instance::FunctionInstance *)> |
208 | 0 | Callback) { |
209 | 0 | LazyCompilationHandler = std::move(Callback); |
210 | 0 | } |
211 | | |
212 | | /// Invoke a WASM function by function instance. |
213 | | Expect<std::vector<std::pair<ValVariant, ValType>>> |
214 | | invoke(const Runtime::Instance::FunctionInstance *FuncInst, |
215 | | Span<const ValVariant> Params, Span<const ValType> ParamTypes); |
216 | | |
217 | | /// Invoke a Component function by function instance. |
218 | | Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>> |
219 | | invoke(const Runtime::Instance::Component::FunctionInstance *FuncInst, |
220 | | Span<const ComponentValVariant> Params, |
221 | | Span<const ComponentValType> ParamTypes); |
222 | | |
223 | | /// Asynchronous invoke a WASM function by function instance. |
224 | | Async<Expect<std::vector<std::pair<ValVariant, ValType>>>> |
225 | | asyncInvoke(const Runtime::Instance::FunctionInstance *FuncInst, |
226 | | Span<const ValVariant> Params, Span<const ValType> ParamTypes); |
227 | | |
228 | | /// Stop execution |
229 | 0 | void stop() noexcept { |
230 | 0 | StopToken.store(1, std::memory_order_relaxed); |
231 | 0 | atomicNotifyAll(); |
232 | 0 | } |
233 | | |
234 | | private: |
235 | | /// Run Wasm bytecode expression for initialization. |
236 | | Expect<void> runExpression(Runtime::StackManager &StackMgr, |
237 | | AST::InstrView Instrs); |
238 | | |
239 | | /// Run Wasm function. |
240 | | Expect<void> runFunction(Runtime::StackManager &StackMgr, |
241 | | const Runtime::Instance::FunctionInstance &Func, |
242 | | Span<const ValVariant> Params); |
243 | | |
244 | | /// Execute instructions. |
245 | | Expect<void> execute(Runtime::StackManager &StackMgr, |
246 | | const AST::InstrView::iterator Start, |
247 | | const AST::InstrView::iterator End); |
248 | | |
249 | | /// \name Functions for instantiation. |
250 | | /// @{ |
251 | | /// Instantiation of Module Instance. |
252 | | Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>> |
253 | | instantiate(Runtime::StoreManager &StoreMgr, const AST::Module &Mod, |
254 | | std::optional<std::string_view> Name = std::nullopt); |
255 | | |
256 | | /// Instantiation of Imports. |
257 | | Expect<void> instantiate( |
258 | | std::function<const Runtime::Instance::ModuleInstance *(std::string_view)> |
259 | | ModuleFinder, |
260 | | Runtime::Instance::ModuleInstance &ModInst, |
261 | | const AST::ImportSection &ImportSec); |
262 | | |
263 | | /// Instantiation of Function Instances. |
264 | | Expect<void> instantiate(Runtime::Instance::ModuleInstance &ModInst, |
265 | | const AST::FunctionSection &FuncSec, |
266 | | const AST::CodeSection &CodeSec); |
267 | | |
268 | | /// Instantiation of Table Instances. |
269 | | Expect<void> instantiate(Runtime::StackManager &StackMgr, |
270 | | Runtime::Instance::ModuleInstance &ModInst, |
271 | | const AST::TableSection &TabSec); |
272 | | |
273 | | /// Instantiation of Memory Instances. |
274 | | Expect<void> instantiate(Runtime::Instance::ModuleInstance &ModInst, |
275 | | const AST::MemorySection &MemSec); |
276 | | |
277 | | /// Instantiateion of Tag Instances. |
278 | | Expect<void> instantiate(Runtime::Instance::ModuleInstance &ModInst, |
279 | | const AST::TagSection &TagSec); |
280 | | |
281 | | /// Instantiation of Global Instances. |
282 | | Expect<void> instantiate(Runtime::StackManager &StackMgr, |
283 | | Runtime::Instance::ModuleInstance &ModInst, |
284 | | const AST::GlobalSection &GlobSec); |
285 | | |
286 | | /// Instantiation of Element Instances. |
287 | | Expect<void> instantiate(Runtime::StackManager &StackMgr, |
288 | | Runtime::Instance::ModuleInstance &ModInst, |
289 | | const AST::ElementSection &ElemSec); |
290 | | |
291 | | /// Initialize table with Element Instances. |
292 | | Expect<void> initTable(Runtime::StackManager &StackMgr, |
293 | | const AST::ElementSection &ElemSec); |
294 | | |
295 | | /// Instantiation of Data Instances. |
296 | | Expect<void> instantiate(Runtime::StackManager &StackMgr, |
297 | | Runtime::Instance::ModuleInstance &ModInst, |
298 | | const AST::DataSection &DataSec); |
299 | | |
300 | | /// Initialize memory with Data Instances. |
301 | | Expect<void> initMemory(Runtime::StackManager &StackMgr, |
302 | | const AST::DataSection &DataSec); |
303 | | |
304 | | /// Instantiation of Exports. |
305 | | Expect<void> instantiate(Runtime::Instance::ModuleInstance &ModInst, |
306 | | const AST::ExportSection &ExportSec); |
307 | | /// @} |
308 | | |
309 | | /// \name Functions for instantiation of component model. |
310 | | /// @{ |
311 | | /// Instantiation of Component Instance. |
312 | | Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>> |
313 | | instantiate(Runtime::StoreManager &StoreMgr, |
314 | | const AST::Component::Component &Comp, |
315 | | std::optional<std::string_view> Name = std::nullopt); |
316 | | |
317 | | /// Instantiation of Child Component Instance. |
318 | | Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>> |
319 | | instantiate(Runtime::Instance::ComponentImportManager &ImportMgr, |
320 | | const AST::Component::Component &Comp); |
321 | | |
322 | | /// Instantiation of Child Core Module Instance. |
323 | | Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>> |
324 | | instantiate(Runtime::Instance::ComponentImportManager &ImportMgr, |
325 | | const AST::Module &Mod); |
326 | | |
327 | | /// Instantiation of Core Module Section. |
328 | | Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst, |
329 | | const AST::Component::CoreModuleSection &CoreModSec); |
330 | | |
331 | | /// Instantiation of Core Instance Section. |
332 | | Expect<void> |
333 | | instantiate(Runtime::Instance::ComponentInstance &CompInst, |
334 | | const AST::Component::CoreInstanceSection &CoreInstSec); |
335 | | |
336 | | /// Instantiation of Core Type Section. |
337 | | Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst, |
338 | | const AST::Component::CoreTypeSection &CoreTypeSec); |
339 | | |
340 | | /// Instantiation of Component Section. |
341 | | Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst, |
342 | | const AST::Component::ComponentSection &CompSec); |
343 | | |
344 | | /// Instantiation of Instance Section. |
345 | | Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst, |
346 | | const AST::Component::InstanceSection &InstSec); |
347 | | |
348 | | /// Instantiation of Alias Section. |
349 | | Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst, |
350 | | const AST::Component::AliasSection &AliasSec); |
351 | | |
352 | | /// Instantiation of Type Section. |
353 | | Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst, |
354 | | const AST::Component::TypeSection &TypeSec); |
355 | | |
356 | | /// Instantiation of Canonical Section. |
357 | | Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst, |
358 | | const AST::Component::CanonSection &CanonSec); |
359 | | |
360 | | /// Instantiation of Start Section. |
361 | | Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst, |
362 | | const AST::Component::StartSection &StartSec); |
363 | | |
364 | | /// Instantiation of Import Section. |
365 | | Expect<void> instantiate(Runtime::StoreManager &StoreMgr, |
366 | | Runtime::Instance::ComponentInstance &CompInst, |
367 | | const AST::Component::ImportSection &ImportSec); |
368 | | |
369 | | /// Instantiation of Import Section in the child component instance. |
370 | | Expect<void> instantiate(Runtime::Instance::ComponentImportManager &ImportMgr, |
371 | | Runtime::Instance::ComponentInstance &CompInst, |
372 | | const AST::Component::ImportSection &ImportSec); |
373 | | |
374 | | /// Instantiation of Export Section. |
375 | | Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst, |
376 | | const AST::Component::ExportSection &ExportSec); |
377 | | /// @} |
378 | | |
379 | | /// \name Helper Functions for canonical ABI |
380 | | /// @{ |
381 | | std::vector<ValVariant> |
382 | | convValsToCoreWASM(Span<const ComponentValVariant> Vals, |
383 | | Span<const ComponentValType> ValTypes, |
384 | | Runtime::Instance::FunctionInstance *RFuncInst, |
385 | | Runtime::Instance::MemoryInstance *MemInst) noexcept; |
386 | | |
387 | | Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>> |
388 | | convValsToComponent(Span<const std::pair<ValVariant, ValType>> CoreVals, |
389 | | Span<const ComponentValType> ValTypes, |
390 | | Runtime::Instance::MemoryInstance *MemInst); |
391 | | /// @} |
392 | | |
393 | | /// \name Helper Functions for block controls. |
394 | | /// @{ |
395 | | /// Helper function for calling functions. Return the continuation iterator. |
396 | | Expect<AST::InstrView::iterator> |
397 | | enterFunction(Runtime::StackManager &StackMgr, |
398 | | const Runtime::Instance::FunctionInstance &Func, |
399 | | const AST::InstrView::iterator RetIt, bool IsTailCall = false); |
400 | | |
401 | | /// Helper function for branching to label. |
402 | | Expect<void> branchToLabel(Runtime::StackManager &StackMgr, |
403 | | const AST::Instruction::JumpDescriptor &JumpDesc, |
404 | | AST::InstrView::iterator &PC) noexcept; |
405 | | |
406 | | /// Helper function for throwing an exception. Pass `ExnInst` on `throw_ref` |
407 | | /// to reuse the exception instance and preserve exnref identity. |
408 | | Expect<void> throwException( |
409 | | Runtime::StackManager &StackMgr, Runtime::Instance::TagInstance &TagInst, |
410 | | AST::InstrView::iterator &PC, |
411 | | const Runtime::Instance::ExceptionInstance *ExnInst = nullptr) noexcept; |
412 | | /// @} |
413 | | |
414 | | /// \name Helper Function for checking memory offset boundary. |
415 | | /// @{ |
416 | | Expect<void> |
417 | | checkOffsetOverflow(const Runtime::Instance::MemoryInstance &MemInst, |
418 | | const AST::Instruction &Instr, const uint64_t Val, |
419 | | const uint64_t Size) const noexcept; |
420 | | /// @} |
421 | | |
422 | | /// \name Helper Functions for GC instructions. |
423 | | /// @{ |
424 | | Expect<RefVariant> structNew(Runtime::StackManager &StackMgr, |
425 | | const uint32_t TypeIdx, |
426 | | Span<const ValVariant> Args = {}) const noexcept; |
427 | | Expect<ValVariant> structGet(Runtime::StackManager &StackMgr, |
428 | | const RefVariant Ref, const uint32_t TypeIdx, |
429 | | const uint32_t Off, |
430 | | const bool IsSigned = false) const noexcept; |
431 | | Expect<void> structSet(Runtime::StackManager &StackMgr, const RefVariant Ref, |
432 | | const ValVariant Val, const uint32_t TypeIdx, |
433 | | const uint32_t Off) const noexcept; |
434 | | Expect<RefVariant> arrayNew(Runtime::StackManager &StackMgr, |
435 | | const uint32_t TypeIdx, const uint32_t Length, |
436 | | Span<const ValVariant> Args = {}) const noexcept; |
437 | | Expect<RefVariant> arrayNewData(Runtime::StackManager &StackMgr, |
438 | | const uint32_t TypeIdx, |
439 | | const uint32_t DataIdx, const uint32_t Start, |
440 | | const uint32_t Length) const noexcept; |
441 | | Expect<RefVariant> arrayNewElem(Runtime::StackManager &StackMgr, |
442 | | const uint32_t TypeIdx, |
443 | | const uint32_t ElemIdx, const uint32_t Start, |
444 | | const uint32_t Length) const noexcept; |
445 | | Expect<ValVariant> arrayGet(Runtime::StackManager &StackMgr, |
446 | | const RefVariant &Ref, const uint32_t TypeIdx, |
447 | | const uint32_t Idx, |
448 | | const bool IsSigned = false) const noexcept; |
449 | | Expect<void> arraySet(Runtime::StackManager &StackMgr, const RefVariant &Ref, |
450 | | const ValVariant &Val, const uint32_t TypeIdx, |
451 | | const uint32_t Idx) const noexcept; |
452 | | Expect<void> arrayFill(Runtime::StackManager &StackMgr, const RefVariant &Ref, |
453 | | const ValVariant &Val, const uint32_t TypeIdx, |
454 | | const uint32_t Idx, const uint32_t Cnt) const noexcept; |
455 | | Expect<void> arrayInitData(Runtime::StackManager &StackMgr, |
456 | | const RefVariant &Ref, const uint32_t TypeIdx, |
457 | | const uint32_t DataIdx, const uint32_t DstIdx, |
458 | | const uint32_t SrcIdx, |
459 | | const uint32_t Cnt) const noexcept; |
460 | | Expect<void> arrayInitElem(Runtime::StackManager &StackMgr, |
461 | | const RefVariant &Ref, const uint32_t TypeIdx, |
462 | | const uint32_t ElemIdx, const uint32_t DstIdx, |
463 | | const uint32_t SrcIdx, |
464 | | const uint32_t Cnt) const noexcept; |
465 | | Expect<void> arrayCopy(Runtime::StackManager &StackMgr, |
466 | | const RefVariant &DstRef, const uint32_t DstTypeIdx, |
467 | | const uint32_t DstIdx, const RefVariant &SrcRef, |
468 | | const uint32_t SrcTypeIdx, const uint32_t SrcIdx, |
469 | | const uint32_t Cnt) const noexcept; |
470 | | /// @} |
471 | | |
472 | | /// \name Helper Functions for atomic operations. |
473 | | /// @{ |
474 | | template <typename T> |
475 | | Expect<uint64_t> atomicWait(Runtime::Instance::MemoryInstance &MemInst, |
476 | | uint64_t Address, EndianValue<T> Expected, |
477 | | int64_t Timeout) noexcept; |
478 | | Expect<uint64_t> atomicNotify(Runtime::Instance::MemoryInstance &MemInst, |
479 | | uint64_t Address, uint64_t Count) noexcept; |
480 | | void atomicNotifyAll() noexcept; |
481 | | /// @} |
482 | | |
483 | | /// \name Helper Functions for getting instances or types. |
484 | | /// @{ |
485 | | /// Helper function for getting defined type by index. |
486 | | const AST::SubType *getDefTypeByIdx(Runtime::StackManager &StackMgr, |
487 | | const uint32_t Idx) const; |
488 | | |
489 | | /// Helper function for getting composite type by index. Assuming validated. |
490 | | const WasmEdge::AST::CompositeType & |
491 | | getCompositeTypeByIdx(Runtime::StackManager &StackMgr, |
492 | | const uint32_t Idx) const noexcept; |
493 | | |
494 | | /// Helper function for getting struct storage type by index. |
495 | | const ValType &getStructStorageTypeByIdx(Runtime::StackManager &StackMgr, |
496 | | const uint32_t Idx, |
497 | | const uint32_t Off) const noexcept; |
498 | | |
499 | | /// Helper function for getting array storage type by index. |
500 | | const ValType &getArrayStorageTypeByIdx(Runtime::StackManager &StackMgr, |
501 | | const uint32_t Idx) const noexcept; |
502 | | |
503 | | /// Helper function for getting function instance by index. |
504 | | Runtime::Instance::FunctionInstance * |
505 | | getFuncInstByIdx(Runtime::StackManager &StackMgr, const uint32_t Idx) const; |
506 | | |
507 | | /// Helper function for getting table instance by index. |
508 | | Runtime::Instance::TableInstance * |
509 | | getTabInstByIdx(Runtime::StackManager &StackMgr, const uint32_t Idx) const; |
510 | | |
511 | | /// Helper function for getting memory instance by index. |
512 | | Runtime::Instance::MemoryInstance * |
513 | | getMemInstByIdx(Runtime::StackManager &StackMgr, const uint32_t Idx) const; |
514 | | |
515 | | /// Helper function for getting tag instance by index. |
516 | | Runtime::Instance::TagInstance * |
517 | | getTagInstByIdx(Runtime::StackManager &StackMgr, const uint32_t Idx) const; |
518 | | |
519 | | /// Helper function for getting global instance by index. |
520 | | Runtime::Instance::GlobalInstance * |
521 | | getGlobInstByIdx(Runtime::StackManager &StackMgr, const uint32_t Idx) const; |
522 | | |
523 | | /// Helper function for getting element instance by index. |
524 | | Runtime::Instance::ElementInstance * |
525 | | getElemInstByIdx(Runtime::StackManager &StackMgr, const uint32_t Idx) const; |
526 | | |
527 | | /// Helper function for getting data instance by index. |
528 | | Runtime::Instance::DataInstance * |
529 | | getDataInstByIdx(Runtime::StackManager &StackMgr, const uint32_t Idx) const; |
530 | | |
531 | | /// Helper function for converting into bottom abstract heap type. |
532 | | TypeCode toBottomType(Runtime::StackManager &StackMgr, |
533 | | const ValType &Type) const; |
534 | | |
535 | | /// Helper function for cleaning unused bits of numeric values in ValVariant. |
536 | | void cleanNumericVal(ValVariant &Val, const ValType &Type) const noexcept; |
537 | | |
538 | | /// Helper function for packing ValVariant for packed type. |
539 | | ValVariant packVal(const ValType &Type, const ValVariant &Val) const noexcept; |
540 | | |
541 | | /// Helper function for packing ValVariant vector for packed type. |
542 | | std::vector<ValVariant> |
543 | | packVals(const ValType &Type, std::vector<ValVariant> &&Vals) const noexcept; |
544 | | |
545 | | /// Helper function for unpacking ValVariant for packed type. |
546 | | ValVariant unpackVal(const ValType &Type, const ValVariant &Val, |
547 | | bool IsSigned = false) const noexcept; |
548 | | /// @} |
549 | | |
550 | | /// \name Interpreter - Run instructions functions |
551 | | /// @{ |
552 | | /// ======= Control instructions ======= |
553 | | Expect<void> runIfElseOp(Runtime::StackManager &StackMgr, |
554 | | const AST::Instruction &Instr, |
555 | | AST::InstrView::iterator &PC) noexcept; |
556 | | Expect<void> runThrowOp(Runtime::StackManager &StackMgr, |
557 | | const AST::Instruction &Instr, |
558 | | AST::InstrView::iterator &PC) noexcept; |
559 | | Expect<void> runThrowRefOp(Runtime::StackManager &StackMgr, |
560 | | const AST::Instruction &Instr, |
561 | | AST::InstrView::iterator &PC) noexcept; |
562 | | Expect<void> runBrOp(Runtime::StackManager &StackMgr, |
563 | | const AST::Instruction &Instr, |
564 | | AST::InstrView::iterator &PC) noexcept; |
565 | | Expect<void> runBrIfOp(Runtime::StackManager &StackMgr, |
566 | | const AST::Instruction &Instr, |
567 | | AST::InstrView::iterator &PC) noexcept; |
568 | | Expect<void> runBrOnNullOp(Runtime::StackManager &StackMgr, |
569 | | const AST::Instruction &Instr, |
570 | | AST::InstrView::iterator &PC) noexcept; |
571 | | Expect<void> runBrOnNonNullOp(Runtime::StackManager &StackMgr, |
572 | | const AST::Instruction &Instr, |
573 | | AST::InstrView::iterator &PC) noexcept; |
574 | | Expect<void> runBrTableOp(Runtime::StackManager &StackMgr, |
575 | | const AST::Instruction &Instr, |
576 | | AST::InstrView::iterator &PC) noexcept; |
577 | | Expect<void> runBrOnCastOp(Runtime::StackManager &StackMgr, |
578 | | const AST::Instruction &Instr, |
579 | | AST::InstrView::iterator &PC, |
580 | | bool IsReverse = false) noexcept; |
581 | | Expect<void> runReturnOp(Runtime::StackManager &StackMgr, |
582 | | AST::InstrView::iterator &PC) noexcept; |
583 | | Expect<void> runCallOp(Runtime::StackManager &StackMgr, |
584 | | const AST::Instruction &Instr, |
585 | | AST::InstrView::iterator &PC, |
586 | | bool IsTailCall = false) noexcept; |
587 | | Expect<void> runCallRefOp(Runtime::StackManager &StackMgr, |
588 | | const AST::Instruction &Instr, |
589 | | AST::InstrView::iterator &PC, |
590 | | bool IsTailCall = false) noexcept; |
591 | | Expect<void> runCallIndirectOp(Runtime::StackManager &StackMgr, |
592 | | const AST::Instruction &Instr, |
593 | | AST::InstrView::iterator &PC, |
594 | | bool IsTailCall = false) noexcept; |
595 | | Expect<void> runTryTableOp(Runtime::StackManager &StackMgr, |
596 | | const AST::Instruction &Instr, |
597 | | AST::InstrView::iterator &PC) noexcept; |
598 | | /// ======= Variable instructions ======= |
599 | | Expect<void> runLocalGetOp(Runtime::StackManager &StackMgr, |
600 | | uint32_t StackOffset) const noexcept; |
601 | | Expect<void> runLocalSetOp(Runtime::StackManager &StackMgr, |
602 | | uint32_t StackOffset) const noexcept; |
603 | | Expect<void> runLocalTeeOp(Runtime::StackManager &StackMgr, |
604 | | uint32_t StackOffset) const noexcept; |
605 | | Expect<void> runGlobalGetOp(Runtime::StackManager &StackMgr, |
606 | | uint32_t Idx) const noexcept; |
607 | | Expect<void> runGlobalSetOp(Runtime::StackManager &StackMgr, |
608 | | uint32_t Idx) const noexcept; |
609 | | /// ======= Reference instructions ======= |
610 | | Expect<void> runRefNullOp(Runtime::StackManager &StackMgr, |
611 | | const ValType &Type) const noexcept; |
612 | | Expect<void> runRefIsNullOp(ValVariant &Val) const noexcept; |
613 | | Expect<void> runRefFuncOp(Runtime::StackManager &StackMgr, |
614 | | uint32_t Idx) const noexcept; |
615 | | Expect<void> runRefEqOp(ValVariant &Val1, |
616 | | const ValVariant &Val2) const noexcept; |
617 | | Expect<void> runRefAsNonNullOp(RefVariant &Val, |
618 | | const AST::Instruction &Instr) const noexcept; |
619 | | Expect<void> runStructNewOp(Runtime::StackManager &StackMgr, |
620 | | const uint32_t TypeIdx, |
621 | | const bool IsDefault = false) const noexcept; |
622 | | Expect<void> runStructGetOp(Runtime::StackManager &StackMgr, |
623 | | const uint32_t TypeIdx, const uint32_t Off, |
624 | | const AST::Instruction &Instr, |
625 | | const bool IsSigned = false) const noexcept; |
626 | | Expect<void> runStructSetOp(Runtime::StackManager &StackMgr, |
627 | | const ValVariant &Val, const uint32_t TypeIdx, |
628 | | const uint32_t Off, |
629 | | const AST::Instruction &Instr) const noexcept; |
630 | | Expect<void> runArrayNewOp(Runtime::StackManager &StackMgr, |
631 | | const uint32_t TypeIdx, const uint32_t InitCnt, |
632 | | uint32_t Length) const noexcept; |
633 | | Expect<void> runArrayNewDataOp(Runtime::StackManager &StackMgr, |
634 | | const uint32_t TypeIdx, const uint32_t DataIdx, |
635 | | const AST::Instruction &Instr) const noexcept; |
636 | | Expect<void> runArrayNewElemOp(Runtime::StackManager &StackMgr, |
637 | | const uint32_t TypeIdx, const uint32_t ElemIdx, |
638 | | const AST::Instruction &Instr) const noexcept; |
639 | | Expect<void> runArrayGetOp(Runtime::StackManager &StackMgr, |
640 | | const uint32_t TypeIdx, |
641 | | const AST::Instruction &Instr, |
642 | | const bool IsSigned = false) const noexcept; |
643 | | Expect<void> runArraySetOp(Runtime::StackManager &StackMgr, |
644 | | const ValVariant &Val, const uint32_t TypeIdx, |
645 | | const AST::Instruction &Instr) const noexcept; |
646 | | Expect<void> runArrayLenOp(ValVariant &Val, |
647 | | const AST::Instruction &Instr) const noexcept; |
648 | | Expect<void> runArrayFillOp(Runtime::StackManager &StackMgr, |
649 | | const uint32_t Cnt, const ValVariant &Val, |
650 | | const uint32_t TypeIdx, |
651 | | const AST::Instruction &Instr) const noexcept; |
652 | | Expect<void> runArrayCopyOp(Runtime::StackManager &StackMgr, |
653 | | const uint32_t Cnt, const uint32_t DstTypeIdx, |
654 | | const uint32_t SrcTypeIdx, |
655 | | const AST::Instruction &Instr) const noexcept; |
656 | | Expect<void> runArrayInitDataOp(Runtime::StackManager &StackMgr, |
657 | | const uint32_t Cnt, const uint32_t TypeIdx, |
658 | | const uint32_t DataIdx, |
659 | | const AST::Instruction &Instr) const noexcept; |
660 | | Expect<void> runArrayInitElemOp(Runtime::StackManager &StackMgr, |
661 | | const uint32_t Cnt, const uint32_t TypeIdx, |
662 | | const uint32_t ElemIdx, |
663 | | const AST::Instruction &Instr) const noexcept; |
664 | | Expect<void> runRefTestOp(const Runtime::Instance::ModuleInstance *ModInst, |
665 | | ValVariant &Val, const AST::Instruction &Instr, |
666 | | const bool IsCast = false) const noexcept; |
667 | | Expect<void> runRefConvOp(RefVariant &Val, TypeCode TCode) const noexcept; |
668 | | Expect<void> runRefI31Op(ValVariant &Val) const noexcept; |
669 | | Expect<void> runI31GetOp(ValVariant &Val, const AST::Instruction &Instr, |
670 | | const bool IsSigned = false) const noexcept; |
671 | | /// ======= Table instructions ======= |
672 | | Expect<void> runTableGetOp(Runtime::StackManager &StackMgr, |
673 | | Runtime::Instance::TableInstance &TabInst, |
674 | | const AST::Instruction &Instr); |
675 | | Expect<void> runTableSetOp(Runtime::StackManager &StackMgr, |
676 | | Runtime::Instance::TableInstance &TabInst, |
677 | | const AST::Instruction &Instr); |
678 | | Expect<void> runTableInitOp(Runtime::StackManager &StackMgr, |
679 | | Runtime::Instance::TableInstance &TabInst, |
680 | | Runtime::Instance::ElementInstance &ElemInst, |
681 | | const AST::Instruction &Instr); |
682 | | Expect<void> runElemDropOp(Runtime::Instance::ElementInstance &ElemInst); |
683 | | Expect<void> runTableCopyOp(Runtime::StackManager &StackMgr, |
684 | | Runtime::Instance::TableInstance &TabInstDst, |
685 | | Runtime::Instance::TableInstance &TabInstSrc, |
686 | | const AST::Instruction &Instr); |
687 | | Expect<void> runTableGrowOp(Runtime::StackManager &StackMgr, |
688 | | Runtime::Instance::TableInstance &TabInst); |
689 | | Expect<void> runTableSizeOp(Runtime::StackManager &StackMgr, |
690 | | Runtime::Instance::TableInstance &TabInst); |
691 | | Expect<void> runTableFillOp(Runtime::StackManager &StackMgr, |
692 | | Runtime::Instance::TableInstance &TabInst, |
693 | | const AST::Instruction &Instr); |
694 | | /// ======= Memory instructions ======= |
695 | | template <typename T, uint32_t BitWidth = sizeof(T) * 8> |
696 | | TypeT<T> runLoadOp(Runtime::StackManager &StackMgr, |
697 | | Runtime::Instance::MemoryInstance &MemInst, |
698 | | const AST::Instruction &Instr); |
699 | | template <typename T, uint32_t BitWidth = sizeof(T) * 8> |
700 | | TypeN<T> runStoreOp(Runtime::StackManager &StackMgr, |
701 | | Runtime::Instance::MemoryInstance &MemInst, |
702 | | const AST::Instruction &Instr); |
703 | | Expect<void> runMemorySizeOp(Runtime::StackManager &StackMgr, |
704 | | Runtime::Instance::MemoryInstance &MemInst); |
705 | | Expect<void> runMemoryGrowOp(Runtime::StackManager &StackMgr, |
706 | | Runtime::Instance::MemoryInstance &MemInst); |
707 | | Expect<void> runMemoryInitOp(Runtime::StackManager &StackMgr, |
708 | | Runtime::Instance::MemoryInstance &MemInst, |
709 | | Runtime::Instance::DataInstance &DataInst, |
710 | | const AST::Instruction &Instr); |
711 | | Expect<void> runDataDropOp(Runtime::Instance::DataInstance &DataInst); |
712 | | Expect<void> runMemoryCopyOp(Runtime::StackManager &StackMgr, |
713 | | Runtime::Instance::MemoryInstance &MemInstDst, |
714 | | Runtime::Instance::MemoryInstance &MemInstSrc, |
715 | | const AST::Instruction &Instr); |
716 | | Expect<void> runMemoryFillOp(Runtime::StackManager &StackMgr, |
717 | | Runtime::Instance::MemoryInstance &MemInst, |
718 | | const AST::Instruction &Instr); |
719 | | /// ======= Test and Relation Numeric instructions ======= |
720 | | template <typename T> TypeU<T> runEqzOp(ValVariant &Val) const; |
721 | | template <typename T> |
722 | | TypeT<T> runEqOp(ValVariant &Val1, const ValVariant &Val2) const; |
723 | | template <typename T> |
724 | | TypeT<T> runNeOp(ValVariant &Val1, const ValVariant &Val2) const; |
725 | | template <typename T> |
726 | | TypeT<T> runLtOp(ValVariant &Val1, const ValVariant &Val2) const; |
727 | | template <typename T> |
728 | | TypeT<T> runGtOp(ValVariant &Val1, const ValVariant &Val2) const; |
729 | | template <typename T> |
730 | | TypeT<T> runLeOp(ValVariant &Val1, const ValVariant &Val2) const; |
731 | | template <typename T> |
732 | | TypeT<T> runGeOp(ValVariant &Val1, const ValVariant &Val2) const; |
733 | | /// ======= Unary Numeric instructions ======= |
734 | | template <typename T> TypeU<T> runClzOp(ValVariant &Val) const; |
735 | | template <typename T> TypeU<T> runCtzOp(ValVariant &Val) const; |
736 | | template <typename T> TypeU<T> runPopcntOp(ValVariant &Val) const; |
737 | | template <typename T> TypeF<T> runAbsOp(ValVariant &Val) const; |
738 | | template <typename T> TypeF<T> runNegOp(ValVariant &Val) const; |
739 | | template <typename T> TypeF<T> runCeilOp(ValVariant &Val) const; |
740 | | template <typename T> TypeF<T> runFloorOp(ValVariant &Val) const; |
741 | | template <typename T> TypeF<T> runTruncOp(ValVariant &Val) const; |
742 | | template <typename T> TypeF<T> runNearestOp(ValVariant &Val) const; |
743 | | template <typename T> TypeF<T> runSqrtOp(ValVariant &Val) const; |
744 | | /// ======= Binary Numeric instructions ======= |
745 | | template <typename T> |
746 | | TypeN<T> runAddOp(ValVariant &Val1, const ValVariant &Val2) const; |
747 | | template <typename T> |
748 | | TypeN<T> runSubOp(ValVariant &Val1, const ValVariant &Val2) const; |
749 | | template <typename T> |
750 | | TypeN<T> runMulOp(ValVariant &Val1, const ValVariant &Val2) const; |
751 | | template <typename T> |
752 | | TypeT<T> runDivOp(const AST::Instruction &Instr, ValVariant &Val1, |
753 | | const ValVariant &Val2) const; |
754 | | template <typename T> |
755 | | TypeI<T> runRemOp(const AST::Instruction &Instr, ValVariant &Val1, |
756 | | const ValVariant &Val2) const; |
757 | | template <typename T> |
758 | | TypeU<T> runAndOp(ValVariant &Val1, const ValVariant &Val2) const; |
759 | | template <typename T> |
760 | | TypeU<T> runOrOp(ValVariant &Val1, const ValVariant &Val2) const; |
761 | | template <typename T> |
762 | | TypeU<T> runXorOp(ValVariant &Val1, const ValVariant &Val2) const; |
763 | | template <typename T> |
764 | | TypeU<T> runShlOp(ValVariant &Val1, const ValVariant &Val2) const; |
765 | | template <typename T> |
766 | | TypeI<T> runShrOp(ValVariant &Val1, const ValVariant &Val2) const; |
767 | | template <typename T> |
768 | | TypeU<T> runRotlOp(ValVariant &Val1, const ValVariant &Val2) const; |
769 | | template <typename T> |
770 | | TypeU<T> runRotrOp(ValVariant &Val1, const ValVariant &Val2) const; |
771 | | template <typename T> |
772 | | TypeF<T> runMinOp(ValVariant &Val1, const ValVariant &Val2) const; |
773 | | template <typename T> |
774 | | TypeF<T> runMaxOp(ValVariant &Val1, const ValVariant &Val2) const; |
775 | | template <typename T> |
776 | | TypeF<T> runCopysignOp(ValVariant &Val1, const ValVariant &Val2) const; |
777 | | /// ======= Cast Numeric instructions ======= |
778 | | template <typename TIn, typename TOut> |
779 | | TypeUU<TIn, TOut> runWrapOp(ValVariant &Val) const; |
780 | | template <typename TIn, typename TOut> |
781 | | TypeFI<TIn, TOut> runTruncateOp(const AST::Instruction &Instr, |
782 | | ValVariant &Val) const; |
783 | | template <typename TIn, typename TOut> |
784 | | TypeFI<TIn, TOut> runTruncateSatOp(ValVariant &Val) const; |
785 | | template <typename TIn, typename TOut, size_t B = sizeof(TIn) * 8> |
786 | | TypeIU<TIn, TOut> runExtendOp(ValVariant &Val) const; |
787 | | template <typename TIn, typename TOut> |
788 | | TypeIF<TIn, TOut> runConvertOp(ValVariant &Val) const; |
789 | | template <typename TIn, typename TOut> |
790 | | TypeFF<TIn, TOut> runDemoteOp(ValVariant &Val) const; |
791 | | template <typename TIn, typename TOut> |
792 | | TypeFF<TIn, TOut> runPromoteOp(ValVariant &Val) const; |
793 | | template <typename TIn, typename TOut> |
794 | | TypeNN<TIn, TOut> runReinterpretOp(ValVariant &Val) const; |
795 | | /// ======= SIMD Memory instructions ======= |
796 | | template <typename TIn, typename TOut> |
797 | | Expect<void> runLoadExpandOp(Runtime::StackManager &StackMgr, |
798 | | Runtime::Instance::MemoryInstance &MemInst, |
799 | | const AST::Instruction &Instr); |
800 | | template <typename T> |
801 | | Expect<void> runLoadSplatOp(Runtime::StackManager &StackMgr, |
802 | | Runtime::Instance::MemoryInstance &MemInst, |
803 | | const AST::Instruction &Instr); |
804 | | template <typename T> |
805 | | Expect<void> runLoadLaneOp(Runtime::StackManager &StackMgr, |
806 | | Runtime::Instance::MemoryInstance &MemInst, |
807 | | const AST::Instruction &Instr); |
808 | | template <typename T> |
809 | | Expect<void> runStoreLaneOp(Runtime::StackManager &StackMgr, |
810 | | Runtime::Instance::MemoryInstance &MemInst, |
811 | | const AST::Instruction &Instr); |
812 | | /// ======= SIMD Lane instructions ======= |
813 | | template <typename TIn, typename TOut = TIn> |
814 | | Expect<void> runExtractLaneOp(ValVariant &Val, const uint8_t Index) const; |
815 | | template <typename TIn, typename TOut = TIn> |
816 | | Expect<void> runReplaceLaneOp(ValVariant &Val1, const ValVariant &Val2, |
817 | | const uint8_t Index) const; |
818 | | /// ======= SIMD Numeric instructions ======= |
819 | | template <typename TIn, typename TOut = TIn> |
820 | | Expect<void> runSplatOp(ValVariant &Val) const; |
821 | | template <typename T> |
822 | | Expect<void> runVectorEqOp(ValVariant &Val1, const ValVariant &Val2) const; |
823 | | template <typename T> |
824 | | Expect<void> runVectorNeOp(ValVariant &Val1, const ValVariant &Val2) const; |
825 | | template <typename T> |
826 | | Expect<void> runVectorLtOp(ValVariant &Val1, const ValVariant &Val2) const; |
827 | | template <typename T> |
828 | | Expect<void> runVectorGtOp(ValVariant &Val1, const ValVariant &Val2) const; |
829 | | template <typename T> |
830 | | Expect<void> runVectorLeOp(ValVariant &Val1, const ValVariant &Val2) const; |
831 | | template <typename T> |
832 | | Expect<void> runVectorGeOp(ValVariant &Val1, const ValVariant &Val2) const; |
833 | | template <typename T> Expect<void> runVectorAbsOp(ValVariant &Val) const; |
834 | | template <typename T> Expect<void> runVectorNegOp(ValVariant &Val) const; |
835 | | inline Expect<void> runVectorPopcntOp(ValVariant &Val) const; |
836 | | template <typename T> Expect<void> runVectorSqrtOp(ValVariant &Val) const; |
837 | | template <typename TIn, typename TOut> |
838 | | Expect<void> runVectorTruncSatOp(ValVariant &Val) const; |
839 | | template <typename TIn, typename TOut> |
840 | | Expect<void> runVectorConvertOp(ValVariant &Val) const; |
841 | | inline Expect<void> runVectorDemoteOp(ValVariant &Val) const; |
842 | | inline Expect<void> runVectorPromoteOp(ValVariant &Val) const; |
843 | | inline Expect<void> runVectorAnyTrueOp(ValVariant &Val) const; |
844 | | template <typename T> Expect<void> runVectorAllTrueOp(ValVariant &Val) const; |
845 | | template <typename T> Expect<void> runVectorBitMaskOp(ValVariant &Val) const; |
846 | | template <typename TIn, typename TOut> |
847 | | Expect<void> runVectorNarrowOp(ValVariant &Val1, |
848 | | const ValVariant &Val2) const; |
849 | | template <typename TIn, typename TOut> |
850 | | Expect<void> runVectorExtendLowOp(ValVariant &Val) const; |
851 | | template <typename TIn, typename TOut> |
852 | | Expect<void> runVectorExtendHighOp(ValVariant &Val) const; |
853 | | template <typename TIn, typename TOut> |
854 | | Expect<void> runVectorExtAddPairwiseOp(ValVariant &Val) const; |
855 | | template <typename TIn, typename TOut> |
856 | | Expect<void> runVectorExtMulLowOp(ValVariant &Val1, |
857 | | const ValVariant &Val2) const; |
858 | | template <typename TIn, typename TOut> |
859 | | Expect<void> runVectorExtMulHighOp(ValVariant &Val1, |
860 | | const ValVariant &Val2) const; |
861 | | inline Expect<void> runVectorQ15MulSatOp(ValVariant &Val1, |
862 | | const ValVariant &Val2) const; |
863 | | template <typename T> |
864 | | Expect<void> runVectorShlOp(ValVariant &Val1, const ValVariant &Val2) const; |
865 | | template <typename T> |
866 | | Expect<void> runVectorShrOp(ValVariant &Val1, const ValVariant &Val2) const; |
867 | | template <typename T> |
868 | | Expect<void> runVectorAddOp(ValVariant &Val1, const ValVariant &Val2) const; |
869 | | template <typename T> |
870 | | Expect<void> runVectorAddSatOp(ValVariant &Val1, |
871 | | const ValVariant &Val2) const; |
872 | | template <typename T> |
873 | | Expect<void> runVectorSubOp(ValVariant &Val1, const ValVariant &Val2) const; |
874 | | template <typename T> |
875 | | Expect<void> runVectorSubSatOp(ValVariant &Val1, |
876 | | const ValVariant &Val2) const; |
877 | | template <typename T> |
878 | | Expect<void> runVectorMulOp(ValVariant &Val1, const ValVariant &Val2) const; |
879 | | template <typename T> |
880 | | Expect<void> runVectorDivOp(ValVariant &Val1, const ValVariant &Val2) const; |
881 | | template <typename T> |
882 | | Expect<void> runVectorMinOp(ValVariant &Val1, const ValVariant &Val2) const; |
883 | | template <typename T> |
884 | | Expect<void> runVectorMaxOp(ValVariant &Val1, const ValVariant &Val2) const; |
885 | | template <typename T> |
886 | | Expect<void> runVectorFMinOp(ValVariant &Val1, const ValVariant &Val2) const; |
887 | | template <typename T> |
888 | | Expect<void> runVectorFMaxOp(ValVariant &Val1, const ValVariant &Val2) const; |
889 | | template <typename T, typename ET> |
890 | | Expect<void> runVectorAvgrOp(ValVariant &Val1, const ValVariant &Val2) const; |
891 | | template <typename T> Expect<void> runVectorCeilOp(ValVariant &Val) const; |
892 | | template <typename T> Expect<void> runVectorFloorOp(ValVariant &Val) const; |
893 | | template <typename T> Expect<void> runVectorTruncOp(ValVariant &Val) const; |
894 | | template <typename T> Expect<void> runVectorNearestOp(ValVariant &Val) const; |
895 | | /// ======= Relaxed SIMD instructions ======= |
896 | | template <typename T> |
897 | | Expect<void> runVectorRelaxedLaneselectOp(ValVariant &Val1, |
898 | | const ValVariant &Val2, |
899 | | const ValVariant &Mask) const; |
900 | | inline Expect<void> |
901 | | runVectorRelaxedIntegerDotProductOp(ValVariant &Val1, |
902 | | const ValVariant &Val2) const; |
903 | | inline Expect<void> runVectorRelaxedIntegerDotProductOpAdd( |
904 | | ValVariant &Val1, const ValVariant &Val2, const ValVariant &C) const; |
905 | | /// ======= Atomic instructions ======= |
906 | | Expect<void> runAtomicNotifyOp(Runtime::StackManager &StackMgr, |
907 | | Runtime::Instance::MemoryInstance &MemInst, |
908 | | const AST::Instruction &Instr); |
909 | | Expect<void> runMemoryFenceOp(); |
910 | | template <typename T> |
911 | | TypeT<T> runAtomicWaitOp(Runtime::StackManager &StackMgr, |
912 | | Runtime::Instance::MemoryInstance &MemInst, |
913 | | const AST::Instruction &Instr); |
914 | | template <typename T, typename I> |
915 | | TypeT<T> runAtomicLoadOp(Runtime::StackManager &StackMgr, |
916 | | Runtime::Instance::MemoryInstance &MemInst, |
917 | | const AST::Instruction &Instr); |
918 | | template <typename T, typename I> |
919 | | TypeT<T> runAtomicStoreOp(Runtime::StackManager &StackMgr, |
920 | | Runtime::Instance::MemoryInstance &MemInst, |
921 | | const AST::Instruction &Instr); |
922 | | template <typename T, typename I> |
923 | | TypeT<T> runAtomicAddOp(Runtime::StackManager &StackMgr, |
924 | | Runtime::Instance::MemoryInstance &MemInst, |
925 | | const AST::Instruction &Instr); |
926 | | template <typename T, typename I> |
927 | | TypeT<T> runAtomicSubOp(Runtime::StackManager &StackMgr, |
928 | | Runtime::Instance::MemoryInstance &MemInst, |
929 | | const AST::Instruction &Instr); |
930 | | template <typename T, typename I> |
931 | | TypeT<T> runAtomicOrOp(Runtime::StackManager &StackMgr, |
932 | | Runtime::Instance::MemoryInstance &MemInst, |
933 | | const AST::Instruction &Instr); |
934 | | template <typename T, typename I> |
935 | | TypeT<T> runAtomicAndOp(Runtime::StackManager &StackMgr, |
936 | | Runtime::Instance::MemoryInstance &MemInst, |
937 | | const AST::Instruction &Instr); |
938 | | template <typename T, typename I> |
939 | | TypeT<T> runAtomicXorOp(Runtime::StackManager &StackMgr, |
940 | | Runtime::Instance::MemoryInstance &MemInst, |
941 | | const AST::Instruction &Instr); |
942 | | template <typename T, typename I> |
943 | | TypeT<T> runAtomicExchangeOp(Runtime::StackManager &StackMgr, |
944 | | Runtime::Instance::MemoryInstance &MemInst, |
945 | | const AST::Instruction &Instr); |
946 | | template <typename T, typename I> |
947 | | TypeT<T> |
948 | | runAtomicCompareExchangeOp(Runtime::StackManager &StackMgr, |
949 | | Runtime::Instance::MemoryInstance &MemInst, |
950 | | const AST::Instruction &Instr); |
951 | | /// @} |
952 | | |
953 | | public: |
954 | | /// \name AOT/JIT - Run compiled functions |
955 | | /// @{ |
956 | | Expect<void> proxyTrap(Runtime::StackManager &StackMgr, |
957 | | const uint32_t Code) noexcept; |
958 | | Expect<void> proxyCall(Runtime::StackManager &StackMgr, |
959 | | const uint32_t FuncIdx, const ValVariant *Args, |
960 | | ValVariant *Rets) noexcept; |
961 | | Expect<void> proxyCallIndirect(Runtime::StackManager &StackMgr, |
962 | | const uint32_t TableIdx, |
963 | | const uint32_t FuncTypeIdx, |
964 | | const uint32_t FuncIdx, const ValVariant *Args, |
965 | | ValVariant *Rets) noexcept; |
966 | | Expect<void> proxyCallRef(Runtime::StackManager &StackMgr, |
967 | | const RefVariant Ref, const ValVariant *Args, |
968 | | ValVariant *Rets) noexcept; |
969 | | Expect<RefVariant> proxyRefFunc(Runtime::StackManager &StackMgr, |
970 | | const uint32_t FuncIdx) noexcept; |
971 | | Expect<RefVariant> proxyStructNew(Runtime::StackManager &StackMgr, |
972 | | const uint32_t TypeIdx, |
973 | | const ValVariant *Args, |
974 | | const uint32_t ArgSize) noexcept; |
975 | | Expect<void> proxyStructGet(Runtime::StackManager &StackMgr, |
976 | | const RefVariant Ref, const uint32_t TypeIdx, |
977 | | const uint32_t Off, const bool IsSigned, |
978 | | ValVariant *Ret) noexcept; |
979 | | Expect<void> proxyStructSet(Runtime::StackManager &StackMgr, |
980 | | const RefVariant Ref, const uint32_t TypeIdx, |
981 | | const uint32_t Off, |
982 | | const ValVariant *Val) noexcept; |
983 | | Expect<RefVariant> proxyArrayNew(Runtime::StackManager &StackMgr, |
984 | | const uint32_t TypeIdx, |
985 | | const uint32_t Length, |
986 | | const ValVariant *Args, |
987 | | const uint32_t ArgSize) noexcept; |
988 | | Expect<RefVariant> proxyArrayNewData(Runtime::StackManager &StackMgr, |
989 | | const uint32_t TypeIdx, |
990 | | const uint32_t DataIdx, |
991 | | const uint32_t Start, |
992 | | const uint32_t Length) noexcept; |
993 | | Expect<RefVariant> proxyArrayNewElem(Runtime::StackManager &StackMgr, |
994 | | const uint32_t TypeIdx, |
995 | | const uint32_t ElemIdx, |
996 | | const uint32_t Start, |
997 | | const uint32_t Length) noexcept; |
998 | | Expect<void> proxyArrayGet(Runtime::StackManager &StackMgr, |
999 | | const RefVariant Ref, const uint32_t TypeIdx, |
1000 | | const uint32_t Idx, const bool IsSigned, |
1001 | | ValVariant *Ret) noexcept; |
1002 | | Expect<void> proxyArraySet(Runtime::StackManager &StackMgr, |
1003 | | const RefVariant Ref, const uint32_t TypeIdx, |
1004 | | const uint32_t Idx, |
1005 | | const ValVariant *Val) noexcept; |
1006 | | Expect<uint32_t> proxyArrayLen(Runtime::StackManager &StackMgr, |
1007 | | const RefVariant Ref) noexcept; |
1008 | | Expect<void> proxyArrayFill(Runtime::StackManager &StackMgr, |
1009 | | const RefVariant Ref, const uint32_t TypeIdx, |
1010 | | const uint32_t Idx, const uint32_t Cnt, |
1011 | | const ValVariant *Val) noexcept; |
1012 | | Expect<void> proxyArrayCopy(Runtime::StackManager &StackMgr, |
1013 | | const RefVariant DstRef, |
1014 | | const uint32_t DstTypeIdx, const uint32_t DstIdx, |
1015 | | const RefVariant SrcRef, |
1016 | | const uint32_t SrcTypeIdx, const uint32_t SrcIdx, |
1017 | | const uint32_t Cnt) noexcept; |
1018 | | Expect<void> proxyArrayInitData(Runtime::StackManager &StackMgr, |
1019 | | const RefVariant Ref, const uint32_t TypeIdx, |
1020 | | const uint32_t DataIdx, const uint32_t DstIdx, |
1021 | | const uint32_t SrcIdx, |
1022 | | const uint32_t Cnt) noexcept; |
1023 | | Expect<void> proxyArrayInitElem(Runtime::StackManager &StackMgr, |
1024 | | const RefVariant Ref, const uint32_t TypeIdx, |
1025 | | const uint32_t ElemIdx, const uint32_t DstIdx, |
1026 | | const uint32_t SrcIdx, |
1027 | | const uint32_t Cnt) noexcept; |
1028 | | Expect<uint32_t> proxyRefTest(Runtime::StackManager &StackMgr, |
1029 | | const RefVariant Ref, ValType VTTest) noexcept; |
1030 | | Expect<RefVariant> proxyRefCast(Runtime::StackManager &StackMgr, |
1031 | | const RefVariant Ref, |
1032 | | ValType VTCast) noexcept; |
1033 | | Expect<RefVariant> proxyTableGet(Runtime::StackManager &StackMgr, |
1034 | | const uint32_t TableIdx, |
1035 | | const uint64_t Off) noexcept; |
1036 | | Expect<void> proxyTableSet(Runtime::StackManager &StackMgr, |
1037 | | const uint32_t TableIdx, const uint64_t Off, |
1038 | | const RefVariant Ref) noexcept; |
1039 | | Expect<void> proxyTableInit(Runtime::StackManager &StackMgr, |
1040 | | const uint32_t TableIdx, const uint32_t ElemIdx, |
1041 | | const uint64_t DstOff, const uint32_t SrcOff, |
1042 | | const uint32_t Len) noexcept; |
1043 | | Expect<void> proxyElemDrop(Runtime::StackManager &StackMgr, |
1044 | | const uint32_t ElemIdx) noexcept; |
1045 | | Expect<void> proxyTableCopy(Runtime::StackManager &StackMgr, |
1046 | | const uint32_t TableIdxDst, |
1047 | | const uint32_t TableIdxSrc, const uint64_t DstOff, |
1048 | | const uint64_t SrcOff, |
1049 | | const uint64_t Len) noexcept; |
1050 | | Expect<uint64_t> proxyTableGrow(Runtime::StackManager &StackMgr, |
1051 | | const uint32_t TableIdx, const RefVariant Val, |
1052 | | const uint64_t NewSize) noexcept; |
1053 | | Expect<uint64_t> proxyTableSize(Runtime::StackManager &StackMgr, |
1054 | | const uint32_t TableIdx) noexcept; |
1055 | | Expect<void> proxyTableFill(Runtime::StackManager &StackMgr, |
1056 | | const uint32_t TableIdx, const uint64_t Off, |
1057 | | const RefVariant Ref, |
1058 | | const uint64_t Len) noexcept; |
1059 | | Expect<uint64_t> proxyMemGrow(Runtime::StackManager &StackMgr, |
1060 | | const uint32_t MemIdx, |
1061 | | const uint64_t NewSize) noexcept; |
1062 | | Expect<uint64_t> proxyMemSize(Runtime::StackManager &StackMgr, |
1063 | | const uint32_t MemIdx) noexcept; |
1064 | | Expect<void> proxyMemInit(Runtime::StackManager &StackMgr, |
1065 | | const uint32_t MemIdx, const uint32_t DataIdx, |
1066 | | const uint64_t DstOff, const uint32_t SrcOff, |
1067 | | const uint32_t Len) noexcept; |
1068 | | Expect<void> proxyDataDrop(Runtime::StackManager &StackMgr, |
1069 | | const uint32_t DataIdx) noexcept; |
1070 | | Expect<void> proxyMemCopy(Runtime::StackManager &StackMgr, |
1071 | | const uint32_t DstMemIdx, const uint32_t SrcMemIdx, |
1072 | | const uint64_t DstOff, const uint64_t SrcOff, |
1073 | | const uint64_t Len) noexcept; |
1074 | | Expect<void> proxyMemFill(Runtime::StackManager &StackMgr, |
1075 | | const uint32_t MemIdx, const uint64_t Off, |
1076 | | const uint8_t Val, const uint64_t Len) noexcept; |
1077 | | Expect<uint64_t> proxyMemAtomicNotify(Runtime::StackManager &StackMgr, |
1078 | | const uint32_t MemIdx, |
1079 | | const uint64_t Offset, |
1080 | | const uint64_t Count) noexcept; |
1081 | | Expect<uint64_t> |
1082 | | proxyMemAtomicWait(Runtime::StackManager &StackMgr, const uint32_t MemIdx, |
1083 | | const uint64_t Offset, const uint64_t Expected, |
1084 | | const int64_t Timeout, const uint32_t BitWidth) noexcept; |
1085 | | Expect<void *> proxyTableGetFuncSymbol(Runtime::StackManager &StackMgr, |
1086 | | const uint32_t TableIdx, |
1087 | | const uint32_t FuncTypeIdx, |
1088 | | const uint32_t FuncIdx) noexcept; |
1089 | | Expect<void *> proxyRefGetFuncSymbol(Runtime::StackManager &StackMgr, |
1090 | | const RefVariant Ref) noexcept; |
1091 | | Expect<void *> proxyFuncGetFuncSymbol(Runtime::StackManager &StackMgr, |
1092 | | const uint32_t FuncIdx) noexcept; |
1093 | | /// @} |
1094 | | |
1095 | | /// Callbacks for compiled modules |
1096 | | static const Executable::IntrinsicsTable Intrinsics; |
1097 | | /// Proxy helper template struct |
1098 | | template <typename FuncPtr> struct ProxyHelper; |
1099 | | |
1100 | | private: |
1101 | | /// Execution context for compiled functions. |
1102 | | struct ExecutionContextStruct { |
1103 | | #if WASMEDGE_ALLOCATOR_IS_STABLE |
1104 | | uint8_t *const *Memories; |
1105 | | #else |
1106 | | uint8_t **const *Memories; |
1107 | | #endif |
1108 | | ValVariant *const *Globals; |
1109 | | std::atomic_uint64_t *InstrCount; |
1110 | | uint64_t *CostTable; |
1111 | | std::atomic_uint64_t *Gas; |
1112 | | uint64_t GasLimit; |
1113 | | std::atomic_uint32_t *StopToken; |
1114 | | }; |
1115 | | |
1116 | | /// Restores thread local VM reference after overwriting it. |
1117 | | struct SavedThreadLocal { |
1118 | | SavedThreadLocal(Executor &Ex, Runtime::StackManager &StackMgr, |
1119 | | const Runtime::Instance::FunctionInstance &Func) noexcept; |
1120 | | |
1121 | | SavedThreadLocal(const SavedThreadLocal &) = delete; |
1122 | | SavedThreadLocal(SavedThreadLocal &&) = delete; |
1123 | | |
1124 | | ~SavedThreadLocal() noexcept; |
1125 | | |
1126 | | Executor *SavedThis; |
1127 | | Runtime::StackManager *SavedCurrentStack; |
1128 | | ExecutionContextStruct SavedExecutionContext; |
1129 | | }; |
1130 | | |
1131 | | /// Pointer to current object. |
1132 | | static thread_local Executor *This; |
1133 | | /// Stack passed into compiled functions |
1134 | | static thread_local Runtime::StackManager *CurrentStack; |
1135 | | /// Execution context for compiled functions |
1136 | | static thread_local ExecutionContextStruct ExecutionContext; |
1137 | | /// Record stack trace on error |
1138 | | static thread_local std::array<uint32_t, 256> StackTrace; |
1139 | | static thread_local size_t StackTraceSize; |
1140 | | |
1141 | | /// WasmEdge configuration |
1142 | | const Configure Conf; |
1143 | | /// Executor statistics |
1144 | | Statistics::Statistics *Stat; |
1145 | | /// Stop execution |
1146 | | std::atomic_uint32_t StopToken = 0; |
1147 | | /// Memory instance this Executor is currently waiting on (for stop()). |
1148 | | std::atomic<Runtime::Instance::MemoryInstance *> WaitingMemory = nullptr; |
1149 | | /// Executor Host Function Handler |
1150 | | HostFuncHandler HostFuncHelper = {}; |
1151 | | /// Callback for lazy function compilation |
1152 | | std::function<Expect<void>(const Runtime::Instance::FunctionInstance *)> |
1153 | | LazyCompilationHandler; |
1154 | | |
1155 | | /// Helper function for triggering lazy compilation. |
1156 | | /// XXX: Calling checkLazyCompilation in one thread while another thread calls |
1157 | | /// unsafeUpgradeToCompiled on the same FuncInst could result in a race |
1158 | | /// condition if checking FuncInst->isCompiledFunction() directly here. As a |
1159 | | /// temporary workaround, checks for compilation state are deferred to the |
1160 | | /// LazyCompilationHandler, which must serialize them against compiled-state |
1161 | | /// upgrades (the lazy JIT engine does so under its internal lock). |
1162 | | Expect<void> checkLazyCompilation( |
1163 | 0 | const Runtime::Instance::FunctionInstance *FuncInst) const noexcept { |
1164 | 0 | if (unlikely(LazyCompilationHandler != nullptr)) { |
1165 | 0 | return LazyCompilationHandler(FuncInst); |
1166 | 0 | } |
1167 | 0 | return {}; |
1168 | 0 | } |
1169 | | }; |
1170 | | |
1171 | | } // namespace Executor |
1172 | | } // namespace WasmEdge |
1173 | | |
1174 | | #include "engine/atomic.ipp" |
1175 | | #include "engine/binary_numeric.ipp" |
1176 | | #include "engine/cast_numeric.ipp" |
1177 | | #include "engine/memory.ipp" |
1178 | | #include "engine/relation_numeric.ipp" |
1179 | | #include "engine/unary_numeric.ipp" |