Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overhaul how type information gets to the CLI #124

Merged
merged 1 commit into from
Apr 14, 2018
Merged

Conversation

alexcrichton
Copy link
Contributor

This commit is a complete overhaul of how the #[wasm_bindgen] macro
communicates type information to the CLI tool, and it's done in a somewhat...
unconventional fashion.

Today we've got a problem where the generated JS needs to understand the types
of each function exported or imported. This understanding is what enables it to
generate the appropriate JS wrappers and such. We want to, however, be quite
flexible and extensible in types that are supported across the boundary, which
means that internally we rely on the trait system to resolve what's what.

Communicating the type information historically was done by creating a four byte
"descriptor" and using associated type projections to communicate that to the
CLI tool. Unfortunately four bytes isn't a lot of space to cram information like
arguments to a generic function, tuple types, etc. In general this just wasn't
flexible enough and the way custom references were treated was also already a
bit of a hack.

This commit takes a radical step of creating a descriptor function for each
function imported/exported. The really crazy part is that the wasm-bindgen CLI
tool now embeds a wasm interpreter and executes these functions when the CLI
tool is invoked. By allowing arbitrary functions to get executed it's now much
easier to inform wasm-bindgen about complicated structures of types. Rest
assured though that all these descriptor functions are automatically unexported
and gc'd away, so this should not have any impact on binary sizes

A new internal trait, WasmDescribe, is added to represent a description of all
types, sort of like a serialization of the structure of a type that
wasm-bindgen can understand. This works by calling a special exported function
with a u32 value a bunch of times. This means that when we run a descriptor we
effectively get a Vec<u32> in the wasm-bindgen CLI tool. This list of
integers can then be parsed into a rich enum for the JS generation to work
with.

This commit currently only retains feature parity with the previous
implementation. I hope to soon solve issues like #123, #104, and #111 with this
support.

}

impl Enum {
fn shared(&self) -> shared::Enum {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trait IntoSharedIr {
    type Shared;

    fn shared(&self) -> Self::Shared;
}

// ...

impl IntoSharedIr for Enum {
    type Shared = shared::Enum;

    fn shared(&self) -> shared::Enum {
        // ...
    }
}

// ...

?

(description.len() >> 0) as u8,
(description.len() >> 8) as u8,
(description.len() >> 16) as u8,
(description.len() >> 24) as u8,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is just code motion, but why is this manual byte ordering here? Feels like something that deserves a comment.

@fitzgen
Copy link
Member

fitzgen commented Apr 13, 2018

This commit takes a radical step of creating a descriptor function for each
function imported/exported. The really crazy part is that the wasm-bindgen CLI
tool now embeds a wasm interpreter and executes these functions when the CLI
tool is invoked. By allowing arbitrary functions to get executed it's now much
easier to inform wasm-bindgen about complicated structures of types. Rest
assured though that all these descriptor functions are automatically unexported
and gc'd away, so this should not have any impact on binary sizes

A new internal trait, WasmDescribe, is added to represent a description of all
types, sort of like a serialization of the structure of a type that
wasm-bindgen can understand. This works by calling a special exported function
with a u32 value a bunch of times. This means that when we run a descriptor we
effectively get a Vec in the wasm-bindgen CLI tool. This list of
integers can then be parsed into a rich enum for the JS generation to work
with.

This seems like a good comment to have at the top of some module -- maybe describe.rs?

@alexcrichton
Copy link
Contributor Author

Thanks for taking a look @fitzgen! There's actually a lot more changes coming soon as well to fix the issues mentioned above, so I think I'm gonna defer rewriting and updating DESIGN.md but I'll be sure to get around to that soon.

This commit is a complete overhaul of how the `#[wasm_bindgen]` macro
communicates type information to the CLI tool, and it's done in a somewhat...
unconventional fashion.

Today we've got a problem where the generated JS needs to understand the types
of each function exported or imported. This understanding is what enables it to
generate the appropriate JS wrappers and such. We want to, however, be quite
flexible and extensible in types that are supported across the boundary, which
means that internally we rely on the trait system to resolve what's what.

Communicating the type information historically was done by creating a four byte
"descriptor" and using associated type projections to communicate that to the
CLI tool. Unfortunately four bytes isn't a lot of space to cram information like
arguments to a generic function, tuple types, etc. In general this just wasn't
flexible enough and the way custom references were treated was also already a
bit of a hack.

This commit takes a radical step of creating a **descriptor function** for each
function imported/exported. The really crazy part is that the `wasm-bindgen` CLI
tool now embeds a wasm interpreter and executes these functions when the CLI
tool is invoked. By allowing arbitrary functions to get executed it's now *much*
easier to inform `wasm-bindgen` about complicated structures of types. Rest
assured though that all these descriptor functions are automatically unexported
and gc'd away, so this should not have any impact on binary sizes

A new internal trait, `WasmDescribe`, is added to represent a description of all
types, sort of like a serialization of the structure of a type that
`wasm-bindgen` can understand. This works by calling a special exported function
with a `u32` value a bunch of times. This means that when we run a descriptor we
effectively get a `Vec<u32>` in the `wasm-bindgen` CLI tool. This list of
integers can then be parsed into a rich `enum` for the JS generation to work
with.

This commit currently only retains feature parity with the previous
implementation. I hope to soon solve issues like #123, #104, and #111 with this
support.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants