Skip to content

Commit 786fcef

Browse files
committed
WIP
1 parent 103ba3a commit 786fcef

File tree

8 files changed

+109
-17
lines changed

8 files changed

+109
-17
lines changed

.github/copilot-instructions.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
## Repository focus
2+
- Header-only C++20 implementation of the WebAssembly Component Model canonical ABI; public surface aggregates through `include/cmcpp.hpp` and the `cmcpp` namespace.
3+
- Core work revolves around marshaling values between C++ types and wasm flat values using `lift_flat`, `lower_flat`, `lift_flat_values`, and `lower_flat_values` templates.
4+
- Project is kept in sync with the upstream spec (`ref/component-model`) and the reference Python definitions (`definitions.py`, `run_tests.py`). Compare against those when adjusting ABI semantics.
5+
6+
## Core headers
7+
- `include/cmcpp/traits.hpp` defines `ValTrait`, type aliases (e.g., `bool_t`, `string_t`), and concept shortcuts that every new type must implement.
8+
- `include/cmcpp/context.hpp` + `InstanceContext` encapsulate guest memory (`std::span<uint8_t>`), realloc callbacks, and host traps; use `createInstanceContext` before calling lift/lower helpers.
9+
- Memory helpers live in `include/cmcpp/load.hpp`/`store.hpp`; always respect `ValTrait<T>::size` and `alignment` from those headers instead of hard-coding layout rules.
10+
11+
## Lift/Lower workflow
12+
- `lower_flat_values` flattens function arguments, auto-switching to heap marshalling when the arity exceeds `MAX_FLAT_PARAMS`; `lift_flat_values` mirrors this when decoding results.
13+
- Heap-based lowering uses `cx.opts.realloc` to allocate guest memory; make sure any caller populates `LiftLowerOptions` with a working realloc when passing heap-backed types (lists, strings, large tuples).
14+
- String conversions rely on the `convert` callback; tests wire this through ICU (`test/host-util.cpp`). Preserve the encoding enum contract (`Encoding::Utf8`, `Encoding::Utf16`, `Encoding::Latin1`, `Encoding::Latin1_Utf16`).
15+
16+
## Adding types or functions
17+
- Extend `ValTrait` specializations and `ValTrait<T>::flat_types` for new composite types before touching lift/lower logic.
18+
- Use concepts from `traits.hpp` (e.g., `List`, `Variant`, `Flags`) so overload resolution stays consistent; mirror patterns in `include/cmcpp/list.hpp`, `variant.hpp`, etc.
19+
- Guard traps with `trap_if(cx, condition, message)` and route all host failures through the `HostTrap` provided by the context rather than throwing ad-hoc exceptions.
20+
21+
## Testing
22+
- Default build enables coverage flags on GCC/Clang; run `cmake --preset linux-ninja-Debug` followed by `cmake --build --preset linux-ninja-Debug` and then `ctest --preset linux-ninja-Debug` (or `ctest -VV` from the build tree).
23+
- C++ tests live in `test/main.cpp` using doctest and ICU for encoding checks; keep new tests near related sections for quick discovery.
24+
- `run_tests.py` exercises the same ABI rules via Python—use it to cross-check tricky canonical ABI edge cases when changing flattening behavior.
25+
26+
## Samples & runtimes
27+
- Enabling `-DBUILD_SAMPLES=ON` builds the WAMR host sample (`samples/wamr`); it wraps host callbacks with `host_function`/`guest_function` helpers defined in `include/wamr.hpp`.
28+
- Sample guest wasm artifacts are generated from `wasm/test.wit` via `wit-bindgen` and `wasm-tools`. The `samples/CMakeLists.txt` external project expects `WASI_SDK_PREFIX` to point at the vcpkg-installed WASI SDK.
29+
- `wasm/build.sh` spins up a dev container to compile wasm components reproducibly; run it if you need to refresh the sample binaries.
30+
31+
## Tooling notes
32+
- Dependencies are managed through `vcpkg.json` with overlays in `vcpkg_overlays/` (notably for WAMR); stick with preset builds so CMake wires in the correct toolchain file automatically.
33+
- Cargo manifest (`Cargo.toml`) is only for fetching `wasm-tools` and `wit-bindgen-cli`; if you touch wasm generation logic, update both the manifest and any scripts referencing those versions.
34+
- Keep documentation alongside code: update `README.md` when introducing new host types or workflows so downstream integrators stay aligned with the canonical ABI behavior.

include/cmcpp/traits.hpp

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
#ifndef CMCPP_TRAITS_HPP
22
#define CMCPP_TRAITS_HPP
33

4+
#include <algorithm>
5+
#include <array>
6+
#include <bitset>
47
#include <cassert>
5-
#include <cstring>
68
#include <cmath>
7-
#include <bitset>
9+
#include <cstdint>
10+
#include <cstring>
11+
#include <functional>
12+
#include <limits>
813
#include <optional>
14+
#include <string>
15+
#include <string_view>
16+
#include <tuple>
17+
#include <type_traits>
18+
#include <utility>
919
#include <variant>
10-
#include <limits>
20+
#include <vector>
1121

1222
#include "boost/pfr.hpp"
1323

@@ -36,11 +46,14 @@ namespace cmcpp
3646
using WasmVal = std::variant<int32_t, int64_t, float32_t, float64_t>;
3747
using WasmValVector = std::vector<WasmVal>;
3848

49+
template <typename>
50+
inline constexpr bool dependent_false_v = false;
51+
3952
template <typename T>
4053
struct WasmValTrait
4154
{
4255
static constexpr WasmValType type = WasmValType::UNKNOWN;
43-
static_assert(WasmValTrait<T>::type != WasmValType::UNKNOWN, "T must be valid WasmValType.");
56+
static_assert(!dependent_false_v<T>, "T must be valid WasmValType.");
4457
};
4558

4659
template <>
@@ -170,7 +183,7 @@ namespace cmcpp
170183
template <typename T>
171184
struct ValTrait
172185
{
173-
static_assert(false, "T is not a valid type for ValTrait. Type: ");
186+
static_assert(!dependent_false_v<T>, "T is not a valid type for ValTrait.");
174187
static constexpr ValType type = ValType::UNKNOWN;
175188
using inner_type = std::monostate;
176189
static constexpr uint32_t size = 0;
@@ -246,8 +259,8 @@ namespace cmcpp
246259
static constexpr uint32_t alignment = 1;
247260
static constexpr std::array<WasmValType, 1> flat_types = {WasmValType::i32};
248261

249-
static constexpr int8_t LOW_VALUE = std::numeric_limits<uint8_t>::lowest();
250-
static constexpr int8_t HIGH_VALUE = std::numeric_limits<uint8_t>::max();
262+
static constexpr uint8_t LOW_VALUE = std::numeric_limits<uint8_t>::lowest();
263+
static constexpr uint8_t HIGH_VALUE = std::numeric_limits<uint8_t>::max();
251264
};
252265

253266
template <>
@@ -428,13 +441,42 @@ namespace cmcpp
428441
string_t str;
429442
u16string_t u16str;
430443

444+
// Maintain both buffers in sync when we carry dual encodings so callers can
445+
// materialize either representation without tracking extra state.
431446
inline void resize(size_t new_size)
432447
{
433-
encoding == Encoding::Latin1 ? str.resize(new_size) : u16str.resize(new_size);
448+
switch (encoding)
449+
{
450+
case Encoding::Latin1:
451+
case Encoding::Utf8:
452+
str.resize(new_size);
453+
break;
454+
case Encoding::Utf16:
455+
u16str.resize(new_size);
456+
break;
457+
case Encoding::Latin1_Utf16:
458+
str.resize(new_size);
459+
u16str.resize(new_size);
460+
break;
461+
}
462+
}
463+
464+
inline void *data()
465+
{
466+
if (encoding == Encoding::Latin1 || encoding == Encoding::Latin1_Utf16)
467+
{
468+
return static_cast<void *>(str.data());
469+
}
470+
return static_cast<void *>(u16str.data());
434471
}
435-
inline void *data() const
472+
473+
inline const void *data() const
436474
{
437-
return encoding == Encoding::Latin1 ? (void *)str.data() : (void *)u16str.data();
475+
if (encoding == Encoding::Latin1 || encoding == Encoding::Latin1_Utf16)
476+
{
477+
return static_cast<const void *>(str.data());
478+
}
479+
return static_cast<const void *>(u16str.data());
438480
}
439481
};
440482
template <>
@@ -739,8 +781,8 @@ namespace cmcpp
739781
using enum_t = uint32_t;
740782

741783
// Func --------------------------------------------------------------------
742-
constexpr uint MAX_FLAT_PARAMS = 16;
743-
constexpr uint MAX_FLAT_RESULTS = 1;
784+
constexpr std::uint32_t MAX_FLAT_PARAMS = 16;
785+
constexpr std::uint32_t MAX_FLAT_RESULTS = 1;
744786

745787
template <typename>
746788
struct func_t_impl;

ref/wasm-micro-runtime

Submodule wasm-micro-runtime updated 304 files

test/main.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,16 @@ void test_overflow_behavior(const std::unique_ptr<LiftLowerContext> &cx, T input
187187
CHECK(result == expected_output);
188188
}
189189

190+
#if defined(__clang__)
191+
#pragma clang diagnostic push
192+
#pragma clang diagnostic ignored "-Wconstant-conversion"
193+
#pragma clang diagnostic ignored "-Wimplicit-int-conversion"
194+
#elif defined(__GNUC__)
195+
#pragma GCC diagnostic push
196+
#pragma GCC diagnostic ignored "-Woverflow"
197+
#pragma GCC diagnostic ignored "-Wconversion"
198+
#endif
199+
190200
TEST_CASE("Numeric Boundary Cases - Overflow Behavior")
191201
{
192202
Heap heap(1024 * 1024);
@@ -247,6 +257,12 @@ TEST_CASE("Numeric Boundary Cases - Overflow Behavior")
247257
test_overflow_behavior<int64_t>(cx, UINT64_MAX, -1);
248258
}
249259

260+
#if defined(__clang__)
261+
#pragma clang diagnostic pop
262+
#elif defined(__GNUC__)
263+
#pragma GCC diagnostic pop
264+
#endif
265+
250266
TEST_CASE("Float Special Values - Enhanced")
251267
{
252268
Heap heap(1024 * 1024);

vcpkg

Submodule vcpkg updated 804 files

vcpkg-configuration.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"default-registry": {
33
"kind": "git",
4-
"baseline": "120deac3062162151622ca4860575a33844ba10b",
4+
"baseline": "4334d8b4c8916018600212ab4dd4bbdc343065d1",
55
"repository": "https://github.com/microsoft/vcpkg"
66
},
77
"registries": [

0 commit comments

Comments
 (0)