Coverage Report

Created: 2026-09-28 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/include/ast/component/canonical.h
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
//===-- wasmedge/ast/component/canonical.h - Canon class definitions ------===//
5
//
6
// Part of the WasmEdge Project.
7
//
8
//===----------------------------------------------------------------------===//
9
///
10
/// \file
11
/// This file contains the declaration of the Canon node related classes.
12
///
13
//===----------------------------------------------------------------------===//
14
#pragma once
15
16
#include "ast/component/valtype.h"
17
#include "common/enum_ast.hpp"
18
#include "common/span.h"
19
20
#include <cstdint>
21
#include <utility>
22
#include <vector>
23
24
namespace WasmEdge {
25
namespace AST {
26
namespace Component {
27
28
// canonopt ::= 0x00                  => string-encoding=utf8
29
//            | 0x01                  => string-encoding=utf16
30
//            | 0x02                  => string-encoding=latin1+utf16
31
//            | 0x03 m:<core:memidx>  => (memory m)
32
//            | 0x04 f:<core:funcidx> => (realloc f)
33
//            | 0x05 f:<core:funcidx> => (post-return f)
34
//            | 0x06                  => async ๐Ÿ”€
35
//            | 0x07 f:<core:funcidx> => (callback f) ๐Ÿ”€
36
37
/// AST Component::CanonOpt definition.
38
class CanonOpt {
39
public:
40
1.14M
  CanonOpt() noexcept : Code(ComponentCanonOptCode::Encode_UTF8), Idx(0) {}
41
42
16.3k
  ComponentCanonOptCode getCode() const noexcept { return Code; }
43
7.54k
  void setCode(const ComponentCanonOptCode C) noexcept { Code = C; }
44
45
314
  uint32_t getIndex() const noexcept { return Idx; }
46
1.38k
  void setIndex(const uint32_t I) noexcept { Idx = I; }
47
48
private:
49
  ComponentCanonOptCode Code;
50
  uint32_t Idx;
51
};
52
53
// canon ::= 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx>
54
//           => (canon lift f opts type-index-space[ft])
55
//         | 0x01 0x00 f:<funcidx> opts:<opts>
56
//           => (canon lower f opts (core func))
57
//         | 0x02 rt:<typeidx>    => (canon resource.new rt (core func))
58
//         | 0x03 rt:<typeidx>    => (canon resource.drop rt (core func))
59
//         | 0x04 rt:<typeidx>    => (canon resource.rep rt (core func))
60
//         | 0x09 rs:<resultlist> opts:<opts>
61
//           => (canon task.return rs opts (core func)) ๐Ÿ”€
62
//         | 0x05                 => (canon task.cancel (core func)) ๐Ÿ”€
63
//         | 0x0a t:<core:valtype> i:<u32>
64
//           => (canon context.get t i (core func)) ๐Ÿ”€
65
//         | 0x0b t:<core:valtype> i:<u32>
66
//           => (canon context.set t i (core func)) ๐Ÿ”€
67
//         | 0x0c cancel?:<cancel?>
68
//           => (canon thread.yield cancel? (core func)) ๐Ÿ”€
69
//         | 0x06 async?:<async?>
70
//           => (canon subtask.cancel async? (core func)) ๐Ÿ”€
71
//         | 0x0d                 => (canon subtask.drop (core func)) ๐Ÿ”€
72
//         | 0x0e t:<typeidx>     => (canon stream.new t (core func)) ๐Ÿ”€
73
//         | 0x0f t:<typeidx> opts:<opts>
74
//           => (canon stream.read t opts (core func)) ๐Ÿ”€
75
//         | 0x10 t:<typeidx> opts:<opts>
76
//           => (canon stream.write t opts (core func)) ๐Ÿ”€
77
//         | 0x11 t:<typeidx> async?:<async?>
78
//           => (canon stream.cancel-read t async? (core func)) ๐Ÿ”€
79
//         | 0x12 t:<typeidx> async?:<async?>
80
//           => (canon stream.cancel-write t async? (core func)) ๐Ÿ”€
81
//         | 0x13 t:<typeidx> => (canon stream.drop-readable t (core func)) ๐Ÿ”€
82
//         | 0x14 t:<typeidx> => (canon stream.drop-writable t (core func)) ๐Ÿ”€
83
//         | 0x15 t:<typeidx> => (canon future.new t (core func)) ๐Ÿ”€
84
//         | 0x16 t:<typeidx> opts:<opts>
85
//           => (canon future.read t opts (core func)) ๐Ÿ”€
86
//         | 0x17 t:<typeidx> opts:<opts>
87
//           => (canon future.write t opts (core func)) ๐Ÿ”€
88
//         | 0x18 t:<typeidx> async?:<async?>
89
//           => (canon future.cancel-read t async? (core func)) ๐Ÿ”€
90
//         | 0x19 t:<typeidx> async?:<async?>
91
//           => (canon future.cancel-write t async? (core func)) ๐Ÿ”€
92
//         | 0x1a t:<typeidx> => (canon future.drop-readable t (core func)) ๐Ÿ”€
93
//         | 0x1b t:<typeidx> => (canon future.drop-writable t (core func)) ๐Ÿ”€
94
//         | 0x1c opts:<opts> => (canon error-context.new opts (core func)) ๐Ÿ“
95
//         | 0x1d opts:<opts>
96
//           => (canon error-context.debug-message opts (core func)) ๐Ÿ“
97
//         | 0x1e                 => (canon error-context.drop (core func)) ๐Ÿ“
98
//         | 0x1f                 => (canon waitable-set.new (core func)) ๐Ÿ”€
99
//         | 0x20 cancel?:<cancel?> m:<core:memoryidx>
100
//           => (canon waitable-set.wait cancel? (memory m) (core func)) ๐Ÿ”€
101
//         | 0x21 cancel?:<cancel?> m:<core:memoryidx>
102
//           => (canon waitable-set.poll cancel? (memory m) (core func)) ๐Ÿ”€
103
//         | 0x22                 => (canon waitable-set.drop (core func)) ๐Ÿ”€
104
//         | 0x23                 => (canon waitable.join (core func)) ๐Ÿ”€
105
//         | 0x24                 => (canon backpressure.inc (core func)) ๐Ÿ”€
106
//         | 0x25                 => (canon backpressure.dec (core func)) ๐Ÿ”€
107
//         | 0x26                 => (canon thread.index (core func)) ๐Ÿงต
108
//         | 0x27 ft:<core:typeidx> tbl:<core:tableidx>
109
//           => (canon thread.new-indirect ft tbl (core func)) ๐Ÿงต
110
//         | 0x28                 => (canon thread.resume-later (core func)) ๐Ÿงต
111
//         | 0x29 cancel?:<cancel?>
112
//           => (canon thread.suspend cancel? (core func)) ๐Ÿงต
113
//         | 0x2a cancel?:<cancel?>
114
//           => (canon thread.suspend-then-resume cancel? (core func)) ๐Ÿงต
115
//         | 0x2b cancel?:<cancel?>
116
//           => (canon thread.yield-then-resume cancel? (core func)) ๐Ÿงต
117
//         | 0x2c cancel?:<cancel?>
118
//           => (canon thread.suspend-then-promote cancel? (core func)) ๐Ÿงต
119
//         | 0x2d cancel?:<cancel?>
120
//           => (canon thread.yield-then-promote cancel? (core func)) ๐Ÿงต
121
//         | 0x40 shared?:<sh?> ft:<core:typeidx>
122
//           => (canon thread.spawn-ref shared? ft (core func)) ๐Ÿงตโ‘ก
123
//         | 0x41 shared?:<sh?> ft:<core:typeidx> tbl:<core:tableidx>
124
//           => (canon thread.spawn-indirect shared? ft tbl (core func)) ๐Ÿงตโ‘ก
125
//         | 0x42 shared?:<sh?>
126
//           => (canon thread.available-parallelism shared? (core func)) ๐Ÿงตโ‘ก
127
// opts    ::= opt*:vec(<canonopt>) => opt*
128
// async?  ::= 0x00 => ฯต
129
//           | 0x01 => async
130
// cancel? ::= 0x00 => ฯต
131
//           | 0x01 => cancellable
132
// sh?     ::= 0x00 => ฯต
133
//           | 0x01 => shared ๐Ÿงตโ‘ก
134
135
// Currently implementing:
136
//   0x00 0x00 (canon lift f opts type-index-space[ft])
137
//   0x01 0x00 (canon lower f opts (core func))
138
//   0x02      (canon resource.new rt (core func))
139
//   0x03      (canon resource.drop rt (core func))
140
//   0x04      (canon resource.rep rt (core func))
141
142
class Canonical {
143
public:
144
161k
  Canonical() noexcept = default;
145
146
83.1k
  ComponentCanonOpCode getOpCode() const noexcept { return Code; }
147
68.3k
  void setOpCode(const ComponentCanonOpCode C) noexcept { Code = C; }
148
149
  // The one-byte flag immediate. It reads as `async?` on subtask.cancel and
150
  // the stream and future cancel forms, and as `cancel?` on thread.yield,
151
  // waitable-set.wait and poll, and the thread.suspend forms.
152
0
  bool getFlagImmediate() const noexcept { return FlagImm; }
153
4.14k
  void setFlagImmediate(const bool V) noexcept { FlagImm = V; }
154
155
38.8k
  uint32_t getIndex() const noexcept { return Idx; }
156
56.1k
  void setIndex(const uint32_t I) noexcept { Idx = I; }
157
158
5.53k
  uint32_t getTargetIndex() const noexcept { return TargetIdx; }
159
11.3k
  void setTargetIndex(const uint32_t I) noexcept { TargetIdx = I; }
160
161
1.90k
  uint32_t getConstVal() const noexcept { return I32; }
162
3.14k
  void setConstVal(const uint32_t V) noexcept { I32 = V; }
163
164
1.83k
  ValType getContextType() const noexcept { return CtxType; }
165
3.14k
  void setContextType(const ValType T) noexcept { CtxType = T; }
166
167
34.7k
  Span<const CanonOpt> getOptions() const noexcept { return Opts; }
168
  /// True when the definition carries the option OptCode.
169
15.5k
  bool hasOption(ComponentCanonOptCode OptCode) const noexcept {
170
15.5k
    for (const auto &Opt : Opts) {
171
5.04k
      if (Opt.getCode() == OptCode) {
172
26
        return true;
173
26
      }
174
5.04k
    }
175
15.5k
    return false;
176
15.5k
  }
177
16.4k
  void setOptions(std::vector<CanonOpt> &&List) noexcept {
178
16.4k
    Opts = std::move(List);
179
16.4k
  }
180
181
1.10k
  Span<const LabelValType> getResultList() const noexcept { return ResultList; }
182
394
  void setResultList(std::vector<LabelValType> &&R) noexcept {
183
394
    ResultList = std::move(R);
184
394
  }
185
1.30k
  void setResultList(const ComponentValType &VT) noexcept {
186
1.30k
    ResultList.clear();
187
1.30k
    ResultList.emplace_back(VT);
188
1.30k
  }
189
190
  /// The core function type of the canonical built-in Code, as the Explainer's
191
  /// synopsis tables give it, with AddrType for the address type of the memory
192
  /// the definition names, or of the table for thread.new-indirect.
193
  /// context.get and context.set take the context slot type, and task.return
194
  /// the lowered results, so their callers form those types themselves.
195
  static std::pair<std::vector<ValType>, std::vector<ValType>>
196
  getBuiltinCoreFuncType(ComponentCanonOpCode Code,
197
34.5k
                         const ValType &AddrType) noexcept {
198
34.5k
    const ValType I32(TypeCode::I32);
199
34.5k
    const ValType I64(TypeCode::I64);
200
34.5k
    switch (Code) {
201
64
    case ComponentCanonOpCode::Backpressure__inc:
202
282
    case ComponentCanonOpCode::Backpressure__dec:
203
373
    case ComponentCanonOpCode::Task__cancel:
204
373
      return {{}, {}};
205
81
    case ComponentCanonOpCode::Yield:
206
350
    case ComponentCanonOpCode::Waitable_set__new:
207
611
    case ComponentCanonOpCode::Thread__index:
208
1.31k
    case ComponentCanonOpCode::Thread__suspend:
209
1.31k
      return {{}, {I32}};
210
0
    case ComponentCanonOpCode::Waitable_set__wait:
211
0
    case ComponentCanonOpCode::Waitable_set__poll:
212
0
      return {{I32, AddrType}, {I32}};
213
116
    case ComponentCanonOpCode::Waitable_set__drop:
214
892
    case ComponentCanonOpCode::Subtask__drop:
215
994
    case ComponentCanonOpCode::Stream__drop_readable:
216
1.60k
    case ComponentCanonOpCode::Stream__drop_writable:
217
1.74k
    case ComponentCanonOpCode::Future__drop_readable:
218
2.94k
    case ComponentCanonOpCode::Future__drop_writable:
219
3.08k
    case ComponentCanonOpCode::Error_context__drop:
220
3.11k
    case ComponentCanonOpCode::Thread__resume_later:
221
3.11k
      return {{I32}, {}};
222
270
    case ComponentCanonOpCode::Waitable__join:
223
270
      return {{I32, I32}, {}};
224
88
    case ComponentCanonOpCode::Subtask__cancel:
225
559
    case ComponentCanonOpCode::Stream__cancel_read:
226
627
    case ComponentCanonOpCode::Stream__cancel_write:
227
708
    case ComponentCanonOpCode::Future__cancel_read:
228
941
    case ComponentCanonOpCode::Future__cancel_write:
229
1.42k
    case ComponentCanonOpCode::Thread__yield_then_resume:
230
1.51k
    case ComponentCanonOpCode::Thread__suspend_then_resume:
231
1.59k
    case ComponentCanonOpCode::Thread__yield_then_promote:
232
1.96k
    case ComponentCanonOpCode::Thread__suspend_then_promote:
233
1.96k
      return {{I32}, {I32}};
234
66
    case ComponentCanonOpCode::Stream__new:
235
26.7k
    case ComponentCanonOpCode::Future__new:
236
26.7k
      return {{}, {I64}};
237
276
    case ComponentCanonOpCode::Stream__read:
238
621
    case ComponentCanonOpCode::Stream__write:
239
621
      return {{I32, AddrType, AddrType}, {AddrType}};
240
128
    case ComponentCanonOpCode::Future__read:
241
201
    case ComponentCanonOpCode::Future__write:
242
201
      return {{I32, AddrType}, {I32}};
243
0
    case ComponentCanonOpCode::Error_context__new:
244
0
      return {{AddrType, AddrType}, {I32}};
245
0
    case ComponentCanonOpCode::Error_context__debug_message:
246
0
      return {{I32, AddrType}, {}};
247
0
    case ComponentCanonOpCode::Thread__new_indirect:
248
0
      return {{AddrType, I32}, {I32}};
249
0
    default:
250
0
      assumingUnreachable();
251
34.5k
    }
252
34.5k
  }
253
254
private:
255
  ComponentCanonOpCode Code = ComponentCanonOpCode::Lift;
256
  bool FlagImm = false;
257
  uint32_t Idx = 0, TargetIdx = 0;
258
  uint32_t I32 = 0;
259
  ValType CtxType = TypeCode::I32;
260
  std::vector<CanonOpt> Opts;
261
  std::vector<LabelValType> ResultList;
262
};
263
264
} // namespace Component
265
} // namespace AST
266
} // namespace WasmEdge