Coverage Report

Created: 2026-11-12 06:35

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/component_valtype.h"
18
#include "common/enum_ast.hpp"
19
#include "common/span.h"
20
#include "common/types.h"
21
22
#include <cstdint>
23
#include <optional>
24
#include <utility>
25
#include <vector>
26
27
namespace WasmEdge {
28
namespace AST {
29
namespace Component {
30
31
// canonopt ::= 0x00                  => string-encoding=utf8
32
//            | 0x01                  => string-encoding=utf16
33
//            | 0x02                  => string-encoding=latin1+utf16
34
//            | 0x03 m:<core:memidx>  => (memory m)
35
//            | 0x04 f:<core:funcidx> => (realloc f)
36
//            | 0x05 f:<core:funcidx> => (post-return f)
37
//            | 0x06                  => async ๐Ÿ”€
38
//            | 0x07 f:<core:funcidx> => (callback f) ๐Ÿ”€
39
40
/// AST Component::CanonOpt definition.
41
class CanonOpt {
42
public:
43
1.56M
  CanonOpt() noexcept : Code(ComponentCanonOptCode::Encode_UTF8), Idx(0) {}
44
45
40.0k
  ComponentCanonOptCode getCode() const noexcept { return Code; }
46
11.5k
  void setCode(const ComponentCanonOptCode C) noexcept { Code = C; }
47
48
460
  uint32_t getIndex() const noexcept { return Idx; }
49
1.42k
  void setIndex(const uint32_t I) noexcept { Idx = I; }
50
51
private:
52
  ComponentCanonOptCode Code;
53
  uint32_t Idx;
54
};
55
56
// canon ::= 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx>
57
//           => (canon lift f opts type-index-space[ft])
58
//         | 0x01 0x00 f:<funcidx> opts:<opts>
59
//           => (canon lower f opts (core func))
60
//         | 0x02 rt:<typeidx>    => (canon resource.new rt (core func))
61
//         | 0x03 rt:<typeidx>    => (canon resource.drop rt (core func))
62
//         | 0x04 rt:<typeidx>    => (canon resource.rep rt (core func))
63
//         | 0x09 rs:<resultlist> opts:<opts>
64
//           => (canon task.return rs opts (core func)) ๐Ÿ”€
65
//         | 0x05                 => (canon task.cancel (core func)) ๐Ÿ”€
66
//         | 0x0a t:<core:valtype> i:<u32>
67
//           => (canon context.get t i (core func)) ๐Ÿ”€
68
//         | 0x0b t:<core:valtype> i:<u32>
69
//           => (canon context.set t i (core func)) ๐Ÿ”€
70
//         | 0x0c 0x00
71
//           => (canon thread.yield (core func)) ๐Ÿ”€
72
//         | 0x06 async?:<async?>
73
//           => (canon subtask.cancel async? (core func)) ๐Ÿ”€
74
//         | 0x0d                 => (canon subtask.drop (core func)) ๐Ÿ”€
75
//         | 0x0e t:<typeidx>     => (canon stream.new t (core func)) ๐Ÿ”€
76
//         | 0x0f t:<typeidx> opts:<opts>
77
//           => (canon stream.read t opts (core func)) ๐Ÿ”€
78
//         | 0x10 t:<typeidx> opts:<opts>
79
//           => (canon stream.write t opts (core func)) ๐Ÿ”€
80
//         | 0x11 t:<typeidx> async?:<async?>
81
//           => (canon stream.cancel-read t async? (core func)) ๐Ÿ”€
82
//         | 0x12 t:<typeidx> async?:<async?>
83
//           => (canon stream.cancel-write t async? (core func)) ๐Ÿ”€
84
//         | 0x13 t:<typeidx> => (canon stream.drop-readable t (core func)) ๐Ÿ”€
85
//         | 0x14 t:<typeidx> => (canon stream.drop-writable t (core func)) ๐Ÿ”€
86
//         | 0x2e t:<typeidx> => (canon stream.forward t (core func)) โžก๏ธ
87
//         | 0x15 t:<typeidx> => (canon future.new t (core func)) ๐Ÿ”€
88
//         | 0x16 t:<typeidx> opts:<opts>
89
//           => (canon future.read t opts (core func)) ๐Ÿ”€
90
//         | 0x17 t:<typeidx> opts:<opts>
91
//           => (canon future.write t opts (core func)) ๐Ÿ”€
92
//         | 0x18 t:<typeidx> async?:<async?>
93
//           => (canon future.cancel-read t async? (core func)) ๐Ÿ”€
94
//         | 0x19 t:<typeidx> async?:<async?>
95
//           => (canon future.cancel-write t async? (core func)) ๐Ÿ”€
96
//         | 0x1a t:<typeidx> => (canon future.drop-readable t (core func)) ๐Ÿ”€
97
//         | 0x1b t:<typeidx> => (canon future.drop-writable t (core func)) ๐Ÿ”€
98
//         | 0x2f t:<typeidx> => (canon future.forward t (core func)) โžก๏ธ
99
//         | 0x1c opts:<opts> => (canon error-context.new opts (core func)) ๐Ÿ“
100
//         | 0x1d opts:<opts>
101
//           => (canon error-context.debug-message opts (core func)) ๐Ÿ“
102
//         | 0x1e                 => (canon error-context.drop (core func)) ๐Ÿ“
103
//         | 0x1f                 => (canon waitable-set.new (core func)) ๐Ÿ”€
104
//         | 0x20 0x00 m:<core:memoryidx>
105
//           => (canon waitable-set.wait (memory m) (core func)) ๐Ÿ”€
106
//         | 0x21 0x00 m:<core:memoryidx>
107
//           => (canon waitable-set.poll (memory m) (core func)) ๐Ÿ”€
108
//         | 0x22                 => (canon waitable-set.drop (core func)) ๐Ÿ”€
109
//         | 0x23                 => (canon waitable.join (core func)) ๐Ÿ”€
110
//         | 0x24                 => (canon backpressure.inc (core func)) ๐Ÿ”€
111
//         | 0x25                 => (canon backpressure.dec (core func)) ๐Ÿ”€
112
//         | 0x26                 => (canon thread.index (core func)) ๐Ÿงต
113
//         | 0x27 ft:<core:typeidx> t:<core:tableidx>
114
//           => (canon thread.new-indirect ft t (core func)) ๐Ÿงต
115
//         | 0x28                 => (canon thread.resume-later (core func)) ๐Ÿงต
116
//         | 0x29 0x00
117
//           => (canon thread.suspend (core func)) ๐Ÿงต
118
//         | 0x2a 0x00
119
//           => (canon thread.suspend-then-resume (core func)) ๐Ÿงต
120
//         | 0x2b 0x00
121
//           => (canon thread.yield-then-resume (core func)) ๐Ÿงต
122
//         | 0x2c 0x00
123
//           => (canon thread.suspend-then-promote (core func)) ๐Ÿงต
124
//         | 0x2d 0x00
125
//           => (canon thread.yield-then-promote (core func)) ๐Ÿงต
126
//         | 0x40 sh?:<sh?> ft:<core:typeidx>
127
//           => (canon thread.spawn-ref sh? ft (core func)) ๐Ÿงตโ‘ก
128
//         | 0x41 sh?:<sh?> ft:<core:typeidx> t:<core:tableidx>
129
//           => (canon thread.spawn-indirect sh? ft t (core func)) ๐Ÿงตโ‘ก
130
//         | 0x42 sh?:<sh?>
131
//           => (canon thread.available-parallelism sh? (core func)) ๐Ÿงตโ‘ก
132
// opts    ::= opt*:vec(<canonopt>) => opt*
133
// async?  ::= 0x00 => ฯต
134
//           | 0x01 => async
135
// sh?     ::= 0x00 => ฯต
136
//           | 0x01 => shared ๐Ÿงตโ‘ก
137
138
// Currently implementing:
139
//   0x00 0x00 (canon lift f opts type-index-space[ft])
140
//   0x01 0x00 (canon lower f opts (core func))
141
//   0x02      (canon resource.new rt (core func))
142
//   0x03      (canon resource.drop rt (core func))
143
//   0x04      (canon resource.rep rt (core func))
144
145
class Canonical {
146
public:
147
2.93M
  Canonical() noexcept = default;
148
149
535k
  ComponentCanonOpCode getOpCode() const noexcept { return Code; }
150
322k
  void setOpCode(const ComponentCanonOpCode C) noexcept { Code = C; }
151
152
  // The `async?` immediate of subtask.cancel and the stream and future cancel
153
  // forms.
154
0
  bool getFlagImmediate() const noexcept { return FlagImm; }
155
6.30k
  void setFlagImmediate(const bool V) noexcept { FlagImm = V; }
156
157
213k
  uint32_t getIndex() const noexcept { return Idx; }
158
250k
  void setIndex(const uint32_t I) noexcept { Idx = I; }
159
160
8.09k
  uint32_t getTargetIndex() const noexcept { return TargetIdx; }
161
9.09k
  void setTargetIndex(const uint32_t I) noexcept { TargetIdx = I; }
162
163
2.58k
  uint32_t getConstVal() const noexcept { return I32; }
164
3.24k
  void setConstVal(const uint32_t V) noexcept { I32 = V; }
165
166
2.48k
  ValType getContextType() const noexcept { return CtxType; }
167
3.24k
  void setContextType(const ValType T) noexcept { CtxType = T; }
168
169
57.1k
  Span<const CanonOpt> getOptions() const noexcept { return Opts; }
170
  /// True when the definition carries the option OptCode.
171
28.3k
  bool hasOption(ComponentCanonOptCode OptCode) const noexcept {
172
28.3k
    for (const auto &Opt : Opts) {
173
15.1k
      if (Opt.getCode() == OptCode) {
174
719
        return true;
175
719
      }
176
15.1k
    }
177
27.5k
    return false;
178
28.3k
  }
179
19.3k
  void setOptions(std::vector<CanonOpt> &&List) noexcept {
180
19.3k
    Opts = std::move(List);
181
19.3k
  }
182
183
  /// The result type of task.return; none for no result.
184
8.38k
  const std::optional<ComponentValType> &getResult() const noexcept {
185
8.38k
    return Result;
186
8.38k
  }
187
4.53k
  void setResult(std::optional<ComponentValType> R) noexcept { Result = R; }
188
189
  /// The core function type of the canonical built-in Code, as the Explainer's
190
  /// synopsis tables give it, with AddrType for the address type of the memory
191
  /// the definition names, or of the table for thread.new-indirect.
192
  /// context.get and context.set take the context slot type, and task.return
193
  /// the lowered results, so their callers form those types themselves.
194
  static std::pair<std::vector<ValType>, std::vector<ValType>>
195
  getBuiltinCoreFuncType(ComponentCanonOpCode Code,
196
256k
                         const ValType &AddrType) noexcept {
197
256k
    const ValType I32(TypeCode::I32);
198
256k
    const ValType I64(TypeCode::I64);
199
256k
    switch (Code) {
200
181
    case ComponentCanonOpCode::Backpressure__inc:
201
434
    case ComponentCanonOpCode::Backpressure__dec:
202
595
    case ComponentCanonOpCode::Task__cancel:
203
595
      return {{}, {}};
204
35
    case ComponentCanonOpCode::Thread__yield:
205
2.52k
    case ComponentCanonOpCode::Waitable_set__new:
206
2.97k
    case ComponentCanonOpCode::Thread__index:
207
3.17k
    case ComponentCanonOpCode::Thread__suspend:
208
3.17k
      return {{}, {I32}};
209
0
    case ComponentCanonOpCode::Waitable_set__wait:
210
0
    case ComponentCanonOpCode::Waitable_set__poll:
211
0
      return {{I32, AddrType}, {I32}};
212
67
    case ComponentCanonOpCode::Waitable_set__drop:
213
3.66k
    case ComponentCanonOpCode::Subtask__drop:
214
3.86k
    case ComponentCanonOpCode::Stream__drop_readable:
215
3.92k
    case ComponentCanonOpCode::Stream__drop_writable:
216
4.00k
    case ComponentCanonOpCode::Future__drop_readable:
217
178k
    case ComponentCanonOpCode::Future__drop_writable:
218
179k
    case ComponentCanonOpCode::Error_context__drop:
219
179k
    case ComponentCanonOpCode::Thread__resume_later:
220
179k
      return {{I32}, {}};
221
387
    case ComponentCanonOpCode::Waitable__join:
222
453
    case ComponentCanonOpCode::Stream__forward:
223
1.82k
    case ComponentCanonOpCode::Future__forward:
224
1.82k
      return {{I32, I32}, {}};
225
132
    case ComponentCanonOpCode::Subtask__cancel:
226
841
    case ComponentCanonOpCode::Stream__cancel_read:
227
1.17k
    case ComponentCanonOpCode::Stream__cancel_write:
228
1.68k
    case ComponentCanonOpCode::Future__cancel_read:
229
5.11k
    case ComponentCanonOpCode::Future__cancel_write:
230
5.44k
    case ComponentCanonOpCode::Thread__yield_then_resume:
231
6.58k
    case ComponentCanonOpCode::Thread__suspend_then_resume:
232
6.64k
    case ComponentCanonOpCode::Thread__yield_then_promote:
233
51.5k
    case ComponentCanonOpCode::Thread__suspend_then_promote:
234
51.5k
      return {{I32}, {I32}};
235
415
    case ComponentCanonOpCode::Stream__new:
236
18.8k
    case ComponentCanonOpCode::Future__new:
237
18.8k
      return {{}, {I64}};
238
67
    case ComponentCanonOpCode::Stream__read:
239
999
    case ComponentCanonOpCode::Stream__write:
240
999
      return {{I32, AddrType, AddrType}, {AddrType}};
241
208
    case ComponentCanonOpCode::Future__read:
242
274
    case ComponentCanonOpCode::Future__write:
243
274
      return {{I32, AddrType}, {I32}};
244
0
    case ComponentCanonOpCode::Error_context__new:
245
0
      return {{AddrType, AddrType}, {I32}};
246
0
    case ComponentCanonOpCode::Error_context__debug_message:
247
0
      return {{I32, AddrType}, {}};
248
0
    case ComponentCanonOpCode::Thread__new_indirect:
249
0
      return {{AddrType, I32}, {I32}};
250
0
    default:
251
0
      assumingUnreachable();
252
256k
    }
253
256k
  }
254
255
private:
256
  ComponentCanonOpCode Code = ComponentCanonOpCode::Lift;
257
  bool FlagImm = false;
258
  uint32_t Idx = 0, TargetIdx = 0;
259
  uint32_t I32 = 0;
260
  ValType CtxType = TypeCode::I32;
261
  std::vector<CanonOpt> Opts;
262
  std::optional<ComponentValType> Result;
263
};
264
265
} // namespace Component
266
} // namespace AST
267
} // namespace WasmEdge