Coverage Report

Created: 2026-07-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/loader/ast/component/component_canonical.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#include "loader/loader.h"
5
6
namespace WasmEdge {
7
namespace Loader {
8
9
22.2k
Expect<void> Loader::loadCanonical(AST::Component::Canonical &C) {
10
22.2k
  auto ReportError = [this](auto E) {
11
362
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_Canonical);
12
362
  };
component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonical(WasmEdge::AST::Component::Canonical&)::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const
Line
Count
Source
10
265
  auto ReportError = [this](auto E) {
11
265
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_Canonical);
12
265
  };
component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonical(WasmEdge::AST::Component::Canonical&)::$_0::operator()<WasmEdge::ErrCode::Value>(WasmEdge::ErrCode::Value) const
Line
Count
Source
10
97
  auto ReportError = [this](auto E) {
11
97
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_Canonical);
12
97
  };
13
  // canon ::= 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx>
14
  //           => (canon lift f opts type-index-space[ft])
15
  //         | 0x01 0x00 f:<funcidx> opts:<opts>
16
  //           => (canon lower f opts (core func))
17
  //         | 0x02 rt:<typeidx>    => (canon resource.new rt (core func))
18
  //         | 0x03 rt:<typeidx>    => (canon resource.drop rt (core func))
19
  //         | 0x07 rt:<typeidx>
20
  //           => (canon resource.drop rt async (core func)) ๐Ÿ”€
21
  //         | 0x04 rt:<typeidx>    => (canon resource.rep rt (core func))
22
  //         | 0x08                 => (canon backpressure.set (core func)) ๐Ÿ”€
23
  //         | 0x09 rs:<resultlist> opts:<opts>
24
  //           => (canon task.return rs opts (core func)) ๐Ÿ”€
25
  //         | 0x05                 => (canon task.cancel (core func)) ๐Ÿ”€
26
  //         | 0x0a 0x7f i:<u32>    => (canon context.get i32 i (core func)) ๐Ÿ”€
27
  //         | 0x0b 0x7f i:<u32>    => (canon context.set i32 i (core func)) ๐Ÿ”€
28
  //         | 0x0c async?:<async>? => (canon yield async? (core func)) ๐Ÿ”€
29
  //         | 0x06 async?:<async?>
30
  //           => (canon subtask.cancel async? (core func)) ๐Ÿ”€
31
  //         | 0x0d                 => (canon subtask.drop (core func)) ๐Ÿ”€
32
  //         | 0x0e t:<typeidx>     => (canon stream.new t (core func)) ๐Ÿ”€
33
  //         | 0x0f t:<typeidx> opts:<opts>
34
  //           => (canon stream.read t opts (core func)) ๐Ÿ”€
35
  //         | 0x10 t:<typeidx> opts:<opts>
36
  //           => (canon stream.write t opts (core func)) ๐Ÿ”€
37
  //         | 0x11 t:<typeidx> async?:<async?>
38
  //           => (canon stream.cancel-read async? (core func)) ๐Ÿ”€
39
  //         | 0x12 t:<typeidx> async?:<async?>
40
  //           => (canon stream.cancel-write async? (core func)) ๐Ÿ”€
41
  //         | 0x13 t:<typeidx>
42
  //           => (canon stream.close-readable t (core func)) ๐Ÿ”€
43
  //         | 0x14 t:<typeidx>
44
  //           => (canon stream.close-writable t (core func)) ๐Ÿ”€
45
  //         | 0x15 t:<typeidx> => (canon future.new t (core func)) ๐Ÿ”€
46
  //         | 0x16 t:<typeidx> opts:<opts>
47
  //           => (canon future.read t opts (core func)) ๐Ÿ”€
48
  //         | 0x17 t:<typeidx> opts:<opts>
49
  //           => (canon future.write t opts (core func)) ๐Ÿ”€
50
  //         | 0x18 t:<typeidx> async?:<async?>
51
  //           => (canon future.cancel-read async? (core func)) ๐Ÿ”€
52
  //         | 0x19 t:<typeidx> async?:<async?>
53
  //           => (canon future.cancel-write async? (core func)) ๐Ÿ”€
54
  //         | 0x1a t:<typeidx>
55
  //           => (canon future.close-readable t (core func)) ๐Ÿ”€
56
  //         | 0x1b t:<typeidx>
57
  //           => (canon future.close-writable t (core func)) ๐Ÿ”€
58
  //         | 0x1c opts:<opts> => (canon error-context.new opts (core func)) ๐Ÿ“
59
  //         | 0x1d opts:<opts>
60
  //           => (canon error-context.debug-message opts (core func)) ๐Ÿ“
61
  //         | 0x1e                => (canon error-context.drop (core func)) ๐Ÿ“
62
  //         | 0x1f                => (canon waitable-set.new (core func)) ๐Ÿ”€
63
  //         | 0x20 async?:<async>? m:<core:memidx>
64
  //           => (canon waitable-set.wait async? (memory m) (core func)) ๐Ÿ”€
65
  //         | 0x21 async?:<async>? m:<core:memidx>
66
  //           => (canon waitable-set.poll async? (memory m) (core func)) ๐Ÿ”€
67
  //         | 0x22                => (canon waitable-set.drop (core func)) ๐Ÿ”€
68
  //         | 0x23                => (canon waitable.join (core func)) ๐Ÿ”€
69
  //         | 0x40 ft:<typeidx>   => (canon thread.spawn_ref ft (core func)) ๐Ÿงต
70
  //         | 0x41 ft:<typeidx> tbl:<core:tableidx>
71
  //           => (canon thread.spawn_indirect ft tbl (core func)) ๐Ÿงต
72
  //         | 0x42 => (canon thread.available_parallelism (core func)) ๐Ÿงต
73
  // async? ::= 0x00 => ฯต
74
  //          | 0x01 => async
75
76
  // Helper: load async? flag.
77
22.2k
  auto LoadAsync = [this, &ReportError, &C]() -> Expect<void> {
78
1.61k
    EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError));
79
1.59k
    if (B == 0x00) {
80
1.18k
      C.setAsync(false);
81
1.18k
    } else if (B == 0x01) {
82
387
      C.setAsync(true);
83
387
    } else {
84
20
      return ReportError(ErrCode::Value::MalformedCanonical);
85
20
    }
86
1.57k
    return {};
87
1.59k
  };
88
89
  // Helper: load opts (vec of canonopt).
90
22.2k
  auto LoadOpts = [this, &C]() -> Expect<void> {
91
9.65k
    std::vector<AST::Component::CanonOpt> Opts;
92
9.65k
    EXPECTED_TRY(loadVec<AST::Component::Canonical>(
93
9.50k
        Opts, [this](AST::Component::CanonOpt &Opt) {
94
9.50k
          return loadCanonicalOption(Opt);
95
9.50k
        }));
96
9.50k
    C.setOptions(std::move(Opts));
97
9.50k
    return {};
98
9.65k
  };
99
100
22.2k
  EXPECTED_TRY(uint8_t Flag, FMgr.readByte().map_error(ReportError));
101
22.1k
  auto Code = static_cast<ComponentCanonOpCode>(Flag);
102
22.1k
  switch (Code) {
103
104
  // 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx>
105
5.15k
  case ComponentCanonOpCode::Lift: {
106
5.15k
    EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError));
107
5.14k
    if (unlikely(B != 0x00)) {
108
17
      return ReportError(ErrCode::Value::MalformedCanonical);
109
17
    }
110
10.2k
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
111
10.2k
    C.setIndex(Idx);
112
10.2k
    EXPECTED_TRY(LoadOpts());
113
5.04k
    EXPECTED_TRY(uint32_t TypeIdx, FMgr.readU32().map_error(ReportError));
114
5.03k
    C.setTargetIndex(TypeIdx);
115
5.03k
    break;
116
5.04k
  }
117
118
  // 0x01 0x00 f:<funcidx> opts:<opts>
119
3.41k
  case ComponentCanonOpCode::Lower: {
120
3.41k
    EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError));
121
3.41k
    if (unlikely(B != 0x00)) {
122
5
      return ReportError(ErrCode::Value::MalformedCanonical);
123
5
    }
124
6.81k
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
125
6.81k
    C.setIndex(Idx);
126
6.81k
    EXPECTED_TRY(LoadOpts());
127
3.38k
    break;
128
6.81k
  }
129
130
  // typeidx-only opcodes
131
3.38k
  case ComponentCanonOpCode::Resource__new:
132
1.27k
  case ComponentCanonOpCode::Resource__drop:
133
1.62k
  case ComponentCanonOpCode::Resource__drop_async:
134
1.95k
  case ComponentCanonOpCode::Resource__rep:
135
2.25k
  case ComponentCanonOpCode::Stream__new:
136
2.52k
  case ComponentCanonOpCode::Stream__close_readable:
137
2.73k
  case ComponentCanonOpCode::Stream__close_writable:
138
2.93k
  case ComponentCanonOpCode::Future__new:
139
3.18k
  case ComponentCanonOpCode::Future__close_readable:
140
3.39k
  case ComponentCanonOpCode::Future__close_writable:
141
3.73k
  case ComponentCanonOpCode::Thread__spawn_ref: {
142
3.73k
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
143
3.67k
    C.setIndex(Idx);
144
3.67k
    break;
145
3.73k
  }
146
147
  // no-arg opcodes
148
1.98k
  case ComponentCanonOpCode::Backpressure__set:
149
2.35k
  case ComponentCanonOpCode::Task__cancel:
150
2.71k
  case ComponentCanonOpCode::Subtask__drop:
151
2.93k
  case ComponentCanonOpCode::Error_context__drop:
152
3.26k
  case ComponentCanonOpCode::Waitable_set__new:
153
5.74k
  case ComponentCanonOpCode::Waitable_set__drop:
154
5.97k
  case ComponentCanonOpCode::Waitable__join:
155
6.57k
  case ComponentCanonOpCode::Thread__available_parallelism:
156
6.57k
    break;
157
158
  // 0x09 rs:<resultlist> opts:<opts>
159
626
  case ComponentCanonOpCode::Task__return: {
160
    // Load resultlist (same encoding as functype resultlist).
161
626
    EXPECTED_TRY(uint8_t RFlag, FMgr.readByte().map_error(ReportError));
162
625
    switch (RFlag) {
163
88
    case 0x00: {
164
88
      ComponentValType VT;
165
88
      EXPECTED_TRY(loadType(VT).map_error([](auto E) {
166
81
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Canonical));
167
81
        return E;
168
81
      }));
169
81
      C.setResultList(VT);
170
81
      break;
171
88
    }
172
535
    case 0x01: {
173
535
      std::vector<AST::Component::LabelValType> ResultList;
174
535
      EXPECTED_TRY(loadVec<AST::Component::Canonical>(
175
498
          ResultList,
176
498
          [this](AST::Component::LabelValType &LV) { return loadType(LV); }));
177
498
      C.setResultList(std::move(ResultList));
178
498
      break;
179
535
    }
180
2
    default:
181
2
      return ReportError(ErrCode::Value::MalformedCanonical);
182
625
    }
183
579
    EXPECTED_TRY(LoadOpts());
184
559
    break;
185
579
  }
186
187
  // 0x0a 0x7f i:<u32> and 0x0b 0x7f i:<u32>
188
559
  case ComponentCanonOpCode::Context__get:
189
102
  case ComponentCanonOpCode::Context__set: {
190
102
    EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError));
191
95
    if (unlikely(B != 0x7f)) {
192
12
      return ReportError(ErrCode::Value::MalformedCanonical);
193
12
    }
194
83
    EXPECTED_TRY(uint32_t Val, FMgr.readU32().map_error(ReportError));
195
80
    C.setConstVal(Val);
196
80
    break;
197
83
  }
198
199
  // async?-only opcodes
200
104
  case ComponentCanonOpCode::Yield:
201
375
  case ComponentCanonOpCode::Subtask__cancel: {
202
375
    EXPECTED_TRY(LoadAsync());
203
363
    break;
204
375
  }
205
206
  // typeidx + opts opcodes
207
363
  case ComponentCanonOpCode::Stream__read:
208
286
  case ComponentCanonOpCode::Stream__write:
209
337
  case ComponentCanonOpCode::Future__read:
210
447
  case ComponentCanonOpCode::Future__write: {
211
447
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
212
434
    C.setIndex(Idx);
213
434
    EXPECTED_TRY(LoadOpts());
214
414
    break;
215
434
  }
216
217
  // typeidx + async? opcodes
218
414
  case ComponentCanonOpCode::Stream__cancel_read:
219
363
  case ComponentCanonOpCode::Stream__cancel_write:
220
825
  case ComponentCanonOpCode::Future__cancel_read:
221
881
  case ComponentCanonOpCode::Future__cancel_write: {
222
881
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
223
874
    C.setIndex(Idx);
224
874
    EXPECTED_TRY(LoadAsync());
225
859
    break;
226
874
  }
227
228
  // opts-only opcodes
229
859
  case ComponentCanonOpCode::Error_context__new:
230
120
  case ComponentCanonOpCode::Error_context__debug_message: {
231
120
    EXPECTED_TRY(LoadOpts());
232
106
    break;
233
120
  }
234
235
  // async? + memidx opcodes
236
261
  case ComponentCanonOpCode::Waitable_set__wait:
237
365
  case ComponentCanonOpCode::Waitable_set__poll: {
238
365
    EXPECTED_TRY(LoadAsync());
239
351
    EXPECTED_TRY(uint32_t MemIdx, FMgr.readU32().map_error(ReportError));
240
346
    C.setIndex(MemIdx);
241
346
    break;
242
351
  }
243
244
  // 0x41 ft:<typeidx> tbl:<core:tableidx>
245
319
  case ComponentCanonOpCode::Thread__spawn_indirect: {
246
319
    EXPECTED_TRY(uint32_t TypeIdx, FMgr.readU32().map_error(ReportError));
247
318
    C.setIndex(TypeIdx);
248
318
    EXPECTED_TRY(uint32_t TblIdx, FMgr.readU32().map_error(ReportError));
249
316
    C.setTargetIndex(TblIdx);
250
316
    break;
251
318
  }
252
253
41
  default:
254
41
    return ReportError(ErrCode::Value::MalformedCanonical);
255
22.1k
  }
256
21.7k
  C.setOpCode(Code);
257
21.7k
  return {};
258
22.1k
}
259
260
9.21k
Expect<void> Loader::loadCanonicalOption(AST::Component::CanonOpt &Opt) {
261
9.21k
  auto ReportError = [this](auto E) {
262
121
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_CanonOpt);
263
121
  };
component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonicalOption(WasmEdge::AST::Component::CanonOpt&)::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const
Line
Count
Source
261
65
  auto ReportError = [this](auto E) {
262
65
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_CanonOpt);
263
65
  };
component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonicalOption(WasmEdge::AST::Component::CanonOpt&)::$_0::operator()<WasmEdge::ErrCode::Value>(WasmEdge::ErrCode::Value) const
Line
Count
Source
261
56
  auto ReportError = [this](auto E) {
262
56
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_CanonOpt);
263
56
  };
264
  // canonopt ::= 0x00                  => string-encoding=utf8
265
  //            | 0x01                  => string-encoding=utf16
266
  //            | 0x02                  => string-encoding=latin1+utf16
267
  //            | 0x03 m:<core:memidx>  => (memory m)
268
  //            | 0x04 f:<core:funcidx> => (realloc f)
269
  //            | 0x05 f:<core:funcidx> => (post-return f)
270
  //            | 0x06                  => async ๐Ÿ”€
271
  //            | 0x07 f:<core:funcidx> => (callback f) ๐Ÿ”€
272
  //            | 0x08                  => always-task-return ๐Ÿ”€
273
274
9.21k
  EXPECTED_TRY(uint8_t Flag, FMgr.readByte().map_error(ReportError));
275
9.17k
  switch (Flag) {
276
4.83k
  case 0x00:
277
6.12k
  case 0x01:
278
6.52k
  case 0x02:
279
6.84k
  case 0x06:
280
8.12k
  case 0x08:
281
8.12k
    break;
282
214
  case 0x03:
283
464
  case 0x04:
284
753
  case 0x05:
285
990
  case 0x07: {
286
990
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
287
971
    Opt.setIndex(Idx);
288
971
    break;
289
990
  }
290
56
  default:
291
56
    return ReportError(ErrCode::Value::UnknownCanonicalOption);
292
9.17k
  }
293
9.09k
  Opt.setCode(static_cast<ComponentCanonOptCode>(Flag));
294
9.09k
  return {};
295
9.17k
}
296
297
} // namespace Loader
298
} // namespace WasmEdge