Stream: git-wasmtime

Topic: wasmtime / issue #9595 Preserve Parameter Names in Compon...


view this post on Zulip Wasmtime GitHub notifications bot (Nov 12 2024 at 08:51):

Swivelgames opened issue #9595:

Feature

Provide an interface for deriving a ComponentFunc params original names

Benefit

Presently, wasmtime provides a number tools that can be leveraged for something that resembles Reflection, but the details for Function Parameters are lossy. Especially for more complex runtime parameter mapping, it would be great if the names of function parameters were preserved, and an interface provided for retrieving them.

Implementation

In order to maintain backwards compatibility, it could likely be something like a param_names() method.

impl ComponentFunc

  pub fn param_names(&self) -> impl ExactSizeIterator<Item = String> + '_`

      Iterates over names of function parameters

Alternatives

There really doesn't seem to be one that's built-in to wasmtime. In order to grab the parameter names, I'd likely need to do something far more complex.

Based on wasm-tools, though, it seems like the name of the params are preserved in the .wasm, which is intriguing.

To my knowledge, ComponentFunc params are the entities that do not have some way of deriving their original names.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 13 2024 at 01:56):

Swivelgames edited issue #9595:

Feature

Provide an interface for deriving a ComponentFunc params original names

Benefit

Presently, wasmtime provides a number tools that can be leveraged for something that resembles Reflection, but the details for Function Parameters are lossy. Especially for more complex runtime parameter mapping, it would be great if the names of function parameters were preserved, and an interface provided for retrieving them.

Implementation

In order to maintain backwards compatibility, it could likely be something like a param_names() method.

impl ComponentFunc

  pub fn param_names(&self) -> impl ExactSizeIterator<Item = String> + '_`

      Iterates over names of function parameters

Alternatives

There really doesn't seem to be one that's built-in to wasmtime. In order to grab the parameter names, I'd likely need to do something far more complex.

Based on wasm-tools, though, it seems like the name of the params are preserved in the .wasm, which is intriguing.

To my knowledge, ComponentFunc params are the entities that do not have some way of deriving their original names.
```[tasklist]

Tasks

~~~

view this post on Zulip Wasmtime GitHub notifications bot (Nov 13 2024 at 01:56):

Swivelgames edited issue #9595:

Feature

Provide an interface for deriving a ComponentFunc params original names

Benefit

Presently, wasmtime provides a number tools that can be leveraged for something that resembles Reflection, but the details for Function Parameters are lossy. Especially for more complex runtime parameter mapping, it would be great if the names of function parameters were preserved, and an interface provided for retrieving them.

Implementation

In order to maintain backwards compatibility, it could likely be something like a param_names() method.

impl ComponentFunc

  pub fn param_names(&self) -> impl ExactSizeIterator<Item = String> + '_`

      Iterates over names of function parameters

Alternatives

There really doesn't seem to be one that's built-in to wasmtime. In order to grab the parameter names, I'd likely need to do something far more complex.

Based on wasm-tools, though, it seems like the name of the params are preserved in the .wasm, which is intriguing.

To my knowledge, ComponentFunc params are the entities that do not have some way of deriving their original names.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 01:30):

Swivelgames commented on issue #9595:

For what it's worth, my personal use-case for this is for a runtime tool that presents the parameter names.

That being said, assigning arguments to parameters via their names is supported by some popular languages, so preserving parameters names could potentially improve the ergonomics when using languages that support named arguments.

  1. C# (Starting at v4)
    csharp MethodName(arg1: 42, arg2: "Hello");

  2. Kotlin
    kotlin myFunction(arg1 = 42, arg2 = "Hello")

  3. Python
    python my_function(arg1=42, arg2="Hello")

  4. PHP
    php my_function(arg1: 42, arg2: "Hello");

  5. Ruby
    ruby my_function(arg1: 42, arg2: "Hello")

  6. Swift
    swift myFunction(arg1: 42, arg2: "Hello")

Other languages support named arguments too, like R, Scala, Lisp, and others, but I can't imagine they're high on the list of targets for WASM/WASI :sweat_smile:

iirc, you can _technically_ do it in C++20 with gcc and clang, but I'm actually not 100% sure about that, and not sure how popular of a feature it is _if you can do it_.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 07:52):

bjorn3 commented on issue #9595:

Are param names part of the abi as opposed to just debuginfo?

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 09:54):

Swivelgames commented on issue #9595:

That's a good question. I'm not sure. I was actually digging into that earlier after I posted my most recent message.

In wasi-parser, for instance, they're represented by a Vector of (String, Type) tuples. In wasm-wave, it has methods for both params and param_names, similar to what I'm proposing here, with the caveat that it will return an empty iterable "if this WasmFunc impl does not support param names."

I imagine there are cases where they're not included, but I think that's still manageable. They could easily be represented either by an Vec<Option<String>> or by their index if they're omitted.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 09:55):

Swivelgames deleted a comment on issue #9595:

That's a good question. I'm not sure. I was actually digging into that earlier after I posted my most recent message.

In wasi-parser, for instance, they're represented by a Vector of (String, Type) tuples. In wasm-wave, it has methods for both params and param_names, similar to what I'm proposing here, with the caveat that it will return an empty iterable "if this WasmFunc impl does not support param names."

I imagine there are cases where they're not included, but I think that's still manageable. They could easily be represented either by an Vec<Option<String>> or by their index if they're omitted.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 09:55):

Swivelgames commented on issue #9595:

@bjorn3 That's a good question. I'm not sure. I was actually digging into that earlier after I posted my most recent message.

In wasi-parser, for instance, they're represented by a Vector of (String, Type) tuples. In wasm-wave, it has methods for both params and param_names, similar to what I'm proposing here, with the caveat that it will return an empty iterable "if this WasmFunc impl does not support param names."

I imagine there are cases where they're not included, but I think that's still manageable. They could easily be represented either by an Vec<Option<String>> or by their index if they're omitted.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 09:55):

Swivelgames edited a comment on issue #9595:

@bjorn3 That's a good question. I'm not sure. I was actually digging into that earlier after I posted my most recent message.

In wasi-parser, for instance, they're represented by a Vector of (String, Type) tuples. In wasm-wave, it has methods for both params() and param_names(), similar to what I'm proposing here, with the caveat that it will return an empty iterable "if this WasmFunc impl does not support param names."

I imagine there are cases where they're not included, but I think that's still manageable. They could easily be represented either by an Vec<Option<String>> or by their index if they're omitted.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 10:03):

bjorn3 commented on issue #9595:

I mean if they are not considered part of the ABI, different components may use different param names for the same function and thus if the host uses named function params derived from the component itself, it wouldn't work with some components even if they are supposed to be abi compatible. Only deriving the named function params that use host uses from a .wit file hard coded into the host would work fine in that case as if the .wit file changes you may need to change the host anyway and can update callers that use named function param at the same time without being affected by the choice of param names by the component that the host wants to load.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 10:07):

Swivelgames commented on issue #9595:

It looks like the serde serializer in wasm-parser also expects them, but omits the names if they're an empty string.

And wasm-encoder expects them as well.

These examples, of course, are being extracted from the .wasm file itself, not the .wit (except maybe wasm-encoder).

But I'm looking around to see if their inclusion is at least outlined in a spec somewhere. :thinking:

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 10:12):

bjorn3 commented on issue #9595:

The fact that it is encoded in the wasm file doesn't mean that it is supposed to affect the abi. It could well be included just to make debugging easier.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 10:22):

Swivelgames commented on issue #9595:

It looks like they're specifically included in the _component-level_ ABI

Component-level type definitions are symmetric to core-level type definitions,
but use a completely different set of value types. Unlike [core:valtype]
which is low-level and assumes a shared linear memory for communicating
compound values, component-level value types assume no shared memory and must
therefore be high-level, describing entire compound values.

/* ... */
functype      ::= (func (param "<label>" <valtype>)* (result <valtype>)?)
/* ... */

In this case they're referred to as "label"s.

They're also included in the Binary format:

functype      ::= 0x40 ps:<paramlist> rs:<resultlist>     => (func ps rs)
paramlist     ::= lt*:vec(<labelvaltype>)                 => (param lt)*

Where labelvaltype is the Label + Type:

labelvaltype  ::= l:<label'> t:<valtype>                  => l t

All _parameter labels_, result labels, record field labels, variant case labels, flag labels, enum case labels, component import names, component export names, instance import names and instance export names must be unique in their containing scope, considering two labels that differ only in case to be equal and thus rejected.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 10:26):

Swivelgames edited a comment on issue #9595:

It looks like they're specifically included in the _component-level_ ABI

Component-level type definitions are symmetric to core-level type definitions,
but use a completely different set of value types. Unlike [core:valtype]
which is low-level and assumes a shared linear memory for communicating
compound values, component-level value types assume no shared memory and must
therefore be high-level, describing entire compound values.

/* ... */
functype      ::= (func (param "<label>" <valtype>)* (result <valtype>)?)
/* ... */

In this case they're referred to as "label"s.

They're also included in the Binary format:

functype      ::= 0x40 ps:<paramlist> rs:<resultlist>     => (func ps rs)
paramlist     ::= lt*:vec(<labelvaltype>)                 => (param lt)*

Where labelvaltype is the Label + Type:

labelvaltype  ::= l:<label'> t:<valtype>                  => l t
label'        ::= len:<u32> l:<label>                     => l    (if len = |l|)

All _parameter labels_, result labels, record field labels, variant case labels, flag labels, enum case labels, component import names, component export names, instance import names and instance export names must be unique in their containing scope, considering two labels that differ only in case to be equal and thus rejected.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 10:30):

Swivelgames commented on issue #9595:

Here's another reference from the canonical-abi/definitions.py :tada:

@dataclass
class FuncType(ExternType):
  params: list[tuple[str,ValType]]

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 10:31):

Swivelgames commented on issue #9595:

So it appears that they're part of the component-level ABI, but not the core-level ABI.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 10:33):

Swivelgames edited a comment on issue #9595:

Here's another reference from the canonical-abi/definitions.py :+1:

@dataclass
class FuncType(ExternType):
  params: list[tuple[str,ValType]]

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 10:41):

bjorn3 commented on issue #9595:

I couldn't find anywhere where the param names are actually checked for equality. AFAICT they are ignored for the purpose of checking if two function types are equal and thus ABI compatible.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 12:08):

Swivelgames commented on issue #9595:

Indeed. It seems my use-case (simply getting the list of parameter names) is supported, but not the additional use-case of implementing host-language named parameters, at least not at the moment.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 12:12):

Swivelgames edited a comment on issue #9595:

Indeed. It seems my use-case (simply getting the list of parameter names of a Component-level function at runtime) is supported, but not the additional use-case of implementing host-language named parameters, at least not at the moment.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 16 2024 at 12:12):

Swivelgames edited a comment on issue #9595:

Indeed. It seems my use-case (simply getting the list of parameter names of a Component-level function at runtime) is supported, but not the additional use-case of implementing host-language named parameters (at least not for the moment).


Last updated: Nov 22 2024 at 16:03 UTC