Coverage Report

Created: 2025-07-01 06:18

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