Stream: wasi

Topic: Reactors and Commands in Preview 2


view this post on Zulip Lann Martin (Jan 04 2024 at 18:13):

What's the current status of the Reactor vs Command distinction in Preview 2? My vague understanding for Commands was that a Command instance would have its "main" function (and no other exports) called exactly once. Is that the expectation for wasi:cli/run? (and if so it seems like that should be documented in either that interface or the wasi:cli/command world)

view this post on Zulip Mossaka (Joe) (Jan 04 2024 at 20:00):

Related to this question, is wasi:http using the reactor mode? If so, could we add an exported setup() function to wasi:http/proxy that register callbacks at the initialization phase?

view this post on Zulip Lann Martin (Jan 04 2024 at 20:02):

:point_up: This is actually (part of) the context for my question: how should reactor initialization be done prior to the implementation of start defs.

view this post on Zulip Mossaka (Joe) (Jan 23 2024 at 23:19):

re: https://github.com/golang/go/issues/65199#issuecomment-1905205827

there isn't an export for reactor-style wasm programs

Background #38248 defined a new compiler directive, go:wasmimport, for interfacing with host defined functions. This allowed calling from Go code into host functions, but it’s still not possible to...

view this post on Zulip Dan Gohman (Jan 24 2024 at 00:11):

What I wrote there is actually wrong; there currently is no initialization mechanism for user code; we can't use the component-model start function, and there is discussion of WASI adding an export for this purpose.

view this post on Zulip Randy Reddig (Jan 24 2024 at 17:32):

"no initialization mechanism for user code"
Is there an initialization mechanism for the runtime or non-user code?

view this post on Zulip Dan Gohman (Jan 24 2024 at 17:36):

There is a component-model start function, that runs on instantiation. Code that doesn't need to call imports can use it. The thing I had forgotten was, that start function is not currently permitted to call imports, which means it wouldn't be friendly to give it to users and say "here, write your init code!" if it's going to trap as soon as they call an import.

view this post on Zulip Dan Gohman (Jan 24 2024 at 17:37):

But, I just talked about this with Luke yesterday, and he's now thinking we can remove the restriction on calling imports. Assuming we do do this, then what I wrote in that issue would become correct again, and we could use the component-model start function for any purpose.

view this post on Zulip Randy Reddig (Jan 24 2024 at 17:37):

Got it, so the component-model start happens too early in the lifecycle to be used by a runtime which is likely to call imports.

view this post on Zulip Randy Reddig (Jan 24 2024 at 17:37):

What are the considerations if that constraint is relaxed?

view this post on Zulip Dan Gohman (Jan 24 2024 at 17:39):

The start function runs automatically on instantiation, so if it can call imports, it means that component instantiation can evoke I/O. The thinking was, there may be situations where users want to instantiate a component, but without letting it do any I/O until a later step.

view this post on Zulip Randy Reddig (Jan 24 2024 at 17:40):

In Go’s case, the runtime picks up a few things from the local filesystem (assuming it’s readable), and user init code can do I/O

view this post on Zulip Randy Reddig (Jan 24 2024 at 17:41):

Assuming that wasi:filesystem and wasi:cli and its dependents would be initialized prior to a user component?

view this post on Zulip Dan Gohman (Jan 24 2024 at 17:42):

In many cases, "the filesystem" is likely to be virtualized, so the resulting component wouldn't actually do that I/O. But yes, not everything will work that way.

view this post on Zulip Randy Reddig (Jan 24 2024 at 17:43):

Maybe a better question is: are components initialized in order of dependence?

view this post on Zulip Dan Gohman (Jan 24 2024 at 17:43):

Also yes, component dependencies are acyclic, and initialized topologically.

view this post on Zulip Randy Reddig (Jan 24 2024 at 17:45):

Somewhat related to Go and the Component Model: we’re currently using wasm-tools component embed and wasm-tools component new to create a component from a Wasm module generated by the TinyGo compiler.

Is there a way to differentiate which realloc gets called a component export or import?

view this post on Zulip Dan Gohman (Jan 24 2024 at 17:47):

I don't think so; the canonical ABI just has one realloc.

view this post on Zulip Randy Reddig (Jan 24 2024 at 17:57):

I’ve spoken with Luke about this, how cabi_realloc might interact with the Go GC, given that it allocates byte slabs, which might not be the correct GC shape for say something like a string which contains a pointer.

view this post on Zulip Pat Hickey (Jan 24 2024 at 17:59):

the canonical abi has one realloc per import or export function - you can assign a different realloc function to each

view this post on Zulip Pat Hickey (Jan 24 2024 at 17:59):

we have some "cheat codes" to do this for us for the preview 1 adapter in wasm-tools component new but no generalized support fori t

view this post on Zulip Randy Reddig (Jan 24 2024 at 18:00):

Luke commented about a cheat code for making allocations cheaper for I/O, e.g. hijacking the next call to realloc before calling read on a stream, to enable BYO buffer.

view this post on Zulip Pat Hickey (Jan 24 2024 at 18:00):

so, if specializing per import/export fn is enough, that may be possible without spec changes, and we just have to encode it somehow in the module and teach component new to do that

view this post on Zulip Pat Hickey (Jan 24 2024 at 18:01):

oh, hmm, thats more/different than i was thinking

view this post on Zulip Pat Hickey (Jan 24 2024 at 18:01):

but it may also be possible

view this post on Zulip Pat Hickey (Jan 24 2024 at 18:01):

thats some bookkeeping youd need to do inside your module

view this post on Zulip Pat Hickey (Jan 24 2024 at 18:02):

vs exposing many distinct reallocs and assigning them to different import/export lift/lowers is something your module would expose and component new would do the wiring for

view this post on Zulip Randy Reddig (Jan 24 2024 at 18:02):

Going back to the Component Model start for a sec, can wasm-tools wire up a module _initialize to the Component Model start section?

view this post on Zulip Pat Hickey (Jan 24 2024 at 18:02):

in theory yes

view this post on Zulip Pat Hickey (Jan 24 2024 at 18:02):

but ill admit i dont fully understand the implications of doing so at the moment, some things in the above conversation were new to me so id need to make sure i really understood what was going on first

view this post on Zulip Pat Hickey (Jan 24 2024 at 18:04):

(maybe cabi_initialize is a better name than _initialize but thats bikeshedding)

view this post on Zulip Peter Huene (Jan 24 2024 at 18:27):

Going back to the Component Model start for a sec, can wasm-tools wire up a module _initialize to the Component Model start section?

Yes, that's something wasm-encoder can do if one were encoding a component manually, but it's not implemented in wit-component when converting a core module to a component.

Additionally, I'll point out that component start sections aren't implemented in Wasmtime as they require fully supporting value import and exports to implement, which are also currently not implemented.

view this post on Zulip Pat Hickey (Jan 24 2024 at 18:29):

can we make a restriction on the spec to eliminate the value imports/exports for now?

view this post on Zulip Peter Huene (Jan 24 2024 at 18:30):

i don't see why not, something like limiting it to arg* of 0 length and r of zero (no result)?

view this post on Zulip Peter Huene (Jan 24 2024 at 18:30):

so easily calling something like _initialize

view this post on Zulip Peter Huene (Jan 24 2024 at 18:32):

could probably just make that limitation in wasmtime and have it non-conforming on start section implementation like it is now (until values are implemented)

view this post on Zulip Dan Gohman (Jan 24 2024 at 18:35):

We should probably put this limitation in the spec.

view this post on Zulip Pat Hickey (Jan 24 2024 at 18:35):

yes we should bubble it up to the spec level with the preview2 emoji as a qualifier

view this post on Zulip Randy Reddig (Jan 24 2024 at 18:59):

Thanks. I think that will help ease the implementation of the go:wasmexport proposal in Go, and simplify our work implementing the Component Model and Preview 2

view this post on Zulip Randy Reddig (Jan 24 2024 at 18:59):

Ideally the Go (and TinyGo) toolchains will be able to emit a component directly, once the spec is formalized.

view this post on Zulip Dan Gohman (Jan 24 2024 at 19:00):

I filed https://github.com/WebAssembly/component-model/pull/297 to remove the restriction on imports, and to add the no-args-no-returns restriction.

Remove the restriction on component start functions calling imports. This allows start functions to run artbitrary user code. And, adjust the 🪙 to include start functions in the MVP, and add a rest...

view this post on Zulip Joel Dice (Jan 24 2024 at 19:04):

Possibly interesting tidbit: componentize-py relies on wasm-tools component link to create a component using shared-everything linking. Part of that process involves synthesizing an "init" module which has a start function that calls any __wasm_call_ctors or _initialize functions found in the input modules. Some of those functions call host imports, and that succeeds because of the order of instantiation inside the component. So calling imports from a (module-level) start function is possible in certain cases, and componentize-py has been relying on that for a while.

view this post on Zulip Peter Huene (Jan 24 2024 at 19:10):

that's implemented with a component start section?

view this post on Zulip Joel Dice (Jan 24 2024 at 19:59):

No, it's a module start section inside the last module to be instantiated inside the component.

view this post on Zulip Joel Dice (Jan 24 2024 at 20:00):

relevant code: https://github.com/bytecodealliance/wasm-tools/blob/6470aa9df1782b4e7a21e5f065d0b991e0797862/crates/wit-component/src/linking.rs#L727-L759

view this post on Zulip Peter Huene (Jan 24 2024 at 20:01):

ah, gotcha!

view this post on Zulip Joel Dice (Jan 24 2024 at 20:09):

Here's the code that ensures the desired instantiation order, FWIW: https://github.com/bytecodealliance/wasm-tools/blob/main/crates/wit-component/src/encoding.rs#L604-L630

view this post on Zulip Dan Gohman (Jan 24 2024 at 20:18):

Can that code call component imports?

view this post on Zulip Joel Dice (Jan 24 2024 at 20:26):

Yes

view this post on Zulip Pat Hickey (Jan 24 2024 at 20:27):

oh! do we even need a component start section if, for the case without argument or return values, module start functions do the trick?

view this post on Zulip Joel Dice (Jan 24 2024 at 20:28):

Well you need to split your code over at least two modules in order for the above trick to work (or have wasm-tools compoonent link do that for you, based on an input shared library).

view this post on Zulip Joel Dice (Jan 24 2024 at 20:30):

It's easy enough for componentize-py since it controls the whole toolchain, but I'm not sure how generalizable it is to other languages and toolchains.

view this post on Zulip Dan Gohman (Jan 24 2024 at 20:32):

Interesting. I wasn't aware we could do that. So yeah, I'd still like to have component start functions, so the core-wasm toolchain story can just be to export a function with a designated name, and wit-component can put it in the component-model start section.

view this post on Zulip Dan Gohman (Jan 24 2024 at 21:02):

While investigating this, I noticed that while you can call imports from the core-wasm start function, the function table isn't always initialized at that time. I was able to call write(1, ...) and it worked, but printf didn't work because it does a call_indirect internally.

view this post on Zulip Dan Gohman (Jan 24 2024 at 21:04):

Or, wait, the table is initialized, but the adapter's table isn't initialized yet.

view this post on Zulip Randy Reddig (Jan 28 2024 at 02:12):

Question regarding the Go wasmexport proposal and how it might interact with cabi_realloc:

  1. Is a guest allowed to make host calls inside of a call to cabi_realloc?
  2. The Go wasmexport proposal presumes that the Go scheduler will be activated and run while the exported function runs, and pause other goroutines when the called func completes. My guess is that might not be desirable in a cabi_realloc call.

view this post on Zulip Alex Crichton (Jan 28 2024 at 02:21):

Is a guest allowed to make host calls inside of a call to cabi_realloc?

Short answer: no.

Long answer: You'll want to take a look at CanonicalABI.md which outlines all of this. Specifically what you'll be interested in here is the may_leave flag. This is notably set to False while lower_values is called, meaning that when values are being lowered into a component (which is when cabi_realloc would be called) the flag is false which means that an import would trap. More-or-less cabi_realloc is expected to be a "stay inside the module" kind of thing.

My guess is that might not be desirable in a cabi_realloc call.

If activating the schedule has high overhead, then yes you probably don't want to do that. If there's low overhead though it may not be an issue. It's worth pointing out that there are no threads in components at this time, and it'll be awhile before there are. That means that in a single-threaded world where you're calling malloc there's not much use for the scheduler, especially if imports can't be called

view this post on Zulip Randy Reddig (Jan 28 2024 at 02:25):

Thanks!

view this post on Zulip Randy Reddig (Jan 28 2024 at 02:27):

I suspect if the Go runtime is adapted for this, then anytime it’s not allowed to call imports, it could block the calling goroutine until it can, and go to another goroutine


Last updated: Dec 23 2024 at 13:07 UTC