Coverage Report

Created: 2025-07-01 06:18

/src/WasmEdge/lib/executor/engine/controlInstr.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
#include <cstdint>
7
8
namespace WasmEdge {
9
namespace Executor {
10
11
Expect<void> Executor::runIfElseOp(Runtime::StackManager &StackMgr,
12
                                   const AST::Instruction &Instr,
13
0
                                   AST::InstrView::iterator &PC) noexcept {
14
  // Get condition.
15
0
  uint32_t Cond = StackMgr.pop().get<uint32_t>();
16
17
  // If non-zero, run if-statement; else, run else-statement.
18
0
  if (Cond == 0) {
19
0
    if (Instr.getJumpElse() == Instr.getJumpEnd()) {
20
      // No else-statement case. Jump to right before End instruction.
21
0
      PC += (Instr.getJumpEnd() - 1);
22
0
    } else {
23
0
      if (Stat) {
24
0
        Stat->incInstrCount();
25
0
        if (unlikely(!Stat->addInstrCost(OpCode::Else))) {
26
0
          return Unexpect(ErrCode::Value::CostLimitExceeded);
27
0
        }
28
0
      }
29
      // Have else-statement case. Jump to Else instruction to continue.
30
0
      PC += Instr.getJumpElse();
31
0
    }
32
0
  }
33
0
  return {};
34
0
}
35
36
Expect<void> Executor::runThrowOp(Runtime::StackManager &StackMgr,
37
                                  const AST::Instruction &Instr,
38
0
                                  AST::InstrView::iterator &PC) noexcept {
39
0
  auto *TagInst = getTagInstByIdx(StackMgr, Instr.getTargetIndex());
40
  // The args will be popped from stack in the throw function.
41
0
  return throwException(StackMgr, *TagInst, PC);
42
0
}
43
44
Expect<void> Executor::runThrowRefOp(Runtime::StackManager &StackMgr,
45
                                     const AST::Instruction &Instr,
46
0
                                     AST::InstrView::iterator &PC) noexcept {
47
0
  const auto Ref = StackMgr.pop().get<RefVariant>();
48
0
  if (Ref.isNull()) {
49
0
    spdlog::error(ErrCode::Value::AccessNullException);
50
0
    spdlog::error(
51
0
        ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
52
0
    return Unexpect(ErrCode::Value::AccessNullException);
53
0
  }
54
0
  auto *TagInst = Ref.getPtr<Runtime::Instance::TagInstance>();
55
0
  return throwException(StackMgr, *TagInst, PC);
56
0
}
57
58
Expect<void> Executor::runBrOp(Runtime::StackManager &StackMgr,
59
                               const AST::Instruction &Instr,
60
0
                               AST::InstrView::iterator &PC) noexcept {
61
0
  return branchToLabel(StackMgr, Instr.getJump(), PC);
62
0
}
63
64
Expect<void> Executor::runBrIfOp(Runtime::StackManager &StackMgr,
65
                                 const AST::Instruction &Instr,
66
0
                                 AST::InstrView::iterator &PC) noexcept {
67
0
  if (StackMgr.pop().get<uint32_t>() != 0) {
68
0
    return runBrOp(StackMgr, Instr, PC);
69
0
  }
70
0
  return {};
71
0
}
72
73
Expect<void> Executor::runBrOnNullOp(Runtime::StackManager &StackMgr,
74
                                     const AST::Instruction &Instr,
75
0
                                     AST::InstrView::iterator &PC) noexcept {
76
0
  if (StackMgr.getTop().get<RefVariant>().isNull()) {
77
0
    StackMgr.pop();
78
0
    return runBrOp(StackMgr, Instr, PC);
79
0
  }
80
0
  return {};
81
0
}
82
83
Expect<void> Executor::runBrOnNonNullOp(Runtime::StackManager &StackMgr,
84
                                        const AST::Instruction &Instr,
85
0
                                        AST::InstrView::iterator &PC) noexcept {
86
0
  if (!StackMgr.getTop().get<RefVariant>().isNull()) {
87
0
    return runBrOp(StackMgr, Instr, PC);
88
0
  }
89
0
  StackMgr.pop();
90
0
  return {};
91
0
}
92
93
Expect<void> Executor::runBrTableOp(Runtime::StackManager &StackMgr,
94
                                    const AST::Instruction &Instr,
95
0
                                    AST::InstrView::iterator &PC) noexcept {
96
  // Get value on top of stack.
97
0
  uint32_t Value = StackMgr.pop().get<uint32_t>();
98
99
  // Do branch.
100
0
  auto LabelTable = Instr.getLabelList();
101
0
  const auto LabelTableSize = static_cast<uint32_t>(LabelTable.size() - 1);
102
0
  if (Value < LabelTableSize) {
103
0
    return branchToLabel(StackMgr, LabelTable[Value], PC);
104
0
  }
105
0
  return branchToLabel(StackMgr, LabelTable[LabelTableSize], PC);
106
0
}
107
108
Expect<void> Executor::runBrOnCastOp(Runtime::StackManager &StackMgr,
109
                                     const AST::Instruction &Instr,
110
                                     AST::InstrView::iterator &PC,
111
0
                                     bool IsReverse) noexcept {
112
  // Get value on top of stack.
113
0
  const auto *ModInst = StackMgr.getModule();
114
0
  const auto &Val = StackMgr.getTop().get<RefVariant>();
115
0
  const auto &VT = Val.getType();
116
0
  Span<const AST::SubType *const> GotTypeList = ModInst->getTypeList();
117
0
  if (!VT.isAbsHeapType()) {
118
0
    auto *Inst = Val.getPtr<Runtime::Instance::CompositeBase>();
119
    // Reference must not be nullptr here because the null references are typed
120
    // with the least abstract heap type.
121
0
    if (Inst->getModule()) {
122
0
      GotTypeList = Inst->getModule()->getTypeList();
123
0
    }
124
0
  }
125
126
0
  if (AST::TypeMatcher::matchType(ModInst->getTypeList(),
127
0
                                  Instr.getBrCast().RType2, GotTypeList,
128
0
                                  VT) != IsReverse) {
129
0
    return branchToLabel(StackMgr, Instr.getBrCast().Jump, PC);
130
0
  }
131
0
  return {};
132
0
}
133
134
Expect<void> Executor::runReturnOp(Runtime::StackManager &StackMgr,
135
0
                                   AST::InstrView::iterator &PC) noexcept {
136
  // Check stop token
137
0
  if (unlikely(StopToken.exchange(0, std::memory_order_relaxed))) {
138
0
    spdlog::error(ErrCode::Value::Interrupted);
139
0
    return Unexpect(ErrCode::Value::Interrupted);
140
0
  }
141
0
  PC = StackMgr.popFrame();
142
0
  return {};
143
0
}
144
145
Expect<void> Executor::runCallOp(Runtime::StackManager &StackMgr,
146
                                 const AST::Instruction &Instr,
147
                                 AST::InstrView::iterator &PC,
148
0
                                 bool IsTailCall) noexcept {
149
  // Get Function address.
150
0
  const auto *FuncInst = getFuncInstByIdx(StackMgr, Instr.getTargetIndex());
151
0
  EXPECTED_TRY(auto NextPC,
152
0
               enterFunction(StackMgr, *FuncInst, PC + 1, IsTailCall));
153
0
  PC = NextPC - 1;
154
0
  return {};
155
0
}
156
157
Expect<void> Executor::runCallRefOp(Runtime::StackManager &StackMgr,
158
                                    const AST::Instruction &Instr,
159
                                    AST::InstrView::iterator &PC,
160
0
                                    bool IsTailCall) noexcept {
161
0
  const auto Ref = StackMgr.pop().get<RefVariant>();
162
0
  if (Ref.isNull()) {
163
0
    spdlog::error(ErrCode::Value::AccessNullFunc);
164
0
    spdlog::error(
165
0
        ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
166
0
    return Unexpect(ErrCode::Value::AccessNullFunc);
167
0
  }
168
169
  // Get Function address.
170
0
  const auto *FuncInst = retrieveFuncRef(Ref);
171
0
  EXPECTED_TRY(auto NextPC,
172
0
               enterFunction(StackMgr, *FuncInst, PC + 1, IsTailCall));
173
0
  PC = NextPC - 1;
174
0
  return {};
175
0
}
176
177
Expect<void> Executor::runCallIndirectOp(Runtime::StackManager &StackMgr,
178
                                         const AST::Instruction &Instr,
179
                                         AST::InstrView::iterator &PC,
180
0
                                         bool IsTailCall) noexcept {
181
  // Get Table Instance
182
0
  const auto *TabInst = getTabInstByIdx(StackMgr, Instr.getSourceIndex());
183
184
  // Get function type at index x.
185
0
  const auto *ModInst = StackMgr.getModule();
186
0
  const auto &ExpDefType = **ModInst->getType(Instr.getTargetIndex());
187
188
  // Pop the value i32.const i from the Stack.
189
0
  uint32_t Idx = StackMgr.pop().get<uint32_t>();
190
191
  // If idx not small than tab.elem, trap.
192
0
  if (Idx >= TabInst->getSize()) {
193
0
    spdlog::error(ErrCode::Value::UndefinedElement);
194
0
    spdlog::error(ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset(),
195
0
                                           {Idx},
196
0
                                           {ValTypeFromType<uint32_t>()}));
197
0
    return Unexpect(ErrCode::Value::UndefinedElement);
198
0
  }
199
200
  // Get function address. The bound is guaranteed.
201
0
  RefVariant Ref = *TabInst->getRefAddr(Idx);
202
0
  if (Ref.isNull()) {
203
0
    spdlog::error(ErrCode::Value::UninitializedElement);
204
0
    spdlog::error(ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset(),
205
0
                                           {Idx},
206
0
                                           {ValTypeFromType<uint32_t>()}));
207
0
    return Unexpect(ErrCode::Value::UninitializedElement);
208
0
  }
209
210
  // Check function type.
211
0
  const auto *FuncInst = retrieveFuncRef(Ref);
212
0
  bool IsMatch = false;
213
0
  if (FuncInst->getModule()) {
214
0
    IsMatch = AST::TypeMatcher::matchType(
215
0
        ModInst->getTypeList(), *ExpDefType.getTypeIndex(),
216
0
        FuncInst->getModule()->getTypeList(), FuncInst->getTypeIndex());
217
0
  } else {
218
    // Independent host module instance case. Matching the composite type
219
    // directly.
220
0
    IsMatch = AST::TypeMatcher::matchType(
221
0
        ModInst->getTypeList(), ExpDefType.getCompositeType(),
222
0
        FuncInst->getHostFunc().getDefinedType().getCompositeType());
223
0
  }
224
0
  if (!IsMatch) {
225
0
    auto &ExpFuncType = ExpDefType.getCompositeType().getFuncType();
226
0
    auto &GotFuncType = FuncInst->getFuncType();
227
0
    spdlog::error(ErrCode::Value::IndirectCallTypeMismatch);
228
0
    spdlog::error(ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset(),
229
0
                                           {Idx},
230
0
                                           {ValTypeFromType<uint32_t>()}));
231
0
    spdlog::error(ErrInfo::InfoMismatch(
232
0
        ExpFuncType.getParamTypes(), ExpFuncType.getReturnTypes(),
233
0
        GotFuncType.getParamTypes(), GotFuncType.getReturnTypes()));
234
0
    return Unexpect(ErrCode::Value::IndirectCallTypeMismatch);
235
0
  }
236
237
  // Enter the function.
238
0
  EXPECTED_TRY(auto NextPC,
239
0
               enterFunction(StackMgr, *FuncInst, PC + 1, IsTailCall));
240
0
  PC = NextPC - 1;
241
0
  return {};
242
0
}
243
244
Expect<void> Executor::runTryTableOp(Runtime::StackManager &StackMgr,
245
                                     const AST::Instruction &Instr,
246
0
                                     AST::InstrView::iterator &PC) noexcept {
247
0
  const auto &TryDesc = Instr.getTryCatch();
248
0
  StackMgr.pushHandler(PC, TryDesc.BlockParamNum, TryDesc.Catch);
249
0
  return {};
250
0
}
251
252
} // namespace Executor
253
} // namespace WasmEdge