Skip to content

Commit b4f6ec0

Browse files
Merge pull request #7 from walkingeyerobot/yfyang
Get futures to work with emscripten mode
2 parents 9130158 + 5c89b09 commit b4f6ec0

File tree

3 files changed

+435
-185
lines changed

3 files changed

+435
-185
lines changed

.cargo/config.toml

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ runner = 'cargo run -p wasm-bindgen-cli --bin wasm-bindgen-test-runner --'
66
[target.'cfg(all(target_arch = "wasm32", target_os = "emscripten"))']
77
rustflags = [
88
"-Cllvm-args=-enable-emscripten-cxx-exceptions=0",
9+
"-Clink-arg=-sERROR_ON_UNDEFINED_SYMBOLS=0",
910
"-Clink-arg=-Wno-undefined",
1011
"-Crelocation-model=static",
1112
]

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

+77-43
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::wit::InstructionData;
99
use crate::wit::{
1010
Adapter, AdapterId, AdapterKind, AdapterType, AuxFunctionArgumentData, Instruction,
1111
};
12+
use crate::OutputMode;
1213
use anyhow::{anyhow, bail, Error};
1314
use std::collections::HashSet;
1415
use std::fmt::Write;
@@ -130,7 +131,7 @@ impl<'a, 'b> Builder<'a, 'b> {
130131
debug_name: &str,
131132
ret_ty_override: &Option<String>,
132133
ret_desc: &Option<String>,
133-
import_deps: &mut Vec<String>,
134+
import_deps: &mut HashSet<String>,
134135
) -> Result<JsFunction, Error> {
135136
if self
136137
.cx
@@ -257,15 +258,15 @@ impl<'a, 'b> Builder<'a, 'b> {
257258
};
258259

259260
if self.catch {
260-
js.cx.expose_handle_error()?;
261+
js.cx.expose_handle_error(import_deps)?;
261262
}
262263

263264
// Generate a try/catch block in debug mode which handles unexpected and
264265
// unhandled exceptions, typically used on imports. This currently just
265266
// logs what happened, but keeps the exception being thrown to propagate
266267
// elsewhere.
267268
if self.log_error {
268-
js.cx.expose_log_error();
269+
js.cx.expose_log_error(import_deps);
269270
}
270271

271272
code.push_str(&call);
@@ -641,11 +642,11 @@ impl<'a, 'b> JsBuilder<'a, 'b> {
641642
self.prelude(&format!("_assertBoolean({});", arg));
642643
}
643644

644-
fn assert_optional_number(&mut self, arg: &str) {
645+
fn assert_optional_number(&mut self, arg: &str, import_deps: &mut HashSet<String>) {
645646
if !self.cx.config.debug {
646647
return;
647648
}
648-
self.cx.expose_is_like_none();
649+
self.cx.expose_is_like_none(import_deps);
649650
self.prelude(&format!("if (!isLikeNone({})) {{", arg));
650651
self.assert_number(arg);
651652
self.prelude("}");
@@ -661,21 +662,21 @@ impl<'a, 'b> JsBuilder<'a, 'b> {
661662
self.prelude(&format!("_assertChar({});", arg));
662663
}
663664

664-
fn assert_optional_bigint(&mut self, arg: &str) {
665+
fn assert_optional_bigint(&mut self, arg: &str, import_deps: &mut HashSet<String>) {
665666
if !self.cx.config.debug {
666667
return;
667668
}
668-
self.cx.expose_is_like_none();
669+
self.cx.expose_is_like_none(import_deps);
669670
self.prelude(&format!("if (!isLikeNone({})) {{", arg));
670671
self.assert_bigint(arg);
671672
self.prelude("}");
672673
}
673674

674-
fn assert_optional_bool(&mut self, arg: &str) {
675+
fn assert_optional_bool(&mut self, arg: &str, import_deps: &mut HashSet<String>) {
675676
if !self.cx.config.debug {
676677
return;
677678
}
678-
self.cx.expose_is_like_none();
679+
self.cx.expose_is_like_none(import_deps);
679680
self.prelude(&format!("if (!isLikeNone({})) {{", arg));
680681
self.assert_bool(arg);
681682
self.prelude("}");
@@ -700,8 +701,9 @@ impl<'a, 'b> JsBuilder<'a, 'b> {
700701
mem: walrus::MemoryId,
701702
malloc: walrus::FunctionId,
702703
realloc: Option<walrus::FunctionId>,
704+
import_deps: &mut HashSet<String>,
703705
) -> Result<(), Error> {
704-
let pass = self.cx.expose_pass_string_to_wasm(mem)?;
706+
let pass = self.cx.expose_pass_string_to_wasm(mem, import_deps)?;
705707
let val = self.pop();
706708
let malloc = self.cx.export_name_of(malloc);
707709
let i = self.tmp();
@@ -720,6 +722,7 @@ impl<'a, 'b> JsBuilder<'a, 'b> {
720722
self.prelude(&format!("const len{} = WASM_VECTOR_LEN;", i));
721723
self.push(format!("ptr{}", i));
722724
self.push(format!("len{}", i));
725+
import_deps.insert(format!("'${}'", pass));
723726
Ok(())
724727
}
725728
}
@@ -729,7 +732,7 @@ fn instruction(
729732
instr: &Instruction,
730733
log_error: &mut bool,
731734
constructor: &Option<String>,
732-
import_deps: &mut Vec<String>,
735+
import_deps: &mut HashSet<String>,
733736
) -> Result<(), Error> {
734737
fn wasm_to_string_enum(name: &str, index: &str) -> String {
735738
// e.g. ["a","b","c"][someIndex]
@@ -880,8 +883,8 @@ fn instruction(
880883

881884
Instruction::OptionInt128ToWasm => {
882885
let val = js.pop();
883-
js.cx.expose_is_like_none();
884-
js.assert_optional_bigint(&val);
886+
js.cx.expose_is_like_none(import_deps);
887+
js.assert_optional_bigint(&val, import_deps);
885888
let (low, high) = int128_to_int64x2(&val);
886889
js.push(format!("!isLikeNone({val})"));
887890
js.push(format!("isLikeNone({val}) ? BigInt(0) : {low}"));
@@ -924,7 +927,7 @@ fn instruction(
924927
let enum_val = js.pop();
925928
js.cx.expose_string_enum(name);
926929
let enum_val_expr = string_enum_to_wasm(name, *invalid, &enum_val);
927-
js.cx.expose_is_like_none();
930+
js.cx.expose_is_like_none(import_deps);
928931

929932
// e.g. isLikeNone(someEnumVal) ? 4 : (string_enum_to_wasm(someEnumVal))
930933
js.push(format!(
@@ -944,7 +947,7 @@ fn instruction(
944947
malloc,
945948
realloc,
946949
} => {
947-
js.string_to_memory(*mem, *malloc, *realloc)?;
950+
js.string_to_memory(*mem, *malloc, *realloc, import_deps)?;
948951
}
949952

950953
Instruction::Retptr { size } => {
@@ -969,7 +972,7 @@ fn instruction(
969972
// Note that we always assume the return pointer is argument 0,
970973
// which is currently the case for LLVM.
971974
let val = js.pop();
972-
let expr = format!(
975+
let mut expr = format!(
973976
"{}().{}({} + {} * {}, {}, true);",
974977
mem,
975978
method,
@@ -978,6 +981,16 @@ fn instruction(
978981
offset,
979982
val,
980983
);
984+
if matches!(js.cx.config.mode, OutputMode::Emscripten) {
985+
expr = format!(
986+
"HEAP_DATA_VIEW.{}({} + {} * {}, {}, true);",
987+
method,
988+
js.arg(0),
989+
size,
990+
offset,
991+
val,
992+
);
993+
}
981994
js.prelude(&expr);
982995
}
983996

@@ -997,10 +1010,18 @@ fn instruction(
9971010
// If we're loading from the return pointer then we must have pushed
9981011
// it earlier, and we always push the same value, so load that value
9991012
// here
1000-
let expr = format!(
1013+
let mut expr = format!(
10011014
"{}().{}(retptr + {} * {}, true)",
10021015
mem, method, size, scaled_offset
10031016
);
1017+
1018+
if matches!(js.cx.config.mode, OutputMode::Emscripten) {
1019+
expr = format!(
1020+
"HEAP_DATA_VIEW.{}(retptr + {} * {}, true)",
1021+
method, size, scaled_offset
1022+
);
1023+
}
1024+
10041025
js.prelude(&format!("var r{} = {};", offset, expr));
10051026
js.push(format!("r{}", offset));
10061027
}
@@ -1053,7 +1074,7 @@ fn instruction(
10531074

10541075
Instruction::I32FromOptionRust { class } => {
10551076
let val = js.pop();
1056-
js.cx.expose_is_like_none();
1077+
js.cx.expose_is_like_none(import_deps);
10571078
let i = js.tmp();
10581079
js.prelude(&format!("let ptr{} = 0;", i));
10591080
js.prelude(&format!("if (!isLikeNone({0})) {{", val));
@@ -1066,10 +1087,12 @@ fn instruction(
10661087

10671088
Instruction::I32FromOptionExternref { table_and_alloc } => {
10681089
let val = js.pop();
1069-
js.cx.expose_is_like_none();
1090+
js.cx.expose_is_like_none(import_deps);
10701091
match table_and_alloc {
10711092
Some((table, alloc)) => {
1072-
let alloc = js.cx.expose_add_to_externref_table(*table, *alloc)?;
1093+
let alloc = js
1094+
.cx
1095+
.expose_add_to_externref_table(*table, *alloc, import_deps)?;
10731096
js.push(format!("isLikeNone({0}) ? 0 : {1}({0})", val, alloc));
10741097
}
10751098
None => {
@@ -1081,22 +1104,22 @@ fn instruction(
10811104

10821105
Instruction::I32FromOptionU32Sentinel => {
10831106
let val = js.pop();
1084-
js.cx.expose_is_like_none();
1085-
js.assert_optional_number(&val);
1107+
js.cx.expose_is_like_none(import_deps);
1108+
js.assert_optional_number(&val, import_deps);
10861109
js.push(format!("isLikeNone({0}) ? 0xFFFFFF : {0}", val));
10871110
}
10881111

10891112
Instruction::I32FromOptionBool => {
10901113
let val = js.pop();
1091-
js.cx.expose_is_like_none();
1092-
js.assert_optional_bool(&val);
1114+
js.cx.expose_is_like_none(import_deps);
1115+
js.assert_optional_bool(&val, import_deps);
10931116
js.push(format!("isLikeNone({0}) ? 0xFFFFFF : {0} ? 1 : 0", val));
10941117
}
10951118

10961119
Instruction::I32FromOptionChar => {
10971120
let val = js.pop();
10981121
let i = js.tmp();
1099-
js.cx.expose_is_like_none();
1122+
js.cx.expose_is_like_none(import_deps);
11001123
js.prelude(&format!(
11011124
"const char{i} = isLikeNone({0}) ? 0xFFFFFF : {0}.codePointAt(0);",
11021125
val
@@ -1111,15 +1134,15 @@ fn instruction(
11111134

11121135
Instruction::I32FromOptionEnum { hole } => {
11131136
let val = js.pop();
1114-
js.cx.expose_is_like_none();
1115-
js.assert_optional_number(&val);
1137+
js.cx.expose_is_like_none(import_deps);
1138+
js.assert_optional_number(&val, import_deps);
11161139
js.push(format!("isLikeNone({0}) ? {1} : {0}", val, hole));
11171140
}
11181141

11191142
Instruction::F64FromOptionSentinelInt { signed } => {
11201143
let val = js.pop();
1121-
js.cx.expose_is_like_none();
1122-
js.assert_optional_number(&val);
1144+
js.cx.expose_is_like_none(import_deps);
1145+
js.assert_optional_number(&val, import_deps);
11231146

11241147
// We need to convert the given number to a 32-bit integer before
11251148
// passing it to the ABI for 2 reasons:
@@ -1141,8 +1164,8 @@ fn instruction(
11411164
}
11421165
Instruction::F64FromOptionSentinelF32 => {
11431166
let val = js.pop();
1144-
js.cx.expose_is_like_none();
1145-
js.assert_optional_number(&val);
1167+
js.cx.expose_is_like_none(import_deps);
1168+
js.assert_optional_number(&val, import_deps);
11461169

11471170
// Similar to the above 32-bit integer variant, we convert the
11481171
// number to a 32-bit *float* before passing it to the ABI. This
@@ -1156,11 +1179,11 @@ fn instruction(
11561179

11571180
Instruction::FromOptionNative { ty } => {
11581181
let val = js.pop();
1159-
js.cx.expose_is_like_none();
1182+
js.cx.expose_is_like_none(import_deps);
11601183
if *ty == ValType::I64 {
1161-
js.assert_optional_bigint(&val);
1184+
js.assert_optional_bigint(&val, import_deps);
11621185
} else {
1163-
js.assert_optional_number(&val);
1186+
js.assert_optional_number(&val, import_deps);
11641187
}
11651188
js.push(format!("!isLikeNone({0})", val));
11661189
js.push(format!(
@@ -1177,7 +1200,9 @@ fn instruction(
11771200

11781201
Instruction::VectorToMemory { kind, malloc, mem } => {
11791202
let val = js.pop();
1180-
let func = js.cx.pass_to_wasm_function(kind.clone(), *mem)?;
1203+
let func = js
1204+
.cx
1205+
.pass_to_wasm_function(kind.clone(), *mem, import_deps)?;
11811206
let malloc = js.cx.export_name_of(*malloc);
11821207
let i = js.tmp();
11831208
js.prelude(&format!(
@@ -1190,6 +1215,7 @@ fn instruction(
11901215
js.prelude(&format!("const len{} = WASM_VECTOR_LEN;", i));
11911216
js.push(format!("ptr{}", i));
11921217
js.push(format!("len{}", i));
1218+
import_deps.insert(format!("'${}'", func));
11931219
}
11941220

11951221
Instruction::UnwrapResult { table_and_drop } => {
@@ -1260,8 +1286,8 @@ fn instruction(
12601286
malloc,
12611287
realloc,
12621288
} => {
1263-
let func = js.cx.expose_pass_string_to_wasm(*mem)?;
1264-
js.cx.expose_is_like_none();
1289+
let func = js.cx.expose_pass_string_to_wasm(*mem, import_deps)?;
1290+
js.cx.expose_is_like_none(import_deps);
12651291
let i = js.tmp();
12661292
let malloc = js.cx.export_name_of(*malloc);
12671293
let val = js.pop();
@@ -1280,11 +1306,14 @@ fn instruction(
12801306
js.prelude(&format!("var len{} = WASM_VECTOR_LEN;", i));
12811307
js.push(format!("ptr{}", i));
12821308
js.push(format!("len{}", i));
1309+
import_deps.insert(format!("'${}'", func));
12831310
}
12841311

12851312
Instruction::OptionVector { kind, mem, malloc } => {
1286-
let func = js.cx.pass_to_wasm_function(kind.clone(), *mem)?;
1287-
js.cx.expose_is_like_none();
1313+
let func = js
1314+
.cx
1315+
.pass_to_wasm_function(kind.clone(), *mem, import_deps)?;
1316+
js.cx.expose_is_like_none(import_deps);
12881317
let i = js.tmp();
12891318
let malloc = js.cx.export_name_of(*malloc);
12901319
let val = js.pop();
@@ -1298,12 +1327,15 @@ fn instruction(
12981327
js.prelude(&format!("var len{} = WASM_VECTOR_LEN;", i));
12991328
js.push(format!("ptr{}", i));
13001329
js.push(format!("len{}", i));
1330+
import_deps.insert(format!("'${}'", func));
13011331
}
13021332

13031333
Instruction::MutableSliceToMemory { kind, malloc, mem } => {
13041334
// Copy the contents of the typed array into wasm.
13051335
let val = js.pop();
1306-
let func = js.cx.pass_to_wasm_function(kind.clone(), *mem)?;
1336+
let func = js
1337+
.cx
1338+
.pass_to_wasm_function(kind.clone(), *mem, import_deps)?;
13071339
let malloc = js.cx.export_name_of(*malloc);
13081340
let i = js.tmp();
13091341
js.prelude(&format!(
@@ -1320,6 +1352,7 @@ fn instruction(
13201352
// Then we give Wasm a reference to the original typed array, so that it can
13211353
// update it with modifications made on the Wasm side before returning.
13221354
js.push(val);
1355+
import_deps.insert(format!("'${}'", func));
13231356
}
13241357

13251358
Instruction::BoolFromI32 => {
@@ -1421,6 +1454,7 @@ fn instruction(
14211454
.collect::<Vec<_>>()
14221455
.join(", ");
14231456
let wrapper = js.cx.adapter_name(*adapter);
1457+
import_deps.insert(format!("'${}'", wrapper));
14241458
if *mutable {
14251459
// Mutable closures need protection against being called
14261460
// recursively, so ensure that we clear out one of the
@@ -1566,8 +1600,8 @@ fn instruction(
15661600

15671601
Instruction::I32FromOptionNonNull => {
15681602
let val = js.pop();
1569-
js.cx.expose_is_like_none();
1570-
js.assert_optional_number(&val);
1603+
js.cx.expose_is_like_none(import_deps);
1604+
js.assert_optional_number(&val, import_deps);
15711605
js.push(format!("isLikeNone({0}) ? 0 : {0}", val));
15721606
}
15731607

@@ -1640,7 +1674,7 @@ impl Invocation {
16401674
args: &[String],
16411675
prelude: &mut String,
16421676
log_error: &mut bool,
1643-
import_deps: &mut Vec<String>,
1677+
import_deps: &mut HashSet<String>,
16441678
) -> Result<String, Error> {
16451679
match self {
16461680
Invocation::Core { id, .. } => {

0 commit comments

Comments
 (0)