Stream: general

Topic: Small questions about WIT


view this post on Zulip Sekoia (Nov 12 2024 at 14:36):

Heya, I'm trying to figure out how the whole component model works, including the canonical ABI (with the goal of compiling my own language to it). I've noticed a few things:

From https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md:

As an optimization, flags are represented as packed bit-vectors. Like variant discriminants, flags use the smallest integer that fits all the bits, falling back to sequences of i32s when there are more than 32 flags.

def alignment_flags(labels):
  n = len(labels)
  assert(0 < n <= 32)
  if n <= 8: return 1
  if n <= 16: return 2
  return 4

First, that assert kinda confuses me. The whole case of "more than 32 flags" is not handled... anywhere, as far as I can tell. Additionally, why not use 64-bit integers too? They're primitives too. I would also say the same thing about Variant discriminators only using up to 32 bits, but honestly 4 billion variants seems like a pretty reasonable limit.

From https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md:

record-fields ::= record-field
                | record-field ',' record-fields?

More generally, it seems like zero-sized types (and impossible types like variants with no variants) are impossible. I guess they're expected to be stripped by whatever generator that makes the WIT data?

I'll probably add further questions to this thread later, but that's it for now.

Repository for design and specification of the Component Model - WebAssembly/component-model
Repository for design and specification of the Component Model - WebAssembly/component-model

view this post on Zulip Lann Martin (Nov 12 2024 at 15:14):

On zero-sized types you can see the rationale here: https://github.com/WebAssembly/component-model/pull/218

In C++, all types must have a non-zero size, so empty structs have size 1. In C, structs with no members are non-standard, though widely supported, with size 0, making them ABI-incompatible with C+...

view this post on Zulip Sekoia (Nov 12 2024 at 15:22):

Interesting, thank you!

view this post on Zulip Alex Crichton (Nov 12 2024 at 16:09):

For flags we recently limited flags to 32 and haven't gotten to go back and update the abi representation

view this post on Zulip Alex Crichton (Nov 12 2024 at 16:09):

The plan is to increase the limit to 64 in the future and use i64 for the representation

view this post on Zulip Alex Crichton (Nov 12 2024 at 16:11):

Some minor extra changes are needed in the spec though to fully handle this

view this post on Zulip Sekoia (Nov 12 2024 at 16:15):

Ah, fair enough!

view this post on Zulip Sekoia (Nov 17 2024 at 00:55):

What are "refines"? They're mentioned when storing/loading variants, but not specified anywhere from what I can tell?

view this post on Zulip Lann Martin (Nov 18 2024 at 13:44):

It looks like the feature was effectively "disabled" in https://github.com/WebAssembly/component-model/pull/255

This PR implements the idea in #229 of qualifying the parts of the current proposal that are not included in the upcoming 'Preview 2' stability milestone. Subtyping wasn't really writt...

view this post on Zulip Sekoia (Nov 18 2024 at 14:07):

Fair enough! Makes my life easier lol

view this post on Zulip Lann Martin (Nov 18 2024 at 14:20):

https://github.com/WebAssembly/component-model/issues/414

The refines feature was removed from the explainer in #255 but is still referenced in the cabi docs. This has caused confusion for at least one person so should probably either be completely remove...

view this post on Zulip Sekoia (Nov 18 2024 at 14:21):

Haha, I was thinking about opening an issue. Thanks!

view this post on Zulip Sekoia (Nov 25 2024 at 19:38):

I'm not sure I understand components at all, honestly. Assuming a non-component-aware host, can it call functions in a component at all (assuming we manually build the serialization?). To me it seems like a WASM component doesn't even use the same format as a WASM core module; I would have expected an extension to the core module using a custom section that gives the format of the module.

I'm trying to build a component from user code, so currently my thought on how to approach that is to use wasm-encode to build up a Module, the byte-ify it, but it's decently low-level and I feel like y'all have probably made a better library for this kind of situation, no?

view this post on Zulip Sekoia (Nov 25 2024 at 19:43):

My current understanding is that a WASM component is a wrapper around a WASM core module, and defines a mapping from core module functions to component functions. When a host wants to call a function from the component, it looks at the signature, lowers the parameters into local memory using realloc (if it can't be easily passed as several arguments), converting its internal representation to the canonical ABI along the way, runs the core function, then gets the return value from local memory, again using the canonical ABI. Is... any of that correct?

And does this mean that any WASM component that uses types that need a linear memory needs to implement a full allocator with realloc support etc?

view this post on Zulip Milan (Nov 25 2024 at 20:17):

I think you're on the right track for a lot of the concepts. The part that may help is that components aren't necessarily a wrapper on a single core wasm module but are generally expected to be composed of multiple core wasm modules and wasm components. This high-level guide painted the picture better for me: https://wasm-components.fermyon.app/encoding.html

view this post on Zulip Sekoia (Nov 25 2024 at 20:21):

I see. Is there a performance loss when joining multiple core wasm modules into one, vs building an equivalent joined core wasm module? Or is it nearly free?

Also, thanks for that high-level guide, that does help.

view this post on Zulip Lann Martin (Nov 25 2024 at 20:24):

That depends on what you mean by "equivalent joined core wasm module"; one answer is that there is no equivalent: components can be written in different languages with e.g. mutually incompatible memory layouts and still composed together.

view this post on Zulip Sekoia (Nov 25 2024 at 20:26):

Fair, I meant in the context of creating a component with full control of the whole pipeline. Is it fine enough to build several modules and link them together, or should I instead creating one big module and export what it needs exported?

view this post on Zulip Lann Martin (Nov 25 2024 at 20:36):

If I'm understanding your question: there is going to be a little more overhead in calling between two components than a function call within a module but apart from that I think its more a question of how you want to organize and connect your components/modules together.

view this post on Zulip Sekoia (Nov 25 2024 at 20:47):

Yeah, that was my question. I'm guessing the runtime really treats them as two separate modules and chains the calls together?

view this post on Zulip Lann Martin (Nov 25 2024 at 21:09):

A non-component-aware runtime would have to do that, yes. I believe that is how jco runs components in the browser, for example. A component-aware runtime like Wasmtime can be a little smarter but Wasm's sandboxing requirements still typically require some memory copies (and other bookkeeping) that wouldn't be necessary in a "native" function call.

JavaScript toolchain for working with WebAssembly Components - bytecodealliance/jco

view this post on Zulip Joel Dice (Nov 25 2024 at 21:09):

Yes, with shared-nothing linking each subcomponent exists in its own sandbox, with the host mediating communication between them.

With the component model, you can use any combination of static linking (everything goes into a single module), shared-everything linking (multiple modules linked together and sharing memory and table(s)), and shared-nothing linking (multiple modules, each with its own memory and table(s)). Each option has its pros and cons, and they can be combined in complementary ways. See also https://github.com/WebAssembly/component-model/blob/main/design/mvp/Linking.md.

Repository for design and specification of the Component Model - WebAssembly/component-model

view this post on Zulip Sekoia (Nov 25 2024 at 21:32):

I see. Thank you very much! Final question for now: what (rust) crates should I use to generate a core module + a WIT interface? There's walrus+wit-component or wasm-encoder as far as I know (wasm-encoder appears to be lower-level), but maybe I'm missing some or some aren't maintained very much anymore?

view this post on Zulip Joel Dice (Nov 25 2024 at 21:43):

wasm-encoder seems like a good choice to me, and can be used in either of two ways to produce a component:

This PR adds BuildTargets.md to define this new concept of "build targets" as presented in both CG-06 and WASI-06-12, which itself was a revision of the earlier "wasit2" idea th...

view this post on Zulip Joel Dice (Nov 25 2024 at 21:46):

I haven't used walrus myself. I've heard it's cool, though, and takes care of the annoying details of managing indexes, etc.

view this post on Zulip Victor Adossi (Nov 26 2024 at 07:05):

Hey also @Sekoia you might want to take a look at the Component Model book -- there are a lot of benefits/extras to components, and that might be a good place to start.

If you prefer a WAT-first approach you can check out some of the tests in the wasmtime crate:

https://github.com/bytecodealliance/wasmtime/blob/2b3fe80b65c4943428ec1d587bf35740cd977401/tests/all/cli_tests/component-basic.wat#L4

You can kind of get a feel for how components wrap and enhance/extend/enhance modules.

Obviously as well with all the other links everyone has provided

A fast and secure runtime for WebAssembly. Contribute to bytecodealliance/wasmtime development by creating an account on GitHub.

Last updated: Dec 23 2024 at 13:07 UTC