Skip to content

Add crate for host-side .net component bindings - #1946

Draft
ludfjig wants to merge 5 commits into
mainfrom
component-wire-format
Draft

ludfjig wants to merge 5 commits into
mainfrom
component-wire-format

Conversation

@ludfjig

@ludfjig ludfjig commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Adds new crate hyperlight-component-csharp which generates c# host bindings from wit. The intended usage is a .NET hyperlight-wasm library, so .net hosts don't need to write rust.

The crate is in rust and not .net for two reasons:

  • WIT parsing uses very convenient wit-parser crate
  • In the future combine the core of this crate with the existing rust bindings crate to make sure they cannot drift

breakign changes:

  • host_bindgen! and guest_bindgen! encode values little-endian (instead of native endian)
  • Functions are named <instance>#<function>, such as wasi:http/types@0.2.0#[method]fields.get rather than wasi::http::[method]fields.get. The old name dropped the interface and version, so functions in different interfaces or versions of one package could collide.

Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
@ludfjig ludfjig added the kind/enhancement For PRs adding features, improving functionality, docs, tests, etc. label Oct 16, 2026
@hyperlight-gh-bot

Copy link
Copy Markdown

Benchmark Results

Measured commit: 9ab4272f7329
Baseline commit: b8783e8cd14d

kvm / amd (Linux) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 798.08 ns (➖ 1.03x slower)
vec_bytes 581.78 ns (➖ 1.06x faster)
373.10 µs (➖ 1.00x faster)

payload_allocation

slot_pool_segmented
262144 571.98 ns (➖ 1.06x slower)
65536 141.93 ns (➖ 1.02x faster)

sandboxes

create_initialized_and_drop
medium 83.03 ms (➖ 1.02x faster)

slot_pool

alloc_dealloc_1500 alloc_dealloc_4096 alloc_dealloc_128
7.75 ns (➖ 1.01x faster) 8.42 ns (➖ 1.00x faster) 7.73 ns (➖ 1.03x faster)

snapshot_files

load_snapshot_unverified
small 93.15 µs (➖ 1.01x faster)

virtq_readonly

slot_pool_segmented_fragmented slot_pool_segmented
262144 7.21 µs (➖ 1.01x slower) 7.47 µs (➖ 1.04x slower)
65536 2.09 µs (➖ 1.07x slower) 1.99 µs (➖ 1.05x faster)

virtq_readwrite

slot_pool_segmented_fragmented slot_pool_segmented
65536 6.39 µs (➖ 1.02x faster) 6.21 µs (➖ 1.03x faster)
8192 1.07 µs (➖ 1.00x faster) 1.11 µs (➖ 1.03x slower)
262144 30.12 µs (➖ 1.04x slower)
kvm / intel (Linux) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 677.42 ns (➖ 1.01x faster)
vec_bytes 518.89 ns (➖ 1.01x faster)
664.80 µs (➖ 1.00x slower)

payload_allocation

slot_pool_segmented
262144 506.80 ns (➖ 1.02x slower)
65536 133.86 ns (➖ 1.04x faster)

sandboxes

create_initialized_and_drop
medium 74.38 ms (➖ 1.00x slower)

slot_pool

alloc_dealloc_1500 alloc_dealloc_4096 alloc_dealloc_128
6.87 ns (➖ 1.00x slower) 6.86 ns (➖ 1.00x slower) 6.86 ns (➖ 1.00x slower)

snapshot_files

load_snapshot_unverified
small 44.65 µs (➖ 1.00x slower)

virtq_readonly

slot_pool_segmented_fragmented slot_pool_segmented
262144 7.48 µs (➖ 1.06x faster) 7.53 µs (➖ 1.03x faster)
65536 2.14 µs (➖ 1.01x faster) 2.13 µs (➖ 1.01x faster)

virtq_readwrite

slot_pool_segmented_fragmented slot_pool_segmented
65536 7.10 µs (➖ 1.01x faster) 7.17 µs (➖ 1.00x faster)
8192 765.83 ns (➖ 1.01x faster) 762.32 ns (➖ 1.03x slower)
262144 30.24 µs (➖ 1.01x faster)
mshv3 / amd (Linux) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 916.61 ns (➖ 1.01x faster)
vec_bytes 713.42 ns (➖ 1.00x faster)
318.21 µs (➖ 1.01x faster)

payload_allocation

slot_pool_segmented
262144 698.24 ns (➖ 1.04x slower)
65536 184.86 ns (➖ 1.00x slower)

sandboxes

create_initialized_and_drop
medium 60.84 ms (➖ 1.02x slower)

slot_pool

alloc_dealloc_1500 alloc_dealloc_4096 alloc_dealloc_128
10.46 ns (➖ 1.05x slower) 10.11 ns (➖ 1.02x slower) 9.91 ns (➖ 1.00x faster)

snapshot_files

load_snapshot_unverified
small 86.45 µs (➖ 1.05x faster)

virtq_readonly

slot_pool_segmented_fragmented slot_pool_segmented
262144 9.44 µs (➖ 1.01x slower) 9.03 µs (➖ 1.10x faster)
65536 2.66 µs (➖ 1.01x faster) 2.57 µs (➖ 1.01x slower)

virtq_readwrite

slot_pool_segmented_fragmented slot_pool_segmented
65536 8.61 µs (➖ 1.00x slower) 8.21 µs (➖ 1.00x slower)
8192 1.35 µs (➖ 1.01x slower) 1.38 µs (➖ 1.03x slower)
262144 35.12 µs (➖ 1.01x faster)
mshv3 / intel (Linux) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 930.77 ns (➖ 1.01x slower)
vec_bytes 654.65 ns (➖ 1.01x slower)
631.47 µs (➖ 1.13x faster)

payload_allocation

slot_pool_segmented
262144 647.40 ns (➖ 1.02x faster)
65536 172.90 ns (➖ 1.00x slower)

sandboxes

create_initialized_and_drop
medium 80.44 ms (➖ 1.03x slower)

slot_pool

alloc_dealloc_1500 alloc_dealloc_4096 alloc_dealloc_128
9.35 ns (➖ 1.01x faster) 9.55 ns (➖ 1.00x faster) 9.28 ns (➖ 1.00x faster)

snapshot_files

load_snapshot_unverified
small 45.98 µs (➖ 1.01x faster)

virtq_readonly

slot_pool_segmented_fragmented slot_pool_segmented
262144 7.99 µs (➖ 1.01x slower) 7.92 µs (➖ 1.00x slower)
65536 2.25 µs (➖ 1.00x slower) 2.25 µs (➖ 1.01x slower)

virtq_readwrite

slot_pool_segmented_fragmented slot_pool_segmented
65536 7.57 µs (➖ 1.00x slower) 7.50 µs (➖ 1.02x faster)
8192 930.60 ns (➖ 1.03x faster) 928.17 ns (➖ 1.02x slower)
262144 38.22 µs (➖ 1.00x faster)
hyperv-ws2025 / amd (Windows) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 1.18 µs (➖ 1.00x slower)
vec_bytes 769.08 ns (➖ 1.02x faster)
1.93 ms (➖ 1.00x slower)

payload_allocation

slot_pool_segmented
262144 828.13 ns (➖ 1.06x slower)
65536 231.48 ns (➖ 1.01x slower)

sandboxes

create_initialized_and_drop
medium 98.23 ms (➖ 1.20x slower)

slot_pool

alloc_dealloc_1500 alloc_dealloc_4096 alloc_dealloc_128
10.34 ns (➖ 1.07x faster) 10.35 ns (➖ 1.04x faster) 10.38 ns (➖ 1.07x faster)

snapshot_files

load_snapshot_unverified
small 698.89 µs (➖ 1.16x faster)

virtq_readonly

slot_pool_segmented_fragmented slot_pool_segmented
262144 8.95 µs (➖ 1.07x faster) 9.21 µs (➖ 1.01x faster)
65536 2.34 µs (➖ 1.04x faster) 2.34 µs (➖ 1.01x faster)

virtq_readwrite

slot_pool_segmented_fragmented slot_pool_segmented
65536 8.83 µs (➖ 1.00x slower) 8.86 µs (➖ 1.02x faster)
8192 1.34 µs (➖ 1.04x faster) 1.32 µs (➖ 1.01x slower)
262144 39.08 µs (➖ 1.00x faster)
hyperv-ws2025 / intel (Windows) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 1.24 µs (➖ 1.03x slower)
vec_bytes 771.46 ns (➖ 1.02x faster)
2.97 ms (➖ 1.02x faster)

payload_allocation

slot_pool_segmented
262144 740.26 ns (➖ 1.00x slower)
65536 214.76 ns (➖ 1.03x slower)

sandboxes

create_initialized_and_drop
medium 102.08 ms (➖ 1.34x faster)

slot_pool

alloc_dealloc_1500 alloc_dealloc_4096 alloc_dealloc_128
10.39 ns (➖ 1.04x slower) 10.06 ns (➖ 1.00x slower) 10.04 ns (➖ 1.01x slower)

snapshot_files

load_snapshot_unverified
small 478.74 µs (➖ 1.03x faster)

virtq_readonly

slot_pool_segmented_fragmented slot_pool_segmented
262144 7.78 µs (➖ 1.02x slower) 7.80 µs (➖ 1.01x slower)
65536 2.40 µs (➖ 1.04x slower) 2.34 µs (➖ 1.00x slower)

virtq_readwrite

slot_pool_segmented_fragmented slot_pool_segmented
65536 8.57 µs (➖ 1.01x faster) 9.00 µs (➖ 1.05x slower)
8192 1.14 µs (➖ 1.09x faster) 1.08 µs (➖ 1.01x faster)
262144 40.60 µs (➖ 1.14x faster)

Reported by cargo ci bench-report --candidate run:38976848863 --config-file bench_report.toml.

@syntactically

Copy link
Copy Markdown
Member

I didn't look at this in detail yet, but I did notice it is not using the same component type elaboration infrastructure from the Rust macros. I think this is probably a mistake as it does not seem to me that most of the more complex cases are possible to get right without the explicit representation of type variables. I think pretty much the only thing in State that is specific to rust is the root_mod field which uses the Mod type that represents the submodule/subtrait structure that is used for Rust. Maybe you can make State parametrised on the type of the root module like that and have a different alternative for holding the information you need for C# syntax trees? Then I think you can follow the same pattern as hyperlight_component_macro to drive the host/guest emit using read_wit_type and then having your own equivalents of rtype::emit_toplevel and host/guest::emit_toplevel that follow the structure of the fully elaborated component inductively. (Probably some of the BindgenInputParams/source stuff can be moved from hyperlight_component_macro to hyperlight_component_util also to reduce duplication).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/enhancement For PRs adding features, improving functionality, docs, tests, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants