Coverage Report

Created: 2026-09-28 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/include/executor/component/canonical_abi.h
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: 2019-2024 Second State INC
3
4
//===-- wasmedge/executor/component/canonical_abi.h -----------------------===//
5
//
6
// Part of the WasmEdge Project.
7
//
8
//===----------------------------------------------------------------------===//
9
///
10
/// \file
11
/// Component Model Canonical ABI helpers (Preview 2, sync only):
12
///   - alignment / elem_size / flatten_type / flatten_functype
13
///   - load / store / lift_flat / lower_flat
14
///
15
/// Spec citations refer to
16
/// https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md
17
///
18
//===----------------------------------------------------------------------===//
19
#pragma once
20
21
#include "ast/component/type.h"
22
#include "common/errcode.h"
23
#include "common/expected.h"
24
#include "common/types.h"
25
#include "runtime/instance/component/component.h"
26
#include "runtime/instance/function.h"
27
#include "runtime/instance/memory.h"
28
29
#include <cstdint>
30
#include <optional>
31
32
namespace WasmEdge {
33
namespace Executor {
34
35
// Forward declaration: store / lowerFlat invoke the guest `realloc` through
36
// Executor::invoke when allocating list / string return areas. Pulling in
37
// executor/executor.h here would form a header cycle, so the call is routed
38
// through this forward-declared pointer instead.
39
class Executor;
40
41
namespace CanonicalABI {
42
43
/// Sync ABI limits (CanonicalABI.md L2815-2817).
44
constexpr uint32_t MaxFlatParams = 16;
45
constexpr uint32_t MaxFlatResults = 1;
46
47
/// Context bundle for canonical-ABI operations. Not every helper requires every
48
/// field — alignment / elem_size / flatten_* only need CompInst to resolve type
49
/// indices; load / store / lift_flat / lower_flat additionally require Mem (and
50
/// Realloc + Exec when allocating list / string return areas, since the
51
/// allocation goes through Executor::invoke on the guest's `realloc` core
52
/// function).
53
struct CanonCtx {
54
  Executor *Exec = nullptr;
55
  Runtime::Instance::MemoryInstance *Mem = nullptr;
56
  Runtime::Instance::FunctionInstance *Realloc = nullptr;
57
  const Runtime::Instance::ComponentInstance *CompInst = nullptr;
58
  /// Guest string encoding for the canon function this context serves
59
  /// (CanonicalABI.md `string-encoding` option). Selects the byte layout used
60
  /// by load / store / lift_flat / lower_flat for `string` values. Defaults to
61
  /// UTF-8; type-only callers (alignment / flatten) never read it.
62
  StringEncoding Enc = StringEncoding::UTF8;
63
};
64
65
/// Resolve a component type index against the component instance.
66
inline const AST::Component::DefType *resolveDefType(const CanonCtx &Cx,
67
0
                                                     uint32_t Idx) noexcept {
68
0
  if (Cx.CompInst != nullptr) {
69
0
    return Cx.CompInst->getType(Idx);
70
0
  }
71
0
  return nullptr;
72
0
}
73
74
/// Discriminant byte width for a variant / enum with NumCases cases.
75
/// CanonicalABI.md L1951-1956 (`def discriminant_type`).
76
uint32_t discriminantSize(uint32_t NumCases) noexcept;
77
78
/// Alignment of a Component Model value type T (ptr_type = i32, deferred).
79
/// CanonicalABI.md L1904-1985.
80
Expect<uint32_t> alignment(const CanonCtx &Cx,
81
                           const ComponentValType &T) noexcept;
82
83
/// Alignment of a defined value type — internal recursion helper. Public so
84
/// callers that already hold a DefValType (e.g., synthesized result tuple)
85
/// can avoid the typeindex round-trip.
86
/// CanonicalABI.md L1904-1985.
87
Expect<uint32_t> alignmentDef(const CanonCtx &Cx,
88
                              const AST::Component::DefValType &T) noexcept;
89
90
/// Byte size of a Component Model value type T in linear memory.
91
/// CanonicalABI.md L1990-2040.
92
Expect<uint32_t> elemSize(const CanonCtx &Cx,
93
                          const ComponentValType &T) noexcept;
94
95
/// Byte size of a defined value type — internal recursion helper.
96
/// CanonicalABI.md L1990-2040.
97
Expect<uint32_t> elemSizeDef(const CanonCtx &Cx,
98
                             const AST::Component::DefValType &T) noexcept;
99
100
/// Result of `flatten_functype`: sequences of core wasm types representing
101
/// the ABI signature seen by core wasm. CanonicalABI.md L2813-2848.
102
struct FlatFuncType {
103
  std::vector<ValType> Params;
104
  std::vector<ValType> Results;
105
};
106
107
/// Flatten a Component Model value type to its core wasm representation.
108
/// CanonicalABI.md L2860-2877.
109
Expect<std::vector<ValType>> flattenType(const CanonCtx &Cx,
110
                                         const ComponentValType &T) noexcept;
111
112
/// Flatten a defined value type — internal recursion helper.
113
/// CanonicalABI.md L2860-2877.
114
Expect<std::vector<ValType>>
115
flattenTypeDef(const CanonCtx &Cx,
116
               const AST::Component::DefValType &T) noexcept;
117
118
/// Flatten a component function type into its core ABI signature. Sync only
119
/// — async is rejected. CanonicalABI.md L2819-2832.
120
///
121
/// `IsLift = true` covers the `canon lift` direction (component-typed
122
/// function exposed as core wasm callee); when results exceed
123
/// MaxFlatResults the core function returns a single i32 return-area pointer.
124
/// `IsLift = false` covers `canon lower` and synthesizes the trailing
125
/// out-pointer parameter when results exceed MaxFlatResults.
126
Expect<FlatFuncType> flattenFuncType(const CanonCtx &Cx,
127
                                     const AST::Component::FuncType &FT,
128
                                     bool IsLift) noexcept;
129
130
/// True iff `T` transitively contains a `list` or `string`. Used by the
131
/// canon-options validation to enforce the spec's `lift(T)` / `lower(T)`
132
/// requirements (CanonicalABI.md L3273-3277). Cycles through type indices
133
/// are bounded by the recursion-guard set the caller passes in.
134
bool containsListOrString(const CanonCtx &Cx,
135
                          const ComponentValType &T) noexcept;
136
137
/// Load a Component Model value of type T from linear memory at Ptr.
138
/// CanonicalABI.md L2050-2289 (and L2305-2322 for own/borrow).
139
///
140
/// Cx must provide a MemoryInstance. Callers are responsible for
141
/// alignment and bounds pre-checks at the top level (per spec
142
/// `lift_flat_values` L3197-3199); load() itself relies on
143
/// MemoryInstance::loadValue for per-primitive bounds checking and does
144
/// not re-validate alignment.
145
Expect<ComponentValVariant> load(const CanonCtx &Cx, uint32_t Ptr,
146
                                 const ComponentValType &T) noexcept;
147
148
/// Load a defined value type — internal recursion helper.
149
Expect<ComponentValVariant>
150
loadDef(const CanonCtx &Cx, uint32_t Ptr,
151
        const AST::Component::DefValType &T) noexcept;
152
153
/// Store a Component Model value of type T into linear memory at Ptr.
154
/// CanonicalABI.md L2360-2735.
155
///
156
/// String / variable-length list storage requires invoking realloc, which is
157
/// not yet wired through this helper — those cases return
158
/// ComponentNotImplInstantiate.
159
Expect<void> store(const CanonCtx &Cx, const ComponentValVariant &V,
160
                   const ComponentValType &T, uint32_t Ptr) noexcept;
161
162
/// Store a value into a defined value type — internal recursion helper.
163
Expect<void> storeDef(const CanonCtx &Cx, const ComponentValVariant &V,
164
                      const AST::Component::DefValType &T,
165
                      uint32_t Ptr) noexcept;
166
167
/// Iterator over a sequence of core wasm values backing a flat lift.
168
/// Mirrors the spec's CoreValueIter (CanonicalABI.md L2928-2948).
169
class FlatIter {
170
public:
171
  FlatIter(Span<const std::pair<ValVariant, ValType>> Vs) noexcept
172
0
      : Pairs(Vs), Singles{} {}
173
0
  FlatIter(Span<const ValVariant> Vs) noexcept : Pairs{}, Singles(Vs) {}
174
175
  /// Read the next core value as a ValVariant. Returns std::nullopt if the
176
  /// iterator is exhausted.
177
0
  std::optional<ValVariant> next() noexcept {
178
0
    if (!Pairs.empty()) {
179
0
      auto V = Pairs[Idx].first;
180
0
      ++Idx;
181
0
      return V;
182
0
    }
183
0
    if (Idx < Singles.size()) {
184
0
      return Singles[Idx++];
185
0
    }
186
0
    return std::nullopt;
187
0
  }
188
0
  bool done() const noexcept {
189
0
    return Idx >= (Pairs.empty() ? Singles.size() : Pairs.size());
190
0
  }
191
0
  size_t pos() const noexcept { return Idx; }
192
193
private:
194
  Span<const std::pair<ValVariant, ValType>> Pairs;
195
  Span<const ValVariant> Singles;
196
  size_t Idx = 0;
197
};
198
199
/// Lift a flat representation of a Component Model value into the rich
200
/// ComponentValVariant. CanonicalABI.md L2957-3084 (lift_flat). The
201
/// CoerceValueIter (spec L3042-3072) handling for variant/option/result
202
/// payloads is implemented; mismatched join slots reinterpret per L3047-3055.
203
Expect<ComponentValVariant> liftFlat(const CanonCtx &Cx, FlatIter &VI,
204
                                     const ComponentValType &T) noexcept;
205
206
/// Lift a defined value type from flat values — internal recursion helper.
207
Expect<ComponentValVariant>
208
liftFlatDef(const CanonCtx &Cx, FlatIter &VI,
209
            const AST::Component::DefValType &T) noexcept;
210
211
/// Lower a ComponentValVariant to its flat representation, the symmetric
212
/// inverse of `liftFlat`. CanonicalABI.md L3086-3192 (lower_flat).
213
///
214
/// String / variable-length list lowering allocates a payload buffer via
215
/// `Cx.Realloc`; callers must populate Exec / Realloc on the CanonCtx.
216
/// Variant/option/result payload coerce (spec L3158-3180) is implemented:
217
/// the selected case's native flat slots are reinterpreted into the joined
218
/// shape and the suffix is zero-padded.
219
Expect<std::vector<ValVariant>> lowerFlat(const CanonCtx &Cx,
220
                                          const ComponentValVariant &V,
221
                                          const ComponentValType &T) noexcept;
222
223
/// Lower a defined value type to flat values — internal recursion helper.
224
Expect<std::vector<ValVariant>>
225
lowerFlatDef(const CanonCtx &Cx, const ComponentValVariant &V,
226
             const AST::Component::DefValType &T) noexcept;
227
228
/// Spec L3193-3202 (`def lift_flat_values`). Reads MaxFlat-bounded flat values
229
/// from VI; when the type list flattens to more than MaxFlat, reads a single
230
/// pointer and loads the synthesized tuple from memory at that pointer.
231
Expect<std::vector<ComponentValVariant>>
232
liftFlatValues(const CanonCtx &Cx, FlatIter &VI,
233
               Span<const ComponentValType> Types, uint32_t MaxFlat) noexcept;
234
235
/// Spec L3212-3232 (`def lower_flat_values`). Lowers Values into flat core
236
/// wasm values. When OutParam is provided, the indirect-store buffer is the
237
/// caller-supplied pointer (lower-direction returning to an out-pointer) and
238
/// the returned vector is empty. When OutParam is std::nullopt, the indirect
239
/// case allocates a buffer via realloc and returns a single i32 pointer.
240
Expect<std::vector<ValVariant>>
241
lowerFlatValues(const CanonCtx &Cx, Span<const ComponentValVariant> Values,
242
                Span<const ComponentValType> Types, uint32_t MaxFlat,
243
                std::optional<uint32_t> OutParam = std::nullopt) noexcept;
244
245
} // namespace CanonicalABI
246
} // namespace Executor
247
} // namespace WasmEdge