Hello! I currently have a PR up for review in the wasm_bindgen
project, and I think it would be helpful to have some more eyes on it. Especially if you're familiar with multithreaded code, atomics, and the Webassembly threading proposal!
I've been experimenting with sharing a Rust object across WebWorkers. For the most part, I followed @alexcrichton's amazing raytracing example. But Alex's example sends a different pointer to each worker, which then owns the pointer. My minimal repro shows how I share the same threadsafe object across many workers.
But my WebWorkers keep throwing errors: "Error: recursive use of an object detected which would lead to unsafe aliasing in rust"
.
...except my code doesn't have any recursion.
But that's okay, because the error message actually means that I've broken Rust's aliasing rules. Someone must be calling an &mut
method.
...except my code doesn't have any &mut
methods.
I tracked the error down to wasm_bindgen::__rt::WasmRefCell
, a small reimplementation of RefCell
that wraps every Rust object we access from JavaScript-land. self.borrow
was data racing like nobody's business, often underflowing to usize::max_value()
! That's a sentinel value that says someone is writing to the object.
So we have a data race in "safe Rust" (at least in the sense that I didn't use any unsafe
blocks, not in the sense that it's okay for me to access __wbg_ptr
and toss those pointers to other WebWorkers). This isn't necessarily WasmRefCell
's fault. It's not a Sync
object, and it wasn't designed to be a Sync
object. But making it thread-safe, by replacing borrow: Cell<usize>
with an AtomicUsize
, solves my problem very neatly, and I don't really have a way to keep using threaded wasm Rust code without it. For now, I'm going to use my PR to keep developing my project.
That said, my proposal does add overhead to, um, every call across the JS/Rust boundary. The compiler is usually able to eliminate the store instructions in WasmRefCell
, but that's no longer true when those store instructions are atomic.
What do people think? Should this use of atomics live behind a command-line flag or config option? Should Rust's safety guarantees extend to sharing an object across WebWorkers in a browser, at least when that object is Sync
?