Add support for mutable slices

This commit adds support for mutable slices to pass the boundary between JS and
Rust. While mutable slices cannot be used as return values they can be listed as
arguments to both exported functions as well as imported functions.

When passing a mutable slice into a Rust function (aka having it as an argument
to an exported Rust function) then like before with a normal slice it's copied
into the wasm memory. Afterwards, however, the updates in the wasm memory will
be reflected back into the original slice. This does require a lot of copying
and probably isn't the most efficient, but it should at least work for the time
being.

The real nifty part happens when Rust passes a mutable slice out to JS. When
doing this it's a very cheap operation that just gets a subarray of the main
wasm memory. Now the wasm memory's buffer can change over time which can produce
surprising results where memory is modified in JS but it may not be reflected
back into Rust. To accomodate this when a JS imported function returns any
updates to the buffer are copied back to Rust if Rust's memory buffer has
changed in the meantime.

Along the way this fixes usage of `slice` to instead use `subarray` as that's
what we really want, no copying. All methods have been updated to use `subarray`
accessors instead of `slice` or constructing new arrays.

Closes #53
This commit is contained in:
Alex Crichton
2018-05-01 10:06:35 -07:00
parent fbb12f519b
commit 0566a97485
6 changed files with 430 additions and 113 deletions

View File

@ -118,6 +118,15 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
setGlobalArgument(len{i}, {global_idx});\n\
", i = i, func = func, arg = name, global_idx = global_idx));
if arg.is_by_ref() {
if arg.is_mut_ref() {
let get = self.cx.memview_function(kind);
self.finally(&format!("\
{arg}.set({get}().subarray(\
ptr{i} / {size}, \
ptr{i} / {size} + len{i}\
));\n\
", i = i, arg = name, get = get, size = kind.size()));
}
self.finally(&format!("\
wasm.__wbindgen_free(ptr{i}, len{i} * {size});\n\
", i = i, size = kind.size()));