3204 lines
113 KiB
Rust
Raw Normal View History

Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
use crate::decode;
use crate::descriptor::{Descriptor, VectorKind};
use crate::{Bindgen, EncodeInto, OutputMode};
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
use failure::{bail, Error, ResultExt};
use std::collections::{BTreeMap, HashMap, HashSet};
2019-02-26 08:44:04 -08:00
use std::env;
use std::fs;
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
use walrus::{MemoryId, Module};
use wasm_bindgen_wasm_interpreter::Interpreter;
mod js2rust;
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
use self::js2rust::{ExportedShim, Js2Rust};
mod rust2js;
use self::rust2js::Rust2Js;
mod closures;
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
pub struct Context<'a> {
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
pub globals: String,
pub imports: String,
pub imports_post: String,
pub footer: String,
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
pub typescript: String,
pub exposed_globals: Option<HashSet<&'static str>>,
pub required_internal_exports: HashSet<&'static str>,
pub imported_functions: HashSet<&'a str>,
pub imported_statics: HashSet<&'a str>,
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
pub config: &'a Bindgen,
pub module: &'a mut Module,
pub start: Option<String>,
/// A map which maintains a list of what identifiers we've imported and what
/// they're named locally.
///
/// The `Option<String>` key is the module that identifiers were imported
/// from, `None` being the global module. The second key is a map of
/// identifiers we've already imported from the module to what they're
/// called locally.
pub imported_names: HashMap<ImportModule<'a>, HashMap<&'a str, String>>,
/// A set of all imported identifiers to the number of times they've been
/// imported, used to generate new identifiers.
pub imported_identifiers: HashMap<String, usize>,
/// A map of all imported shim functions which can actually be directly
/// imported from the containing module. The mapping here maps to a tuple,
/// where the first element is the module to import from and the second
/// element is the name to import from the module.
///
/// Note that for `direct_imports` no shims are generated in JS that
/// wasm-bindgen emits.
pub direct_imports: HashMap<&'a str, (&'a str, &'a str)>,
pub exported_classes: Option<BTreeMap<String, ExportedClass>>,
pub function_table_needed: bool,
pub interpreter: &'a mut Interpreter,
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
pub memory: MemoryId,
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
/// A map of all local modules we've found, from the identifier they're
/// known as to their actual JS contents.
pub local_modules: HashMap<&'a str, &'a str>,
/// A map of how many snippets we've seen from each unique crate identifier,
/// used to number snippets correctly when writing them to the filesystem
/// when there's multiple snippets within one crate that aren't all part of
/// the same `Program`.
pub snippet_offsets: HashMap<&'a str, usize>,
/// All package.json dependencies we've learned about so far
pub package_json_read: HashSet<&'a str>,
/// A map of the name of npm dependencies we've loaded so far to the path
/// they're defined in as well as their version specification.
pub npm_dependencies: HashMap<String, (&'a str, String)>,
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
pub anyref: wasm_bindgen_anyref_xform::Context,
}
#[derive(Default)]
pub struct ExportedClass {
comments: String,
contents: String,
typescript: String,
has_constructor: bool,
wrap_needed: bool,
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
pub struct SubContext<'a, 'b: 'a> {
pub program: &'b decode::Program<'b>,
pub cx: &'a mut Context<'b>,
pub vendor_prefixes: HashMap<&'b str, Vec<&'b str>>,
}
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
pub enum ImportTarget {
Function(String),
Method(String),
Constructor(String),
StructuralMethod(String),
StructuralGetter(Option<String>, String),
StructuralSetter(Option<String>, String),
StructuralIndexingGetter(Option<String>),
StructuralIndexingSetter(Option<String>),
StructuralIndexingDeleter(Option<String>),
}
/// Return value of `determine_import` which is where we look at an imported
/// function AST and figure out where it's actually being imported from
/// (performing some validation checks and whatnot).
enum Import<'a> {
/// An item is imported from the global scope. The `name` is what's imported
/// and the optional `field` is the field on that item we're importing.
Global {
name: &'a str,
field: Option<&'a str>,
},
/// Same as `Global`, except the `name` is imported via an ESM import from
/// the specified `module` path.
Module {
module: &'a str,
name: &'a str,
field: Option<&'a str>,
},
/// Same as `Module`, except we're importing from a local module defined in
/// a local JS snippet.
LocalModule {
module: &'a str,
name: &'a str,
field: Option<&'a str>,
},
/// Same as `Module`, except we're importing from an `inline_js` attribute
InlineJs {
unique_crate_identifier: &'a str,
snippet_idx_in_crate: usize,
name: &'a str,
field: Option<&'a str>,
},
/// A global import which may have a number of vendor prefixes associated
/// with it, like `webkitAudioPrefix`. The `name` is the name to test
/// whether it's prefixed.
VendorPrefixed {
name: &'a str,
prefixes: Vec<&'a str>,
},
}
const INITIAL_HEAP_VALUES: &[&str] = &["undefined", "null", "true", "false"];
// Must be kept in sync with `src/lib.rs` of the `wasm-bindgen` crate
const INITIAL_HEAP_OFFSET: usize = 32;
Add support for optional slice types (#507) * Shard the `convert.rs` module into sub-modules Hopefully this'll make the organization a little nicer over time! * Start adding support for optional types This commit starts adding support for optional types to wasm-bindgen as arguments/return values to functions. The strategy here is to add two new traits, `OptionIntoWasmAbi` and `OptionFromWasmAbi`. These two traits are used as a blanket impl to implement `IntoWasmAbi` and `FromWasmAbi` for `Option<T>`. Some consequences of this design: * It should be possible to ensure `Option<SomeForeignType>` implements to/from wasm traits. This is because the option-based traits can be implemented for foreign types. * A specialized implementation is possible for all types, so there's no need for `Option<T>` to introduce unnecessary overhead. * Two new traits is a bit unforutnate but I can't currently think of an alternative design that works for the above two constraints, although it doesn't mean one doesn't exist! * The error messages for "can't use this type here" is actually halfway decent because it says these new traits need to be implemented, which provides a good place to document and talk about what's going on here! * Nested references like `Option<&T>` can't implement `FromWasmAbi`. This means that you can't define a function in Rust which takes `Option<&str>`. It may be possible to do this one day but it'll likely require more trait trickery than I'm capable of right now. * Add support for optional slices This commit adds support for optional slice types, things like strings and arrays. The null representation of these has a pointer value of 0, which should never happen in normal Rust. Otherwise the various plumbing is done throughout the tooling to enable these types in all locations. * Fix `takeObject` on global sentinels These don't have a reference count as they're always expected to work, so avoid actually dropping a reference on them. * Remove some no longer needed bindings * Add support for optional anyref types This commit adds support for optional imported class types. Each type imported with `#[wasm_bindgen]` automatically implements the relevant traits and now supports `Option<Foo>` in various argument/return positions. * Fix building without the `std` feature * Actually fix the build... * Add support for optional types to WebIDL Closes #502
2018-07-19 14:44:23 -05:00
impl<'a> Context<'a> {
fn should_write_global(&mut self, name: &'static str) -> bool {
self.exposed_globals.as_mut().unwrap().insert(name)
}
fn export(&mut self, name: &str, contents: &str, comments: Option<String>) {
let contents = contents.trim();
if let Some(ref c) = comments {
self.globals.push_str(c);
2019-02-27 20:09:28 +00:00
self.typescript.push_str(c);
}
let global = match self.config.mode {
OutputMode::Node {
experimental_modules: false,
} => {
if contents.starts_with("class") {
format!("{1}\nmodule.exports.{0} = {0};\n", name, contents)
} else {
format!("module.exports.{} = {};\n", name, contents)
}
}
OutputMode::NoModules { .. } => {
if contents.starts_with("class") {
format!("{1}\n__exports.{0} = {0};\n", name, contents)
} else {
format!("__exports.{} = {};\n", name, contents)
}
}
OutputMode::Bundler { .. }
| OutputMode::Node {
experimental_modules: true,
} => {
if contents.starts_with("function") {
format!("export function {}{}\n", name, &contents[8..])
} else if contents.starts_with("class") {
format!("export {}\n", contents)
} else {
format!("export const {} = {};\n", name, contents)
}
}
OutputMode::Web => {
// In web mode there's no need to export the internals of
// wasm-bindgen as we're not using the module itself as the
// import object but rather the `__exports` map we'll be
// initializing below.
let export = if name.starts_with("__wbindgen")
|| name.starts_with("__wbg_")
|| name.starts_with("__widl_")
{
""
} else {
"export "
};
if contents.starts_with("function") {
format!("{}function {}{}\n", export, name, &contents[8..])
} else if contents.starts_with("class") {
format!("{}{}\n", export, contents)
} else {
format!("{}const {} = {};\n", export, name, contents)
}
}
};
2018-04-14 09:37:49 -07:00
self.global(&global);
if self.config.mode.web() {
self.global(&format!("__exports.{} = {0};", name));
}
}
2018-06-27 22:42:34 -07:00
fn require_internal_export(&mut self, name: &'static str) -> Result<(), Error> {
if !self.required_internal_exports.insert(name) {
2018-06-27 22:42:34 -07:00
return Ok(());
}
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
if self.module.exports.iter().any(|e| e.name == name) {
return Ok(());
}
2018-06-27 22:42:34 -07:00
bail!(
"the exported function `{}` is required to generate bindings \
but it was not found in the wasm file, perhaps the `std` feature \
of the `wasm-bindgen` crate needs to be enabled?",
name
);
}
pub fn finalize(&mut self, module_name: &str) -> Result<(String, String), Error> {
// Wire up all default intrinsics, those which don't have any sort of
// dependency on the clsoure/anyref/etc passes. This is where almost all
// intrinsics are wired up.
self.wire_up_initial_intrinsics()?;
// Next up, perform our closure rewriting pass. This is where we'll
// update invocations of the closure intrinsics we have to instead call
// appropriate JS functions which actually create closures.
closures::rewrite(self).with_context(|_| "failed to generate internal closure shims")?;
// Finalize all bindings for JS classes. This is where we'll generate JS
// glue for all classes as well as finish up a few final imports like
// `__wrap` and such.
self.write_classes()?;
// And now that we're almost ready, run the final "anyref" pass. This is
// where we transform a wasm module which doesn't actually use `anyref`
// anywhere to using the type internally. The transformation here is
// based off all the previous data we've collected so far for each
// import/export listed.
self.anyref.run(self.module)?;
// With our transforms finished, we can now wire up the final list of
// intrinsics which may depend on the passes run above.
self.wire_up_late_intrinsics()?;
// We're almost done here, so we can delete any internal exports (like
// `__wbindgen_malloc`) if none of our JS glue actually needed it.
self.unexport_unused_internal_exports();
// Handle the `start` function, if one was specified. If we're in a
// --test mode (such as wasm-bindgen-test-runner) then we skip this
// entirely. Otherwise we want to first add a start function to the
// `start` section if one is specified.
//
// Note that once a start function is added, if any, we immediately
// un-start it. This is done because we require that the JS glue
// initializes first, so we execute wasm startup manually once the JS
// glue is all in place.
let mut needs_manual_start = false;
if self.config.emit_start {
self.add_start_function()?;
needs_manual_start = self.unstart_start_function();
}
// If our JS glue needs to access the function table, then do so here.
// JS closure shim generation may access the function table as an
// example, but if there's no closures in the module there's no need to
// export it!
self.export_table()?;
// After all we've done, especially
// `unexport_unused_internal_exports()`, we probably have a bunch of
// garbage in the module that's no longer necessary, so delete
// everything that we don't actually need.
walrus::passes::gc::run(self.module);
// Almost there, but before we're done make sure to rewrite the `module`
// field of all imports in the wasm module. The field is currently
// always `__wbindgen_placeholder__` coming out of rustc, but we need to
// update that here to the shim file or an actual ES module.
self.rewrite_imports(module_name);
// We likely made a ton of modifications, so add ourselves to the
// producers section!
self.update_producers_section();
// Cause any future calls to `should_write_global` to panic, making sure
// we don't ask for items which we can no longer emit.
drop(self.exposed_globals.take().unwrap());
Ok(self.finalize_js(module_name, needs_manual_start))
}
/// Performs the task of actually generating the final JS module, be it
/// `--target no-modules`, `--target web`, or for bundlers. This is the very
/// last step performed in `finalize`.
fn finalize_js(&mut self, module_name: &str, needs_manual_start: bool) -> (String, String) {
2019-04-01 19:45:53 -03:00
let mut ts = self.typescript.clone();
let mut js = String::new();
if self.config.mode.no_modules() {
js.push_str("(function() {\n");
}
// Depending on the output mode, generate necessary glue to actually
// import the wasm file in one way or another.
2019-04-01 19:45:53 -03:00
let mut init = (String::new(), String::new());
match &self.config.mode {
// In `--target no-modules` mode we need to both expose a name on
// the global object as well as generate our own custom start
// function.
OutputMode::NoModules { global } => {
js.push_str("const __exports = {};\n");
js.push_str("let wasm;\n");
init = self.gen_init(&module_name, needs_manual_start);
self.footer.push_str(&format!(
"self.{} = Object.assign(init, __exports);\n",
global
));
}
// With normal CommonJS node we need to defer requiring the wasm
// until the end so most of our own exports are hooked up
OutputMode::Node {
experimental_modules: false,
} => {
self.footer
.push_str(&format!("wasm = require('./{}_bg');\n", module_name));
if needs_manual_start {
self.footer.push_str("wasm.__wbindgen_start();\n");
}
js.push_str("var wasm;\n");
}
// With Bundlers and modern ES6 support in Node we can simply import
// the wasm file as if it were an ES module and let the
// bundler/runtime take care of it.
OutputMode::Bundler { .. }
| OutputMode::Node {
experimental_modules: true,
} => {
self.imports
.push_str(&format!("import * as wasm from './{}_bg';\n", module_name));
if needs_manual_start {
self.footer.push_str("wasm.__wbindgen_start();\n");
}
}
// With a browser-native output we're generating an ES module, but
// browsers don't support natively importing wasm right now so we
// expose the same initialization function as `--target no-modules`
// as the default export of the module.
OutputMode::Web => {
self.imports_post.push_str("const __exports = {};\n");
self.imports_post.push_str("let wasm;\n");
init = self.gen_init(&module_name, needs_manual_start);
self.footer.push_str("export default init;\n");
}
}
2019-04-01 19:45:53 -03:00
let (init_js, init_ts) = init;
ts.push_str(&init_ts);
// Emit all the JS for importing all our functionality
assert!(
!self.config.mode.uses_es_modules() || js.is_empty(),
"ES modules require imports to be at the start of the file"
);
js.push_str(&self.imports);
js.push_str("\n");
js.push_str(&self.imports_post);
js.push_str("\n");
// Emit all our exports from this module
js.push_str(&self.globals);
js.push_str("\n");
// Generate the initialization glue, if there was any
2019-04-01 19:45:53 -03:00
js.push_str(&init_js);
js.push_str("\n");
js.push_str(&self.footer);
js.push_str("\n");
if self.config.mode.no_modules() {
js.push_str("})();\n");
}
while js.contains("\n\n\n") {
js = js.replace("\n\n\n", "\n\n");
}
2019-04-01 19:45:53 -03:00
(js, ts)
}
fn wire_up_initial_intrinsics(&mut self) -> Result<(), Error> {
self.bind("__wbindgen_string_new", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_string_new",
&[],
true,
);
me.expose_get_string_from_wasm();
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
Ok(format!(
"function(p, l) {{ return {}; }}",
me.add_heap_object("getStringFromWasm(p, l)")
2018-06-27 22:42:34 -07:00
))
})?;
self.bind("__wbindgen_number_new", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_number_new",
&[],
true,
);
Ok(format!(
"function(i) {{ return {}; }}",
me.add_heap_object("i")
))
})?;
self.bind("__wbindgen_number_get", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_number_get",
&[(0, false)],
false,
);
me.expose_uint8_memory();
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
Ok(format!(
2018-06-27 22:42:34 -07:00
"
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
function(n, invalid) {{
let obj = {};
2018-06-15 12:55:37 -05:00
if (typeof(obj) === 'number') return obj;
getUint8Memory()[invalid] = 1;
return 0;
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
}}
",
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.get_object("n"),
2018-06-27 22:42:34 -07:00
))
})?;
self.bind("__wbindgen_is_null", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_is_null",
&[(0, false)],
false,
);
Ok(format!(
"function(i) {{ return {} === null ? 1 : 0; }}",
me.get_object("i")
2018-06-27 22:42:34 -07:00
))
})?;
self.bind("__wbindgen_is_undefined", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_is_undefined",
&[(0, false)],
false,
);
Ok(format!(
"function(i) {{ return {} === undefined ? 1 : 0; }}",
me.get_object("i")
2018-06-27 22:42:34 -07:00
))
})?;
self.bind("__wbindgen_boolean_get", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_boolean_get",
&[(0, false)],
false,
);
Ok(format!(
2018-06-27 22:42:34 -07:00
"
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
function(i) {{
let v = {};
return typeof(v) === 'boolean' ? (v ? 1 : 0) : 2;
}}
",
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.get_object("i"),
2018-06-27 22:42:34 -07:00
))
})?;
self.bind("__wbindgen_symbol_new", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_symbol_new",
&[],
true,
);
me.expose_get_string_from_wasm();
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
let expr = "ptr === 0 ? Symbol() : Symbol(getStringFromWasm(ptr, len))";
Ok(format!(
"function(ptr, len) {{ return {}; }}",
me.add_heap_object(expr)
2018-06-27 22:42:34 -07:00
))
})?;
self.bind("__wbindgen_is_symbol", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_is_symbol",
&[(0, false)],
false,
);
Ok(format!(
"function(i) {{ return typeof({}) === 'symbol' ? 1 : 0; }}",
me.get_object("i")
2018-06-27 22:42:34 -07:00
))
})?;
Create the `web-sys` crate mechanically from WebIDL (#409) * Create a new `web-sys` crate This will eventually contain all the WebIDL-generated bindings to Web APIs. * ci: Test the new `web-sys` crate in CI * web-sys: Add a small README * web-sys: Vendor all the WebIDL files from mozilla-central * backend: Add a pass to remove AST items that use undefined imports This is necessary for the WebIDL frontend, which can't translate many WebIDL constructs into equivalent wasm-bindgen AST things yet. It lets us make incremental progress: we can generate bindings to methods we can support right now even though there might be methods on the same interface that we can't support yet. * webidl: Add a bunch of missing semicolons * webidl: Make parsing private It was only `pub` so that we could test it, but we ended up moving towards integration tests rather than unit tests that assert particular ASTs are parsed from WebIDL files. * webidl: Remove uses of undefined import types * test-project-builder: Build projects in "very verbose" mode This helps for debugging failing WebIDL-related tests. * test-project-builder: Add more profiling timers * test-project-builder: Detect when webpack-dev-server fails Instead of going into an infinite loop, detect when webpack-dev-server fails to start up and early exit the test. * webidl: Specify version for dev-dependency on wasm-bindgen-backend Instead of only a relative path. * guide: Add section about contributing to `web-sys` * WIP enable Event.webidl Still need to fix and finish the test. * Update expected webidl output * Start out a test's status as incomplete That way if we don't fill it in the error message doesn't look quite so bizarre * Fix onerror function in headless mode Otherwise we don't see any output! * Fix package.json/node_modules handling in project generation Make sure these are looked up in the git project root rather than the crate root * Avoid logging body text This was meant for debugging and is otherwise pretty noisy * Fix a relative path * More expected test fixes * Fix a typo * test-project-builder: Allow asynchronous tests * webidl: Convert [Unforgeable] attributes into `#[wasm_bindgen(structural)]` Fixes #432 * test-project-builder: Print generated WebIDL bindings for debugging purposes Helps debug bad WebIDL bindings generation inside tests. * When we can't find a descriptor, say which one can't be found This helps when debugging things that need to become structural. * web-sys: Test bindings for Event * ci: Use `--manifest-path dir` instead of `cd dir && ...` * web-sys: Just move .webidl files isntead of symlinking to enable them * tests: Polyfill Array.prototype.values for older browsers in CI * test-project-builder: Don't panic on poisoned headless test mutex We only use it to serialize headless tests so that we don't try to bind the port concurrently. Its OK to run another headless test if an earlier one panicked. * JsValue: Add {is,as}_{object,function} methods Allows dynamically casting values to `js::Object` and `js::Function`. * tidy: Fix whitespace and missing semicolons * Allow for dynamic feature detection of methods If we create bindings to a method that doesn't exist in this implementation, then it shouldn't fail until if/when we actually try and invoke that missing method. * tests: Do feature detection in Array.prototype.values test * Add JsValue::{is_string, as_js_string} methods And document all the cast/convert/check methods for js value. * eslint: allow backtick string literals * Only generate a fallback import function for non-structural imports
2018-07-09 16:35:25 -07:00
self.bind("__wbindgen_is_object", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_is_object",
&[(0, false)],
false,
);
Ok(format!(
Create the `web-sys` crate mechanically from WebIDL (#409) * Create a new `web-sys` crate This will eventually contain all the WebIDL-generated bindings to Web APIs. * ci: Test the new `web-sys` crate in CI * web-sys: Add a small README * web-sys: Vendor all the WebIDL files from mozilla-central * backend: Add a pass to remove AST items that use undefined imports This is necessary for the WebIDL frontend, which can't translate many WebIDL constructs into equivalent wasm-bindgen AST things yet. It lets us make incremental progress: we can generate bindings to methods we can support right now even though there might be methods on the same interface that we can't support yet. * webidl: Add a bunch of missing semicolons * webidl: Make parsing private It was only `pub` so that we could test it, but we ended up moving towards integration tests rather than unit tests that assert particular ASTs are parsed from WebIDL files. * webidl: Remove uses of undefined import types * test-project-builder: Build projects in "very verbose" mode This helps for debugging failing WebIDL-related tests. * test-project-builder: Add more profiling timers * test-project-builder: Detect when webpack-dev-server fails Instead of going into an infinite loop, detect when webpack-dev-server fails to start up and early exit the test. * webidl: Specify version for dev-dependency on wasm-bindgen-backend Instead of only a relative path. * guide: Add section about contributing to `web-sys` * WIP enable Event.webidl Still need to fix and finish the test. * Update expected webidl output * Start out a test's status as incomplete That way if we don't fill it in the error message doesn't look quite so bizarre * Fix onerror function in headless mode Otherwise we don't see any output! * Fix package.json/node_modules handling in project generation Make sure these are looked up in the git project root rather than the crate root * Avoid logging body text This was meant for debugging and is otherwise pretty noisy * Fix a relative path * More expected test fixes * Fix a typo * test-project-builder: Allow asynchronous tests * webidl: Convert [Unforgeable] attributes into `#[wasm_bindgen(structural)]` Fixes #432 * test-project-builder: Print generated WebIDL bindings for debugging purposes Helps debug bad WebIDL bindings generation inside tests. * When we can't find a descriptor, say which one can't be found This helps when debugging things that need to become structural. * web-sys: Test bindings for Event * ci: Use `--manifest-path dir` instead of `cd dir && ...` * web-sys: Just move .webidl files isntead of symlinking to enable them * tests: Polyfill Array.prototype.values for older browsers in CI * test-project-builder: Don't panic on poisoned headless test mutex We only use it to serialize headless tests so that we don't try to bind the port concurrently. Its OK to run another headless test if an earlier one panicked. * JsValue: Add {is,as}_{object,function} methods Allows dynamically casting values to `js::Object` and `js::Function`. * tidy: Fix whitespace and missing semicolons * Allow for dynamic feature detection of methods If we create bindings to a method that doesn't exist in this implementation, then it shouldn't fail until if/when we actually try and invoke that missing method. * tests: Do feature detection in Array.prototype.values test * Add JsValue::{is_string, as_js_string} methods And document all the cast/convert/check methods for js value. * eslint: allow backtick string literals * Only generate a fallback import function for non-structural imports
2018-07-09 16:35:25 -07:00
"
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
function(i) {{
const val = {};
Create the `web-sys` crate mechanically from WebIDL (#409) * Create a new `web-sys` crate This will eventually contain all the WebIDL-generated bindings to Web APIs. * ci: Test the new `web-sys` crate in CI * web-sys: Add a small README * web-sys: Vendor all the WebIDL files from mozilla-central * backend: Add a pass to remove AST items that use undefined imports This is necessary for the WebIDL frontend, which can't translate many WebIDL constructs into equivalent wasm-bindgen AST things yet. It lets us make incremental progress: we can generate bindings to methods we can support right now even though there might be methods on the same interface that we can't support yet. * webidl: Add a bunch of missing semicolons * webidl: Make parsing private It was only `pub` so that we could test it, but we ended up moving towards integration tests rather than unit tests that assert particular ASTs are parsed from WebIDL files. * webidl: Remove uses of undefined import types * test-project-builder: Build projects in "very verbose" mode This helps for debugging failing WebIDL-related tests. * test-project-builder: Add more profiling timers * test-project-builder: Detect when webpack-dev-server fails Instead of going into an infinite loop, detect when webpack-dev-server fails to start up and early exit the test. * webidl: Specify version for dev-dependency on wasm-bindgen-backend Instead of only a relative path. * guide: Add section about contributing to `web-sys` * WIP enable Event.webidl Still need to fix and finish the test. * Update expected webidl output * Start out a test's status as incomplete That way if we don't fill it in the error message doesn't look quite so bizarre * Fix onerror function in headless mode Otherwise we don't see any output! * Fix package.json/node_modules handling in project generation Make sure these are looked up in the git project root rather than the crate root * Avoid logging body text This was meant for debugging and is otherwise pretty noisy * Fix a relative path * More expected test fixes * Fix a typo * test-project-builder: Allow asynchronous tests * webidl: Convert [Unforgeable] attributes into `#[wasm_bindgen(structural)]` Fixes #432 * test-project-builder: Print generated WebIDL bindings for debugging purposes Helps debug bad WebIDL bindings generation inside tests. * When we can't find a descriptor, say which one can't be found This helps when debugging things that need to become structural. * web-sys: Test bindings for Event * ci: Use `--manifest-path dir` instead of `cd dir && ...` * web-sys: Just move .webidl files isntead of symlinking to enable them * tests: Polyfill Array.prototype.values for older browsers in CI * test-project-builder: Don't panic on poisoned headless test mutex We only use it to serialize headless tests so that we don't try to bind the port concurrently. Its OK to run another headless test if an earlier one panicked. * JsValue: Add {is,as}_{object,function} methods Allows dynamically casting values to `js::Object` and `js::Function`. * tidy: Fix whitespace and missing semicolons * Allow for dynamic feature detection of methods If we create bindings to a method that doesn't exist in this implementation, then it shouldn't fail until if/when we actually try and invoke that missing method. * tests: Do feature detection in Array.prototype.values test * Add JsValue::{is_string, as_js_string} methods And document all the cast/convert/check methods for js value. * eslint: allow backtick string literals * Only generate a fallback import function for non-structural imports
2018-07-09 16:35:25 -07:00
return typeof(val) === 'object' && val !== null ? 1 : 0;
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
}}",
me.get_object("i"),
Create the `web-sys` crate mechanically from WebIDL (#409) * Create a new `web-sys` crate This will eventually contain all the WebIDL-generated bindings to Web APIs. * ci: Test the new `web-sys` crate in CI * web-sys: Add a small README * web-sys: Vendor all the WebIDL files from mozilla-central * backend: Add a pass to remove AST items that use undefined imports This is necessary for the WebIDL frontend, which can't translate many WebIDL constructs into equivalent wasm-bindgen AST things yet. It lets us make incremental progress: we can generate bindings to methods we can support right now even though there might be methods on the same interface that we can't support yet. * webidl: Add a bunch of missing semicolons * webidl: Make parsing private It was only `pub` so that we could test it, but we ended up moving towards integration tests rather than unit tests that assert particular ASTs are parsed from WebIDL files. * webidl: Remove uses of undefined import types * test-project-builder: Build projects in "very verbose" mode This helps for debugging failing WebIDL-related tests. * test-project-builder: Add more profiling timers * test-project-builder: Detect when webpack-dev-server fails Instead of going into an infinite loop, detect when webpack-dev-server fails to start up and early exit the test. * webidl: Specify version for dev-dependency on wasm-bindgen-backend Instead of only a relative path. * guide: Add section about contributing to `web-sys` * WIP enable Event.webidl Still need to fix and finish the test. * Update expected webidl output * Start out a test's status as incomplete That way if we don't fill it in the error message doesn't look quite so bizarre * Fix onerror function in headless mode Otherwise we don't see any output! * Fix package.json/node_modules handling in project generation Make sure these are looked up in the git project root rather than the crate root * Avoid logging body text This was meant for debugging and is otherwise pretty noisy * Fix a relative path * More expected test fixes * Fix a typo * test-project-builder: Allow asynchronous tests * webidl: Convert [Unforgeable] attributes into `#[wasm_bindgen(structural)]` Fixes #432 * test-project-builder: Print generated WebIDL bindings for debugging purposes Helps debug bad WebIDL bindings generation inside tests. * When we can't find a descriptor, say which one can't be found This helps when debugging things that need to become structural. * web-sys: Test bindings for Event * ci: Use `--manifest-path dir` instead of `cd dir && ...` * web-sys: Just move .webidl files isntead of symlinking to enable them * tests: Polyfill Array.prototype.values for older browsers in CI * test-project-builder: Don't panic on poisoned headless test mutex We only use it to serialize headless tests so that we don't try to bind the port concurrently. Its OK to run another headless test if an earlier one panicked. * JsValue: Add {is,as}_{object,function} methods Allows dynamically casting values to `js::Object` and `js::Function`. * tidy: Fix whitespace and missing semicolons * Allow for dynamic feature detection of methods If we create bindings to a method that doesn't exist in this implementation, then it shouldn't fail until if/when we actually try and invoke that missing method. * tests: Do feature detection in Array.prototype.values test * Add JsValue::{is_string, as_js_string} methods And document all the cast/convert/check methods for js value. * eslint: allow backtick string literals * Only generate a fallback import function for non-structural imports
2018-07-09 16:35:25 -07:00
))
})?;
Create the `web-sys` crate mechanically from WebIDL (#409) * Create a new `web-sys` crate This will eventually contain all the WebIDL-generated bindings to Web APIs. * ci: Test the new `web-sys` crate in CI * web-sys: Add a small README * web-sys: Vendor all the WebIDL files from mozilla-central * backend: Add a pass to remove AST items that use undefined imports This is necessary for the WebIDL frontend, which can't translate many WebIDL constructs into equivalent wasm-bindgen AST things yet. It lets us make incremental progress: we can generate bindings to methods we can support right now even though there might be methods on the same interface that we can't support yet. * webidl: Add a bunch of missing semicolons * webidl: Make parsing private It was only `pub` so that we could test it, but we ended up moving towards integration tests rather than unit tests that assert particular ASTs are parsed from WebIDL files. * webidl: Remove uses of undefined import types * test-project-builder: Build projects in "very verbose" mode This helps for debugging failing WebIDL-related tests. * test-project-builder: Add more profiling timers * test-project-builder: Detect when webpack-dev-server fails Instead of going into an infinite loop, detect when webpack-dev-server fails to start up and early exit the test. * webidl: Specify version for dev-dependency on wasm-bindgen-backend Instead of only a relative path. * guide: Add section about contributing to `web-sys` * WIP enable Event.webidl Still need to fix and finish the test. * Update expected webidl output * Start out a test's status as incomplete That way if we don't fill it in the error message doesn't look quite so bizarre * Fix onerror function in headless mode Otherwise we don't see any output! * Fix package.json/node_modules handling in project generation Make sure these are looked up in the git project root rather than the crate root * Avoid logging body text This was meant for debugging and is otherwise pretty noisy * Fix a relative path * More expected test fixes * Fix a typo * test-project-builder: Allow asynchronous tests * webidl: Convert [Unforgeable] attributes into `#[wasm_bindgen(structural)]` Fixes #432 * test-project-builder: Print generated WebIDL bindings for debugging purposes Helps debug bad WebIDL bindings generation inside tests. * When we can't find a descriptor, say which one can't be found This helps when debugging things that need to become structural. * web-sys: Test bindings for Event * ci: Use `--manifest-path dir` instead of `cd dir && ...` * web-sys: Just move .webidl files isntead of symlinking to enable them * tests: Polyfill Array.prototype.values for older browsers in CI * test-project-builder: Don't panic on poisoned headless test mutex We only use it to serialize headless tests so that we don't try to bind the port concurrently. Its OK to run another headless test if an earlier one panicked. * JsValue: Add {is,as}_{object,function} methods Allows dynamically casting values to `js::Object` and `js::Function`. * tidy: Fix whitespace and missing semicolons * Allow for dynamic feature detection of methods If we create bindings to a method that doesn't exist in this implementation, then it shouldn't fail until if/when we actually try and invoke that missing method. * tests: Do feature detection in Array.prototype.values test * Add JsValue::{is_string, as_js_string} methods And document all the cast/convert/check methods for js value. * eslint: allow backtick string literals * Only generate a fallback import function for non-structural imports
2018-07-09 16:35:25 -07:00
self.bind("__wbindgen_is_function", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_is_function",
&[(0, false)],
false,
);
Ok(format!(
"function(i) {{ return typeof({}) === 'function' ? 1 : 0; }}",
me.get_object("i")
Create the `web-sys` crate mechanically from WebIDL (#409) * Create a new `web-sys` crate This will eventually contain all the WebIDL-generated bindings to Web APIs. * ci: Test the new `web-sys` crate in CI * web-sys: Add a small README * web-sys: Vendor all the WebIDL files from mozilla-central * backend: Add a pass to remove AST items that use undefined imports This is necessary for the WebIDL frontend, which can't translate many WebIDL constructs into equivalent wasm-bindgen AST things yet. It lets us make incremental progress: we can generate bindings to methods we can support right now even though there might be methods on the same interface that we can't support yet. * webidl: Add a bunch of missing semicolons * webidl: Make parsing private It was only `pub` so that we could test it, but we ended up moving towards integration tests rather than unit tests that assert particular ASTs are parsed from WebIDL files. * webidl: Remove uses of undefined import types * test-project-builder: Build projects in "very verbose" mode This helps for debugging failing WebIDL-related tests. * test-project-builder: Add more profiling timers * test-project-builder: Detect when webpack-dev-server fails Instead of going into an infinite loop, detect when webpack-dev-server fails to start up and early exit the test. * webidl: Specify version for dev-dependency on wasm-bindgen-backend Instead of only a relative path. * guide: Add section about contributing to `web-sys` * WIP enable Event.webidl Still need to fix and finish the test. * Update expected webidl output * Start out a test's status as incomplete That way if we don't fill it in the error message doesn't look quite so bizarre * Fix onerror function in headless mode Otherwise we don't see any output! * Fix package.json/node_modules handling in project generation Make sure these are looked up in the git project root rather than the crate root * Avoid logging body text This was meant for debugging and is otherwise pretty noisy * Fix a relative path * More expected test fixes * Fix a typo * test-project-builder: Allow asynchronous tests * webidl: Convert [Unforgeable] attributes into `#[wasm_bindgen(structural)]` Fixes #432 * test-project-builder: Print generated WebIDL bindings for debugging purposes Helps debug bad WebIDL bindings generation inside tests. * When we can't find a descriptor, say which one can't be found This helps when debugging things that need to become structural. * web-sys: Test bindings for Event * ci: Use `--manifest-path dir` instead of `cd dir && ...` * web-sys: Just move .webidl files isntead of symlinking to enable them * tests: Polyfill Array.prototype.values for older browsers in CI * test-project-builder: Don't panic on poisoned headless test mutex We only use it to serialize headless tests so that we don't try to bind the port concurrently. Its OK to run another headless test if an earlier one panicked. * JsValue: Add {is,as}_{object,function} methods Allows dynamically casting values to `js::Object` and `js::Function`. * tidy: Fix whitespace and missing semicolons * Allow for dynamic feature detection of methods If we create bindings to a method that doesn't exist in this implementation, then it shouldn't fail until if/when we actually try and invoke that missing method. * tests: Do feature detection in Array.prototype.values test * Add JsValue::{is_string, as_js_string} methods And document all the cast/convert/check methods for js value. * eslint: allow backtick string literals * Only generate a fallback import function for non-structural imports
2018-07-09 16:35:25 -07:00
))
})?;
self.bind("__wbindgen_is_string", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_is_string",
&[(0, false)],
false,
);
Ok(format!(
"function(i) {{ return typeof({}) === 'string' ? 1 : 0; }}",
me.get_object("i")
Create the `web-sys` crate mechanically from WebIDL (#409) * Create a new `web-sys` crate This will eventually contain all the WebIDL-generated bindings to Web APIs. * ci: Test the new `web-sys` crate in CI * web-sys: Add a small README * web-sys: Vendor all the WebIDL files from mozilla-central * backend: Add a pass to remove AST items that use undefined imports This is necessary for the WebIDL frontend, which can't translate many WebIDL constructs into equivalent wasm-bindgen AST things yet. It lets us make incremental progress: we can generate bindings to methods we can support right now even though there might be methods on the same interface that we can't support yet. * webidl: Add a bunch of missing semicolons * webidl: Make parsing private It was only `pub` so that we could test it, but we ended up moving towards integration tests rather than unit tests that assert particular ASTs are parsed from WebIDL files. * webidl: Remove uses of undefined import types * test-project-builder: Build projects in "very verbose" mode This helps for debugging failing WebIDL-related tests. * test-project-builder: Add more profiling timers * test-project-builder: Detect when webpack-dev-server fails Instead of going into an infinite loop, detect when webpack-dev-server fails to start up and early exit the test. * webidl: Specify version for dev-dependency on wasm-bindgen-backend Instead of only a relative path. * guide: Add section about contributing to `web-sys` * WIP enable Event.webidl Still need to fix and finish the test. * Update expected webidl output * Start out a test's status as incomplete That way if we don't fill it in the error message doesn't look quite so bizarre * Fix onerror function in headless mode Otherwise we don't see any output! * Fix package.json/node_modules handling in project generation Make sure these are looked up in the git project root rather than the crate root * Avoid logging body text This was meant for debugging and is otherwise pretty noisy * Fix a relative path * More expected test fixes * Fix a typo * test-project-builder: Allow asynchronous tests * webidl: Convert [Unforgeable] attributes into `#[wasm_bindgen(structural)]` Fixes #432 * test-project-builder: Print generated WebIDL bindings for debugging purposes Helps debug bad WebIDL bindings generation inside tests. * When we can't find a descriptor, say which one can't be found This helps when debugging things that need to become structural. * web-sys: Test bindings for Event * ci: Use `--manifest-path dir` instead of `cd dir && ...` * web-sys: Just move .webidl files isntead of symlinking to enable them * tests: Polyfill Array.prototype.values for older browsers in CI * test-project-builder: Don't panic on poisoned headless test mutex We only use it to serialize headless tests so that we don't try to bind the port concurrently. Its OK to run another headless test if an earlier one panicked. * JsValue: Add {is,as}_{object,function} methods Allows dynamically casting values to `js::Object` and `js::Function`. * tidy: Fix whitespace and missing semicolons * Allow for dynamic feature detection of methods If we create bindings to a method that doesn't exist in this implementation, then it shouldn't fail until if/when we actually try and invoke that missing method. * tests: Do feature detection in Array.prototype.values test * Add JsValue::{is_string, as_js_string} methods And document all the cast/convert/check methods for js value. * eslint: allow backtick string literals * Only generate a fallback import function for non-structural imports
2018-07-09 16:35:25 -07:00
))
})?;
self.bind("__wbindgen_string_get", &|me| {
me.expose_pass_string_to_wasm()?;
me.expose_uint32_memory();
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_string_get",
&[(0, false)],
false,
);
Ok(format!(
2018-06-27 22:42:34 -07:00
"
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
function(i, len_ptr) {{
let obj = {};
2018-06-15 12:55:37 -05:00
if (typeof(obj) !== 'string') return 0;
const ptr = passStringToWasm(obj);
getUint32Memory()[len_ptr / 4] = WASM_VECTOR_LEN;
return ptr;
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
}}
",
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.get_object("i"),
2018-06-27 22:42:34 -07:00
))
})?;
2019-01-10 23:37:12 +00:00
self.bind("__wbindgen_debug_string", &|me| {
me.expose_pass_string_to_wasm()?;
me.expose_uint32_memory();
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
let debug_str = "
val => {
// primitive types
const type = typeof val;
if (type == 'number' || type == 'boolean' || val == null) {
return `${val}`;
}
if (type == 'string') {
return `\"${val}\"`;
}
if (type == 'symbol') {
const description = val.description;
if (description == null) {
return 'Symbol';
} else {
return `Symbol(${description})`;
2019-01-10 23:37:12 +00:00
}
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
}
if (type == 'function') {
const name = val.name;
if (typeof name == 'string' && name.length > 0) {
return `Function(${name})`;
2019-01-10 23:37:12 +00:00
} else {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
return 'Function';
2019-01-10 23:37:12 +00:00
}
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
}
// objects
if (Array.isArray(val)) {
const length = val.length;
let debug = '[';
if (length > 0) {
debug += debug_str(val[0]);
2019-01-10 23:37:12 +00:00
}
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
for(let i = 1; i < length; i++) {
debug += ', ' + debug_str(val[i]);
2019-01-16 10:46:26 +00:00
}
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
debug += ']';
return debug;
}
// Test for built-in
const builtInMatches = /\\[object ([^\\]]+)\\]/.exec(toString.call(val));
let className;
if (builtInMatches.length > 1) {
className = builtInMatches[1];
} else {
// Failed to match the standard '[object ClassName]'
return toString.call(val);
}
if (className == 'Object') {
// we're a user defined class or Object
// JSON.stringify avoids problems with cycles, and is generally much
// easier than looping through ownProperties of `val`.
try {
return 'Object(' + JSON.stringify(val) + ')';
} catch (_) {
return 'Object';
}
}
// errors
if (val instanceof Error) {
return `${val.name}: ${val.message}\n${val.stack}`;
}
// TODO we could test for more things here, like `Set`s and `Map`s.
return className;
}
";
Ok(format!(
"
function(i, len_ptr) {{
const debug_str = {};
const toString = Object.prototype.toString;
const val = {};
2019-01-10 23:37:12 +00:00
const debug = debug_str(val);
const ptr = passStringToWasm(debug);
getUint32Memory()[len_ptr / 4] = WASM_VECTOR_LEN;
return ptr;
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
}}
",
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
debug_str,
me.get_object("i"),
))
})?;
self.bind("__wbindgen_cb_drop", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_cb_drop",
&[(0, true)],
false,
);
Ok(format!(
2018-06-27 22:42:34 -07:00
"
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
function(i) {{
const obj = {}.original;
if (obj.cnt-- == 1) {{
obj.a = 0;
return 1;
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
}}
return 0;
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
}}
",
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.take_object("i"),
2018-06-27 22:42:34 -07:00
))
})?;
self.bind("__wbindgen_cb_forget", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
Ok(if me.config.anyref {
// TODO: we should rewrite this in the anyref xform to not even
// call into JS
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_cb_drop",
&[(0, true)],
false,
);
String::from("function(obj) {}")
} else {
me.expose_drop_ref();
"dropObject".to_string()
})
})?;
self.bind("__wbindgen_json_parse", &|me| {
me.expose_get_string_from_wasm();
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_json_parse",
&[],
true,
);
let expr = "JSON.parse(getStringFromWasm(ptr, len))";
let expr = me.add_heap_object(expr);
Ok(format!("function(ptr, len) {{ return {}; }}", expr))
})?;
self.bind("__wbindgen_json_serialize", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.anyref.import_xform(
"__wbindgen_placeholder__",
"__wbindgen_json_serialize",
&[(0, false)],
false,
);
me.expose_pass_string_to_wasm()?;
me.expose_uint32_memory();
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
Ok(format!(
2018-06-27 22:42:34 -07:00
"
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
function(idx, ptrptr) {{
const ptr = passStringToWasm(JSON.stringify({}));
getUint32Memory()[ptrptr / 4] = ptr;
return WASM_VECTOR_LEN;
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
}}
",
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
me.get_object("idx"),
2018-06-27 22:42:34 -07:00
))
})?;
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
self.bind("__wbindgen_jsval_eq", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
Ok(format!(
"function(a, b) {{ return {} === {} ? 1 : 0; }}",
me.get_object("a"),
me.get_object("b")
2018-06-27 22:42:34 -07:00
))
})?;
self.bind("__wbindgen_memory", &|me| {
let mem = me.memory();
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
Ok(format!(
"function() {{ return {}; }}",
me.add_heap_object(mem)
))
})?;
self.bind("__wbindgen_module", &|me| {
if !me.config.mode.no_modules() && !me.config.mode.web() {
2018-11-27 12:07:59 -08:00
bail!(
"`wasm_bindgen::module` is currently only supported with \
`--target no-modules` and `--target web`"
2018-11-27 12:07:59 -08:00
);
}
Ok(format!(
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
"function() {{ return {}; }}",
me.add_heap_object("init.__wbindgen_wasm_module")
))
})?;
self.bind("__wbindgen_function_table", &|me| {
me.function_table_needed = true;
Ok(format!(
"function() {{ return {}; }}",
me.add_heap_object("wasm.__wbg_function_table")
))
})?;
self.bind("__wbindgen_rethrow", &|me| {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
Ok(format!(
"function(idx) {{ throw {}; }}",
me.take_object("idx")
))
})?;
self.bind("__wbindgen_throw", &|me| {
me.expose_get_string_from_wasm();
Ok(String::from(
"
function(ptr, len) {
throw new Error(getStringFromWasm(ptr, len));
}
",
))
})?;
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
Ok(())
}
/// Provide implementations of remaining intrinsics after initial passes
/// have been run on the wasm module.
///
/// The intrinsics implemented here are added very late in the process or
/// otherwise may be overwritten by passes (such as the anyref pass). As a
/// result they don't go into the initial list of intrinsics but go just at
/// the end.
fn wire_up_late_intrinsics(&mut self) -> Result<(), Error> {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
// After the anyref pass has executed, if this intrinsic is needed then
// we expose a function which initializes it
self.bind("__wbindgen_init_anyref_table", &|me| {
me.expose_anyref_table();
Ok(String::from(
"function() {
const table = wasm.__wbg_anyref_table;
const offset = table.grow(4);
table.set(offset + 0, undefined);
table.set(offset + 1, null);
table.set(offset + 2, true);
table.set(offset + 3, false);
}",
))
})?;
// make sure that the anyref pass runs before binding this as anyref may
// remove calls to this import and then gc would remove it
self.bind("__wbindgen_object_clone_ref", &|me| {
me.expose_get_object();
me.expose_add_heap_object();
Ok(String::from(
"
function(idx) {
return addHeapObject(getObject(idx));
}
",
))
})?;
// like above, make sure anyref runs first and the anyref pass may
// remove usages of this.
self.bind("__wbindgen_object_drop_ref", &|me| {
me.expose_drop_ref();
Ok(String::from("function(i) { dropObject(i); }"))
})?;
Ok(())
}
2019-04-01 19:45:53 -03:00
fn ts_for_init_fn(has_memory: bool) -> String {
let (memory_doc, memory_param) = if has_memory {
(
"* @param {WebAssembly.Memory} maybe_memory\n",
", maybe_memory: WebAssembly.Memory",
)
} else {
("", "")
};
format!(
"\n\
/**\n\
* If `module_or_path` is {{RequestInfo}}, makes a request and\n\
* for everything else, calls `WebAssembly.instantiate` directly.\n\
*\n\
* @param {{RequestInfo | BufferSource | WebAssembly.Module}} module_or_path\n\
{}\
*\n\
* @returns {{Promise<any>}}\n\
*/\n\
export function init \
(module_or_path: RequestInfo | BufferSource | WebAssembly.Module{}): Promise<any>;
",
memory_doc, memory_param
)
}
fn gen_init(&mut self, module_name: &str, needs_manual_start: bool) -> (String, String) {
let mem = self.module.memories.get(self.memory);
let (init_memory1, init_memory2) = if mem.import.is_some() {
let mut memory = String::from("new WebAssembly.Memory({");
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
memory.push_str(&format!("initial:{}", mem.initial));
if let Some(max) = mem.maximum {
memory.push_str(&format!(",maximum:{}", max));
}
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
if mem.shared {
memory.push_str(",shared:true");
}
memory.push_str("})");
self.imports_post.push_str("let memory;\n");
(
format!("memory = __exports.memory = maybe_memory;"),
format!("memory = __exports.memory = {};", memory),
2018-04-05 19:50:26 +05:45
)
} else {
(String::new(), String::new())
2018-04-05 19:50:26 +05:45
};
2019-04-01 19:45:53 -03:00
let init_memory_arg = if mem.import.is_some() {
", maybe_memory"
} else {
""
};
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
2019-04-01 19:45:53 -03:00
let ts = Self::ts_for_init_fn(mem.import.is_some());
let js = format!(
"\
function init(module{init_memory_arg}) {{
let result;
const imports = {{ './{module}': __exports }};
if (module instanceof URL || typeof module === 'string' || module instanceof Request) {{
{init_memory2}
const response = fetch(module);
if (typeof WebAssembly.instantiateStreaming === 'function') {{
result = WebAssembly.instantiateStreaming(response, imports)
.catch(e => {{
console.warn(\"`WebAssembly.instantiateStreaming` failed. Assuming this is \
because your server does not serve wasm with \
`application/wasm` MIME type. Falling back to \
`WebAssembly.instantiate` which is slower. Original \
error:\\n\", e);
return response
.then(r => r.arrayBuffer())
.then(bytes => WebAssembly.instantiate(bytes, imports));
}});
}} else {{
result = response
.then(r => r.arrayBuffer())
.then(bytes => WebAssembly.instantiate(bytes, imports));
}}
}} else {{
{init_memory1}
result = WebAssembly.instantiate(module, imports)
.then(result => {{
if (result instanceof WebAssembly.Instance) {{
return {{ instance: result, module }};
}} else {{
return result;
}}
}});
}}
return result.then(({{instance, module}}) => {{
wasm = instance.exports;
init.__wbindgen_wasm_module = module;
{start}
return wasm;
}});
}}
",
2019-04-01 19:45:53 -03:00
init_memory_arg = init_memory_arg,
module = module_name,
init_memory1 = init_memory1,
init_memory2 = init_memory2,
start = if needs_manual_start {
"wasm.__wbindgen_start();"
} else {
""
},
2019-04-01 19:45:53 -03:00
);
(js, ts)
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
2018-06-27 22:42:34 -07:00
fn bind(
&mut self,
name: &str,
f: &Fn(&mut Self) -> Result<String, Error>,
) -> Result<(), Error> {
if !self.wasm_import_needed(name) {
return Ok(());
}
let contents = f(self)
2018-06-27 22:42:34 -07:00
.with_context(|_| format!("failed to generate internal JS function `{}`", name))?;
self.export(name, &contents, None);
Ok(())
}
fn write_classes(&mut self) -> Result<(), Error> {
for (class, exports) in self.exported_classes.take().unwrap() {
self.write_class(&class, &exports)?;
}
Ok(())
}
fn write_class(&mut self, name: &str, class: &ExportedClass) -> Result<(), Error> {
let mut dst = format!("class {} {{\n", name);
let mut ts_dst = format!("export {}", dst);
let (mkweakref, freeref) = if self.config.weak_refs {
// When weak refs are enabled we use them to automatically free the
// contents of an exported rust class when it's gc'd. Note that a
// manual `free` function still exists for deterministic
// destruction.
//
// This is implemented by using a `WeakRefGroup` to run finalizers
// for all `WeakRef` objects that it creates. Upon construction of
// a new wasm object we use `makeRef` with "holdings" of a thunk to
// free the wasm instance. Once the `this` (the instance we're
// creating) is gc'd then the finalizer will run with the
// `WeakRef`, and we'll pull out the `holdings`, our pointer.
//
// Note, though, that if manual finalization happens we want to
// cancel the `WeakRef`-generated finalization, so we retain the
// `WeakRef` in a global map. This global map is then used to
// `drop()` the `WeakRef` (cancel finalization) whenever it is
// finalized.
self.expose_cleanup_groups();
let mk = format!("addCleanup(this, this.ptr, free{});", name);
let free = "
CLEANUPS_MAP.get(ptr).drop();
CLEANUPS_MAP.delete(ptr);
";
(mk, free)
} else {
(String::new(), "")
};
if self.config.debug && !class.has_constructor {
dst.push_str(
2018-06-27 22:42:34 -07:00
"
constructor() {
throw new Error('cannot invoke `new` directly');
}
",
);
}
let mut wrap_needed = class.wrap_needed;
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
let new_name = wasm_bindgen_shared::new_function(&name);
if self.wasm_import_needed(&new_name) {
wrap_needed = true;
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
self.anyref
.import_xform("__wbindgen_placeholder__", &new_name, &[], true);
let expr = format!("{}.__wrap(ptr)", name);
let expr = self.add_heap_object(&expr);
let body = format!("function(ptr) {{ return {}; }}", expr);
self.export(&new_name, &body, None);
}
if wrap_needed {
dst.push_str(&format!(
"
static __wrap(ptr) {{
const obj = Object.create({}.prototype);
obj.ptr = ptr;
{}
return obj;
}}
",
name,
mkweakref.replace("this", "obj"),
));
}
self.global(&format!(
"
function free{}(ptr) {{
{}
wasm.{}(ptr);
}}
",
name,
freeref,
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
wasm_bindgen_shared::free_function(&name)
));
2018-06-27 22:42:34 -07:00
dst.push_str(&format!(
"
free() {{
const ptr = this.ptr;
this.ptr = 0;
free{}(ptr);
}}
",
name,
2018-06-27 22:42:34 -07:00
));
ts_dst.push_str(" free(): void;");
dst.push_str(&class.contents);
ts_dst.push_str(&class.typescript);
dst.push_str("}\n");
ts_dst.push_str("}\n");
self.export(&name, &dst, Some(class.comments.clone()));
self.typescript.push_str(&ts_dst);
Ok(())
}
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
fn export_table(&mut self) -> Result<(), Error> {
if !self.function_table_needed {
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
return Ok(());
}
let id = match self.module.tables.main_function_table()? {
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
Some(id) => id,
None => bail!("no function table found in module"),
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
};
self.module.exports.add("__wbg_function_table", id);
Ok(())
}
fn rewrite_imports(&mut self, module_name: &str) {
for (name, contents) in self._rewrite_imports(module_name) {
self.export(&name, &contents, None);
}
}
2018-06-27 22:42:34 -07:00
fn _rewrite_imports(&mut self, module_name: &str) -> Vec<(String, String)> {
let mut math_imports = Vec::new();
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
for import in self.module.imports.iter_mut() {
if import.module == "__wbindgen_placeholder__" {
import.module.truncate(0);
if let Some((module, name)) = self.direct_imports.get(import.name.as_str()) {
import.name.truncate(0);
import.module.push_str(module);
import.name.push_str(name);
} else {
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
import.module.push_str("./");
import.module.push_str(module_name);
}
2018-04-07 13:06:36 +05:45
continue;
}
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
if import.module != "env" {
2018-04-07 13:06:36 +05:45
continue;
}
// If memory is imported we'll have exported it from the shim module
// so let's import it from there.
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
//
// TODO: we should track this is in a more first-class fashion
// rather than just matching on strings.
if import.name == "memory" {
import.module.truncate(0);
import.module.push_str("./");
import.module.push_str(module_name);
continue;
}
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
let renamed_import = format!("__wbindgen_{}", import.name);
let mut bind_math = |expr: &str| {
2018-06-27 22:42:34 -07:00
math_imports.push((renamed_import.clone(), format!("function{}", expr)));
};
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
// Note that since Rust 1.32.0 this is no longer necessary. Imports
// of these functions were fixed in rust-lang/rust#54257 and we're
// just waiting until pre-1.32.0 compilers are basically no longer
// in use to remove this.
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
match import.name.as_str() {
"Math_acos" => bind_math("(x) { return Math.acos(x); }"),
"Math_asin" => bind_math("(x) { return Math.asin(x); }"),
"Math_atan" => bind_math("(x) { return Math.atan(x); }"),
"Math_atan2" => bind_math("(x, y) { return Math.atan2(x, y); }"),
"Math_cbrt" => bind_math("(x) { return Math.cbrt(x); }"),
"Math_cosh" => bind_math("(x) { return Math.cosh(x); }"),
"Math_expm1" => bind_math("(x) { return Math.expm1(x); }"),
"Math_hypot" => bind_math("(x, y) { return Math.hypot(x, y); }"),
"Math_log1p" => bind_math("(x) { return Math.log1p(x); }"),
"Math_sinh" => bind_math("(x) { return Math.sinh(x); }"),
"Math_tan" => bind_math("(x) { return Math.tan(x); }"),
"Math_tanh" => bind_math("(x) { return Math.tanh(x); }"),
_ => continue,
}
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
import.module.truncate(0);
import.module.push_str("./");
import.module.push_str(module_name);
import.name = renamed_import.clone();
}
math_imports
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
fn unexport_unused_internal_exports(&mut self) {
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
let mut to_remove = Vec::new();
for export in self.module.exports.iter() {
match export.name.as_str() {
// These are some internal imports set by LLD but currently
// we've got no use case for continuing to export them, so
// blacklist them.
"__heap_base" | "__data_end" | "__indirect_function_table" => {
to_remove.push(export.id());
}
// Otherwise only consider our special exports, which all start
// with the same prefix which hopefully only we're using.
n if n.starts_with("__wbindgen") => {
if !self.required_internal_exports.contains(n) {
to_remove.push(export.id());
}
}
_ => {}
}
}
for id in to_remove {
self.module.exports.delete(id);
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
}
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
fn expose_drop_ref(&mut self) {
if !self.should_write_global("drop_ref") {
2018-04-07 13:06:36 +05:45
return;
}
self.expose_global_heap();
self.expose_global_heap_next();
// Note that here we check if `idx` shouldn't actually be dropped. This
// is due to the fact that `JsValue::null()` and friends can be passed
// by value to JS where we'll automatically call this method. Those
// constants, however, cannot be dropped. See #1054 for removing this
// branch.
//
// Otherwise the free operation here is pretty simple, just appending to
// the linked list of heap slots that are free.
2018-06-27 22:42:34 -07:00
self.global(&format!(
"
function dropObject(idx) {{
Add support for optional slice types (#507) * Shard the `convert.rs` module into sub-modules Hopefully this'll make the organization a little nicer over time! * Start adding support for optional types This commit starts adding support for optional types to wasm-bindgen as arguments/return values to functions. The strategy here is to add two new traits, `OptionIntoWasmAbi` and `OptionFromWasmAbi`. These two traits are used as a blanket impl to implement `IntoWasmAbi` and `FromWasmAbi` for `Option<T>`. Some consequences of this design: * It should be possible to ensure `Option<SomeForeignType>` implements to/from wasm traits. This is because the option-based traits can be implemented for foreign types. * A specialized implementation is possible for all types, so there's no need for `Option<T>` to introduce unnecessary overhead. * Two new traits is a bit unforutnate but I can't currently think of an alternative design that works for the above two constraints, although it doesn't mean one doesn't exist! * The error messages for "can't use this type here" is actually halfway decent because it says these new traits need to be implemented, which provides a good place to document and talk about what's going on here! * Nested references like `Option<&T>` can't implement `FromWasmAbi`. This means that you can't define a function in Rust which takes `Option<&str>`. It may be possible to do this one day but it'll likely require more trait trickery than I'm capable of right now. * Add support for optional slices This commit adds support for optional slice types, things like strings and arrays. The null representation of these has a pointer value of 0, which should never happen in normal Rust. Otherwise the various plumbing is done throughout the tooling to enable these types in all locations. * Fix `takeObject` on global sentinels These don't have a reference count as they're always expected to work, so avoid actually dropping a reference on them. * Remove some no longer needed bindings * Add support for optional anyref types This commit adds support for optional imported class types. Each type imported with `#[wasm_bindgen]` automatically implements the relevant traits and now supports `Option<Foo>` in various argument/return positions. * Fix building without the `std` feature * Actually fix the build... * Add support for optional types to WebIDL Closes #502
2018-07-19 14:44:23 -05:00
if (idx < {}) return;
heap[idx] = heap_next;
heap_next = idx;
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}}
",
INITIAL_HEAP_OFFSET + INITIAL_HEAP_VALUES.len(),
2018-06-27 22:42:34 -07:00
));
}
fn expose_global_heap(&mut self) {
if !self.should_write_global("heap") {
2018-04-07 13:06:36 +05:45
return;
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
assert!(!self.config.anyref);
self.global(&format!("const heap = new Array({});", INITIAL_HEAP_OFFSET));
self.global("heap.fill(undefined);");
self.global(&format!("heap.push({});", INITIAL_HEAP_VALUES.join(", ")));
}
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
fn expose_global_heap_next(&mut self) {
if !self.should_write_global("heap_next") {
2018-04-07 13:06:36 +05:45
return;
}
self.expose_global_heap();
self.global("let heap_next = heap.length;");
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
fn expose_get_object(&mut self) {
if !self.should_write_global("get_object") {
2018-04-07 13:06:36 +05:45
return;
}
self.expose_global_heap();
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
// Accessing a heap object is just a simple index operation due to how
// the stack/heap are laid out.
self.global("function getObject(idx) { return heap[idx]; }");
}
fn expose_assert_num(&mut self) {
if !self.should_write_global("assert_num") {
2018-04-07 13:06:36 +05:45
return;
}
2018-06-27 22:42:34 -07:00
self.global(&format!(
"
function _assertNum(n) {{
2018-06-15 12:55:37 -05:00
if (typeof(n) !== 'number') throw new Error('expected a number argument');
}}
"
2018-06-27 22:42:34 -07:00
));
}
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
fn expose_assert_bool(&mut self) {
if !self.should_write_global("assert_bool") {
2018-04-07 13:06:36 +05:45
return;
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
2018-06-27 22:42:34 -07:00
self.global(&format!(
"
function _assertBoolean(n) {{
2018-06-15 12:55:37 -05:00
if (typeof(n) !== 'boolean') {{
throw new Error('expected a boolean argument');
2018-06-15 12:55:37 -05:00
}}
}}
"
2018-06-27 22:42:34 -07:00
));
}
fn expose_wasm_vector_len(&mut self) {
if !self.should_write_global("wasm_vector_len") {
return;
}
self.global("let WASM_VECTOR_LEN = 0;");
}
fn expose_pass_string_to_wasm(&mut self) -> Result<(), Error> {
if !self.should_write_global("pass_string_to_wasm") {
return Ok(());
}
self.require_internal_export("__wbindgen_malloc")?;
self.expose_wasm_vector_len();
let debug = if self.config.debug {
"
2018-06-15 12:55:37 -05:00
if (typeof(arg) !== 'string') throw new Error('expected a string argument');
"
} else {
""
};
// If we are targeting Node.js, it doesn't have `encodeInto` yet
// but it does have `Buffer::write` which has similar semantics but
// doesn't require creating intermediate view using `subarray`
// and also has `Buffer::byteLength` to calculate size upfront.
if self.config.mode.nodejs() {
self.expose_node_buffer_memory();
self.global(&format!(
"
function passStringToWasm(arg) {{
{}
const size = Buffer.byteLength(arg);
const ptr = wasm.__wbindgen_malloc(size);
getNodeBufferMemory().write(arg, ptr, size);
WASM_VECTOR_LEN = size;
return ptr;
}}
",
debug,
));
return Ok(());
}
self.expose_text_encoder();
self.expose_uint8_memory();
// The first implementation we have for this is to use
// `TextEncoder#encode` which has been around for quite some time.
let use_encode = format!(
2018-06-27 22:42:34 -07:00
"
{}
const buf = cachedTextEncoder.encode(arg);
const ptr = wasm.__wbindgen_malloc(buf.length);
2018-04-03 13:20:56 -07:00
getUint8Memory().set(buf, ptr);
WASM_VECTOR_LEN = buf.length;
return ptr;
",
2018-06-27 22:42:34 -07:00
debug
);
// Another possibility is to use `TextEncoder#encodeInto` which is much
// newer and isn't implemented everywhere yet. It's more efficient,
// however, becaues it allows us to elide an intermediate allocation.
let use_encode_into = format!(
"
{}
let size = arg.length;
let ptr = wasm.__wbindgen_malloc(size);
let writeOffset = 0;
while (true) {{
const view = getUint8Memory().subarray(ptr + writeOffset, ptr + size);
const {{ read, written }} = cachedTextEncoder.encodeInto(arg, view);
if (read === arg.length) {{
break;
}}
arg = arg.substring(read);
writeOffset += written;
ptr = wasm.__wbindgen_realloc(ptr, size, size += arg.length * 3);
}}
WASM_VECTOR_LEN = writeOffset;
return ptr;
",
debug
);
// Looks like `encodeInto` doesn't currently work when the memory passed
// in is backed by a `SharedArrayBuffer`, so force usage of `encode` if
// a `SharedArrayBuffer` is in use.
let shared = self.module.memories.get(self.memory).shared;
match self.config.encode_into {
EncodeInto::Always if !shared => {
self.require_internal_export("__wbindgen_realloc")?;
self.global(&format!(
"function passStringToWasm(arg) {{ {} }}",
use_encode_into,
));
}
EncodeInto::Test if !shared => {
self.require_internal_export("__wbindgen_realloc")?;
self.global(&format!(
"
let passStringToWasm;
if (typeof cachedTextEncoder.encodeInto === 'function') {{
passStringToWasm = function(arg) {{ {} }};
}} else {{
passStringToWasm = function(arg) {{ {} }};
}}
",
use_encode_into, use_encode,
));
}
_ => {
self.global(&format!(
"function passStringToWasm(arg) {{ {} }}",
use_encode,
));
}
}
Ok(())
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
fn expose_pass_array8_to_wasm(&mut self) -> Result<(), Error> {
self.expose_uint8_memory();
self.pass_array_to_wasm("passArray8ToWasm", "getUint8Memory", 1)
}
fn expose_pass_array16_to_wasm(&mut self) -> Result<(), Error> {
self.expose_uint16_memory();
self.pass_array_to_wasm("passArray16ToWasm", "getUint16Memory", 2)
}
fn expose_pass_array32_to_wasm(&mut self) -> Result<(), Error> {
self.expose_uint32_memory();
self.pass_array_to_wasm("passArray32ToWasm", "getUint32Memory", 4)
}
fn expose_pass_array64_to_wasm(&mut self) -> Result<(), Error> {
self.expose_uint64_memory();
self.pass_array_to_wasm("passArray64ToWasm", "getUint64Memory", 8)
}
fn expose_pass_array_f32_to_wasm(&mut self) -> Result<(), Error> {
self.expose_f32_memory();
self.pass_array_to_wasm("passArrayF32ToWasm", "getFloat32Memory", 4)
}
fn expose_pass_array_f64_to_wasm(&mut self) -> Result<(), Error> {
self.expose_f64_memory();
self.pass_array_to_wasm("passArrayF64ToWasm", "getFloat64Memory", 8)
}
fn expose_pass_array_jsvalue_to_wasm(&mut self) -> Result<(), Error> {
if !self.should_write_global("pass_array_jsvalue") {
return Ok(());
}
self.require_internal_export("__wbindgen_malloc")?;
self.expose_uint32_memory();
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
if self.config.anyref {
// TODO: using `addToAnyrefTable` goes back and forth between wasm
// and JS a lot, we should have a bulk operation for this.
self.expose_add_to_anyref_table()?;
self.global(
"
function passArrayJsValueToWasm(array) {
const ptr = wasm.__wbindgen_malloc(array.length * 4);
const mem = getUint32Memory();
for (let i = 0; i < array.length; i++) {
mem[ptr / 4 + i] = addToAnyrefTable(array[i]);
}
WASM_VECTOR_LEN = array.length;
return ptr;
}
",
);
} else {
self.expose_add_heap_object();
self.global(
"
function passArrayJsValueToWasm(array) {
const ptr = wasm.__wbindgen_malloc(array.length * 4);
const mem = getUint32Memory();
for (let i = 0; i < array.length; i++) {
mem[ptr / 4 + i] = addHeapObject(array[i]);
}
WASM_VECTOR_LEN = array.length;
return ptr;
}
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
",
);
}
Ok(())
}
2018-06-27 22:42:34 -07:00
fn pass_array_to_wasm(
&mut self,
name: &'static str,
delegate: &str,
size: usize,
) -> Result<(), Error> {
if !self.should_write_global(name) {
2018-06-27 22:42:34 -07:00
return Ok(());
}
self.require_internal_export("__wbindgen_malloc")?;
self.expose_wasm_vector_len();
2018-06-27 22:42:34 -07:00
self.global(&format!(
"
function {}(arg) {{
const ptr = wasm.__wbindgen_malloc(arg.length * {size});
{}().set(arg, ptr / {size});
WASM_VECTOR_LEN = arg.length;
return ptr;
}}
",
2018-06-27 22:42:34 -07:00
name,
delegate,
size = size
));
Ok(())
}
fn expose_text_encoder(&mut self) {
if !self.should_write_global("text_encoder") {
2018-04-07 13:06:36 +05:45
return;
}
self.expose_text_processor("TextEncoder");
2018-02-05 16:39:11 -08:00
}
fn expose_text_decoder(&mut self) {
if !self.should_write_global("text_decoder") {
2018-04-07 13:06:36 +05:45
return;
2018-02-05 16:39:11 -08:00
}
self.expose_text_processor("TextDecoder");
}
fn expose_text_processor(&mut self, s: &str) {
if self.config.mode.nodejs_experimental_modules() {
2018-11-27 12:07:59 -08:00
self.imports
.push_str(&format!("import {{ {} }} from 'util';\n", s));
self.global(&format!("let cached{0} = new {0}('utf-8');", s));
} else if self.config.mode.nodejs() {
self.global(&format!("const {0} = require('util').{0};", s));
self.global(&format!("let cached{0} = new {0}('utf-8');", s));
} else if !self.config.mode.always_run_in_browser() {
2018-11-27 12:07:59 -08:00
self.global(&format!(
"
const l{0} = typeof {0} === 'undefined' ? \
require('util').{0} : {0};\
2018-11-27 12:07:59 -08:00
",
s
));
self.global(&format!("let cached{0} = new l{0}('utf-8');", s));
} else {
self.global(&format!("let cached{0} = new {0}('utf-8');", s));
}
}
2018-02-05 16:39:11 -08:00
fn expose_get_string_from_wasm(&mut self) {
if !self.should_write_global("get_string_from_wasm") {
2018-04-07 13:06:36 +05:45
return;
}
self.expose_text_decoder();
self.expose_uint8_memory();
// Typically we try to give a raw view of memory out to `TextDecoder` to
// avoid copying too much data. If, however, a `SharedArrayBuffer` is
// being used it looks like that is rejected by `TextDecoder` or
// otherwise doesn't work with it. When we detect a shared situation we
// use `slice` which creates a new array instead of `subarray` which
// creates just a view. That way in shared mode we copy more data but in
// non-shared mode there's no need to copy the data except for the
// string itself.
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
let is_shared = self.module.memories.get(self.memory).shared;
let method = if is_shared { "slice" } else { "subarray" };
self.global(&format!(
"
function getStringFromWasm(ptr, len) {{
return cachedTextDecoder.decode(getUint8Memory().{}(ptr, ptr + len));
}}
",
method
));
2018-02-05 16:39:11 -08:00
}
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
fn expose_get_array_js_value_from_wasm(&mut self) -> Result<(), Error> {
if !self.should_write_global("get_array_js_value_from_wasm") {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
return Ok(());
2018-02-28 10:56:56 +01:00
}
self.expose_uint32_memory();
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
if self.config.anyref {
self.expose_anyref_table();
self.global(
"
function getArrayJsValueFromWasm(ptr, len) {
const mem = getUint32Memory();
const slice = mem.subarray(ptr / 4, ptr / 4 + len);
const result = [];
for (let i = 0; i < slice.length; i++) {
result.push(wasm.__wbg_anyref_table.get(slice[i]));
}
wasm.__wbindgen_drop_anyref_slice(ptr, len);
return result;
}
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
",
);
self.require_internal_export("__wbindgen_drop_anyref_slice")?;
} else {
self.expose_take_object();
self.global(
"
function getArrayJsValueFromWasm(ptr, len) {
const mem = getUint32Memory();
const slice = mem.subarray(ptr / 4, ptr / 4 + len);
const result = [];
for (let i = 0; i < slice.length; i++) {
result.push(takeObject(slice[i]));
}
return result;
}
",
);
}
Ok(())
2018-02-28 10:56:56 +01:00
}
fn expose_get_array_i8_from_wasm(&mut self) {
self.expose_int8_memory();
self.arrayget("getArrayI8FromWasm", "getInt8Memory", 1);
}
fn expose_get_array_u8_from_wasm(&mut self) {
self.expose_uint8_memory();
self.arrayget("getArrayU8FromWasm", "getUint8Memory", 1);
}
fn expose_get_clamped_array_u8_from_wasm(&mut self) {
self.expose_clamped_uint8_memory();
self.arrayget("getClampedArrayU8FromWasm", "getUint8ClampedMemory", 1);
}
fn expose_get_array_i16_from_wasm(&mut self) {
self.expose_int16_memory();
self.arrayget("getArrayI16FromWasm", "getInt16Memory", 2);
}
fn expose_get_array_u16_from_wasm(&mut self) {
self.expose_uint16_memory();
self.arrayget("getArrayU16FromWasm", "getUint16Memory", 2);
}
fn expose_get_array_i32_from_wasm(&mut self) {
self.expose_int32_memory();
self.arrayget("getArrayI32FromWasm", "getInt32Memory", 4);
}
fn expose_get_array_u32_from_wasm(&mut self) {
self.expose_uint32_memory();
self.arrayget("getArrayU32FromWasm", "getUint32Memory", 4);
}
fn expose_get_array_i64_from_wasm(&mut self) {
self.expose_int64_memory();
self.arrayget("getArrayI64FromWasm", "getInt64Memory", 8);
}
fn expose_get_array_u64_from_wasm(&mut self) {
self.expose_uint64_memory();
self.arrayget("getArrayU64FromWasm", "getUint64Memory", 8);
}
fn expose_get_array_f32_from_wasm(&mut self) {
self.expose_f32_memory();
self.arrayget("getArrayF32FromWasm", "getFloat32Memory", 4);
}
fn expose_get_array_f64_from_wasm(&mut self) {
self.expose_f64_memory();
self.arrayget("getArrayF64FromWasm", "getFloat64Memory", 8);
}
fn arrayget(&mut self, name: &'static str, mem: &'static str, size: usize) {
if !self.should_write_global(name) {
2018-04-07 13:06:36 +05:45
return;
}
2018-06-27 22:42:34 -07:00
self.global(&format!(
"
function {name}(ptr, len) {{
return {mem}().subarray(ptr / {size}, ptr / {size} + len);
}}
",
name = name,
mem = mem,
size = size,
));
}
fn expose_node_buffer_memory(&mut self) {
self.memview("getNodeBufferMemory", "Buffer.from");
}
fn expose_int8_memory(&mut self) {
self.memview("getInt8Memory", "new Int8Array");
}
fn expose_uint8_memory(&mut self) {
self.memview("getUint8Memory", "new Uint8Array");
}
fn expose_clamped_uint8_memory(&mut self) {
self.memview("getUint8ClampedMemory", "new Uint8ClampedArray");
}
fn expose_int16_memory(&mut self) {
self.memview("getInt16Memory", "new Int16Array");
}
fn expose_uint16_memory(&mut self) {
self.memview("getUint16Memory", "new Uint16Array");
}
fn expose_int32_memory(&mut self) {
self.memview("getInt32Memory", "new Int32Array");
}
fn expose_uint32_memory(&mut self) {
self.memview("getUint32Memory", "new Uint32Array");
}
fn expose_int64_memory(&mut self) {
self.memview("getInt64Memory", "new BigInt64Array");
}
fn expose_uint64_memory(&mut self) {
self.memview("getUint64Memory", "new BigUint64Array");
}
fn expose_f32_memory(&mut self) {
self.memview("getFloat32Memory", "new Float32Array");
}
fn expose_f64_memory(&mut self) {
self.memview("getFloat64Memory", "new Float64Array");
}
fn memview_function(&mut self, t: VectorKind) -> &'static str {
match t {
VectorKind::String => {
self.expose_uint8_memory();
"getUint8Memory"
}
VectorKind::I8 => {
self.expose_int8_memory();
"getInt8Memory"
}
VectorKind::U8 => {
self.expose_uint8_memory();
"getUint8Memory"
}
VectorKind::ClampedU8 => {
self.expose_clamped_uint8_memory();
"getUint8ClampedMemory"
}
VectorKind::I16 => {
self.expose_int16_memory();
"getInt16Memory"
}
VectorKind::U16 => {
self.expose_uint16_memory();
"getUint16Memory"
}
VectorKind::I32 => {
self.expose_int32_memory();
"getInt32Memory"
}
VectorKind::U32 => {
self.expose_uint32_memory();
"getUint32Memory"
}
VectorKind::I64 => {
self.expose_int64_memory();
"getInt64Memory"
}
VectorKind::U64 => {
self.expose_uint64_memory();
"getUint64Memory"
}
VectorKind::F32 => {
self.expose_f32_memory();
"getFloat32Memory"
}
VectorKind::F64 => {
self.expose_f64_memory();
"getFloat64Memory"
}
VectorKind::Anyref => {
self.expose_uint32_memory();
"getUint32Memory"
}
}
}
fn memview(&mut self, name: &'static str, js: &str) {
if !self.should_write_global(name) {
2018-04-07 13:06:36 +05:45
return;
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
let mem = self.memory();
2018-06-27 22:42:34 -07:00
self.global(&format!(
"
let cache{name} = null;
function {name}() {{
if (cache{name} === null || cache{name}.buffer !== {mem}.buffer) {{
cache{name} = {js}({mem}.buffer);
2018-06-15 12:55:37 -05:00
}}
return cache{name};
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}}
",
name = name,
js = js,
mem = mem,
));
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
fn expose_assert_class(&mut self) {
if !self.should_write_global("assert_class") {
2018-04-07 13:06:36 +05:45
return;
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
self.global(
2018-06-27 22:42:34 -07:00
"
function _assertClass(instance, klass) {
if (!(instance instanceof klass)) {
throw new Error(`expected instance of ${klass.name}`);
}
return instance.ptr;
}
",
);
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
fn expose_global_stack_pointer(&mut self) {
if !self.should_write_global("stack_pointer") {
return;
}
self.global(&format!("let stack_pointer = {};", INITIAL_HEAP_OFFSET));
}
fn expose_borrowed_objects(&mut self) {
if !self.should_write_global("borrowed_objects") {
2018-04-07 13:06:36 +05:45
return;
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
self.expose_global_heap();
self.expose_global_stack_pointer();
// Our `stack_pointer` points to where we should start writing stack
// objects, and the `stack_pointer` is incremented in a `finally` block
// after executing this. Once we've reserved stack space we write the
// value. Eventually underflow will throw an exception, but JS sort of
// just handles it today...
self.global(
2018-06-27 22:42:34 -07:00
"
function addBorrowedObject(obj) {
if (stack_pointer == 1) throw new Error('out of js stack');
heap[--stack_pointer] = obj;
return stack_pointer;
}
2018-11-30 13:04:05 -08:00
",
);
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
fn expose_take_object(&mut self) {
if !self.should_write_global("take_object") {
2018-04-07 13:06:36 +05:45
return;
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
self.expose_get_object();
self.expose_drop_ref();
self.global(
2018-06-27 22:42:34 -07:00
"
function takeObject(idx) {
const ret = getObject(idx);
dropObject(idx);
return ret;
}
",
);
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
fn expose_add_heap_object(&mut self) {
if !self.should_write_global("add_heap_object") {
2018-04-07 13:06:36 +05:45
return;
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
self.expose_global_heap();
self.expose_global_heap_next();
let set_heap_next = if self.config.debug {
2018-06-27 22:42:34 -07:00
String::from(
"
if (typeof(heap_next) !== 'number') throw new Error('corrupt heap');
",
2018-06-27 22:42:34 -07:00
)
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
} else {
String::new()
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
};
// Allocating a slot on the heap first goes through the linked list
// (starting at `heap_next`). Once that linked list is exhausted we'll
// be pointing beyond the end of the array, at which point we'll reserve
// one more slot and use that.
2018-06-27 22:42:34 -07:00
self.global(&format!(
"
function addHeapObject(obj) {{
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
{}
heap[idx] = obj;
return idx;
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}}
",
set_heap_next
2018-06-27 22:42:34 -07:00
));
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
fn expose_handle_error(&mut self) -> Result<(), Error> {
2019-02-04 02:08:08 +01:00
if !self.should_write_global("handle_error") {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
return Ok(());
2019-02-04 02:08:08 +01:00
}
self.expose_uint32_memory();
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
if self.config.anyref {
self.expose_add_to_anyref_table()?;
self.global(
"
function handleError(exnptr, e) {
const idx = addToAnyrefTable(e);
const view = getUint32Memory();
view[exnptr / 4] = 1;
view[exnptr / 4 + 1] = idx;
}
",
);
} else {
self.expose_add_heap_object();
self.global(
"
function handleError(exnptr, e) {
const view = getUint32Memory();
view[exnptr / 4] = 1;
view[exnptr / 4 + 1] = addHeapObject(e);
}
",
);
}
Ok(())
2019-02-04 02:08:08 +01:00
}
fn wasm_import_needed(&self, name: &str) -> bool {
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
self.module
.imports
2018-06-27 22:42:34 -07:00
.iter()
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
.any(|i| i.module == "__wbindgen_placeholder__" && i.name == name)
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
fn pass_to_wasm_function(&mut self, t: VectorKind) -> Result<&'static str, Error> {
let s = match t {
VectorKind::String => {
self.expose_pass_string_to_wasm()?;
"passStringToWasm"
}
VectorKind::I8 | VectorKind::U8 | VectorKind::ClampedU8 => {
self.expose_pass_array8_to_wasm()?;
"passArray8ToWasm"
}
2018-06-27 22:42:34 -07:00
VectorKind::U16 | VectorKind::I16 => {
self.expose_pass_array16_to_wasm()?;
"passArray16ToWasm"
}
2018-06-27 22:42:34 -07:00
VectorKind::I32 | VectorKind::U32 => {
self.expose_pass_array32_to_wasm()?;
"passArray32ToWasm"
}
2018-06-27 22:42:34 -07:00
VectorKind::I64 | VectorKind::U64 => {
self.expose_pass_array64_to_wasm()?;
"passArray64ToWasm"
}
VectorKind::F32 => {
self.expose_pass_array_f32_to_wasm()?;
"passArrayF32ToWasm"
}
VectorKind::F64 => {
self.expose_pass_array_f64_to_wasm()?;
"passArrayF64ToWasm"
}
VectorKind::Anyref => {
self.expose_pass_array_jsvalue_to_wasm()?;
"passArrayJsValueToWasm"
}
};
Ok(s)
}
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
fn expose_get_vector_from_wasm(&mut self, ty: VectorKind) -> Result<&'static str, Error> {
Ok(match ty {
VectorKind::String => {
self.expose_get_string_from_wasm();
"getStringFromWasm"
}
VectorKind::I8 => {
self.expose_get_array_i8_from_wasm();
"getArrayI8FromWasm"
}
VectorKind::U8 => {
self.expose_get_array_u8_from_wasm();
"getArrayU8FromWasm"
}
VectorKind::ClampedU8 => {
self.expose_get_clamped_array_u8_from_wasm();
"getClampedArrayU8FromWasm"
}
VectorKind::I16 => {
self.expose_get_array_i16_from_wasm();
"getArrayI16FromWasm"
}
VectorKind::U16 => {
self.expose_get_array_u16_from_wasm();
"getArrayU16FromWasm"
}
VectorKind::I32 => {
self.expose_get_array_i32_from_wasm();
"getArrayI32FromWasm"
}
VectorKind::U32 => {
self.expose_get_array_u32_from_wasm();
"getArrayU32FromWasm"
}
VectorKind::I64 => {
self.expose_get_array_i64_from_wasm();
"getArrayI64FromWasm"
}
VectorKind::U64 => {
self.expose_get_array_u64_from_wasm();
"getArrayU64FromWasm"
}
VectorKind::F32 => {
self.expose_get_array_f32_from_wasm();
"getArrayF32FromWasm"
}
VectorKind::F64 => {
self.expose_get_array_f64_from_wasm();
"getArrayF64FromWasm"
}
Overhaul how type information gets to the CLI 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.
2018-04-13 07:33:46 -07:00
VectorKind::Anyref => {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
self.expose_get_array_js_value_from_wasm()?;
2018-02-28 10:56:56 +01:00
"getArrayJsValueFromWasm"
}
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
})
}
Start removal of vector special-casing This commit starts wasm-bindgen down a path of removing the special casing it currently has around vectors, slices, and strings. This has long been a thorn in wasm-bindgen's side as it doesn't handle other kinds of vectors and otherwise is very inflexible with future additions. Additionally it leads to a lot of duplicated-ish code throughout various portions of codegen. The fundamental reason for this was that two arguments were required to be passed back to wasm, and I couldn't figure out a way to shove both those arguments into a function argument. The new strategy here is that there is one global stack well known to both JS and Rust which arguments *may* also be transferred between. By default all ABI arguments pass as literal function arguments, but if two or more arguments need to be passed then the extra ones are all passed through this global stack. The stack is effectively temporary scratch space when crossing the JS/Rust boundary (both ways). No long term storage is intended here. The `simple` test is passing as a result of this commit, using strings internally. The `Vector` type in the AST has been removed (yay!) and the bulk of the implementation of slices and vectors now resides in the `wasm-bindgen` crate itself, defining how to pass all these arguments around. The JS generator, however, still needs to know about all the sorts of vectors so it can generate appropriate code for JS. Future commits will continue cleanup and get the rest of the tests working.
2018-03-31 07:57:47 -07:00
fn expose_global_argument_ptr(&mut self) -> Result<(), Error> {
if !self.should_write_global("global_argument_ptr") {
return Ok(());
Start removal of vector special-casing This commit starts wasm-bindgen down a path of removing the special casing it currently has around vectors, slices, and strings. This has long been a thorn in wasm-bindgen's side as it doesn't handle other kinds of vectors and otherwise is very inflexible with future additions. Additionally it leads to a lot of duplicated-ish code throughout various portions of codegen. The fundamental reason for this was that two arguments were required to be passed back to wasm, and I couldn't figure out a way to shove both those arguments into a function argument. The new strategy here is that there is one global stack well known to both JS and Rust which arguments *may* also be transferred between. By default all ABI arguments pass as literal function arguments, but if two or more arguments need to be passed then the extra ones are all passed through this global stack. The stack is effectively temporary scratch space when crossing the JS/Rust boundary (both ways). No long term storage is intended here. The `simple` test is passing as a result of this commit, using strings internally. The `Vector` type in the AST has been removed (yay!) and the bulk of the implementation of slices and vectors now resides in the `wasm-bindgen` crate itself, defining how to pass all these arguments around. The JS generator, however, still needs to know about all the sorts of vectors so it can generate appropriate code for JS. Future commits will continue cleanup and get the rest of the tests working.
2018-03-31 07:57:47 -07:00
}
self.require_internal_export("__wbindgen_global_argument_ptr")?;
2018-06-27 22:42:34 -07:00
self.global(
"
Start removal of vector special-casing This commit starts wasm-bindgen down a path of removing the special casing it currently has around vectors, slices, and strings. This has long been a thorn in wasm-bindgen's side as it doesn't handle other kinds of vectors and otherwise is very inflexible with future additions. Additionally it leads to a lot of duplicated-ish code throughout various portions of codegen. The fundamental reason for this was that two arguments were required to be passed back to wasm, and I couldn't figure out a way to shove both those arguments into a function argument. The new strategy here is that there is one global stack well known to both JS and Rust which arguments *may* also be transferred between. By default all ABI arguments pass as literal function arguments, but if two or more arguments need to be passed then the extra ones are all passed through this global stack. The stack is effectively temporary scratch space when crossing the JS/Rust boundary (both ways). No long term storage is intended here. The `simple` test is passing as a result of this commit, using strings internally. The `Vector` type in the AST has been removed (yay!) and the bulk of the implementation of slices and vectors now resides in the `wasm-bindgen` crate itself, defining how to pass all these arguments around. The JS generator, however, still needs to know about all the sorts of vectors so it can generate appropriate code for JS. Future commits will continue cleanup and get the rest of the tests working.
2018-03-31 07:57:47 -07:00
let cachedGlobalArgumentPtr = null;
function globalArgumentPtr() {
if (cachedGlobalArgumentPtr === null) {
Start removal of vector special-casing This commit starts wasm-bindgen down a path of removing the special casing it currently has around vectors, slices, and strings. This has long been a thorn in wasm-bindgen's side as it doesn't handle other kinds of vectors and otherwise is very inflexible with future additions. Additionally it leads to a lot of duplicated-ish code throughout various portions of codegen. The fundamental reason for this was that two arguments were required to be passed back to wasm, and I couldn't figure out a way to shove both those arguments into a function argument. The new strategy here is that there is one global stack well known to both JS and Rust which arguments *may* also be transferred between. By default all ABI arguments pass as literal function arguments, but if two or more arguments need to be passed then the extra ones are all passed through this global stack. The stack is effectively temporary scratch space when crossing the JS/Rust boundary (both ways). No long term storage is intended here. The `simple` test is passing as a result of this commit, using strings internally. The `Vector` type in the AST has been removed (yay!) and the bulk of the implementation of slices and vectors now resides in the `wasm-bindgen` crate itself, defining how to pass all these arguments around. The JS generator, however, still needs to know about all the sorts of vectors so it can generate appropriate code for JS. Future commits will continue cleanup and get the rest of the tests working.
2018-03-31 07:57:47 -07:00
cachedGlobalArgumentPtr = wasm.__wbindgen_global_argument_ptr();
}
Start removal of vector special-casing This commit starts wasm-bindgen down a path of removing the special casing it currently has around vectors, slices, and strings. This has long been a thorn in wasm-bindgen's side as it doesn't handle other kinds of vectors and otherwise is very inflexible with future additions. Additionally it leads to a lot of duplicated-ish code throughout various portions of codegen. The fundamental reason for this was that two arguments were required to be passed back to wasm, and I couldn't figure out a way to shove both those arguments into a function argument. The new strategy here is that there is one global stack well known to both JS and Rust which arguments *may* also be transferred between. By default all ABI arguments pass as literal function arguments, but if two or more arguments need to be passed then the extra ones are all passed through this global stack. The stack is effectively temporary scratch space when crossing the JS/Rust boundary (both ways). No long term storage is intended here. The `simple` test is passing as a result of this commit, using strings internally. The `Vector` type in the AST has been removed (yay!) and the bulk of the implementation of slices and vectors now resides in the `wasm-bindgen` crate itself, defining how to pass all these arguments around. The JS generator, however, still needs to know about all the sorts of vectors so it can generate appropriate code for JS. Future commits will continue cleanup and get the rest of the tests working.
2018-03-31 07:57:47 -07:00
return cachedGlobalArgumentPtr;
}
",
2018-06-27 22:42:34 -07:00
);
Ok(())
Start removal of vector special-casing This commit starts wasm-bindgen down a path of removing the special casing it currently has around vectors, slices, and strings. This has long been a thorn in wasm-bindgen's side as it doesn't handle other kinds of vectors and otherwise is very inflexible with future additions. Additionally it leads to a lot of duplicated-ish code throughout various portions of codegen. The fundamental reason for this was that two arguments were required to be passed back to wasm, and I couldn't figure out a way to shove both those arguments into a function argument. The new strategy here is that there is one global stack well known to both JS and Rust which arguments *may* also be transferred between. By default all ABI arguments pass as literal function arguments, but if two or more arguments need to be passed then the extra ones are all passed through this global stack. The stack is effectively temporary scratch space when crossing the JS/Rust boundary (both ways). No long term storage is intended here. The `simple` test is passing as a result of this commit, using strings internally. The `Vector` type in the AST has been removed (yay!) and the bulk of the implementation of slices and vectors now resides in the `wasm-bindgen` crate itself, defining how to pass all these arguments around. The JS generator, however, still needs to know about all the sorts of vectors so it can generate appropriate code for JS. Future commits will continue cleanup and get the rest of the tests working.
2018-03-31 07:57:47 -07:00
}
fn expose_get_inherited_descriptor(&mut self) {
if !self.should_write_global("get_inherited_descriptor") {
2018-06-27 22:42:34 -07:00
return;
}
// It looks like while rare some browsers will move descriptors up the
// property chain which runs the risk of breaking wasm-bindgen-generated
// code because we're looking for precise descriptor functions rather
// than relying on the prototype chain like most "normal JS" projects
// do.
//
// As a result we have a small helper here which will walk the prototype
// chain looking for a descriptor. For some more information on this see
// #109
2018-06-27 22:42:34 -07:00
self.global(
"
function GetOwnOrInheritedPropertyDescriptor(obj, id) {
while (obj) {
let desc = Object.getOwnPropertyDescriptor(obj, id);
if (desc) return desc;
obj = Object.getPrototypeOf(obj);
}
return {}
}
",
2018-06-27 22:42:34 -07:00
);
}
fn expose_u32_cvt_shim(&mut self) -> &'static str {
let name = "u32CvtShim";
if !self.should_write_global(name) {
2018-06-27 22:42:34 -07:00
return name;
}
self.global(&format!("const {} = new Uint32Array(2);", name));
name
}
fn expose_int64_cvt_shim(&mut self) -> &'static str {
let name = "int64CvtShim";
if !self.should_write_global(name) {
2018-06-27 22:42:34 -07:00
return name;
}
let n = self.expose_u32_cvt_shim();
2018-06-27 22:42:34 -07:00
self.global(&format!(
"const {} = new BigInt64Array({}.buffer);",
name, n
));
name
}
fn expose_uint64_cvt_shim(&mut self) -> &'static str {
let name = "uint64CvtShim";
if !self.should_write_global(name) {
2018-06-27 22:42:34 -07:00
return name;
}
let n = self.expose_u32_cvt_shim();
2018-06-27 22:42:34 -07:00
self.global(&format!(
"const {} = new BigUint64Array({}.buffer);",
name, n
));
name
}
Add support for optional slice types (#507) * Shard the `convert.rs` module into sub-modules Hopefully this'll make the organization a little nicer over time! * Start adding support for optional types This commit starts adding support for optional types to wasm-bindgen as arguments/return values to functions. The strategy here is to add two new traits, `OptionIntoWasmAbi` and `OptionFromWasmAbi`. These two traits are used as a blanket impl to implement `IntoWasmAbi` and `FromWasmAbi` for `Option<T>`. Some consequences of this design: * It should be possible to ensure `Option<SomeForeignType>` implements to/from wasm traits. This is because the option-based traits can be implemented for foreign types. * A specialized implementation is possible for all types, so there's no need for `Option<T>` to introduce unnecessary overhead. * Two new traits is a bit unforutnate but I can't currently think of an alternative design that works for the above two constraints, although it doesn't mean one doesn't exist! * The error messages for "can't use this type here" is actually halfway decent because it says these new traits need to be implemented, which provides a good place to document and talk about what's going on here! * Nested references like `Option<&T>` can't implement `FromWasmAbi`. This means that you can't define a function in Rust which takes `Option<&str>`. It may be possible to do this one day but it'll likely require more trait trickery than I'm capable of right now. * Add support for optional slices This commit adds support for optional slice types, things like strings and arrays. The null representation of these has a pointer value of 0, which should never happen in normal Rust. Otherwise the various plumbing is done throughout the tooling to enable these types in all locations. * Fix `takeObject` on global sentinels These don't have a reference count as they're always expected to work, so avoid actually dropping a reference on them. * Remove some no longer needed bindings * Add support for optional anyref types This commit adds support for optional imported class types. Each type imported with `#[wasm_bindgen]` automatically implements the relevant traits and now supports `Option<Foo>` in various argument/return positions. * Fix building without the `std` feature * Actually fix the build... * Add support for optional types to WebIDL Closes #502
2018-07-19 14:44:23 -05:00
fn expose_is_like_none(&mut self) {
if !self.should_write_global("is_like_none") {
return;
Add support for optional slice types (#507) * Shard the `convert.rs` module into sub-modules Hopefully this'll make the organization a little nicer over time! * Start adding support for optional types This commit starts adding support for optional types to wasm-bindgen as arguments/return values to functions. The strategy here is to add two new traits, `OptionIntoWasmAbi` and `OptionFromWasmAbi`. These two traits are used as a blanket impl to implement `IntoWasmAbi` and `FromWasmAbi` for `Option<T>`. Some consequences of this design: * It should be possible to ensure `Option<SomeForeignType>` implements to/from wasm traits. This is because the option-based traits can be implemented for foreign types. * A specialized implementation is possible for all types, so there's no need for `Option<T>` to introduce unnecessary overhead. * Two new traits is a bit unforutnate but I can't currently think of an alternative design that works for the above two constraints, although it doesn't mean one doesn't exist! * The error messages for "can't use this type here" is actually halfway decent because it says these new traits need to be implemented, which provides a good place to document and talk about what's going on here! * Nested references like `Option<&T>` can't implement `FromWasmAbi`. This means that you can't define a function in Rust which takes `Option<&str>`. It may be possible to do this one day but it'll likely require more trait trickery than I'm capable of right now. * Add support for optional slices This commit adds support for optional slice types, things like strings and arrays. The null representation of these has a pointer value of 0, which should never happen in normal Rust. Otherwise the various plumbing is done throughout the tooling to enable these types in all locations. * Fix `takeObject` on global sentinels These don't have a reference count as they're always expected to work, so avoid actually dropping a reference on them. * Remove some no longer needed bindings * Add support for optional anyref types This commit adds support for optional imported class types. Each type imported with `#[wasm_bindgen]` automatically implements the relevant traits and now supports `Option<Foo>` in various argument/return positions. * Fix building without the `std` feature * Actually fix the build... * Add support for optional types to WebIDL Closes #502
2018-07-19 14:44:23 -05:00
}
self.global(
"
Add support for optional slice types (#507) * Shard the `convert.rs` module into sub-modules Hopefully this'll make the organization a little nicer over time! * Start adding support for optional types This commit starts adding support for optional types to wasm-bindgen as arguments/return values to functions. The strategy here is to add two new traits, `OptionIntoWasmAbi` and `OptionFromWasmAbi`. These two traits are used as a blanket impl to implement `IntoWasmAbi` and `FromWasmAbi` for `Option<T>`. Some consequences of this design: * It should be possible to ensure `Option<SomeForeignType>` implements to/from wasm traits. This is because the option-based traits can be implemented for foreign types. * A specialized implementation is possible for all types, so there's no need for `Option<T>` to introduce unnecessary overhead. * Two new traits is a bit unforutnate but I can't currently think of an alternative design that works for the above two constraints, although it doesn't mean one doesn't exist! * The error messages for "can't use this type here" is actually halfway decent because it says these new traits need to be implemented, which provides a good place to document and talk about what's going on here! * Nested references like `Option<&T>` can't implement `FromWasmAbi`. This means that you can't define a function in Rust which takes `Option<&str>`. It may be possible to do this one day but it'll likely require more trait trickery than I'm capable of right now. * Add support for optional slices This commit adds support for optional slice types, things like strings and arrays. The null representation of these has a pointer value of 0, which should never happen in normal Rust. Otherwise the various plumbing is done throughout the tooling to enable these types in all locations. * Fix `takeObject` on global sentinels These don't have a reference count as they're always expected to work, so avoid actually dropping a reference on them. * Remove some no longer needed bindings * Add support for optional anyref types This commit adds support for optional imported class types. Each type imported with `#[wasm_bindgen]` automatically implements the relevant traits and now supports `Option<Foo>` in various argument/return positions. * Fix building without the `std` feature * Actually fix the build... * Add support for optional types to WebIDL Closes #502
2018-07-19 14:44:23 -05:00
function isLikeNone(x) {
return x === undefined || x === null;
}
",
);
Add support for optional slice types (#507) * Shard the `convert.rs` module into sub-modules Hopefully this'll make the organization a little nicer over time! * Start adding support for optional types This commit starts adding support for optional types to wasm-bindgen as arguments/return values to functions. The strategy here is to add two new traits, `OptionIntoWasmAbi` and `OptionFromWasmAbi`. These two traits are used as a blanket impl to implement `IntoWasmAbi` and `FromWasmAbi` for `Option<T>`. Some consequences of this design: * It should be possible to ensure `Option<SomeForeignType>` implements to/from wasm traits. This is because the option-based traits can be implemented for foreign types. * A specialized implementation is possible for all types, so there's no need for `Option<T>` to introduce unnecessary overhead. * Two new traits is a bit unforutnate but I can't currently think of an alternative design that works for the above two constraints, although it doesn't mean one doesn't exist! * The error messages for "can't use this type here" is actually halfway decent because it says these new traits need to be implemented, which provides a good place to document and talk about what's going on here! * Nested references like `Option<&T>` can't implement `FromWasmAbi`. This means that you can't define a function in Rust which takes `Option<&str>`. It may be possible to do this one day but it'll likely require more trait trickery than I'm capable of right now. * Add support for optional slices This commit adds support for optional slice types, things like strings and arrays. The null representation of these has a pointer value of 0, which should never happen in normal Rust. Otherwise the various plumbing is done throughout the tooling to enable these types in all locations. * Fix `takeObject` on global sentinels These don't have a reference count as they're always expected to work, so avoid actually dropping a reference on them. * Remove some no longer needed bindings * Add support for optional anyref types This commit adds support for optional imported class types. Each type imported with `#[wasm_bindgen]` automatically implements the relevant traits and now supports `Option<Foo>` in various argument/return positions. * Fix building without the `std` feature * Actually fix the build... * Add support for optional types to WebIDL Closes #502
2018-07-19 14:44:23 -05:00
}
fn expose_cleanup_groups(&mut self) {
if !self.should_write_global("cleanup_groups") {
return;
}
self.global(
"
const CLEANUPS = new WeakRefGroup(x => x.holdings());
const CLEANUPS_MAP = new Map();
function addCleanup(obj, ptr, free) {
const ref = CLEANUPS.makeRef(obj, () => free(ptr));
CLEANUPS_MAP.set(ptr, ref);
}
",
);
}
fn describe(&mut self, name: &str) -> Option<Descriptor> {
Overhaul how type information gets to the CLI 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.
2018-04-13 07:33:46 -07:00
let name = format!("__wbindgen_describe_{}", name);
let descriptor = self.interpreter.interpret_descriptor(&name, self.module)?;
Some(Descriptor::decode(descriptor))
Overhaul how type information gets to the CLI 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.
2018-04-13 07:33:46 -07:00
}
2018-04-14 09:37:49 -07:00
fn global(&mut self, s: &str) {
let s = s.trim();
// Ensure a blank line between adjacent items, and ensure everything is
// terminated with a newline.
while !self.globals.ends_with("\n\n\n") && !self.globals.ends_with("*/\n") {
2018-04-14 09:37:49 -07:00
self.globals.push_str("\n");
}
self.globals.push_str(s);
self.globals.push_str("\n");
2018-04-14 09:37:49 -07:00
}
Speed up Travis by running Webpack in fewer tests (#381) * Reorganize Travis configuration * Add a `JOB` env var descriptor to all matrix entries. Not used anywhere but is useful when viewing the whole build on Travis's web interface. * Reorganize where builds are located, moving slow builds first and fast ones last. * Change checking the CLI builds from `cargo build` to `cargo check` * Use YAML references to reduce some duplication * Print some more timing statistics for each test * Extract `Project` helper in tests to a module This'll help make it a bit more extensible over time. At the same time the methods are also slightly reorganized to read more clearly from top to bottom. * Migrate all tests away from Webpack Wepback can take a significant amount of time to execute and when it's multiplied by hundreds of tests that adds up really quickly! After investigating Node's `--experimental-modules` option it looks like it's suitable for our use so this switches all tests to using JS files (moving away from TypeScript as well) with `--experimental-modules` with Node. Tests will be selectively re-enabled with webpack and node.js specific output (that doesn't require `--experimental-modules`), coming in later commits. * Restore the node test for node.js output Ensures it's workable as-is * Only generate typescript with webpack * Only read wasm files for webpack * Skip package.json/node_modules for now * Only generate webpack config if needed * Start a dedicated test module for typescript Will hopefully verify the generated Typescript compiles OK. * Remove unneeded `node` method * Fixup some rebase conflicts * Don't run asmjs example on travis * Fixup generator tests * Attempt to fix windows * Comment windows fix * More test fixes * More exclusions * More test fixes * Relax eslint regex Catch mjs modules as well * Fix eslint * Speed up travis on examples slightly
2018-07-04 22:37:09 -05:00
fn use_node_require(&self) -> bool {
self.config.mode.nodejs() && !self.config.mode.nodejs_experimental_modules()
Speed up Travis by running Webpack in fewer tests (#381) * Reorganize Travis configuration * Add a `JOB` env var descriptor to all matrix entries. Not used anywhere but is useful when viewing the whole build on Travis's web interface. * Reorganize where builds are located, moving slow builds first and fast ones last. * Change checking the CLI builds from `cargo build` to `cargo check` * Use YAML references to reduce some duplication * Print some more timing statistics for each test * Extract `Project` helper in tests to a module This'll help make it a bit more extensible over time. At the same time the methods are also slightly reorganized to read more clearly from top to bottom. * Migrate all tests away from Webpack Wepback can take a significant amount of time to execute and when it's multiplied by hundreds of tests that adds up really quickly! After investigating Node's `--experimental-modules` option it looks like it's suitable for our use so this switches all tests to using JS files (moving away from TypeScript as well) with `--experimental-modules` with Node. Tests will be selectively re-enabled with webpack and node.js specific output (that doesn't require `--experimental-modules`), coming in later commits. * Restore the node test for node.js output Ensures it's workable as-is * Only generate typescript with webpack * Only read wasm files for webpack * Skip package.json/node_modules for now * Only generate webpack config if needed * Start a dedicated test module for typescript Will hopefully verify the generated Typescript compiles OK. * Remove unneeded `node` method * Fixup some rebase conflicts * Don't run asmjs example on travis * Fixup generator tests * Attempt to fix windows * Comment windows fix * More test fixes * More exclusions * More test fixes * Relax eslint regex Catch mjs modules as well * Fix eslint * Speed up travis on examples slightly
2018-07-04 22:37:09 -05:00
}
fn memory(&mut self) -> &'static str {
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
if self.module.memories.get(self.memory).import.is_some() {
"memory"
} else {
"wasm.memory"
}
}
fn require_class_wrap(&mut self, class: &str) {
self.exported_classes
.as_mut()
.expect("classes already written")
.entry(class.to_string())
.or_insert_with(ExportedClass::default)
.wrap_needed = true;
}
fn import_identifier(&mut self, import: Import<'a>) -> String {
// Here's where it's a bit tricky. We need to make sure that importing
// the same identifier from two different modules works, and they're
// named uniquely below. Additionally if we've already imported the same
// identifier from the module in question then we'd like to reuse the
// one that was previously imported.
//
// Our `imported_names` map keeps track of all imported identifiers from
// modules, mapping the imported names onto names actually available for
// use in our own module. If our identifier isn't present then we
// generate a new identifier and are sure to generate the appropriate JS
// import for our new identifier.
let use_node_require = self.use_node_require();
let imported_identifiers = &mut self.imported_identifiers;
let imports = &mut self.imports;
let imports_post = &mut self.imports_post;
let identifier = self
.imported_names
.entry(import.module())
.or_insert_with(Default::default)
.entry(import.name())
.or_insert_with(|| {
let name = generate_identifier(import.name(), imported_identifiers);
match &import {
Import::Module { .. }
| Import::LocalModule { .. }
| Import::InlineJs { .. } => {
// When doing a modular import local snippets (either
// inline or not) are routed to a local `./snippets`
// directory which the rest of `wasm-bindgen` will fill
// in.
let path = match import {
Import::Module { module, .. } => module.to_string(),
Import::LocalModule { module, .. } => format!("./snippets/{}", module),
Import::InlineJs {
unique_crate_identifier,
snippet_idx_in_crate,
..
} => format!(
"./snippets/{}/inline{}.js",
unique_crate_identifier, snippet_idx_in_crate
),
_ => unreachable!(),
};
if use_node_require {
imports.push_str(&format!(
"const {} = require(String.raw`{}`).{};\n",
2018-11-27 12:07:59 -08:00
name,
path,
2018-11-27 12:07:59 -08:00
import.name()
));
} else if import.name() == name {
imports.push_str(&format!("import {{ {} }} from '{}';\n", name, path));
} else {
imports.push_str(&format!(
"import {{ {} as {} }} from '{}';\n",
2018-11-27 12:07:59 -08:00
import.name(),
name,
path
));
}
name
}
Import::VendorPrefixed { prefixes, .. } => {
imports_post.push_str("const l");
imports_post.push_str(&name);
imports_post.push_str(" = ");
switch(imports_post, &name, "", prefixes);
imports_post.push_str(";\n");
fn switch(dst: &mut String, name: &str, prefix: &str, left: &[&str]) {
if left.len() == 0 {
dst.push_str(prefix);
return dst.push_str(name);
}
dst.push_str("(typeof ");
dst.push_str(prefix);
dst.push_str(name);
dst.push_str(" == 'undefined' ? ");
match left.len() {
1 => {
dst.push_str(&left[0]);
dst.push_str(name);
}
_ => switch(dst, name, &left[0], &left[1..]),
}
dst.push_str(" : ");
dst.push_str(prefix);
dst.push_str(name);
dst.push_str(")");
}
format!("l{}", name)
}
Import::Global { .. } => name,
}
});
// If there's a namespace we didn't actually import `item` but rather
// the namespace, so access through that.
match import.field() {
Some(field) => format!("{}.{}", identifier, field),
None => identifier.clone(),
}
}
fn generated_import_target(
&mut self,
name: Import<'a>,
import: &decode::ImportFunction<'a>,
) -> Result<ImportTarget, Error> {
let method_data = match &import.method {
Some(data) => data,
None => {
let name = self.import_identifier(name);
if import.structural || !name.contains(".") {
2018-11-27 12:07:59 -08:00
return Ok(ImportTarget::Function(name));
}
self.global(&format!("const {}_target = {};", import.shim, name));
let target = format!("{}_target", import.shim);
2018-11-27 12:07:59 -08:00
return Ok(ImportTarget::Function(target));
}
};
let class = self.import_identifier(name);
let op = match &method_data.kind {
decode::MethodKind::Constructor => {
return Ok(ImportTarget::Constructor(class.to_string()));
}
decode::MethodKind::Operation(op) => op,
};
if import.structural {
2018-11-27 12:07:59 -08:00
let class = if op.is_static {
Some(class.clone())
} else {
None
};
return Ok(match &op.kind {
decode::OperationKind::Regular => {
let name = import.function.name.to_string();
match class {
Some(c) => ImportTarget::Function(format!("{}.{}", c, name)),
None => ImportTarget::StructuralMethod(name),
}
}
decode::OperationKind::Getter(g) => {
ImportTarget::StructuralGetter(class, g.to_string())
}
decode::OperationKind::Setter(s) => {
ImportTarget::StructuralSetter(class, s.to_string())
}
decode::OperationKind::IndexingGetter => {
ImportTarget::StructuralIndexingGetter(class)
}
decode::OperationKind::IndexingSetter => {
ImportTarget::StructuralIndexingSetter(class)
}
decode::OperationKind::IndexingDeleter => {
ImportTarget::StructuralIndexingDeleter(class)
}
2018-11-27 12:07:59 -08:00
});
}
2018-11-27 12:07:59 -08:00
let target = format!(
"typeof {0} === 'undefined' ? null : {}{}",
class,
if op.is_static { "" } else { ".prototype" }
);
let (mut target, name) = match &op.kind {
2018-11-27 12:07:59 -08:00
decode::OperationKind::Regular => (
format!("{}.{}", target, import.function.name),
&import.function.name,
),
decode::OperationKind::Getter(g) => {
self.expose_get_inherited_descriptor();
2018-11-27 12:07:59 -08:00
(
format!(
"GetOwnOrInheritedPropertyDescriptor({}, '{}').get",
target, g,
),
g,
)
}
decode::OperationKind::Setter(s) => {
self.expose_get_inherited_descriptor();
2018-11-27 12:07:59 -08:00
(
format!(
"GetOwnOrInheritedPropertyDescriptor({}, '{}').set",
target, s,
),
s,
)
}
2018-11-27 12:07:59 -08:00
decode::OperationKind::IndexingGetter => panic!("indexing getter should be structural"),
decode::OperationKind::IndexingSetter => panic!("indexing setter should be structural"),
decode::OperationKind::IndexingDeleter => {
panic!("indexing deleter should be structural")
}
};
2018-11-27 12:07:59 -08:00
target.push_str(&format!(
" || function() {{
throw new Error(`wasm-bindgen: {}.{} does not exist`);
2018-11-27 12:07:59 -08:00
}}",
class, name
));
if op.is_static {
target.insert(0, '(');
target.push_str(").bind(");
target.push_str(&class);
target.push_str(")");
}
self.global(&format!("const {}_target = {};", import.shim, target));
Ok(if op.is_static {
ImportTarget::Function(format!("{}_target", import.shim))
} else {
ImportTarget::Method(format!("{}_target", import.shim))
})
}
/// Update the wasm file's `producers` section to include information about
/// the wasm-bindgen tool.
///
/// Specified at:
/// https://github.com/WebAssembly/tool-conventions/blob/master/ProducersSection.md
fn update_producers_section(&mut self) {
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
self.module
.producers
.add_processed_by("wasm-bindgen", &wasm_bindgen_shared::version());
}
fn add_start_function(&mut self) -> Result<(), Error> {
let start = match &self.start {
Some(name) => name.clone(),
None => return Ok(()),
};
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
let export = match self.module.exports.iter().find(|e| e.name == start) {
Some(export) => export,
None => bail!("export `{}` not found", start),
};
let id = match export.item {
walrus::ExportItem::Function(i) => i,
_ => bail!("export `{}` wasn't a function", start),
};
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
let prev_start = match self.module.start {
Some(f) => f,
None => {
self.module.start = Some(id);
return Ok(());
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
}
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
};
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
// Note that we call the previous start function, if any, first. This is
// because the start function currently only shows up when it's injected
// through thread/anyref transforms. These injected start functions need
// to happen before user code, so we always schedule them first.
let mut builder = walrus::FunctionBuilder::new();
let call1 = builder.call(prev_start, Box::new([]));
let call2 = builder.call(id, Box::new([]));
let ty = self.module.funcs.get(id).ty();
let new_start = builder.finish(ty, Vec::new(), vec![call1, call2], self.module);
self.module.start = Some(new_start);
Ok(())
}
/// If a start function is present, it removes it from the `start` section
/// of the wasm module and then moves it to an exported function, named
/// `__wbindgen_start`.
fn unstart_start_function(&mut self) -> bool {
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
let start = match self.module.start.take() {
Some(id) => id,
None => return false,
};
self.module.exports.add("__wbindgen_start", start);
true
}
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
fn expose_anyref_table(&mut self) {
assert!(self.config.anyref);
if !self.should_write_global("anyref_table") {
return;
}
self.module
.exports
.add("__wbg_anyref_table", self.anyref.anyref_table_id());
}
fn expose_add_to_anyref_table(&mut self) -> Result<(), Error> {
assert!(self.config.anyref);
if !self.should_write_global("add_to_anyref_table") {
return Ok(());
}
self.expose_anyref_table();
self.require_internal_export("__wbindgen_anyref_table_alloc")?;
self.global(
"
function addToAnyrefTable(obj) {
const idx = wasm.__wbindgen_anyref_table_alloc();
wasm.__wbg_anyref_table.set(idx, obj);
return idx;
}
",
);
Ok(())
}
fn add_heap_object(&mut self, expr: &str) -> String {
if self.config.anyref {
expr.to_string()
} else {
self.expose_add_heap_object();
format!("addHeapObject({})", expr)
}
}
fn take_object(&mut self, expr: &str) -> String {
if self.config.anyref {
expr.to_string()
} else {
self.expose_take_object();
format!("takeObject({})", expr)
}
}
fn get_object(&mut self, expr: &str) -> String {
if self.config.anyref {
expr.to_string()
} else {
self.expose_get_object();
format!("getObject({})", expr)
}
}
}
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
impl<'a, 'b> SubContext<'a, 'b> {
pub fn generate(&mut self) -> Result<(), Error> {
for m in self.program.local_modules.iter() {
// All local modules we find should be unique, but the same module
// may have showed up in a few different blocks. If that's the case
// all the same identifiers should have the same contents.
if let Some(prev) = self.cx.local_modules.insert(m.identifier, m.contents) {
assert_eq!(prev, m.contents);
}
}
for f in self.program.exports.iter() {
2018-06-27 22:42:34 -07:00
self.generate_export(f).with_context(|_| {
format!(
"failed to generate bindings for Rust export `{}`",
f.function.name
)
})?;
}
for f in self.program.imports.iter() {
if let decode::ImportKind::Type(ty) = &f.kind {
self.register_vendor_prefix(ty);
}
}
for f in self.program.imports.iter() {
self.generate_import(f)?;
}
2018-02-22 12:01:38 +01:00
for e in self.program.enums.iter() {
self.generate_enum(e);
}
for s in self.program.structs.iter() {
self.generate_struct(s).with_context(|_| {
2018-11-30 13:04:05 -08:00
format!("failed to generate bindings for Rust struct `{}`", s.name,)
})?;
}
for s in self.program.typescript_custom_sections.iter() {
self.cx.typescript.push_str(s);
self.cx.typescript.push_str("\n\n");
}
if let Some(path) = self.program.package_json {
self.add_package_json(path)?;
}
Ok(())
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
fn generate_export(&mut self, export: &decode::Export<'b>) -> Result<(), Error> {
if let Some(ref class) = export.class {
assert!(!export.start);
2018-04-07 13:06:36 +05:45
return self.generate_export_for_class(class, export);
}
let descriptor = match self.cx.describe(&export.function.name) {
None => return Ok(()),
Some(d) => d,
};
if export.start {
self.set_start_function(export.function.name)?;
}
let (js, ts, js_doc) = Js2Rust::new(&export.function.name, self.cx)
2019-03-14 08:46:42 -03:00
.process(descriptor.unwrap_function(), &export.function.arg_names)?
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
.finish(
"function",
&format!("wasm.{}", export.function.name),
ExportedShim::Named(&export.function.name),
);
2018-06-27 22:42:34 -07:00
self.cx.export(
&export.function.name,
&js,
Some(format_doc_comments(&export.comments, Some(js_doc))),
2018-06-27 22:42:34 -07:00
);
self.cx.globals.push_str("\n");
self.cx.typescript.push_str("export ");
self.cx.typescript.push_str(&ts);
self.cx.typescript.push_str("\n");
Ok(())
}
fn set_start_function(&mut self, start: &str) -> Result<(), Error> {
if let Some(prev) = &self.cx.start {
2018-11-30 13:04:05 -08:00
bail!(
"cannot flag `{}` as start function as `{}` is \
already the start function",
start,
prev
);
}
self.cx.start = Some(start.to_string());
Ok(())
}
fn generate_export_for_class(
&mut self,
class_name: &'b str,
export: &decode::Export,
) -> Result<(), Error> {
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
let wasm_name =
wasm_bindgen_shared::struct_function_export_name(class_name, &export.function.name);
let descriptor = match self.cx.describe(&wasm_name) {
None => return Ok(()),
Some(d) => d,
};
let function_name = if export.is_constructor {
"constructor"
} else {
&export.function.name
};
let (js, ts, js_doc) = Js2Rust::new(function_name, self.cx)
.method(export.method, export.consumed)
.constructor(if export.is_constructor {
Some(class_name)
} else {
None
2018-11-27 12:07:59 -08:00
})
2019-03-14 08:46:42 -03:00
.process(descriptor.unwrap_function(), &export.function.arg_names)?
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
.finish(
"",
&format!("wasm.{}", wasm_name),
ExportedShim::Named(&wasm_name),
);
2018-06-27 22:42:34 -07:00
let class = self
.cx
.exported_classes
.as_mut()
.expect("classes already written")
2018-06-27 22:42:34 -07:00
.entry(class_name.to_string())
.or_insert(ExportedClass::default());
2018-06-27 22:42:34 -07:00
class
.contents
.push_str(&format_doc_comments(&export.comments, Some(js_doc)));
class.typescript.push_str(" "); // Indentation
if export.is_constructor {
if class.has_constructor {
bail!("found duplicate constructor `{}`", export.function.name);
}
class.has_constructor = true;
} else if !export.method {
2018-04-03 13:20:56 -07:00
class.contents.push_str("static ");
class.typescript.push_str("static ");
}
class.contents.push_str(function_name);
class.contents.push_str(&js);
class.contents.push_str("\n");
class.typescript.push_str(&ts);
class.typescript.push_str("\n");
Ok(())
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
fn generate_import(&mut self, import: &decode::Import<'b>) -> Result<(), Error> {
match import.kind {
decode::ImportKind::Function(ref f) => {
2018-06-27 22:42:34 -07:00
self.generate_import_function(import, f).with_context(|_| {
format!(
"failed to generate bindings for JS import `{}`",
f.function.name
)
})?;
}
decode::ImportKind::Static(ref s) => {
2018-06-27 22:42:34 -07:00
self.generate_import_static(import, s).with_context(|_| {
format!("failed to generate bindings for JS import `{}`", s.name)
})?;
}
decode::ImportKind::Type(ref ty) => {
self.generate_import_type(import, ty).with_context(|_| {
format!("failed to generate bindings for JS import `{}`", ty.name,)
})?;
}
decode::ImportKind::Enum(_) => {}
}
Ok(())
}
fn generate_import_static(
&mut self,
info: &decode::Import<'b>,
import: &decode::ImportStatic<'b>,
2018-06-27 22:42:34 -07:00
) -> Result<(), Error> {
// The same static can be imported in multiple locations, so only
// generate bindings once for it.
if !self.cx.imported_statics.insert(import.shim) {
return Ok(());
}
// TODO: should support more types to import here
let obj = self.import_name(info, &import.name)?;
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
self.cx
.anyref
.import_xform("__wbindgen_placeholder__", &import.shim, &[], true);
let body = format!("function() {{ return {}; }}", self.cx.add_heap_object(&obj));
self.cx.export(&import.shim, &body, None);
Ok(())
}
2018-06-27 22:42:34 -07:00
fn generate_import_function(
&mut self,
info: &decode::Import<'b>,
import: &decode::ImportFunction<'b>,
2018-06-27 22:42:34 -07:00
) -> Result<(), Error> {
if !self.cx.wasm_import_needed(&import.shim) {
return Ok(());
}
// It's possible for the same function to be imported in two locations,
// but we only want to generate one.
if !self.cx.imported_functions.insert(import.shim) {
return Ok(());
}
let descriptor = match self.cx.describe(&import.shim) {
None => return Ok(()),
Some(d) => d,
};
// Figure out the name that we're importing to dangle further references
// off of. This is the function name if there's no method all here, or
// the class if there's a method call.
let name = match &import.method {
Some(data) => self.determine_import(info, &data.class)?,
None => self.determine_import(info, &import.function.name)?,
};
// Build up our shim's state, and we'll use that to guide whether we
// actually emit an import here or not.
let mut shim = Rust2Js::new(self.cx);
if shim.cx.config.debug {
shim.catch_and_rethrow(true);
}
shim.catch(import.catch)
.variadic(import.variadic)
.process(descriptor.unwrap_function())?;
// If this is a bare function import and the shim doesn't actually do
// anything (all argument/return conversions are noops) then we can wire
// up the wasm import directly to the destination. We don't actually
// wire up anything here, but we record it to get wired up later.
if import.method.is_none() && shim.is_noop() {
2018-11-27 12:07:59 -08:00
if let Import::Module {
module,
name,
field: None,
} = name
{
shim.cx.direct_imports.insert(import.shim, (module, name));
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
if shim.ret_anyref || shim.anyref_args.len() > 0 {
shim.cx.anyref.import_xform(
"__wbindgen_placeholder__",
&import.shim,
&shim.anyref_args,
shim.ret_anyref,
);
}
2018-11-27 12:07:59 -08:00
return Ok(());
}
}
// If the above optimization fails then we actually generate the import
// here (possibly emitting some glue in our JS module) and then emit the
// shim as the wasm will be importing the shim.
let target = shim.cx.generated_import_target(name, import)?;
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
let js = shim.finish(&target, &import.shim)?;
shim.cx.export(&import.shim, &js, None);
Ok(())
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
2018-02-22 12:01:38 +01:00
fn generate_import_type(
&mut self,
info: &decode::Import<'b>,
import: &decode::ImportType<'b>,
) -> Result<(), Error> {
if !self.cx.wasm_import_needed(&import.instanceof_shim) {
return Ok(());
}
let name = self.import_name(info, &import.name)?;
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
self.cx.anyref.import_xform(
"__wbindgen_placeholder__",
&import.instanceof_shim,
&[(0, false)],
false,
);
let body = format!(
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
"function(idx) {{ return {} instanceof {} ? 1 : 0; }}",
self.cx.get_object("idx"),
name
);
self.cx.export(&import.instanceof_shim, &body, None);
Ok(())
}
fn generate_enum(&mut self, enum_: &decode::Enum) {
2018-02-22 12:01:38 +01:00
let mut variants = String::new();
for variant in enum_.variants.iter() {
variants.push_str(&format!("{}:{},", variant.name, variant.value));
2018-02-22 12:01:38 +01:00
}
2018-06-27 22:42:34 -07:00
self.cx.export(
&enum_.name,
&format!("Object.freeze({{ {} }})", variants),
Some(format_doc_comments(&enum_.comments, None)),
2018-06-27 22:42:34 -07:00
);
self.cx
.typescript
.push_str(&format!("export enum {} {{", enum_.name));
2018-02-23 17:30:18 +01:00
for variant in enum_.variants.iter() {
self.cx
.typescript
.push_str(&format!("\n {},", variant.name));
2018-02-23 17:30:18 +01:00
}
self.cx.typescript.push_str("\n}\n");
2018-02-22 12:01:38 +01:00
}
fn generate_struct(&mut self, struct_: &decode::Struct) -> Result<(), Error> {
let mut dst = String::new();
let mut ts_dst = String::new();
for field in struct_.fields.iter() {
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
let wasm_getter = wasm_bindgen_shared::struct_field_get(&struct_.name, &field.name);
let wasm_setter = wasm_bindgen_shared::struct_field_set(&struct_.name, &field.name);
let descriptor = match self.cx.describe(&wasm_getter) {
None => continue,
Some(d) => d,
};
let set = {
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
let setter = ExportedShim::Named(&wasm_setter);
let mut cx = Js2Rust::new(&field.name, self.cx);
cx.method(true, false)
2019-03-14 08:46:42 -03:00
.argument(&descriptor, None)?
.ret(&Descriptor::Unit)?;
ts_dst.push_str(&format!(
"\n {}{}: {};",
if field.readonly { "readonly " } else { "" },
field.name,
&cx.js_arguments[0].1
));
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
cx.finish("", &format!("wasm.{}", wasm_setter), setter).0
};
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
let getter = ExportedShim::Named(&wasm_getter);
let (get, _ts, js_doc) = Js2Rust::new(&field.name, self.cx)
.method(true, false)
.ret(&descriptor)?
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
.finish("", &format!("wasm.{}", wasm_getter), getter);
if !dst.ends_with("\n") {
dst.push_str("\n");
}
dst.push_str(&format_doc_comments(&field.comments, Some(js_doc)));
dst.push_str("get ");
dst.push_str(&field.name);
dst.push_str(&get);
dst.push_str("\n");
if !field.readonly {
dst.push_str("set ");
dst.push_str(&field.name);
dst.push_str(&set);
}
}
let class = self
.cx
.exported_classes
.as_mut()
.expect("classes already written")
.entry(struct_.name.to_string())
.or_insert_with(Default::default);
class.comments = format_doc_comments(&struct_.comments, None);
class.contents.push_str(&dst);
class.contents.push_str("\n");
class.typescript.push_str(&ts_dst);
class.typescript.push_str("\n");
Ok(())
}
2018-11-27 12:07:59 -08:00
fn register_vendor_prefix(&mut self, info: &decode::ImportType<'b>) {
if info.vendor_prefixes.len() == 0 {
2018-11-27 12:07:59 -08:00
return;
}
self.vendor_prefixes
.entry(info.name)
.or_insert(Vec::new())
.extend(info.vendor_prefixes.iter().cloned());
}
2018-11-27 12:07:59 -08:00
fn determine_import(
&self,
import: &decode::Import<'b>,
item: &'b str,
) -> Result<Import<'b>, Error> {
// First up, imports don't work at all in `--target no-modules` mode as
// we're not sure how to import them.
let is_local_snippet = match import.module {
decode::ImportModule::Named(s) => self.cx.local_modules.contains_key(s),
decode::ImportModule::RawNamed(_) => false,
decode::ImportModule::Inline(_) => true,
decode::ImportModule::None => false,
};
if self.cx.config.mode.no_modules() {
if is_local_snippet {
bail!(
"local JS snippets are not supported with `--target no-modules`; \
use `--target web` or no flag instead",
);
}
if let decode::ImportModule::Named(module) = &import.module {
2018-06-27 22:42:34 -07:00
bail!(
"import from `{}` module not allowed with `--target no-modules`; \
use `nodejs`, `web`, or `bundler` target instead",
2018-06-27 22:42:34 -07:00
module
);
2018-04-11 14:22:20 +05:45
}
}
2018-04-11 14:22:20 +05:45
// FIXME: currently we require that local JS snippets are written in ES
// module syntax for imports/exports, but nodejs uses CommonJS to handle
// this meaning that local JS snippets are basically guaranteed to be
// incompatible. We need to implement a pass that translates the ES
// module syntax in the snippet to a CommonJS module, which is in theory
// not that hard but is a chunk of work to do.
if is_local_snippet && self.cx.config.mode.nodejs() {
2019-02-26 08:44:04 -08:00
// have a small unergonomic escape hatch for our webidl-tests tests
if env::var("WBINDGEN_I_PROMISE_JS_SYNTAX_WORKS_IN_NODE").is_err() {
bail!(
"local JS snippets are not supported with `--target nodejs`; \
2019-02-26 08:44:04 -08:00
see rustwasm/rfcs#6 for more details, but this restriction \
will be lifted in the future"
);
}
}
// Similar to `--target no-modules`, only allow vendor prefixes
// basically for web apis, shouldn't be necessary for things like npm
// packages or other imported items.
let vendor_prefixes = self.vendor_prefixes.get(item);
if let Some(vendor_prefixes) = vendor_prefixes {
assert!(vendor_prefixes.len() > 0);
if is_local_snippet {
bail!(
"local JS snippets do not support vendor prefixes for \
the import of `{}` with a polyfill of `{}`",
item,
&vendor_prefixes[0]
);
}
if let decode::ImportModule::Named(module) = &import.module {
bail!(
"import of `{}` from `{}` has a polyfill of `{}` listed, but
vendor prefixes aren't supported when importing from modules",
item,
module,
&vendor_prefixes[0],
);
}
if let Some(ns) = &import.js_namespace {
2018-11-27 12:07:59 -08:00
bail!(
"import of `{}` through js namespace `{}` isn't supported \
right now when it lists a polyfill",
item,
ns
);
}
return Ok(Import::VendorPrefixed {
name: item,
prefixes: vendor_prefixes.clone(),
2018-11-27 12:07:59 -08:00
});
}
let (name, field) = match import.js_namespace {
Some(ns) => (ns, Some(item)),
None => (item, None),
2018-11-27 12:07:59 -08:00
};
Ok(match import.module {
decode::ImportModule::Named(module) if is_local_snippet => Import::LocalModule {
module,
name,
field,
},
decode::ImportModule::Named(module) | decode::ImportModule::RawNamed(module) => {
Import::Module {
module,
name,
field,
}
}
decode::ImportModule::Inline(idx) => {
let offset = *self
.cx
.snippet_offsets
.get(self.program.unique_crate_identifier)
.unwrap_or(&0);
Import::InlineJs {
unique_crate_identifier: self.program.unique_crate_identifier,
snippet_idx_in_crate: idx as usize + offset,
name,
field,
}
}
decode::ImportModule::None => Import::Global { name, field },
})
}
2018-11-27 12:07:59 -08:00
fn import_name(&mut self, import: &decode::Import<'b>, item: &'b str) -> Result<String, Error> {
let import = self.determine_import(import, item)?;
Ok(self.cx.import_identifier(import))
}
fn add_package_json(&mut self, path: &'b str) -> Result<(), Error> {
if !self.cx.package_json_read.insert(path) {
return Ok(());
}
if !self.cx.config.mode.nodejs() && !self.cx.config.mode.bundler() {
bail!(
"NPM dependencies have been specified in `{}` but \
this is only compatible with the `bundler` and `nodejs` targets"
);
}
let contents = fs::read_to_string(path).context(format!("failed to read `{}`", path))?;
let json: serde_json::Value = serde_json::from_str(&contents)?;
let object = match json.as_object() {
Some(s) => s,
None => bail!(
"expected `package.json` to have an JSON object in `{}`",
path
),
};
let mut iter = object.iter();
let (key, value) = match iter.next() {
Some(pair) => pair,
None => return Ok(()),
};
if key != "dependencies" || iter.next().is_some() {
bail!(
"NPM manifest found at `{}` can currently only have one key, \
`dependencies`, and no other fields",
path
);
}
let value = match value.as_object() {
Some(s) => s,
None => bail!("expected `dependencies` to be a JSON object in `{}`", path),
};
for (name, value) in value.iter() {
let value = match value.as_str() {
Some(s) => s,
None => bail!(
"keys in `dependencies` are expected to be strings in `{}`",
path
),
};
if let Some((prev, _prev_version)) = self.cx.npm_dependencies.get(name) {
bail!(
"dependency on NPM package `{}` specified in two `package.json` files, \
which at the time is not allowed:\n * {}\n * {}",
name,
path,
prev
)
}
self.cx
.npm_dependencies
.insert(name.to_string(), (path, value.to_string()));
}
Ok(())
}
}
#[derive(Hash, Eq, PartialEq)]
pub enum ImportModule<'a> {
Named(&'a str),
Inline(&'a str, usize),
None,
}
impl<'a> Import<'a> {
fn module(&self) -> ImportModule<'a> {
match self {
Import::Module { module, .. } | Import::LocalModule { module, .. } => {
ImportModule::Named(module)
}
Import::InlineJs {
unique_crate_identifier,
snippet_idx_in_crate,
..
} => ImportModule::Inline(unique_crate_identifier, *snippet_idx_in_crate),
Import::Global { .. } | Import::VendorPrefixed { .. } => ImportModule::None,
}
}
fn field(&self) -> Option<&'a str> {
match self {
Import::Module { field, .. }
| Import::LocalModule { field, .. }
| Import::InlineJs { field, .. }
| Import::Global { field, .. } => *field,
Import::VendorPrefixed { .. } => None,
}
}
fn name(&self) -> &'a str {
match self {
2018-11-27 12:07:59 -08:00
Import::Module { name, .. }
| Import::LocalModule { name, .. }
| Import::InlineJs { name, .. }
2018-11-27 12:07:59 -08:00
| Import::Global { name, .. }
| Import::VendorPrefixed { name, .. } => *name,
}
}
}
fn generate_identifier(name: &str, used_names: &mut HashMap<String, usize>) -> String {
let cnt = used_names.entry(name.to_string()).or_insert(0);
*cnt += 1;
// We want to mangle `default` at once, so we can support default exports and don't generate
// invalid glue code like this: `import { default } from './module';`.
if *cnt == 1 && name != "default" {
name.to_string()
} else {
format!("{}{}", name, cnt)
}
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
fn format_doc_comments(comments: &[&str], js_doc_comments: Option<String>) -> String {
2018-06-27 22:42:34 -07:00
let body: String = comments
.iter()
.map(|c| format!("*{}\n", c.trim_matches('"')))
.collect();
let doc = if let Some(docs) = js_doc_comments {
2018-07-13 22:36:51 -07:00
docs.lines().map(|l| format!("* {} \n", l)).collect()
} else {
String::new()
};
format!("/**\n{}{}*/\n", body, doc)
2018-06-27 22:42:34 -07:00
}
#[test]
fn test_generate_identifier() {
let mut used_names: HashMap<String, usize> = HashMap::new();
assert_eq!(
generate_identifier("someVar", &mut used_names),
"someVar".to_string()
);
assert_eq!(
generate_identifier("someVar", &mut used_names),
"someVar2".to_string()
);
assert_eq!(
generate_identifier("default", &mut used_names),
"default1".to_string()
);
assert_eq!(
generate_identifier("default", &mut used_names),
"default2".to_string()
);
}