Skip to content

Commit 335c0b1

Browse files
committed
Add support for modules importing memory
The default of Rust wasm binaries is to export the memory that they contain, but LLD also supports an `--import-memory` option where memory is imported into a module instead. It's looking like importing memory is along the lines of how shared memory wasm modules will work (they'll all import the same memory). This commit adds support to wasm-bindgen to support modules which import memory. Memory accessors are tweaked to no longer always assume that the wasm module exports its memory. Additionally JS bindings will create a `memory` option automatically because LLD always imports memory from an `env` module which won't actually exist.
1 parent 8ce7465 commit 335c0b1

File tree

3 files changed

+53
-15
lines changed

3 files changed

+53
-15
lines changed

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

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub struct Context<'a> {
4343
pub exported_classes: HashMap<String, ExportedClass>,
4444
pub function_table_needed: bool,
4545
pub interpreter: &'a mut Interpreter,
46+
pub memory_init: Option<ResizableLimits>,
4647
}
4748

4849
#[derive(Default)]
@@ -377,6 +378,7 @@ impl<'a> Context<'a> {
377378
))
378379
})?;
379380

381+
self.create_memory_export();
380382
self.unexport_unused_internal_exports();
381383
self.gc()?;
382384

@@ -685,6 +687,20 @@ impl<'a> Context<'a> {
685687
}
686688
}
687689

690+
fn create_memory_export(&mut self) {
691+
let limits = match self.memory_init.clone() {
692+
Some(limits) => limits,
693+
None => return,
694+
};
695+
let mut initializer = String::from("new WebAssembly.Memory({");
696+
initializer.push_str(&format!("initial:{}", limits.initial()));
697+
if let Some(max) = limits.maximum() {
698+
initializer.push_str(&format!(",maximum:{}", max));
699+
}
700+
initializer.push_str("})");
701+
self.export("memory", &initializer, None);
702+
}
703+
688704
fn rewrite_imports(&mut self, module_name: &str) {
689705
for (name, contents) in self._rewrite_imports(module_name) {
690706
self.export(&name, &contents, None);
@@ -715,6 +731,15 @@ impl<'a> Context<'a> {
715731
continue;
716732
}
717733

734+
// If memory is imported we'll have exported it from the shim module
735+
// so let's import it from there.
736+
if import.field() == "memory" {
737+
import.module_mut().truncate(0);
738+
import.module_mut().push_str("./");
739+
import.module_mut().push_str(module_name);
740+
continue
741+
}
742+
718743
let renamed_import = format!("__wbindgen_{}", import.field());
719744
let mut bind_math = |expr: &str| {
720745
math_imports.push((renamed_import.clone(), format!("function{}", expr)));
@@ -1333,18 +1358,20 @@ impl<'a> Context<'a> {
13331358
if !self.exposed_globals.insert(name) {
13341359
return;
13351360
}
1361+
let mem = self.memory();
13361362
self.global(&format!(
13371363
"
13381364
let cache{name} = null;
13391365
function {name}() {{
1340-
if (cache{name} === null || cache{name}.buffer !== wasm.memory.buffer) {{
1341-
cache{name} = new {js}(wasm.memory.buffer);
1366+
if (cache{name} === null || cache{name}.buffer !== {mem}.buffer) {{
1367+
cache{name} = new {js}({mem}.buffer);
13421368
}}
13431369
return cache{name};
13441370
}}
13451371
",
13461372
name = name,
13471373
js = js,
1374+
mem = mem,
13481375
));
13491376
}
13501377

@@ -1690,6 +1717,29 @@ impl<'a> Context<'a> {
16901717
fn use_node_require(&self) -> bool {
16911718
self.config.nodejs && !self.config.nodejs_experimental_modules
16921719
}
1720+
1721+
fn memory(&mut self) -> &'static str {
1722+
if self.module.memory_section().is_some() {
1723+
return "wasm.memory";
1724+
}
1725+
1726+
let (entry, mem) = self.module.import_section()
1727+
.expect("must import memory")
1728+
.entries()
1729+
.iter()
1730+
.filter_map(|i| {
1731+
match i.external() {
1732+
External::Memory(m) => Some((i, m)),
1733+
_ => None,
1734+
}
1735+
})
1736+
.next()
1737+
.expect("must import memory");
1738+
assert_eq!(entry.module(), "env");
1739+
assert_eq!(entry.field(), "memory");
1740+
self.memory_init = Some(mem.limits().clone());
1741+
"memory"
1742+
}
16931743
}
16941744

16951745
impl<'a, 'b> SubContext<'a, 'b> {

crates/cli-support/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ impl Bindgen {
200200
module: &mut module,
201201
function_table_needed: false,
202202
interpreter: &mut instance,
203+
memory_init: None,
203204
};
204205
for program in programs.iter() {
205206
js::SubContext {

crates/cli-support/src/wasm2es6js.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -150,19 +150,6 @@ impl Output {
150150
if let Some(i) = self.module.import_section() {
151151
let mut set = HashSet::new();
152152
for entry in i.entries() {
153-
match *entry.external() {
154-
External::Function(_) => {}
155-
External::Table(_) => {
156-
bail!("wasm imports a table which isn't supported yet");
157-
}
158-
External::Memory(_) => {
159-
bail!("wasm imports memory which isn't supported yet");
160-
}
161-
External::Global(_) => {
162-
bail!("wasm imports globals which aren't supported yet");
163-
}
164-
}
165-
166153
if !set.insert(entry.module()) {
167154
continue;
168155
}

0 commit comments

Comments
 (0)