Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Parameter maybe_memory should be optional #2133

Closed
d3lm opened this issue May 12, 2020 · 5 comments · Fixed by #2469
Closed

Parameter maybe_memory should be optional #2133

d3lm opened this issue May 12, 2020 · 5 comments · Fixed by #2469
Labels

Comments

@d3lm
Copy link
Contributor

d3lm commented May 12, 2020

Describe the Bug

I have noticed that when the compilation target is web that the maybe_parameter of the initi(input, maybe_memory) is required. The name implies that it might be missing and especially for the first call to init it's most likely missing if input is a string and the module is fetched. Only subsequent calls might have memory. Maybe we change the type of this to also accept null or undefined or mark it as optional.

I think it would make sense to have a sanity check in load that, if module is not a function nor a Response object, meaning it's a WebAssembly module, then we add a check to ensure that maybe_memory is not undefined.

Alternatively, we can pass null! for memory_memory but to me this feels hacky.

Steps to Reproduce

  1. Compile Rust to wasm32-unknown-unknown with target being web

If there is a solution to this and a clear path, I am volunteering to work on a PR to get this resolved.

@d3lm d3lm added the bug label May 12, 2020
@alexcrichton
Copy link
Contributor

Thanks for the report, but I believe that this parameter is already optional and not required if memory isn't imported. It should only be required if the wasm module imports memory, in which case there's nothing we can do if it's not supplied.

@Pauan
Copy link
Contributor

Pauan commented May 14, 2020

@alexcrichton Hmmm, but this is the generated code when multithreading is enabled:

async function load(module, imports, maybe_memory) {
    if (typeof Response === 'function' && module instanceof Response) {
        memory = imports.wbg.memory = new WebAssembly.Memory({initial:17,maximum:16384,shared:true});
        if (typeof WebAssembly.instantiateStreaming === 'function') {
            try {
                return await WebAssembly.instantiateStreaming(module, imports);

            } catch (e) {
                if (module.headers.get('Content-Type') != 'application/wasm') {
                    console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);

                } else {
                    throw e;
                }
            }
        }

        const bytes = await module.arrayBuffer();
        return await WebAssembly.instantiate(bytes, imports);

    } else {
        memory = imports.wbg.memory = maybe_memory;
        const instance = await WebAssembly.instantiate(module, imports);

        if (instance instanceof WebAssembly.Instance) {
            return { instance, module };

        } else {
            return instance;
        }
    }
}

So if you pass in a Module or ArrayBuffer then it won't work properly. So it should instead be something like this:

async function load(module, imports, maybe_memory) {
    if (maybe_memory == null) {
        maybe_memory = new WebAssembly.Memory({initial:17,maximum:16384,shared:true});
    }

    memory = imports.wbg.memory = maybe_memory;

    if (typeof Response === 'function' && module instanceof Response) {
        if (typeof WebAssembly.instantiateStreaming === 'function') {
            try {
                return await WebAssembly.instantiateStreaming(module, imports);

            } catch (e) {
                if (module.headers.get('Content-Type') != 'application/wasm') {
                    console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);

                } else {
                    throw e;
                }
            }
        }

        const bytes = await module.arrayBuffer();
        return await WebAssembly.instantiate(bytes, imports);

    } else {
        const instance = await WebAssembly.instantiate(module, imports);

        if (instance instanceof WebAssembly.Instance) {
            return { instance, module };

        } else {
            return instance;
        }
    }
}

Also the .d.ts file should make maybe_memory optional, like this:

export default function init (module_or_path?: InitInput | Promise<InitInput>, maybe_memory?: WebAssembly.Memory): Promise<InitOutput>;

@Pauan Pauan reopened this May 14, 2020
@alexcrichton
Copy link
Contributor

Ah sorry, yes, that seems like a reasonable update to me!

@RReverser
Copy link
Member

Can confirm, we discussed this on the original PR and I've also ran into this recently and left a comment there but haven't gotten around to submitting issue. #1412 (comment)

Thanks @d3lm!

@d3lm
Copy link
Contributor Author

d3lm commented May 25, 2020

Yep, I agree with @Pauan. The code he provided is what I was hoping for, to make the wasm memory optional especially for the generated type definition.

RReverser added a commit to RReverser/wasm-bindgen that referenced this issue Feb 26, 2021
As the name implies, it's already optional, but wasn't marked as such in TS.

We could put some more complicated / stricter types here depending on type of the first argument, but at least this fixes the issue for TS consumers.

Fixes rustwasm#2133
alexcrichton pushed a commit that referenced this issue Mar 4, 2021
* Make maybe_memory optional in TS

As the name implies, it's already optional, but wasn't marked as such in TS.

We could put some more complicated / stricter types here depending on type of the first argument, but at least this fixes the issue for TS consumers.

Fixes #2133

* Add rust-toolchain to raytrace example

It should always be built with nightly, and this file sets the toolchain for Rustup.

* Rework init_memory

 - Unify `init_memory` for `maybe_memory` case to use either the explicitly given value or the default (`new WebAssembly.Memory(...)`).
 - Move it to the main `init` function where all other `imports` are assigned too.
 - Remove global `memory` variable which doesn't seem to be used by anything.

* Format

* Update cargo fmt & reformat again

* Use explicit nightly version for Raytracer on CI

* Delete rust-toolchain

* Update azure-pipelines.yml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants