Skip to content

Commit

Permalink
Add ability to set stack size for spawned threads (#3995)
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda authored Jul 28, 2024
1 parent 277868a commit 7ad1a27
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 60 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@
* Add WebIDL definitions relating to `Popover API`.
[#3977](https://github.com/rustwasm/wasm-bindgen/pull/3977)

* Added the `thread_stack_size` property to the object parameter of `default()` (`init()`) and `initSync()`, making it possible to set the stack size of spawned threads. `__wbindgen_thread_destroy()` now has a third optional parameter for the stack size, the default stack size is assumed when not passing it. When calling from the thread to be destroyed, by passing no parameters, the correct stack size is determined internally.
[#3995](https://github.com/rustwasm/wasm-bindgen/pull/3995)

### Changed

* Stabilize Web Share API.
Expand Down Expand Up @@ -86,6 +89,12 @@
* Deprecate `AudioBufferSourceNode.onended` and `AudioBufferSourceNode.stop()`.
[#4020](https://github.com/rustwasm/wasm-bindgen/pull/4020)

* Increase default stack size for spawned threads from 1 to 2 MB.
[#3995](https://github.com/rustwasm/wasm-bindgen/pull/3995)

* Deprecated parameters to `default` (`init`) and `initSync` in favor of an object.
[#3995](https://github.com/rustwasm/wasm-bindgen/pull/3995)

### Fixed

* Copy port from headless test server when using `WASM_BINDGEN_TEST_ADDRESS`.
Expand Down Expand Up @@ -118,6 +127,9 @@
* Fixed Deno support.
[#3990](https://github.com/rustwasm/wasm-bindgen/pull/3990)

* Fix `__wbindgen_thread_destroy()` ignoring parameters.
[#3995](https://github.com/rustwasm/wasm-bindgen/pull/3995)

--------------------------------------------------------------------------------

## [0.2.92](https://github.com/rustwasm/wasm-bindgen/compare/0.2.91...0.2.92)
Expand Down
84 changes: 63 additions & 21 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ pub struct Context<'a> {

/// A flag to track if the stack pointer setter shim has been injected.
stack_pointer_shim_injected: bool,

/// If threading is enabled.
threads_enabled: bool,
}

#[derive(Default)]
Expand Down Expand Up @@ -107,6 +110,7 @@ impl<'a> Context<'a> {
wasm_import_definitions: Default::default(),
exported_classes: Some(Default::default()),
config,
threads_enabled: config.threads.is_enabled(module),
module,
npm_dependencies: Default::default(),
next_export_idx: 0,
Expand Down Expand Up @@ -613,12 +617,17 @@ impl<'a> Context<'a> {

let (memory_doc, memory_param) = if has_memory {
(
"* @param {WebAssembly.Memory} maybe_memory\n",
", maybe_memory?: WebAssembly.Memory",
"* @param {WebAssembly.Memory} memory - Deprecated.\n",
", memory?: WebAssembly.Memory",
)
} else {
("", "")
};
let stack_size = if self.threads_enabled {
", thread_stack_size?: number"
} else {
""
};
let arg_optional = if has_module_or_path_optional { "?" } else { "" };
// With TypeScript 3.8.3, I'm seeing that any "export"s at the root level cause TypeScript to ignore all "declare" statements.
// So using "declare" everywhere for at least the NoModules option.
Expand All @@ -639,12 +648,12 @@ impl<'a> Context<'a> {
* Instantiates the given `module`, which can either be bytes or\n\
* a precompiled `WebAssembly.Module`.\n\
*\n\
* @param {{SyncInitInput}} module\n\
* @param {{{{ module: SyncInitInput{memory_param}{stack_size} }}}} module - Passing `SyncInitInput` directly is deprecated.\n\
{memory_doc}\
*\n\
* @returns {{InitOutput}}\n\
*/\n\
export function initSync(module: SyncInitInput{memory_param}): InitOutput;\n\n\
export function initSync(module: {{ module: SyncInitInput{memory_param}{stack_size} }} | SyncInitInput{memory_param}): InitOutput;\n\n\
",
memory_doc = memory_doc,
memory_param = memory_param
Expand All @@ -664,13 +673,13 @@ impl<'a> Context<'a> {
* If `module_or_path` is {{RequestInfo}} or {{URL}}, makes a request and\n\
* for everything else, calls `WebAssembly.instantiate` directly.\n\
*\n\
* @param {{InitInput | Promise<InitInput>}} module_or_path\n\
* @param {{{{ module_or_path: InitInput | Promise<InitInput>{memory_param}{stack_size} }}}} module_or_path - Passing `InitInput` directly is deprecated.\n\
{}\
*\n\
* @returns {{Promise<InitOutput>}}\n\
*/\n\
{setup_function_declaration} \
(module_or_path{}: InitInput | Promise<InitInput>{}): Promise<InitOutput>;\n",
(module_or_path{}: {{ module_or_path: InitInput | Promise<InitInput>{memory_param}{stack_size} }} | InitInput | Promise<InitInput>{}): Promise<InitOutput>;\n",
memory_doc, arg_optional, memory_param,
output = output,
sync_init_function = sync_init_function,
Expand All @@ -692,7 +701,7 @@ impl<'a> Context<'a> {
if let Some(id) = mem.import {
self.module.imports.get_mut(id).module = module_name.to_string();
init_memory = format!(
"imports.{}.memory = maybe_memory || new WebAssembly.Memory({{",
"imports.{}.memory = memory || new WebAssembly.Memory({{",
module_name
);
init_memory.push_str(&format!("initial:{}", mem.initial));
Expand All @@ -703,7 +712,7 @@ impl<'a> Context<'a> {
init_memory.push_str(",shared:true");
}
init_memory.push_str("});");
init_memory_arg = ", maybe_memory";
init_memory_arg = ", memory";
has_memory = true;
}
}
Expand All @@ -712,14 +721,14 @@ impl<'a> Context<'a> {
match self.config.mode {
OutputMode::Web => format!(
"\
if (typeof input === 'undefined') {{
input = new URL('{stem}_bg.wasm', import.meta.url);
if (typeof module_or_path === 'undefined') {{
module_or_path = new URL('{stem}_bg.wasm', import.meta.url);
}}",
stem = self.config.stem()?
),
OutputMode::NoModules { .. } => "\
if (typeof input === 'undefined' && typeof script_src !== 'undefined') {
input = script_src.replace(/\\.js$/, '_bg.wasm');
if (typeof module_or_path === 'undefined' && typeof script_src !== 'undefined') {
module_or_path = script_src.replace(/\\.js$/, '_bg.wasm');
}"
.to_string(),
_ => "".to_string(),
Expand Down Expand Up @@ -836,21 +845,28 @@ impl<'a> Context<'a> {
return imports;
}}
function __wbg_init_memory(imports, maybe_memory) {{
function __wbg_init_memory(imports, memory) {{
{init_memory}
}}
function __wbg_finalize_init(instance, module) {{
function __wbg_finalize_init(instance, module{init_stack_size_arg}) {{
wasm = instance.exports;
__wbg_init.__wbindgen_wasm_module = module;
{init_memviews}
{init_stack_size_check}
{start}
return wasm;
}}
function initSync(module{init_memory_arg}) {{
if (wasm !== undefined) return wasm;
{init_stack_size}
if (typeof module !== 'undefined' && Object.getPrototypeOf(module) === Object.prototype)
({{module{init_memory_arg}{init_stack_size_arg}}} = module)
else
console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
const imports = __wbg_get_imports();
__wbg_init_memory(imports{init_memory_arg});
Expand All @@ -861,36 +877,62 @@ impl<'a> Context<'a> {
const instance = new WebAssembly.Instance(module, imports);
return __wbg_finalize_init(instance, module);
return __wbg_finalize_init(instance, module{init_stack_size_arg});
}}
async function __wbg_init(input{init_memory_arg}) {{
async function __wbg_init(module_or_path{init_memory_arg}) {{
if (wasm !== undefined) return wasm;
{init_stack_size}
if (typeof module_or_path !== 'undefined' && Object.getPrototypeOf(module_or_path) === Object.prototype)
({{module_or_path{init_memory_arg}{init_stack_size_arg}}} = module_or_path)
else
console.warn('using deprecated parameters for the initialization function; pass a single object instead')
{default_module_path}
const imports = __wbg_get_imports();
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {{
input = fetch(input);
if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {{
module_or_path = fetch(module_or_path);
}}
__wbg_init_memory(imports{init_memory_arg});
const {{ instance, module }} = await __wbg_load(await input, imports);
const {{ instance, module }} = await __wbg_load(await module_or_path, imports);
return __wbg_finalize_init(instance, module);
return __wbg_finalize_init(instance, module{init_stack_size_arg});
}}
",
init_memory_arg = init_memory_arg,
default_module_path = default_module_path,
init_memory = init_memory,
init_memviews = init_memviews,
start = if needs_manual_start {
start = if needs_manual_start && self.threads_enabled {
"wasm.__wbindgen_start(thread_stack_size);"
} else if needs_manual_start {
"wasm.__wbindgen_start();"
} else {
""
},
imports_init = imports_init,
init_stack_size = if self.threads_enabled {
"let thread_stack_size"
} else {
""
},
init_stack_size_arg = if self.threads_enabled {
", thread_stack_size"
} else {
""
},
init_stack_size_check = if self.threads_enabled {
format!(
"if (typeof thread_stack_size !== 'undefined' && (typeof thread_stack_size !== 'number' || thread_stack_size === 0 || thread_stack_size % {} !== 0)) {{ throw 'invalid stack size' }}",
wasm_bindgen_threads_xform::PAGE_SIZE,
)
} else {
String::new()
},
);

Ok((js, ts))
Expand Down
40 changes: 32 additions & 8 deletions crates/cli/tests/wasm-bindgen/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,11 +332,17 @@ fn default_module_path_target_web() {
let contents = fs::read_to_string(out_dir.join("default_module_path_target_web.js")).unwrap();
assert!(contents.contains(
"\
async function __wbg_init(input) {
async function __wbg_init(module_or_path) {
if (wasm !== undefined) return wasm;
if (typeof input === 'undefined') {
input = new URL('default_module_path_target_web_bg.wasm', import.meta.url);
if (typeof module_or_path !== 'undefined' && Object.getPrototypeOf(module_or_path) === Object.prototype)
({module_or_path} = module_or_path)
else
console.warn('using deprecated parameters for the initialization function; pass a single object instead')
if (typeof module_or_path === 'undefined') {
module_or_path = new URL('default_module_path_target_web_bg.wasm', import.meta.url);
}",
));
}
Expand All @@ -361,11 +367,17 @@ fn default_module_path_target_no_modules() {
));
assert!(contents.contains(
"\
async function __wbg_init(input) {
async function __wbg_init(module_or_path) {
if (wasm !== undefined) return wasm;
if (typeof input === 'undefined' && typeof script_src !== 'undefined') {
input = script_src.replace(/\\.js$/, '_bg.wasm');
if (typeof module_or_path !== 'undefined' && Object.getPrototypeOf(module_or_path) === Object.prototype)
({module_or_path} = module_or_path)
else
console.warn('using deprecated parameters for the initialization function; pass a single object instead')
if (typeof module_or_path === 'undefined' && typeof script_src !== 'undefined') {
module_or_path = script_src.replace(/\\.js$/, '_bg.wasm');
}",
));
}
Expand All @@ -384,10 +396,16 @@ fn omit_default_module_path_target_web() {
fs::read_to_string(out_dir.join("omit_default_module_path_target_web.js")).unwrap();
assert!(contents.contains(
"\
async function __wbg_init(input) {
async function __wbg_init(module_or_path) {
if (wasm !== undefined) return wasm;
if (typeof module_or_path !== 'undefined' && Object.getPrototypeOf(module_or_path) === Object.prototype)
({module_or_path} = module_or_path)
else
console.warn('using deprecated parameters for the initialization function; pass a single object instead')
const imports = __wbg_get_imports();",
));
}
Expand All @@ -406,10 +424,16 @@ fn omit_default_module_path_target_no_modules() {
fs::read_to_string(out_dir.join("omit_default_module_path_target_no_modules.js")).unwrap();
assert!(contents.contains(
"\
async function __wbg_init(input) {
async function __wbg_init(module_or_path) {
if (wasm !== undefined) return wasm;
if (typeof module_or_path !== 'undefined' && Object.getPrototypeOf(module_or_path) === Object.prototype)
({module_or_path} = module_or_path)
else
console.warn('using deprecated parameters for the initialization function; pass a single object instead')
const imports = __wbg_get_imports();",
));
}
Expand Down
Loading

0 comments on commit 7ad1a27

Please sign in to comment.