Coverage Report

Created: 2026-08-14 06:41

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
21.3k
Expect<void> Loader::loadCanonical(AST::Component::Canonical &C) {
10
21.3k
  auto ReportError = [this](auto E) {
11
359
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_Canonical);
12
359
  };
component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonical(WasmEdge::AST::Component::Canonical&)::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const
Line
Count
Source
10
248
  auto ReportError = [this](auto E) {
11
248
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_Canonical);
12
248
  };
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
111
  auto ReportError = [this](auto E) {
11
111
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_Canonical);
12
111
  };
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
21.3k
  auto LoadAsync = [this, &ReportError, &C]() -> Expect<void> {
78
890
    EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError));
79
865
    if (B == 0x00) {
80
488
      C.setAsync(false);
81
488
    } else if (B == 0x01) {
82
348
      C.setAsync(true);
83
348
    } else {
84
29
      return ReportError(ErrCode::Value::MalformedCanonical);
85
29
    }
86
836
    return {};
87
865
  };
88
89
  // Helper: load opts (vec of canonopt).
90
21.3k
  auto LoadOpts = [this, &C]() -> Expect<void> {
91
10.1k
    std::vector<AST::Component::CanonOpt> Opts;
92
10.1k
    EXPECTED_TRY(loadVec<AST::Component::Canonical>(
93
9.97k
        Opts, [this](AST::Component::CanonOpt &Opt) {
94
9.97k
          return loadCanonicalOption(Opt);
95
9.97k
        }));
96
9.97k
    C.setOptions(std::move(Opts));
97
9.97k
    return {};
98
10.1k
  };
99
100
21.3k
  EXPECTED_TRY(uint8_t Flag, FMgr.readByte().map_error(ReportError));
101
21.2k
  auto Code = static_cast<ComponentCanonOpCode>(Flag);
102
21.2k
  switch (Code) {
103
104
  // 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx>
105
5.64k
  case ComponentCanonOpCode::Lift: {
106
5.64k
    EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError));
107
5.63k
    if (unlikely(B != 0x00)) {
108
22
      return ReportError(ErrCode::Value::MalformedCanonical);
109
22
    }
110
11.2k
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
111
11.2k
    C.setIndex(Idx);
112
11.2k
    EXPECTED_TRY(LoadOpts());
113
5.55k
    EXPECTED_TRY(uint32_t TypeIdx, FMgr.readU32().map_error(ReportError));
114
5.55k
    C.setTargetIndex(TypeIdx);
115
5.55k
    break;
116
5.55k
  }
117
118
  // 0x01 0x00 f:<funcidx> opts:<opts>
119
2.43k
  case ComponentCanonOpCode::Lower: {
120
2.43k
    EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError));
121
2.42k
    if (unlikely(B != 0x00)) {
122
11
      return ReportError(ErrCode::Value::MalformedCanonical);
123
11
    }
124
4.83k
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
125
4.83k
    C.setIndex(Idx);
126
4.83k
    EXPECTED_TRY(LoadOpts());
127
2.39k
    break;
128
4.83k
  }
129
130
  // typeidx-only opcodes
131
2.39k
  case ComponentCanonOpCode::Resource__new:
132
2.93k
  case ComponentCanonOpCode::Resource__drop:
133
3.53k
  case ComponentCanonOpCode::Resource__drop_async:
134
4.31k
  case ComponentCanonOpCode::Resource__rep:
135
4.61k
  case ComponentCanonOpCode::Stream__new:
136
4.89k
  case ComponentCanonOpCode::Stream__close_readable:
137
5.14k
  case ComponentCanonOpCode::Stream__close_writable:
138
5.34k
  case ComponentCanonOpCode::Future__new:
139
5.55k
  case ComponentCanonOpCode::Future__close_readable:
140
5.77k
  case ComponentCanonOpCode::Future__close_writable:
141
5.98k
  case ComponentCanonOpCode::Thread__spawn_ref: {
142
5.98k
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
143
5.93k
    C.setIndex(Idx);
144
5.93k
    break;
145
5.98k
  }
146
147
  // no-arg opcodes
148
1.36k
  case ComponentCanonOpCode::Backpressure__set:
149
1.59k
  case ComponentCanonOpCode::Task__cancel:
150
1.80k
  case ComponentCanonOpCode::Subtask__drop:
151
2.05k
  case ComponentCanonOpCode::Error_context__drop:
152
2.49k
  case ComponentCanonOpCode::Waitable_set__new:
153
2.74k
  case ComponentCanonOpCode::Waitable_set__drop:
154
3.00k
  case ComponentCanonOpCode::Waitable__join:
155
3.65k
  case ComponentCanonOpCode::Thread__available_parallelism:
156
3.65k
    break;
157
158
  // 0x09 rs:<resultlist> opts:<opts>
159
1.34k
  case ComponentCanonOpCode::Task__return: {
160
    // Load resultlist (same encoding as functype resultlist).
161
1.34k
    EXPECTED_TRY(uint8_t RFlag, FMgr.readByte().map_error(ReportError));
162
1.34k
    switch (RFlag) {
163
163
    case 0x00: {
164
163
      ComponentValType VT;
165
163
      EXPECTED_TRY(loadType(VT).map_error([](auto E) {
166
155
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Canonical));
167
155
        return E;
168
155
      }));
169
155
      C.setResultList(VT);
170
155
      break;
171
163
    }
172
1.17k
    case 0x01: {
173
1.17k
      std::vector<AST::Component::LabelValType> ResultList;
174
1.17k
      EXPECTED_TRY(loadVec<AST::Component::Canonical>(
175
1.13k
          ResultList,
176
1.13k
          [this](AST::Component::LabelValType &LV) { return loadType(LV); }));
177
1.13k
      C.setResultList(std::move(ResultList));
178
1.13k
      break;
179
1.17k
    }
180
3
    default:
181
3
      return ReportError(ErrCode::Value::MalformedCanonical);
182
1.34k
    }
183
1.28k
    EXPECTED_TRY(LoadOpts());
184
1.26k
    break;
185
1.28k
  }
186
187
  // 0x0a 0x7f i:<u32> and 0x0b 0x7f i:<u32>
188
1.26k
  case ComponentCanonOpCode::Context__get:
189
133
  case ComponentCanonOpCode::Context__set: {
190
133
    EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError));
191
129
    if (unlikely(B != 0x7f)) {
192
10
      return ReportError(ErrCode::Value::MalformedCanonical);
193
10
    }
194
119
    EXPECTED_TRY(uint32_t Val, FMgr.readU32().map_error(ReportError));
195
118
    C.setConstVal(Val);
196
118
    break;
197
119
  }
198
199
  // async?-only opcodes
200
106
  case ComponentCanonOpCode::Yield:
201
235
  case ComponentCanonOpCode::Subtask__cancel: {
202
235
    EXPECTED_TRY(LoadAsync());
203
216
    break;
204
235
  }
205
206
  // typeidx + opts opcodes
207
216
  case ComponentCanonOpCode::Stream__read:
208
482
  case ComponentCanonOpCode::Stream__write:
209
568
  case ComponentCanonOpCode::Future__read:
210
621
  case ComponentCanonOpCode::Future__write: {
211
621
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
212
606
    C.setIndex(Idx);
213
606
    EXPECTED_TRY(LoadOpts());
214
564
    break;
215
606
  }
216
217
  // typeidx + async? opcodes
218
564
  case ComponentCanonOpCode::Stream__cancel_read:
219
167
  case ComponentCanonOpCode::Stream__cancel_write:
220
250
  case ComponentCanonOpCode::Future__cancel_read:
221
349
  case ComponentCanonOpCode::Future__cancel_write: {
222
349
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
223
337
    C.setIndex(Idx);
224
337
    EXPECTED_TRY(LoadAsync());
225
317
    break;
226
337
  }
227
228
  // opts-only opcodes
229
317
  case ComponentCanonOpCode::Error_context__new:
230
227
  case ComponentCanonOpCode::Error_context__debug_message: {
231
227
    EXPECTED_TRY(LoadOpts());
232
194
    break;
233
227
  }
234
235
  // async? + memidx opcodes
236
213
  case ComponentCanonOpCode::Waitable_set__wait:
237
318
  case ComponentCanonOpCode::Waitable_set__poll: {
238
318
    EXPECTED_TRY(LoadAsync());
239
303
    EXPECTED_TRY(uint32_t MemIdx, FMgr.readU32().map_error(ReportError));
240
301
    C.setIndex(MemIdx);
241
301
    break;
242
303
  }
243
244
  // 0x41 ft:<typeidx> tbl:<core:tableidx>
245
274
  case ComponentCanonOpCode::Thread__spawn_indirect: {
246
274
    EXPECTED_TRY(uint32_t TypeIdx, FMgr.readU32().map_error(ReportError));
247
273
    C.setIndex(TypeIdx);
248
273
    EXPECTED_TRY(uint32_t TblIdx, FMgr.readU32().map_error(ReportError));
249
269
    C.setTargetIndex(TblIdx);
250
269
    break;
251
273
  }
252
253
36
  default:
254
36
    return ReportError(ErrCode::Value::MalformedCanonical);
255
21.2k
  }
256
20.7k
  C.setOpCode(Code);
257
20.7k
  return {};
258
21.2k
}
259
260
9.72k
Expect<void> Loader::loadCanonicalOption(AST::Component::CanonOpt &Opt) {
261
9.72k
  auto ReportError = [this](auto E) {
262
108
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_CanonOpt);
263
108
  };
component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonicalOption(WasmEdge::AST::Component::CanonOpt&)::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const
Line
Count
Source
261
59
  auto ReportError = [this](auto E) {
262
59
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_CanonOpt);
263
59
  };
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
49
  auto ReportError = [this](auto E) {
262
49
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_CanonOpt);
263
49
  };
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.72k
  EXPECTED_TRY(uint8_t Flag, FMgr.readByte().map_error(ReportError));
275
9.68k
  switch (Flag) {
276
4.19k
  case 0x00:
277
6.57k
  case 0x01:
278
7.07k
  case 0x02:
279
7.34k
  case 0x06:
280
8.61k
  case 0x08:
281
8.61k
    break;
282
267
  case 0x03:
283
489
  case 0x04:
284
773
  case 0x05:
285
1.01k
  case 0x07: {
286
1.01k
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
287
995
    Opt.setIndex(Idx);
288
995
    break;
289
1.01k
  }
290
49
  default:
291
49
    return ReportError(ErrCode::Value::UnknownCanonicalOption);
292
9.68k
  }
293
9.61k
  Opt.setCode(static_cast<ComponentCanonOptCode>(Flag));
294
9.61k
  return {};
295
9.68k
}
296
297
} // namespace Loader
298
} // namespace WasmEdge