WebAssembly / interface-types

Other
641 stars 57 forks source link

Are `i32` and `s32` the same? #86

Open alexcrichton opened 4 years ago

alexcrichton commented 4 years ago

The wasm core spec has the i32 type, and the interface types spec currently has the s32 (signed 32-bit integer) type. We also have the ability to connect the core wasm module's imports with an adapter function, such as:

(module 
    (import "" "" (func (param i32)))
    (@interface implement (import "" "") (param ??) (; ... ;)))

What should ?? be here? I can see one of two options here for validators to implement:

Do others have thoughts on how best to tackle this? This is the same issue for i64 and s64. I don't think this is an issue for f32 and f64 since there's clearly only one way to interpret it there.

I would personally lean towards keeping these distinct types, but also having a validation pass that the exported adapter functions are not allowed to have core wasm type i32/i64 in their type signatures.

fgmccabe commented 4 years ago

Essentially the interface types and core wasm types are distinct. So i32 would need to be coerced to either signed or unsigned. The rationale is that core wasm types are implementation types and interface types are oriented to api specification.

On Tue, Nov 19, 2019 at 10:35 AM Alex Crichton notifications@github.com wrote:

The wasm core spec has the i32 type, and the interface types spec currently has the s32 (signed 32-bit integer) type. We also have the ability to connect the core wasm module's imports with an adapter function, such as:

(module (import "" "" (func (param i32))) (@interface implement (import "" "") (param ??) (; ... ;)))

What should ?? be here? I can see one of two options here for validators to implement:

-

Both i32 and s32 are the same type. Interface adapters would only list interface types as parameters and results, and to match i32 you'd have to write s32. The downside of this approach is that we're unifying these two types and implicitly saying that any i32 coming from the core wasm module is signed, which isn't necessarily always correct. Additionally if the core wasm spec later gets a u16 type, for example, we'd have to be careful to also ensure that it unifies with the adapter type u16, but this may not be the easiest thing to do.

The i32 and s32 types are distinct, so they do not unify. This means that adapter functions must be able to list core wasm types as parameters/results. The upside of this approach is that the two worlds are a bit more sequestered from each other. The downside, however, is that you can export an adapter function with the i32 type as a parameter or a result, so we still have to define what an i32 is, which is probably going to be a signed integer.

Do others have thoughts on how best to tackle this? This is the same issue for i64 and s64. I don't think this is an issue for f32 and f64 since there's clearly only one way to interpret it there.

I would personally lean towards keeping these distinct types, but also having a validation pass that the exported adapter functions are not allowed to have core wasm type i32/i64 in their type signatures.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/WebAssembly/interface-types/issues/86?email_source=notifications&email_token=AAQAXUENYDBAVZWNRBN4GATQUQWWVA5CNFSM4JPHSS4KYY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4H2NXVEA, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQAXUD37BAQP4QIMADTEBLQUQWWVANCNFSM4JPHSS4A .

-- Francis McCabe SWE

devsnek commented 4 years ago

i32 is just some 32 bit "thing". The interface types would say whether to treat that as signed or unsigned.

alexcrichton commented 4 years ago

The main thrust of this issue is that I thought that the intention was that the two types were different, but due to the impelment functionality of hooking up an adapter function to a wasm core import they weren't as different as I originally thought. The existence of this functionality implies that interface adapter functions are actually a function from a list of types to a list of types where the set of types on each end is the union of interface types and wasm core types. (where f32 and f64 are supposably the same element in each set).

If we want to keep the two types distinct we need to rationalize this somehow. What does it mean for i32/i64 wasm core types to show up in interface adapter exports? Are there other type checking/validation things to concern ourselves with if these two types are distinct? (e.g. I thought arg.get would always produce an interface types, but it can actually produce an interface type or a wasm type)

devsnek commented 4 years ago

i have admittedly not been as active with interface types as i'd like to be, but i think i'd expect there to be s32 and u32 in interface types which cover i32, and then all three of those would be valid within interface types.

fgmccabe commented 4 years ago

There is a special situation with f32/f64; but otherwise there should be no overlap between the two schemas. EIther a function has an interface type signature or a core wasm signature. Mixing is not a good idea. This is probably not well enough signaled at the moment.

On Tue, Nov 19, 2019 at 11:15 AM Alex Crichton notifications@github.com wrote:

The main thrust of this issue is that I thought that the intention was that the two types were different, but due to the impelment functionality of hooking up an adapter function to a wasm core import they weren't as different as I originally thought. The existence of this functionality implies that interface adapter functions are actually a function from a list of types to a list of types where the set of types on each end is the union of interface types and wasm core types. (where f32 and f64 are supposably the same element in each set).

If we want to keep the two types distinct we need to rationalize this somehow. What does it mean for i32/i64 wasm core types to show up in interface adapter exports? Are there other type checking/validation things to concern ourselves with if these two types are distinct? (e.g. I thought arg.get would always produce an interface types, but it can actually produce an interface type or a wasm type)

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/WebAssembly/interface-types/issues/86?email_source=notifications&email_token=AAQAXUFVCCAMP4MEIUBPZD3QUQ3L3A5CNFSM4JPHSS4KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEEPMLFQ#issuecomment-555664790, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQAXUC5QFBW7KXYHPMTGD3QUQ3L3ANCNFSM4JPHSS4A .

-- Francis McCabe SWE

alexcrichton commented 4 years ago

@fgmccabe

EIther a function has an interface type signature or a core wasm signature.

To clarify, this is what I'm mostly opening this issue about. As written today with the explainer this is not currently upheld. For example the original comment on this issue lists an example where an adapter function must have a core wasm type in its signature.

This issue is either:

lukewagner commented 4 years ago

I think we have to consider adapter functions that implement a core import differently from adapter functions that are exported. The former must use core wasm types and only core wasm types to match the core wasm import's function signature. For the latter, it seems attractive to say "only interface types" (with f32, f64, anyref, and some other future core types explicitly included), but I think we need to be a bit more nuanced so that we can support use cases like a single "nanoprocess" that is composed of multiple modules sharing a memory. In this case, interface types would be used to describe the external interface of the nanoprocess, but core types would be used for imports within the nanoprocess.

alexcrichton commented 4 years ago

@lukewagner it sounds like you're advocating (to confirm) for distinct types, but also not forbidding i32/i64 in exports and requiring that host languages, environments, and such will have to specify a definition for i32/i64?

lukewagner commented 4 years ago

That would address the "dynamically-linked nanoprocess" use case. The reason I was ambiguous is that I've been wondering about a slightly more nuanced approach of trying to distinguish imports between nanoprocesses (which should logically only use interface types) and imports between the "main" module and its ".dll" modules (which should logically only use core wasm types).

One idea is to say: imported/exported adapter functions can only use interface types while "re-exported" core imported/exported functions would, of course, only use core wasm types. "Re-export"/"Re-import" hasn't been spelled out in detail yet, but we've discussed it informally as a way to trivially propagate the core module's imports/exports into the adapted module's imports/exports. But ultimately this is just a restriction on the general case (of allowing the full union of types), so I'm not sure if it's worth making.

Serentty commented 4 years ago

I would be happy if modules are not allowed to use i32 at all through interfaces, and had to specify signedness. Having APIs which leave signedness unspecified just seems like an oversight.