Coverage Report

Created: 2026-08-13 06: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
20.4k
Expect<void> Loader::loadCanonical(AST::Component::Canonical &C) {
10
20.4k
  auto ReportError = [this](auto E) {
11
296
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_Canonical);
12
296
  };
component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonical(WasmEdge::AST::Component::Canonical&)::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const
Line
Count
Source
10
187
  auto ReportError = [this](auto E) {
11
187
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_Canonical);
12
187
  };
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
109
  auto ReportError = [this](auto E) {
11
109
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_Canonical);
12
109
  };
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
20.4k
  auto LoadAsync = [this, &ReportError, &C]() -> Expect<void> {
78
938
    EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError));
79
923
    if (B == 0x00) {
80
531
      C.setAsync(false);
81
531
    } else if (B == 0x01) {
82
357
      C.setAsync(true);
83
357
    } else {
84
35
      return ReportError(ErrCode::Value::MalformedCanonical);
85
35
    }
86
888
    return {};
87
923
  };
88
89
  // Helper: load opts (vec of canonopt).
90
20.4k
  auto LoadOpts = [this, &C]() -> Expect<void> {
91
8.67k
    std::vector<AST::Component::CanonOpt> Opts;
92
8.67k
    EXPECTED_TRY(loadVec<AST::Component::Canonical>(
93
8.53k
        Opts, [this](AST::Component::CanonOpt &Opt) {
94
8.53k
          return loadCanonicalOption(Opt);
95
8.53k
        }));
96
8.53k
    C.setOptions(std::move(Opts));
97
8.53k
    return {};
98
8.67k
  };
99
100
20.4k
  EXPECTED_TRY(uint8_t Flag, FMgr.readByte().map_error(ReportError));
101
20.3k
  auto Code = static_cast<ComponentCanonOpCode>(Flag);
102
20.3k
  switch (Code) {
103
104
  // 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx>
105
4.28k
  case ComponentCanonOpCode::Lift: {
106
4.28k
    EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError));
107
4.27k
    if (unlikely(B != 0x00)) {
108
28
      return ReportError(ErrCode::Value::MalformedCanonical);
109
28
    }
110
8.49k
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
111
8.49k
    C.setIndex(Idx);
112
8.49k
    EXPECTED_TRY(LoadOpts());
113
4.21k
    EXPECTED_TRY(uint32_t TypeIdx, FMgr.readU32().map_error(ReportError));
114
4.20k
    C.setTargetIndex(TypeIdx);
115
4.20k
    break;
116
4.21k
  }
117
118
  // 0x01 0x00 f:<funcidx> opts:<opts>
119
2.17k
  case ComponentCanonOpCode::Lower: {
120
2.17k
    EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError));
121
2.16k
    if (unlikely(B != 0x00)) {
122
7
      return ReportError(ErrCode::Value::MalformedCanonical);
123
7
    }
124
4.31k
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
125
4.31k
    C.setIndex(Idx);
126
4.31k
    EXPECTED_TRY(LoadOpts());
127
2.14k
    break;
128
4.31k
  }
129
130
  // typeidx-only opcodes
131
2.14k
  case ComponentCanonOpCode::Resource__new:
132
3.37k
  case ComponentCanonOpCode::Resource__drop:
133
3.72k
  case ComponentCanonOpCode::Resource__drop_async:
134
4.51k
  case ComponentCanonOpCode::Resource__rep:
135
4.99k
  case ComponentCanonOpCode::Stream__new:
136
5.27k
  case ComponentCanonOpCode::Stream__close_readable:
137
5.91k
  case ComponentCanonOpCode::Stream__close_writable:
138
6.13k
  case ComponentCanonOpCode::Future__new:
139
6.43k
  case ComponentCanonOpCode::Future__close_readable:
140
6.63k
  case ComponentCanonOpCode::Future__close_writable:
141
6.86k
  case ComponentCanonOpCode::Thread__spawn_ref: {
142
6.86k
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
143
6.82k
    C.setIndex(Idx);
144
6.82k
    break;
145
6.86k
  }
146
147
  // no-arg opcodes
148
1.46k
  case ComponentCanonOpCode::Backpressure__set:
149
1.72k
  case ComponentCanonOpCode::Task__cancel:
150
1.80k
  case ComponentCanonOpCode::Subtask__drop:
151
2.07k
  case ComponentCanonOpCode::Error_context__drop:
152
2.30k
  case ComponentCanonOpCode::Waitable_set__new:
153
2.57k
  case ComponentCanonOpCode::Waitable_set__drop:
154
2.77k
  case ComponentCanonOpCode::Waitable__join:
155
3.33k
  case ComponentCanonOpCode::Thread__available_parallelism:
156
3.33k
    break;
157
158
  // 0x09 rs:<resultlist> opts:<opts>
159
1.38k
  case ComponentCanonOpCode::Task__return: {
160
    // Load resultlist (same encoding as functype resultlist).
161
1.38k
    EXPECTED_TRY(uint8_t RFlag, FMgr.readByte().map_error(ReportError));
162
1.38k
    switch (RFlag) {
163
313
    case 0x00: {
164
313
      ComponentValType VT;
165
313
      EXPECTED_TRY(loadType(VT).map_error([](auto E) {
166
307
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Canonical));
167
307
        return E;
168
307
      }));
169
307
      C.setResultList(VT);
170
307
      break;
171
313
    }
172
1.07k
    case 0x01: {
173
1.07k
      std::vector<AST::Component::LabelValType> ResultList;
174
1.07k
      EXPECTED_TRY(loadVec<AST::Component::Canonical>(
175
1.03k
          ResultList,
176
1.03k
          [this](AST::Component::LabelValType &LV) { return loadType(LV); }));
177
1.03k
      C.setResultList(std::move(ResultList));
178
1.03k
      break;
179
1.07k
    }
180
1
    default:
181
1
      return ReportError(ErrCode::Value::MalformedCanonical);
182
1.38k
    }
183
1.34k
    EXPECTED_TRY(LoadOpts());
184
1.32k
    break;
185
1.34k
  }
186
187
  // 0x0a 0x7f i:<u32> and 0x0b 0x7f i:<u32>
188
1.32k
  case ComponentCanonOpCode::Context__get:
189
142
  case ComponentCanonOpCode::Context__set: {
190
142
    EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError));
191
138
    if (unlikely(B != 0x7f)) {
192
4
      return ReportError(ErrCode::Value::MalformedCanonical);
193
4
    }
194
134
    EXPECTED_TRY(uint32_t Val, FMgr.readU32().map_error(ReportError));
195
133
    C.setConstVal(Val);
196
133
    break;
197
134
  }
198
199
  // async?-only opcodes
200
129
  case ComponentCanonOpCode::Yield:
201
248
  case ComponentCanonOpCode::Subtask__cancel: {
202
248
    EXPECTED_TRY(LoadAsync());
203
229
    break;
204
248
  }
205
206
  // typeidx + opts opcodes
207
229
  case ComponentCanonOpCode::Stream__read:
208
560
  case ComponentCanonOpCode::Stream__write:
209
639
  case ComponentCanonOpCode::Future__read:
210
676
  case ComponentCanonOpCode::Future__write: {
211
676
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
212
663
    C.setIndex(Idx);
213
663
    EXPECTED_TRY(LoadOpts());
214
624
    break;
215
663
  }
216
217
  // typeidx + async? opcodes
218
624
  case ComponentCanonOpCode::Stream__cancel_read:
219
173
  case ComponentCanonOpCode::Stream__cancel_write:
220
255
  case ComponentCanonOpCode::Future__cancel_read:
221
357
  case ComponentCanonOpCode::Future__cancel_write: {
222
357
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
223
351
    C.setIndex(Idx);
224
351
    EXPECTED_TRY(LoadAsync());
225
336
    break;
226
351
  }
227
228
  // opts-only opcodes
229
336
  case ComponentCanonOpCode::Error_context__new:
230
265
  case ComponentCanonOpCode::Error_context__debug_message: {
231
265
    EXPECTED_TRY(LoadOpts());
232
236
    break;
233
265
  }
234
235
  // async? + memidx opcodes
236
236
  case ComponentCanonOpCode::Waitable_set__wait:
237
339
  case ComponentCanonOpCode::Waitable_set__poll: {
238
339
    EXPECTED_TRY(LoadAsync());
239
323
    EXPECTED_TRY(uint32_t MemIdx, FMgr.readU32().map_error(ReportError));
240
321
    C.setIndex(MemIdx);
241
321
    break;
242
323
  }
243
244
  // 0x41 ft:<typeidx> tbl:<core:tableidx>
245
246
  case ComponentCanonOpCode::Thread__spawn_indirect: {
246
246
    EXPECTED_TRY(uint32_t TypeIdx, FMgr.readU32().map_error(ReportError));
247
244
    C.setIndex(TypeIdx);
248
244
    EXPECTED_TRY(uint32_t TblIdx, FMgr.readU32().map_error(ReportError));
249
242
    C.setTargetIndex(TblIdx);
250
242
    break;
251
244
  }
252
253
34
  default:
254
34
    return ReportError(ErrCode::Value::MalformedCanonical);
255
20.3k
  }
256
19.9k
  C.setOpCode(Code);
257
19.9k
  return {};
258
20.3k
}
259
260
9.64k
Expect<void> Loader::loadCanonicalOption(AST::Component::CanonOpt &Opt) {
261
9.64k
  auto ReportError = [this](auto E) {
262
87
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_CanonOpt);
263
87
  };
component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonicalOption(WasmEdge::AST::Component::CanonOpt&)::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const
Line
Count
Source
261
45
  auto ReportError = [this](auto E) {
262
45
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_CanonOpt);
263
45
  };
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
42
  auto ReportError = [this](auto E) {
262
42
    return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_CanonOpt);
263
42
  };
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.64k
  EXPECTED_TRY(uint8_t Flag, FMgr.readByte().map_error(ReportError));
275
9.61k
  switch (Flag) {
276
4.14k
  case 0x00:
277
6.46k
  case 0x01:
278
6.75k
  case 0x02:
279
7.06k
  case 0x06:
280
8.51k
  case 0x08:
281
8.51k
    break;
282
284
  case 0x03:
283
551
  case 0x04:
284
814
  case 0x05:
285
1.05k
  case 0x07: {
286
1.05k
    EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError));
287
1.03k
    Opt.setIndex(Idx);
288
1.03k
    break;
289
1.05k
  }
290
42
  default:
291
42
    return ReportError(ErrCode::Value::UnknownCanonicalOption);
292
9.61k
  }
293
9.55k
  Opt.setCode(static_cast<ComponentCanonOptCode>(Flag));
294
9.55k
  return {};
295
9.61k
}
296
297
} // namespace Loader
298
} // namespace WasmEdge