/src/WasmEdge/lib/executor/engine/refInstr.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | #include "executor/executor.h" |
5 | | |
6 | | namespace WasmEdge { |
7 | | namespace Executor { |
8 | | |
9 | | namespace { |
10 | | |
11 | | template <typename... T> |
12 | | ErrCode logError(const ErrCode &Code, const AST::Instruction &Instr, |
13 | 0 | T &&...F) noexcept { |
14 | 0 | spdlog::error(Code); |
15 | 0 | (F(), ...); |
16 | 0 | spdlog::error(ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); |
17 | 0 | return Code; |
18 | 0 | } Unexecuted instantiation: refInstr.cpp:WasmEdge::ErrCode WasmEdge::Executor::(anonymous namespace)::logError<WasmEdge::Executor::Executor::runArrayNewDataOp(WasmEdge::Runtime::StackManager&, unsigned int, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}>(WasmEdge::ErrCode const&, WasmEdge::AST::Instruction const&, WasmEdge::Executor::Executor::runArrayNewDataOp(WasmEdge::Runtime::StackManager&, unsigned int, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}&&)Unexecuted instantiation: refInstr.cpp:WasmEdge::ErrCode WasmEdge::Executor::(anonymous namespace)::logError<WasmEdge::Executor::Executor::runArrayNewElemOp(WasmEdge::Runtime::StackManager&, unsigned int, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}>(WasmEdge::ErrCode const&, WasmEdge::AST::Instruction const&, WasmEdge::Executor::Executor::runArrayNewElemOp(WasmEdge::Runtime::StackManager&, unsigned int, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}&&)Unexecuted instantiation: refInstr.cpp:WasmEdge::ErrCode WasmEdge::Executor::(anonymous namespace)::logError<WasmEdge::Executor::Executor::runArrayGetOp(WasmEdge::Runtime::StackManager&, unsigned int, WasmEdge::AST::Instruction const&, bool) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}>(WasmEdge::ErrCode const&, WasmEdge::AST::Instruction const&, WasmEdge::Executor::Executor::runArrayGetOp(WasmEdge::Runtime::StackManager&, unsigned int, WasmEdge::AST::Instruction const&, bool) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}&&)Unexecuted instantiation: refInstr.cpp:WasmEdge::ErrCode WasmEdge::Executor::(anonymous namespace)::logError<WasmEdge::Executor::Executor::runArraySetOp(WasmEdge::Runtime::StackManager&, WasmEdge::Variant<unsigned int, int, unsigned long, long, float, double, unsigned __int128, __int128, cxx26::simd::basic_vec<unsigned long, cxx26::simd::detail::vector_ext_abi<2> >, cxx26::simd::basic_vec<long, cxx26::simd::detail::vector_ext_abi<2> >, cxx26::simd::basic_vec<unsigned int, cxx26::simd::detail::vector_ext_abi<4> >, cxx26::simd::basic_vec<int, cxx26::simd::detail::vector_ext_abi<4> >, cxx26::simd::basic_vec<unsigned short, cxx26::simd::detail::vector_ext_abi<8> >, cxx26::simd::basic_vec<short, cxx26::simd::detail::vector_ext_abi<8> >, cxx26::simd::basic_vec<unsigned char, cxx26::simd::detail::vector_ext_abi<16> >, cxx26::simd::basic_vec<signed char, cxx26::simd::detail::vector_ext_abi<16> >, cxx26::simd::basic_vec<float, cxx26::simd::detail::vector_ext_abi<4> >, cxx26::simd::basic_vec<double, cxx26::simd::detail::vector_ext_abi<2> >, WasmEdge::RefVariant> const&, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}>(WasmEdge::ErrCode const&, WasmEdge::AST::Instruction const&, WasmEdge::Executor::Executor::runArraySetOp(WasmEdge::Runtime::StackManager&, WasmEdge::Variant<unsigned int, int, unsigned long, long, float, double, unsigned __int128, __int128, cxx26::simd::basic_vec<unsigned long, cxx26::simd::detail::vector_ext_abi<2> >, cxx26::simd::basic_vec<long, cxx26::simd::detail::vector_ext_abi<2> >, cxx26::simd::basic_vec<unsigned int, cxx26::simd::detail::vector_ext_abi<4> >, cxx26::simd::basic_vec<int, cxx26::simd::detail::vector_ext_abi<4> >, cxx26::simd::basic_vec<unsigned short, cxx26::simd::detail::vector_ext_abi<8> >, cxx26::simd::basic_vec<short, cxx26::simd::detail::vector_ext_abi<8> >, cxx26::simd::basic_vec<unsigned char, cxx26::simd::detail::vector_ext_abi<16> >, cxx26::simd::basic_vec<signed char, cxx26::simd::detail::vector_ext_abi<16> >, cxx26::simd::basic_vec<float, cxx26::simd::detail::vector_ext_abi<4> >, cxx26::simd::basic_vec<double, cxx26::simd::detail::vector_ext_abi<2> >, WasmEdge::RefVariant> const&, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}&&)Unexecuted instantiation: refInstr.cpp:WasmEdge::ErrCode WasmEdge::Executor::(anonymous namespace)::logError<WasmEdge::Executor::Executor::runArrayFillOp(WasmEdge::Runtime::StackManager&, unsigned int, WasmEdge::Variant<unsigned int, int, unsigned long, long, float, double, unsigned __int128, __int128, cxx26::simd::basic_vec<unsigned long, cxx26::simd::detail::vector_ext_abi<2> >, cxx26::simd::basic_vec<long, cxx26::simd::detail::vector_ext_abi<2> >, cxx26::simd::basic_vec<unsigned int, cxx26::simd::detail::vector_ext_abi<4> >, cxx26::simd::basic_vec<int, cxx26::simd::detail::vector_ext_abi<4> >, cxx26::simd::basic_vec<unsigned short, cxx26::simd::detail::vector_ext_abi<8> >, cxx26::simd::basic_vec<short, cxx26::simd::detail::vector_ext_abi<8> >, cxx26::simd::basic_vec<unsigned char, cxx26::simd::detail::vector_ext_abi<16> >, cxx26::simd::basic_vec<signed char, cxx26::simd::detail::vector_ext_abi<16> >, cxx26::simd::basic_vec<float, cxx26::simd::detail::vector_ext_abi<4> >, cxx26::simd::basic_vec<double, cxx26::simd::detail::vector_ext_abi<2> >, WasmEdge::RefVariant> const&, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}>(WasmEdge::ErrCode const&, WasmEdge::AST::Instruction const&, WasmEdge::Executor::Executor::runArrayFillOp(WasmEdge::Runtime::StackManager&, unsigned int, WasmEdge::Variant<unsigned int, int, unsigned long, long, float, double, unsigned __int128, __int128, cxx26::simd::basic_vec<unsigned long, cxx26::simd::detail::vector_ext_abi<2> >, cxx26::simd::basic_vec<long, cxx26::simd::detail::vector_ext_abi<2> >, cxx26::simd::basic_vec<unsigned int, cxx26::simd::detail::vector_ext_abi<4> >, cxx26::simd::basic_vec<int, cxx26::simd::detail::vector_ext_abi<4> >, cxx26::simd::basic_vec<unsigned short, cxx26::simd::detail::vector_ext_abi<8> >, cxx26::simd::basic_vec<short, cxx26::simd::detail::vector_ext_abi<8> >, cxx26::simd::basic_vec<unsigned char, cxx26::simd::detail::vector_ext_abi<16> >, cxx26::simd::basic_vec<signed char, cxx26::simd::detail::vector_ext_abi<16> >, cxx26::simd::basic_vec<float, cxx26::simd::detail::vector_ext_abi<4> >, cxx26::simd::basic_vec<double, cxx26::simd::detail::vector_ext_abi<2> >, WasmEdge::RefVariant> const&, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}&&)Unexecuted instantiation: refInstr.cpp:WasmEdge::ErrCode WasmEdge::Executor::(anonymous namespace)::logError<WasmEdge::Executor::Executor::runArrayCopyOp(WasmEdge::Runtime::StackManager&, unsigned int, unsigned int, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}>(WasmEdge::ErrCode const&, WasmEdge::AST::Instruction const&, WasmEdge::Executor::Executor::runArrayCopyOp(WasmEdge::Runtime::StackManager&, unsigned int, unsigned int, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}&&)Unexecuted instantiation: refInstr.cpp:WasmEdge::ErrCode WasmEdge::Executor::(anonymous namespace)::logError<WasmEdge::Executor::Executor::runArrayInitDataOp(WasmEdge::Runtime::StackManager&, unsigned int, unsigned int, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}, WasmEdge::Executor::Executor::runArrayInitDataOp(WasmEdge::Runtime::StackManager&, unsigned int, unsigned int, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#2}>(WasmEdge::ErrCode const&, WasmEdge::AST::Instruction const&, WasmEdge::Executor::Executor::runArrayInitDataOp(WasmEdge::Runtime::StackManager&, unsigned int, unsigned int, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}&&, WasmEdge::Executor::Executor::runArrayInitDataOp(WasmEdge::Runtime::StackManager&, unsigned int, unsigned int, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#2}&&)Unexecuted instantiation: refInstr.cpp:WasmEdge::ErrCode WasmEdge::Executor::(anonymous namespace)::logError<WasmEdge::Executor::Executor::runArrayInitElemOp(WasmEdge::Runtime::StackManager&, unsigned int, unsigned int, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}, WasmEdge::Executor::Executor::runArrayInitElemOp(WasmEdge::Runtime::StackManager&, unsigned int, unsigned int, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#2}>(WasmEdge::ErrCode const&, WasmEdge::AST::Instruction const&, WasmEdge::Executor::Executor::runArrayInitElemOp(WasmEdge::Runtime::StackManager&, unsigned int, unsigned int, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#1}&&, WasmEdge::Executor::Executor::runArrayInitElemOp(WasmEdge::Runtime::StackManager&, unsigned int, unsigned int, unsigned int, WasmEdge::AST::Instruction const&) const::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const::{lambda()#2}&&) |
19 | | |
20 | 0 | ErrCode logError(const ErrCode &Code, const AST::Instruction &Instr) noexcept { |
21 | 0 | spdlog::error(Code); |
22 | 0 | spdlog::error(ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); |
23 | 0 | return Code; |
24 | 0 | } |
25 | | |
26 | | void logArrayOOB(const ErrCode &Code, const uint32_t Idx, const uint32_t Cnt, |
27 | 0 | const RefVariant &Ref) noexcept { |
28 | 0 | if (Code == ErrCode::Value::ArrayOutOfBounds) { |
29 | 0 | const auto *Inst = Ref.getPtr<Runtime::Instance::ArrayInstance>(); |
30 | 0 | spdlog::error(ErrInfo::InfoBoundary(static_cast<uint64_t>(Idx), Cnt, |
31 | 0 | Inst->getLength())); |
32 | 0 | } |
33 | 0 | } |
34 | | |
35 | | void logDoubleArrayOOB(const ErrCode &Code, const uint32_t Idx1, |
36 | | const uint32_t Cnt1, const RefVariant &Ref1, |
37 | | const uint32_t Idx2, const uint32_t Cnt2, |
38 | 0 | const RefVariant &Ref2) noexcept { |
39 | 0 | if (Code == ErrCode::Value::ArrayOutOfBounds) { |
40 | 0 | const auto *Inst1 = Ref1.getPtr<Runtime::Instance::ArrayInstance>(); |
41 | 0 | const auto *Inst2 = Ref2.getPtr<Runtime::Instance::ArrayInstance>(); |
42 | 0 | if (static_cast<uint64_t>(Idx1) + static_cast<uint64_t>(Cnt1) > |
43 | 0 | Inst1->getLength()) { |
44 | 0 | spdlog::error(ErrInfo::InfoBoundary(static_cast<uint64_t>(Idx1), Cnt1, |
45 | 0 | Inst1->getLength())); |
46 | 0 | } else if (static_cast<uint64_t>(Idx2) + static_cast<uint64_t>(Cnt2) > |
47 | 0 | Inst2->getLength()) { |
48 | 0 | spdlog::error(ErrInfo::InfoBoundary(static_cast<uint64_t>(Idx2), Cnt2, |
49 | 0 | Inst2->getLength())); |
50 | 0 | } |
51 | 0 | } |
52 | 0 | } |
53 | | |
54 | | void logMemoryOOB(const ErrCode &Code, |
55 | | const Runtime::Instance::DataInstance &DataInst, |
56 | 0 | const uint32_t Idx, const uint32_t Length) noexcept { |
57 | 0 | if (Code == ErrCode::Value::MemoryOutOfBounds) { |
58 | 0 | spdlog::error(ErrInfo::InfoBoundary( |
59 | 0 | static_cast<uint64_t>(Idx), Length, |
60 | 0 | static_cast<uint32_t>(DataInst.getData().size()))); |
61 | 0 | } |
62 | 0 | } |
63 | | |
64 | | void logTableOOB(const ErrCode &Code, |
65 | | const Runtime::Instance::ElementInstance &ElemInst, |
66 | 0 | const uint32_t Idx, const uint32_t Length) noexcept { |
67 | 0 | if (Code == ErrCode::Value::TableOutOfBounds) { |
68 | 0 | auto ElemSrc = ElemInst.getRefs(); |
69 | 0 | spdlog::error(ErrInfo::InfoBoundary(static_cast<uint64_t>(Idx), Length, |
70 | 0 | static_cast<uint32_t>(ElemSrc.size()))); |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | | } // namespace |
75 | | |
76 | | Expect<void> Executor::runRefNullOp(Runtime::StackManager &StackMgr, |
77 | 0 | const ValType &Type) const noexcept { |
78 | | // A null reference is typed with the least type in its respective hierarchy. |
79 | 0 | StackMgr.push(RefVariant(toBottomType(StackMgr.getModule(), Type))); |
80 | 0 | return {}; |
81 | 0 | } |
82 | | |
83 | 0 | Expect<void> Executor::runRefIsNullOp(ValVariant &Val) const noexcept { |
84 | 0 | Val.emplace<uint32_t>(Val.get<RefVariant>().isNull() ? 1U : 0U); |
85 | 0 | return {}; |
86 | 0 | } |
87 | | |
88 | | Expect<void> Executor::runRefFuncOp(Runtime::StackManager &StackMgr, |
89 | 0 | uint32_t Idx) const noexcept { |
90 | 0 | const auto *FuncInst = getFuncInstByIdx(StackMgr.getModule(), Idx); |
91 | 0 | StackMgr.push(RefVariant(FuncInst->getDefType(), FuncInst)); |
92 | 0 | return {}; |
93 | 0 | } |
94 | | |
95 | | Expect<void> Executor::runRefEqOp(ValVariant &Val1, |
96 | 0 | const ValVariant &Val2) const noexcept { |
97 | 0 | Val1.emplace<uint32_t>(Val1.get<RefVariant>().getPtr<void>() == |
98 | 0 | Val2.get<RefVariant>().getPtr<void>() |
99 | 0 | ? 1U |
100 | 0 | : 0U); |
101 | 0 | return {}; |
102 | 0 | } |
103 | | |
104 | | Expect<void> |
105 | | Executor::runRefAsNonNullOp(RefVariant &Ref, |
106 | 0 | const AST::Instruction &Instr) const noexcept { |
107 | 0 | if (Ref.isNull()) { |
108 | 0 | return Unexpect(logError(ErrCode::Value::CastNullToNonNull, Instr)); |
109 | 0 | } |
110 | 0 | ValType Type = Ref.getType(); |
111 | 0 | Ref.setType(Type.toNonNullableRef()); |
112 | 0 | return {}; |
113 | 0 | } |
114 | | |
115 | | Expect<void> Executor::runStructNewOp(Runtime::StackManager &StackMgr, |
116 | | const uint32_t TypeIdx, |
117 | 0 | const bool IsDefault) const noexcept { |
118 | 0 | if (IsDefault) { |
119 | 0 | StackMgr.push(*structNew(StackMgr.getModule(), TypeIdx)); |
120 | 0 | } else { |
121 | 0 | const auto &CompType = getCompositeTypeByIdx(StackMgr.getModule(), TypeIdx); |
122 | 0 | const uint32_t N = static_cast<uint32_t>(CompType.getFieldTypes().size()); |
123 | 0 | std::vector<ValVariant> Vals = StackMgr.pop(N); |
124 | 0 | StackMgr.push(*structNew(StackMgr.getModule(), TypeIdx, Vals)); |
125 | 0 | } |
126 | 0 | return {}; |
127 | 0 | } |
128 | | |
129 | | Expect<void> Executor::runStructGetOp(Runtime::StackManager &StackMgr, |
130 | | const uint32_t TypeIdx, |
131 | | const uint32_t Off, |
132 | | const AST::Instruction &Instr, |
133 | 0 | const bool IsSigned) const noexcept { |
134 | 0 | const RefVariant Ref = StackMgr.getTop().get<RefVariant>(); |
135 | 0 | EXPECTED_TRY(auto Val, |
136 | 0 | structGet(StackMgr.getModule(), Ref, TypeIdx, Off, IsSigned) |
137 | 0 | .map_error([&](auto E) { return logError(E, Instr); })); |
138 | 0 | StackMgr.getTop() = Val; |
139 | 0 | return {}; |
140 | 0 | } |
141 | | |
142 | | Expect<void> |
143 | | Executor::runStructSetOp(Runtime::StackManager &StackMgr, const ValVariant &Val, |
144 | | const uint32_t TypeIdx, const uint32_t Off, |
145 | 0 | const AST::Instruction &Instr) const noexcept { |
146 | 0 | const RefVariant Ref = StackMgr.pop().get<RefVariant>(); |
147 | 0 | EXPECTED_TRY(structSet(StackMgr.getModule(), Ref, Val, TypeIdx, Off) |
148 | 0 | .map_error([&](auto E) { return logError(E, Instr); })); |
149 | 0 | return {}; |
150 | 0 | } |
151 | | |
152 | | Expect<void> Executor::runArrayNewOp(Runtime::StackManager &StackMgr, |
153 | | const uint32_t TypeIdx, |
154 | | const uint32_t InitCnt, |
155 | 0 | uint32_t Length) const noexcept { |
156 | 0 | assuming(InitCnt == 0 || InitCnt == 1 || InitCnt == Length); |
157 | 0 | if (InitCnt == 0) { |
158 | 0 | StackMgr.push(*arrayNew(StackMgr.getModule(), TypeIdx, Length)); |
159 | 0 | } else if (InitCnt == 1) { |
160 | 0 | StackMgr.getTop().emplace<RefVariant>( |
161 | 0 | *arrayNew(StackMgr.getModule(), TypeIdx, Length, {StackMgr.getTop()})); |
162 | 0 | } else { |
163 | 0 | StackMgr.push( |
164 | 0 | *arrayNew(StackMgr.getModule(), TypeIdx, Length, StackMgr.pop(Length))); |
165 | 0 | } |
166 | 0 | return {}; |
167 | 0 | } |
168 | | |
169 | | Expect<void> |
170 | | Executor::runArrayNewDataOp(Runtime::StackManager &StackMgr, |
171 | | const uint32_t TypeIdx, const uint32_t DataIdx, |
172 | 0 | const AST::Instruction &Instr) const noexcept { |
173 | 0 | const uint32_t Length = StackMgr.pop().get<uint32_t>(); |
174 | 0 | const uint32_t Start = StackMgr.getTop().get<uint32_t>(); |
175 | 0 | EXPECTED_TRY( |
176 | 0 | auto InstRef, |
177 | 0 | arrayNewData(StackMgr.getModule(), TypeIdx, DataIdx, Start, Length) |
178 | 0 | .map_error([&](auto E) { |
179 | 0 | auto *DataInst = getDataInstByIdx(StackMgr.getModule(), DataIdx); |
180 | 0 | const uint32_t BSize = |
181 | 0 | getArrayStorageTypeByIdx(StackMgr.getModule(), TypeIdx) |
182 | 0 | .getBitWidth() / |
183 | 0 | 8; |
184 | 0 | return logError(E, Instr, [&]() { |
185 | 0 | return logMemoryOOB(E, *DataInst, Start, BSize * Length); |
186 | 0 | }); |
187 | 0 | })); |
188 | 0 | StackMgr.getTop().emplace<RefVariant>(InstRef); |
189 | 0 | return {}; |
190 | 0 | } |
191 | | |
192 | | Expect<void> |
193 | | Executor::runArrayNewElemOp(Runtime::StackManager &StackMgr, |
194 | | const uint32_t TypeIdx, const uint32_t ElemIdx, |
195 | 0 | const AST::Instruction &Instr) const noexcept { |
196 | 0 | const uint32_t Length = StackMgr.pop().get<uint32_t>(); |
197 | 0 | const uint32_t Start = StackMgr.getTop().get<uint32_t>(); |
198 | 0 | EXPECTED_TRY( |
199 | 0 | auto InstRef, |
200 | 0 | arrayNewElem(StackMgr.getModule(), TypeIdx, ElemIdx, Start, Length) |
201 | 0 | .map_error([&](auto E) { |
202 | 0 | auto *ElemInst = getElemInstByIdx(StackMgr.getModule(), ElemIdx); |
203 | 0 | return logError(E, Instr, [&]() { |
204 | 0 | return logTableOOB(E, *ElemInst, Start, Length); |
205 | 0 | }); |
206 | 0 | })); |
207 | 0 | StackMgr.getTop().emplace<RefVariant>(InstRef); |
208 | 0 | return {}; |
209 | 0 | } |
210 | | |
211 | | Expect<void> Executor::runArrayGetOp(Runtime::StackManager &StackMgr, |
212 | | const uint32_t TypeIdx, |
213 | | const AST::Instruction &Instr, |
214 | 0 | const bool IsSigned) const noexcept { |
215 | 0 | const uint32_t Idx = StackMgr.pop().get<uint32_t>(); |
216 | 0 | const RefVariant Ref = StackMgr.getTop().get<RefVariant>(); |
217 | 0 | EXPECTED_TRY(auto Val, |
218 | 0 | arrayGet(StackMgr.getModule(), Ref, TypeIdx, Idx, IsSigned) |
219 | 0 | .map_error([&](auto E) { |
220 | 0 | return logError(E, Instr, [&]() { |
221 | 0 | return logArrayOOB(E, Idx, 1, Ref); |
222 | 0 | }); |
223 | 0 | })); |
224 | 0 | StackMgr.getTop() = Val; |
225 | 0 | return {}; |
226 | 0 | } |
227 | | |
228 | | Expect<void> |
229 | | Executor::runArraySetOp(Runtime::StackManager &StackMgr, const ValVariant &Val, |
230 | | const uint32_t TypeIdx, |
231 | 0 | const AST::Instruction &Instr) const noexcept { |
232 | 0 | const uint32_t Idx = StackMgr.pop().get<uint32_t>(); |
233 | 0 | const RefVariant Ref = StackMgr.pop().get<RefVariant>(); |
234 | 0 | EXPECTED_TRY(arraySet(StackMgr.getModule(), Ref, Val, TypeIdx, Idx) |
235 | 0 | .map_error([&](auto E) { |
236 | 0 | return logError(E, Instr, [&]() { |
237 | 0 | return logArrayOOB(E, Idx, 1, Ref); |
238 | 0 | }); |
239 | 0 | })); |
240 | 0 | return {}; |
241 | 0 | } |
242 | | |
243 | | Expect<void> |
244 | | Executor::runArrayLenOp(ValVariant &Val, |
245 | 0 | const AST::Instruction &Instr) const noexcept { |
246 | 0 | const auto *Inst = |
247 | 0 | Val.get<RefVariant>().getPtr<Runtime::Instance::ArrayInstance>(); |
248 | 0 | if (Inst == nullptr) { |
249 | 0 | return Unexpect(logError(ErrCode::Value::AccessNullArray, Instr)); |
250 | 0 | } |
251 | 0 | Val.emplace<uint32_t>(Inst->getLength()); |
252 | 0 | return {}; |
253 | 0 | } |
254 | | |
255 | | Expect<void> |
256 | | Executor::runArrayFillOp(Runtime::StackManager &StackMgr, const uint32_t Cnt, |
257 | | const ValVariant &Val, const uint32_t TypeIdx, |
258 | 0 | const AST::Instruction &Instr) const noexcept { |
259 | 0 | const uint32_t Idx = StackMgr.pop().get<uint32_t>(); |
260 | 0 | const RefVariant Ref = StackMgr.pop().get<RefVariant>(); |
261 | 0 | EXPECTED_TRY(arrayFill(StackMgr.getModule(), Ref, Val, TypeIdx, Idx, Cnt) |
262 | 0 | .map_error([&](auto E) { |
263 | 0 | return logError(E, Instr, [&]() { |
264 | 0 | return logArrayOOB(E, Idx, Cnt, Ref); |
265 | 0 | }); |
266 | 0 | })); |
267 | 0 | return {}; |
268 | 0 | } |
269 | | |
270 | | Expect<void> |
271 | | Executor::runArrayCopyOp(Runtime::StackManager &StackMgr, const uint32_t Cnt, |
272 | | const uint32_t DstTypeIdx, const uint32_t SrcTypeIdx, |
273 | 0 | const AST::Instruction &Instr) const noexcept { |
274 | 0 | const uint32_t SrcIdx = StackMgr.pop().get<uint32_t>(); |
275 | 0 | const RefVariant SrcRef = StackMgr.pop().get<RefVariant>(); |
276 | 0 | const uint32_t DstIdx = StackMgr.pop().get<uint32_t>(); |
277 | 0 | const RefVariant DstRef = StackMgr.pop().get<RefVariant>(); |
278 | 0 | EXPECTED_TRY(arrayCopy(StackMgr.getModule(), DstRef, DstTypeIdx, DstIdx, |
279 | 0 | SrcRef, SrcTypeIdx, SrcIdx, Cnt) |
280 | 0 | .map_error([&](auto E) { |
281 | 0 | return logError(E, Instr, [&]() { |
282 | 0 | return logDoubleArrayOOB(E, SrcIdx, Cnt, SrcRef, DstIdx, |
283 | 0 | Cnt, DstRef); |
284 | 0 | }); |
285 | 0 | })); |
286 | 0 | return {}; |
287 | 0 | } |
288 | | |
289 | | Expect<void> Executor::runArrayInitDataOp( |
290 | | Runtime::StackManager &StackMgr, const uint32_t Cnt, const uint32_t TypeIdx, |
291 | 0 | const uint32_t DataIdx, const AST::Instruction &Instr) const noexcept { |
292 | 0 | const uint32_t SrcIdx = StackMgr.pop().get<uint32_t>(); |
293 | 0 | const uint32_t DstIdx = StackMgr.pop().get<uint32_t>(); |
294 | 0 | const RefVariant Ref = StackMgr.pop().get<RefVariant>(); |
295 | 0 | EXPECTED_TRY( |
296 | 0 | arrayInitData(StackMgr.getModule(), Ref, TypeIdx, DataIdx, DstIdx, SrcIdx, |
297 | 0 | Cnt) |
298 | 0 | .map_error([&](auto E) { |
299 | 0 | auto *DataInst = getDataInstByIdx(StackMgr.getModule(), DataIdx); |
300 | 0 | const uint32_t BSize = |
301 | 0 | getArrayStorageTypeByIdx(StackMgr.getModule(), TypeIdx) |
302 | 0 | .getBitWidth() / |
303 | 0 | 8; |
304 | 0 | return logError( |
305 | 0 | E, Instr, [&]() { return logArrayOOB(E, DstIdx, Cnt, Ref); }, |
306 | 0 | [&]() { |
307 | 0 | return logMemoryOOB(E, *DataInst, SrcIdx, Cnt * BSize); |
308 | 0 | }); |
309 | 0 | })); |
310 | 0 | return {}; |
311 | 0 | } |
312 | | |
313 | | Expect<void> Executor::runArrayInitElemOp( |
314 | | Runtime::StackManager &StackMgr, const uint32_t Cnt, const uint32_t TypeIdx, |
315 | 0 | const uint32_t ElemIdx, const AST::Instruction &Instr) const noexcept { |
316 | 0 | const uint32_t SrcIdx = StackMgr.pop().get<uint32_t>(); |
317 | 0 | const uint32_t DstIdx = StackMgr.pop().get<uint32_t>(); |
318 | 0 | const RefVariant Ref = StackMgr.pop().get<RefVariant>(); |
319 | 0 | EXPECTED_TRY( |
320 | 0 | arrayInitElem(StackMgr.getModule(), Ref, TypeIdx, ElemIdx, DstIdx, SrcIdx, |
321 | 0 | Cnt) |
322 | 0 | .map_error([&](auto E) { |
323 | 0 | auto *ElemInst = getElemInstByIdx(StackMgr.getModule(), ElemIdx); |
324 | 0 | return logError( |
325 | 0 | E, Instr, [&]() { return logArrayOOB(E, DstIdx, Cnt, Ref); }, |
326 | 0 | [&]() { return logTableOOB(E, *ElemInst, SrcIdx, Cnt); }); |
327 | 0 | })); |
328 | 0 | return {}; |
329 | 0 | } |
330 | | |
331 | | Expect<void> |
332 | | Executor::runRefTestOp(const Runtime::Instance::ModuleInstance *ModInst, |
333 | | ValVariant &Val, const AST::Instruction &Instr, |
334 | 0 | const bool IsCast) const noexcept { |
335 | 0 | if (matchRef(ModInst, Instr.getValType(), Val.get<RefVariant>())) { |
336 | 0 | if (!IsCast) { |
337 | 0 | Val.emplace<uint32_t>(1U); |
338 | 0 | } |
339 | 0 | } else { |
340 | 0 | if (IsCast) { |
341 | 0 | spdlog::error(ErrCode::Value::CastFailed); |
342 | 0 | spdlog::error(ErrInfo::InfoMismatch(Instr.getValType(), |
343 | 0 | Val.get<RefVariant>().getType())); |
344 | 0 | spdlog::error( |
345 | 0 | ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); |
346 | 0 | return Unexpect(ErrCode::Value::CastFailed); |
347 | 0 | } else { |
348 | 0 | Val.emplace<uint32_t>(0U); |
349 | 0 | } |
350 | 0 | } |
351 | 0 | return {}; |
352 | 0 | } |
353 | | |
354 | | Expect<void> Executor::runRefConvOp(RefVariant &Ref, |
355 | 0 | TypeCode TCode) const noexcept { |
356 | 0 | if (TCode == TypeCode::AnyRef) { |
357 | | // Internalize. |
358 | 0 | if (Ref.isNull()) { |
359 | 0 | Ref = RefVariant(ValType(TypeCode::RefNull, TypeCode::NullRef)); |
360 | 0 | } else { |
361 | 0 | ValType VT = Ref.getType(); |
362 | 0 | VT.setInternalized(); |
363 | 0 | if (VT.isExternRefType()) { |
364 | 0 | VT = ValType(TypeCode::Ref, TypeCode::AnyRef); |
365 | 0 | } |
366 | 0 | Ref.setType(VT); |
367 | 0 | } |
368 | 0 | } else { |
369 | | // Externalize. |
370 | 0 | if (Ref.isNull()) { |
371 | 0 | Ref = RefVariant(ValType(TypeCode::RefNull, TypeCode::NullExternRef)); |
372 | 0 | } else { |
373 | | // Use the externalize flag because the value type information should be |
374 | | // reserved when a reference being externalized and internalized. |
375 | 0 | ValType VT = Ref.getType(); |
376 | 0 | VT.setExternalized(); |
377 | 0 | Ref.setType(VT); |
378 | 0 | } |
379 | 0 | } |
380 | 0 | return {}; |
381 | 0 | } |
382 | | |
383 | 0 | Expect<void> Executor::runRefI31Op(ValVariant &Val) const noexcept { |
384 | 0 | uint32_t RefNum = (Val.get<uint32_t>() & 0x7FFFFFFFU) | 0x80000000U; |
385 | 0 | Val = RefVariant(ValType(TypeCode::Ref, TypeCode::I31Ref), |
386 | 0 | reinterpret_cast<void *>(static_cast<uint64_t>(RefNum))); |
387 | 0 | return {}; |
388 | 0 | } |
389 | | |
390 | | Expect<void> Executor::runI31GetOp(ValVariant &Val, |
391 | | const AST::Instruction &Instr, |
392 | 0 | const bool IsSigned) const noexcept { |
393 | 0 | uint32_t RefNum = static_cast<uint32_t>( |
394 | 0 | reinterpret_cast<uintptr_t>(Val.get<RefVariant>().getPtr<void>())); |
395 | 0 | if ((RefNum & 0x80000000U) == 0) { |
396 | 0 | return Unexpect(logError(ErrCode::Value::AccessNullI31, Instr)); |
397 | 0 | } |
398 | 0 | RefNum &= 0x7FFFFFFFU; |
399 | 0 | if (IsSigned) { |
400 | 0 | RefNum |= ((RefNum & 0x40000000U) << 1); |
401 | 0 | } |
402 | 0 | Val.emplace<uint32_t>(RefNum); |
403 | 0 | return {}; |
404 | 0 | } |
405 | | |
406 | | Expect<RefVariant> |
407 | | Executor::structNew(const Runtime::Instance::ModuleInstance *ModInstArg, |
408 | | const uint32_t TypeIdx, |
409 | 0 | Span<const ValVariant> Args) const noexcept { |
410 | | /// TODO: The array and struct instances are currently owned by the module |
411 | | /// instance because they refer to the defined types of the module instances. |
412 | | /// This may be changed after applying the garbage collection mechanism. |
413 | 0 | const auto &CompType = getCompositeTypeByIdx(ModInstArg, TypeIdx); |
414 | 0 | uint32_t N = static_cast<uint32_t>(CompType.getFieldTypes().size()); |
415 | 0 | auto *ModInst = const_cast<Runtime::Instance::ModuleInstance *>(ModInstArg); |
416 | 0 | std::vector<ValVariant> Vals(N); |
417 | 0 | for (uint32_t I = 0; I < N; I++) { |
418 | 0 | const auto &VType = CompType.getFieldTypes()[I].getStorageType(); |
419 | 0 | if (Args.size() > 0) { |
420 | 0 | Vals[I] = packVal(VType, Args[I]); |
421 | 0 | } else { |
422 | 0 | Vals[I] = VType.isRefType() |
423 | 0 | ? ValVariant(RefVariant(toBottomType(ModInstArg, VType))) |
424 | 0 | : ValVariant(static_cast<uint128_t>(0U)); |
425 | 0 | } |
426 | 0 | } |
427 | 0 | WasmEdge::Runtime::Instance::StructInstance *Inst = |
428 | 0 | ModInst->newStruct(TypeIdx, std::move(Vals)); |
429 | 0 | return RefVariant(Inst->getDefType(), Inst); |
430 | 0 | } |
431 | | |
432 | | Expect<ValVariant> |
433 | | Executor::structGet(const Runtime::Instance::ModuleInstance *ModInst, |
434 | | const RefVariant Ref, const uint32_t TypeIdx, |
435 | 0 | const uint32_t Off, const bool IsSigned) const noexcept { |
436 | 0 | const auto *Inst = Ref.getPtr<Runtime::Instance::StructInstance>(); |
437 | 0 | if (Inst == nullptr) { |
438 | 0 | return Unexpect(ErrCode::Value::AccessNullStruct); |
439 | 0 | } |
440 | 0 | const auto &VType = getStructStorageTypeByIdx(ModInst, TypeIdx, Off); |
441 | 0 | return unpackVal(VType, Inst->getField(Off), IsSigned); |
442 | 0 | } |
443 | | |
444 | | Expect<void> |
445 | | Executor::structSet(const Runtime::Instance::ModuleInstance *ModInst, |
446 | | const RefVariant Ref, const ValVariant Val, |
447 | 0 | const uint32_t TypeIdx, const uint32_t Off) const noexcept { |
448 | 0 | auto *Inst = Ref.getPtr<Runtime::Instance::StructInstance>(); |
449 | 0 | if (Inst == nullptr) { |
450 | 0 | return Unexpect(ErrCode::Value::AccessNullStruct); |
451 | 0 | } |
452 | 0 | const auto &VType = getStructStorageTypeByIdx(ModInst, TypeIdx, Off); |
453 | 0 | Inst->getField(Off) = packVal(VType, Val); |
454 | 0 | return {}; |
455 | 0 | } |
456 | | |
457 | | Expect<RefVariant> |
458 | | Executor::arrayNew(const Runtime::Instance::ModuleInstance *ModInstArg, |
459 | | const uint32_t TypeIdx, const uint32_t Length, |
460 | 0 | Span<const ValVariant> Args) const noexcept { |
461 | | /// TODO: The array and struct instances are currently owned by the module |
462 | | /// instance because they refer to the defined types of the module instances. |
463 | | /// This may be changed after applying the garbage collection mechanism. |
464 | 0 | const auto &VType = getArrayStorageTypeByIdx(ModInstArg, TypeIdx); |
465 | 0 | WasmEdge::Runtime::Instance::ArrayInstance *Inst = nullptr; |
466 | 0 | auto *ModInst = const_cast<Runtime::Instance::ModuleInstance *>(ModInstArg); |
467 | 0 | if (Args.size() == 0) { |
468 | | // New and fill with default values. |
469 | 0 | auto InitVal = VType.isRefType() |
470 | 0 | ? ValVariant(RefVariant(toBottomType(ModInstArg, VType))) |
471 | 0 | : ValVariant(static_cast<uint128_t>(0U)); |
472 | 0 | Inst = ModInst->newArray(TypeIdx, Length, InitVal); |
473 | 0 | } else if (Args.size() == 1) { |
474 | | // Create and fill with the argument value. |
475 | 0 | Inst = ModInst->newArray(TypeIdx, Length, packVal(VType, Args[0])); |
476 | 0 | } else { |
477 | | // Create with arguments. |
478 | 0 | Inst = ModInst->newArray( |
479 | 0 | TypeIdx, |
480 | 0 | packVals(VType, std::vector<ValVariant>(Args.begin(), Args.end()))); |
481 | 0 | } |
482 | 0 | return RefVariant(Inst->getDefType(), Inst); |
483 | 0 | } |
484 | | |
485 | | Expect<RefVariant> |
486 | | Executor::arrayNewData(const Runtime::Instance::ModuleInstance *ModInstArg, |
487 | | const uint32_t TypeIdx, const uint32_t DataIdx, |
488 | | const uint32_t Start, |
489 | 0 | const uint32_t Length) const noexcept { |
490 | 0 | const auto &VType = getArrayStorageTypeByIdx(ModInstArg, TypeIdx); |
491 | 0 | const uint32_t BSize = VType.getBitWidth() / 8; |
492 | 0 | auto *DataInst = getDataInstByIdx(ModInstArg, DataIdx); |
493 | 0 | assuming(DataInst); |
494 | 0 | if (static_cast<uint64_t>(Start) + static_cast<uint64_t>(Length) * BSize > |
495 | 0 | DataInst->getData().size()) { |
496 | 0 | return Unexpect(ErrCode::Value::MemoryOutOfBounds); |
497 | 0 | } |
498 | 0 | auto *ModInst = const_cast<Runtime::Instance::ModuleInstance *>(ModInstArg); |
499 | 0 | std::vector<ValVariant> Args; |
500 | 0 | Args.reserve(Length); |
501 | 0 | for (uint32_t Idx = 0; Idx < Length; Idx++) { |
502 | | // The value has been packed. |
503 | 0 | Args.push_back(DataInst->loadValue(Start + Idx * BSize, BSize)); |
504 | 0 | } |
505 | 0 | WasmEdge::Runtime::Instance::ArrayInstance *Inst = |
506 | 0 | ModInst->newArray(TypeIdx, std::move(Args)); |
507 | 0 | return RefVariant(Inst->getDefType(), Inst); |
508 | 0 | } |
509 | | |
510 | | Expect<RefVariant> |
511 | | Executor::arrayNewElem(const Runtime::Instance::ModuleInstance *ModInstArg, |
512 | | const uint32_t TypeIdx, const uint32_t ElemIdx, |
513 | | const uint32_t Start, |
514 | 0 | const uint32_t Length) const noexcept { |
515 | 0 | const auto &VType = getArrayStorageTypeByIdx(ModInstArg, TypeIdx); |
516 | 0 | auto *ElemInst = getElemInstByIdx(ModInstArg, ElemIdx); |
517 | 0 | assuming(ElemInst); |
518 | 0 | auto ElemSrc = ElemInst->getRefs(); |
519 | 0 | if (static_cast<uint64_t>(Start) + static_cast<uint64_t>(Length) > |
520 | 0 | ElemSrc.size()) { |
521 | 0 | return Unexpect(ErrCode::Value::TableOutOfBounds); |
522 | 0 | } |
523 | 0 | std::vector<ValVariant> Refs(ElemSrc.begin() + Start, |
524 | 0 | ElemSrc.begin() + Start + Length); |
525 | 0 | auto *ModInst = const_cast<Runtime::Instance::ModuleInstance *>(ModInstArg); |
526 | 0 | WasmEdge::Runtime::Instance::ArrayInstance *Inst = |
527 | 0 | ModInst->newArray(TypeIdx, packVals(VType, std::move(Refs))); |
528 | 0 | return RefVariant(Inst->getDefType(), Inst); |
529 | 0 | } |
530 | | |
531 | | Expect<ValVariant> |
532 | | Executor::arrayGet(const Runtime::Instance::ModuleInstance *ModInst, |
533 | | const RefVariant &Ref, const uint32_t TypeIdx, |
534 | 0 | const uint32_t Idx, const bool IsSigned) const noexcept { |
535 | 0 | const auto *Inst = Ref.getPtr<Runtime::Instance::ArrayInstance>(); |
536 | 0 | if (Inst == nullptr) { |
537 | 0 | return Unexpect(ErrCode::Value::AccessNullArray); |
538 | 0 | } |
539 | 0 | if (Idx >= Inst->getLength()) { |
540 | 0 | return Unexpect(ErrCode::Value::ArrayOutOfBounds); |
541 | 0 | } |
542 | 0 | const auto &VType = getArrayStorageTypeByIdx(ModInst, TypeIdx); |
543 | 0 | return unpackVal(VType, Inst->getData(Idx), IsSigned); |
544 | 0 | } |
545 | | |
546 | | Expect<void> |
547 | | Executor::arraySet(const Runtime::Instance::ModuleInstance *ModInst, |
548 | | const RefVariant &Ref, const ValVariant &Val, |
549 | 0 | const uint32_t TypeIdx, const uint32_t Idx) const noexcept { |
550 | 0 | auto *Inst = Ref.getPtr<Runtime::Instance::ArrayInstance>(); |
551 | 0 | if (Inst == nullptr) { |
552 | 0 | return Unexpect(ErrCode::Value::AccessNullArray); |
553 | 0 | } |
554 | 0 | if (Idx >= Inst->getLength()) { |
555 | 0 | return Unexpect(ErrCode::Value::ArrayOutOfBounds); |
556 | 0 | } |
557 | 0 | const auto &VType = getArrayStorageTypeByIdx(ModInst, TypeIdx); |
558 | 0 | Inst->getData(Idx) = packVal(VType, Val); |
559 | 0 | return {}; |
560 | 0 | } |
561 | | |
562 | | Expect<void> |
563 | | Executor::arrayFill(const Runtime::Instance::ModuleInstance *ModInst, |
564 | | const RefVariant &Ref, const ValVariant &Val, |
565 | | const uint32_t TypeIdx, const uint32_t Idx, |
566 | 0 | const uint32_t Cnt) const noexcept { |
567 | 0 | auto *Inst = Ref.getPtr<Runtime::Instance::ArrayInstance>(); |
568 | 0 | if (Inst == nullptr) { |
569 | 0 | return Unexpect(ErrCode::Value::AccessNullArray); |
570 | 0 | } |
571 | 0 | if (static_cast<uint64_t>(Idx) + static_cast<uint64_t>(Cnt) > |
572 | 0 | Inst->getLength()) { |
573 | 0 | return Unexpect(ErrCode::Value::ArrayOutOfBounds); |
574 | 0 | } |
575 | 0 | const auto &VType = getArrayStorageTypeByIdx(ModInst, TypeIdx); |
576 | 0 | auto Arr = Inst->getArray(); |
577 | 0 | std::fill(Arr.begin() + Idx, Arr.begin() + Idx + Cnt, packVal(VType, Val)); |
578 | 0 | return {}; |
579 | 0 | } |
580 | | |
581 | | Expect<void> Executor::arrayInitData( |
582 | | const Runtime::Instance::ModuleInstance *ModInst, const RefVariant &Ref, |
583 | | const uint32_t TypeIdx, const uint32_t DataIdx, const uint32_t DstIdx, |
584 | 0 | const uint32_t SrcIdx, const uint32_t Cnt) const noexcept { |
585 | 0 | auto *Inst = Ref.getPtr<Runtime::Instance::ArrayInstance>(); |
586 | 0 | if (Inst == nullptr) { |
587 | 0 | return Unexpect(ErrCode::Value::AccessNullArray); |
588 | 0 | } |
589 | 0 | if (static_cast<uint64_t>(DstIdx) + static_cast<uint64_t>(Cnt) > |
590 | 0 | Inst->getLength()) { |
591 | 0 | return Unexpect(ErrCode::Value::ArrayOutOfBounds); |
592 | 0 | } |
593 | 0 | const auto &VType = getArrayStorageTypeByIdx(ModInst, TypeIdx); |
594 | 0 | const uint32_t BSize = VType.getBitWidth() / 8; |
595 | 0 | auto *DataInst = getDataInstByIdx(ModInst, DataIdx); |
596 | 0 | assuming(DataInst); |
597 | 0 | if (static_cast<uint64_t>(SrcIdx) + static_cast<uint64_t>(Cnt) * BSize > |
598 | 0 | DataInst->getData().size()) { |
599 | 0 | return Unexpect(ErrCode::Value::MemoryOutOfBounds); |
600 | 0 | } |
601 | | |
602 | 0 | for (uint32_t Idx = 0; Idx < Cnt; Idx++) { |
603 | | // The value has been packed. |
604 | 0 | Inst->getData(DstIdx + Idx) = |
605 | 0 | DataInst->loadValue(SrcIdx + Idx * BSize, BSize); |
606 | 0 | } |
607 | 0 | return {}; |
608 | 0 | } |
609 | | |
610 | | Expect<void> Executor::arrayInitElem( |
611 | | const Runtime::Instance::ModuleInstance *ModInst, const RefVariant &Ref, |
612 | | const uint32_t TypeIdx, const uint32_t ElemIdx, const uint32_t DstIdx, |
613 | 0 | const uint32_t SrcIdx, const uint32_t Cnt) const noexcept { |
614 | 0 | auto *Inst = Ref.getPtr<Runtime::Instance::ArrayInstance>(); |
615 | 0 | if (Inst == nullptr) { |
616 | 0 | return Unexpect(ErrCode::Value::AccessNullArray); |
617 | 0 | } |
618 | 0 | if (static_cast<uint64_t>(DstIdx) + static_cast<uint64_t>(Cnt) > |
619 | 0 | Inst->getLength()) { |
620 | 0 | return Unexpect(ErrCode::Value::ArrayOutOfBounds); |
621 | 0 | } |
622 | 0 | const auto &VType = getArrayStorageTypeByIdx(ModInst, TypeIdx); |
623 | 0 | auto *ElemInst = getElemInstByIdx(ModInst, ElemIdx); |
624 | 0 | assuming(ElemInst); |
625 | 0 | auto ElemSrc = ElemInst->getRefs(); |
626 | 0 | if (static_cast<uint64_t>(SrcIdx) + static_cast<uint64_t>(Cnt) > |
627 | 0 | ElemSrc.size()) { |
628 | 0 | return Unexpect(ErrCode::Value::TableOutOfBounds); |
629 | 0 | } |
630 | | |
631 | 0 | auto Arr = Inst->getArray(); |
632 | | // The value has been packed. |
633 | 0 | std::transform(ElemSrc.begin() + SrcIdx, ElemSrc.begin() + SrcIdx + Cnt, |
634 | 0 | Arr.begin() + DstIdx, |
635 | 0 | [&](const RefVariant &V) { return packVal(VType, V); }); |
636 | 0 | return {}; |
637 | 0 | } |
638 | | |
639 | | Expect<void> |
640 | | Executor::arrayCopy(const Runtime::Instance::ModuleInstance *ModInst, |
641 | | const RefVariant &DstRef, const uint32_t DstTypeIdx, |
642 | | const uint32_t DstIdx, const RefVariant &SrcRef, |
643 | | const uint32_t SrcTypeIdx, const uint32_t SrcIdx, |
644 | 0 | const uint32_t Cnt) const noexcept { |
645 | 0 | auto *SrcInst = SrcRef.getPtr<Runtime::Instance::ArrayInstance>(); |
646 | 0 | auto *DstInst = DstRef.getPtr<Runtime::Instance::ArrayInstance>(); |
647 | 0 | if (SrcInst == nullptr) { |
648 | 0 | return Unexpect(ErrCode::Value::AccessNullArray); |
649 | 0 | } |
650 | 0 | if (DstInst == nullptr) { |
651 | 0 | return Unexpect(ErrCode::Value::AccessNullArray); |
652 | 0 | } |
653 | 0 | if (static_cast<uint64_t>(SrcIdx) + static_cast<uint64_t>(Cnt) > |
654 | 0 | SrcInst->getLength()) { |
655 | 0 | return Unexpect(ErrCode::Value::ArrayOutOfBounds); |
656 | 0 | } |
657 | 0 | if (static_cast<uint64_t>(DstIdx) + static_cast<uint64_t>(Cnt) > |
658 | 0 | DstInst->getLength()) { |
659 | 0 | return Unexpect(ErrCode::Value::ArrayOutOfBounds); |
660 | 0 | } |
661 | | |
662 | 0 | auto SrcArr = SrcInst->getArray(); |
663 | 0 | auto DstArr = DstInst->getArray(); |
664 | 0 | const auto &SrcVType = getArrayStorageTypeByIdx(ModInst, SrcTypeIdx); |
665 | 0 | const auto &DstVType = getArrayStorageTypeByIdx(ModInst, DstTypeIdx); |
666 | 0 | if (DstIdx <= SrcIdx) { |
667 | 0 | std::transform(SrcArr.begin() + SrcIdx, SrcArr.begin() + SrcIdx + Cnt, |
668 | 0 | DstArr.begin() + DstIdx, [&](const ValVariant &V) { |
669 | 0 | return packVal(DstVType, unpackVal(SrcVType, V)); |
670 | 0 | }); |
671 | 0 | } else { |
672 | 0 | std::transform(std::make_reverse_iterator(SrcArr.begin() + SrcIdx + Cnt), |
673 | 0 | std::make_reverse_iterator(SrcArr.begin() + SrcIdx), |
674 | 0 | std::make_reverse_iterator(DstArr.begin() + DstIdx + Cnt), |
675 | 0 | [&](const ValVariant &V) { |
676 | 0 | return packVal(DstVType, unpackVal(SrcVType, V)); |
677 | 0 | }); |
678 | 0 | } |
679 | 0 | return {}; |
680 | 0 | } |
681 | | |
682 | | } // namespace Executor |
683 | | } // namespace WasmEdge |