Skip to content

Commit e5cc853

Browse files
committed
Call main only once
1 parent 564ce74 commit e5cc853

File tree

3 files changed

+63
-18
lines changed

3 files changed

+63
-18
lines changed

crates/cli-support/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,8 @@ impl Bindgen {
331331
.context("failed getting Wasm module")?,
332332
};
333333

334-
self.threads
334+
let thread_counter_addr = self
335+
.threads
335336
.run(&mut module)
336337
.with_context(|| "failed to prepare module for threading")?;
337338

@@ -363,6 +364,7 @@ impl Bindgen {
363364
&mut module,
364365
self.externref,
365366
self.wasm_interface_types,
367+
thread_counter_addr,
366368
self.emit_start,
367369
)?;
368370

crates/cli-support/src/wit/mod.rs

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::str;
88
use walrus::MemoryId;
99
use walrus::{ExportId, FunctionId, ImportId, Module};
1010
use wasm_bindgen_shared::struct_function_export_name;
11+
use wasm_bindgen_threads_xform::ThreadCounterAddr;
1112

1213
mod incoming;
1314
mod nonstandard;
@@ -32,6 +33,7 @@ struct Context<'a> {
3233
descriptors: HashMap<String, Descriptor>,
3334
externref_enabled: bool,
3435
wasm_interface_types: bool,
36+
thread_counter_addr: Option<ThreadCounterAddr>,
3537
support_start: bool,
3638
}
3739

@@ -47,6 +49,7 @@ pub fn process(
4749
module: &mut Module,
4850
externref_enabled: bool,
4951
wasm_interface_types: bool,
52+
thread_counter_addr: Option<ThreadCounterAddr>,
5053
support_start: bool,
5154
) -> Result<(NonstandardWitSectionId, WasmBindgenAuxId), Error> {
5255
let mut storage = Vec::new();
@@ -66,6 +69,7 @@ pub fn process(
6669
start_found: false,
6770
externref_enabled,
6871
wasm_interface_types,
72+
thread_counter_addr,
6973
support_start,
7074
};
7175
cx.init()?;
@@ -476,22 +480,38 @@ impl<'a> Context<'a> {
476480
return Ok(());
477481
}
478482

479-
let prev_start = match self.module.start {
480-
Some(f) => f,
481-
None => {
482-
self.module.start = Some(id);
483-
return Ok(());
484-
}
483+
let prev_start = if let Some(prev_start) = self.module.start {
484+
// Note that we call the previous start function, if any, first. This is
485+
// because the start function currently only shows up when it's injected
486+
// through thread/externref transforms. These injected start functions
487+
// need to happen before user code, so we always schedule them first.
488+
let mut builder = walrus::FunctionBuilder::new(&mut self.module.types, &[], &[]);
489+
builder.func_body().call(prev_start);
490+
Some(builder)
491+
} else {
492+
None
485493
};
486494

487-
// Note that we call the previous start function, if any, first. This is
488-
// because the start function currently only shows up when it's injected
489-
// through thread/externref transforms. These injected start functions
490-
// need to happen before user code, so we always schedule them first.
491-
let mut builder = walrus::FunctionBuilder::new(&mut self.module.types, &[], &[]);
492-
builder.func_body().call(prev_start).call(id);
493-
let new_start = builder.finish(Vec::new(), &mut self.module.funcs);
494-
self.module.start = Some(new_start);
495+
if let Some(thread_counter_addr) = self.thread_counter_addr {
496+
// If we support shared memory, we re-use the thread counter address to
497+
// call the start function only once.
498+
let mut builder = prev_start
499+
.unwrap_or_else(|| walrus::FunctionBuilder::new(&mut self.module.types, &[], &[]));
500+
501+
thread_counter_addr.wrap_start(self.memory()?, builder.func_body(), id);
502+
503+
self.module.start = Some(builder.finish(Vec::new(), &mut self.module.funcs));
504+
} else if let Some(mut builder) = prev_start {
505+
// If we don't support shared memory, we still have to call the start
506+
// function if we had a previous start function.
507+
builder.func_body().call(id);
508+
self.module.start = Some(builder.finish(Vec::new(), &mut self.module.funcs));
509+
} else {
510+
// If we didn't have a previous start function and don't support shared memory,
511+
// just add the start function.
512+
self.module.start = Some(id);
513+
}
514+
495515
Ok(())
496516
}
497517

crates/threads-xform/src/lib.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use anyhow::{anyhow, bail, Error};
22
use std::cmp;
33
use std::env;
4+
use walrus::ir::BinaryOp;
5+
use walrus::ir::LoadKind;
46
use walrus::ir::Value;
57
use walrus::{
68
ir::MemArg, ExportItem, FunctionId, GlobalId, GlobalKind, InitExpr, InstrSeqBuilder, MemoryId,
@@ -23,6 +25,9 @@ pub struct Config {
2325
enabled: bool,
2426
}
2527

28+
#[derive(Clone, Copy)]
29+
pub struct ThreadCounterAddr(i32);
30+
2631
impl Config {
2732
/// Create a new configuration with default settings.
2833
pub fn new() -> Config {
@@ -103,9 +108,9 @@ impl Config {
103108
/// * Some stack space is prepared for each thread after the first one.
104109
///
105110
/// More and/or less may happen here over time, stay tuned!
106-
pub fn run(&self, module: &mut Module) -> Result<(), Error> {
111+
pub fn run(&self, module: &mut Module) -> Result<Option<ThreadCounterAddr>, Error> {
107112
if !self.is_enabled(module) {
108-
return Ok(());
113+
return Ok(None);
109114
}
110115

111116
let memory = wasm_conventions::get_memory(module)?;
@@ -165,7 +170,25 @@ impl Config {
165170
// should not be called from an agent that cannot block (e.g. the main document thread).
166171
inject_destroy(module, &tls, &stack, memory)?;
167172

168-
Ok(())
173+
Ok(Some(ThreadCounterAddr(thread_counter_addr)))
174+
}
175+
}
176+
177+
impl ThreadCounterAddr {
178+
pub fn wrap_start(self, memory: MemoryId, mut body: InstrSeqBuilder, id: FunctionId) {
179+
// This happens after the thread counter was already increased, so "1"
180+
// means we are in the first thread.
181+
body.i32_const(self.0)
182+
.load(memory, LoadKind::I32 { atomic: true }, ATOMIC_MEM_ARG)
183+
.i32_const(1)
184+
.binop(BinaryOp::I32Eq)
185+
.if_else(
186+
None,
187+
|body| {
188+
body.call(id);
189+
},
190+
|_| {},
191+
);
169192
}
170193
}
171194

0 commit comments

Comments
 (0)