Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b4f6ec0

Browse files
authoredMar 13, 2025··
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 77 additions & 43 deletions
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, .. } => {

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

Lines changed: 357 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ impl<'a> Context<'a> {
243243
ExportJs::Function(function) => {
244244
let body = function.strip_prefix("function").unwrap();
245245
if export_name == definition_name {
246-
format!("Module.{} = function{}\n", export_name, body)
246+
format!("Module.{} = function{};\n", export_name, body)
247247
} else {
248248
format!(
249249
"function {}{}\nexport {{ {} as {} }};\n",
@@ -667,8 +667,6 @@ __wbg_set_wasm(wasm);"
667667
push_with_newline("var LibraryWbg = {\n");
668668
push_with_newline(&self.emscripten_library);
669669
push_with_newline(&init_js);
670-
push_with_newline("$initBindgen__deps: ['$addOnInit'],");
671-
push_with_newline("$initBindgen__postset: 'addOnInit(initBindgen);',");
672670
push_with_newline(
673671
"$initBindgen: () => {\n
674672
wasmExports.__wbindgen_start();",
@@ -987,7 +985,31 @@ __wbg_set_wasm(wasm);"
987985
}
988986

989987
let js = match &self.config.mode {
990-
OutputMode::Emscripten => imports_init.to_string(),
988+
OutputMode::Emscripten => {
989+
let mut global_emscripten_initializer: String = Default::default();
990+
for global_dep in self.emscripten_deps.iter() {
991+
let mut global = "";
992+
if global_dep == "'$WASM_VECTOR_LEN'" {
993+
global = "$WASM_VECTOR_LEN: '0',";
994+
} else if global_dep == "'$TextEncoder'" {
995+
global = "$textEncoder: \"new TextEncoder()\",";
996+
}
997+
998+
if global != "" {
999+
global_emscripten_initializer = format!(
1000+
"{}{}\n",
1001+
global_emscripten_initializer, global
1002+
);
1003+
}
1004+
}
1005+
format!(
1006+
"\
1007+
{}
1008+
{}
1009+
$initBindgen__deps: ['$addOnInit'],
1010+
$initBindgen__postset: 'addOnInit(initBindgen);',
1011+
", imports_init.to_string(), global_emscripten_initializer
1012+
)}
9911013
_ => format!(
9921014
"\
9931015
async function __wbg_load(module, imports) {{
@@ -1520,15 +1542,25 @@ __wbg_set_wasm(wasm);"
15201542
);
15211543
}
15221544

1523-
fn expose_wasm_vector_len(&mut self) {
1545+
fn expose_wasm_vector_len(&mut self, import_deps: &mut HashSet<String>) {
1546+
import_deps.insert("'$WASM_VECTOR_LEN'".to_string());
15241547
if !self.should_write_global("wasm_vector_len") {
15251548
return;
15261549
}
1527-
self.global("let WASM_VECTOR_LEN = 0;");
1550+
if matches!(self.config.mode, OutputMode::Emscripten) {
1551+
self.emscripten_deps
1552+
.insert("'$WASM_VECTOR_LEN'".to_string());
1553+
} else {
1554+
self.global("let WASM_VECTOR_LEN = 0;");
1555+
}
15281556
}
15291557

1530-
fn expose_pass_string_to_wasm(&mut self, memory: MemoryId) -> Result<MemView, Error> {
1531-
self.expose_wasm_vector_len();
1558+
fn expose_pass_string_to_wasm(
1559+
&mut self,
1560+
memory: MemoryId,
1561+
import_deps: &mut HashSet<String>,
1562+
) -> Result<MemView, Error> {
1563+
self.expose_wasm_vector_len(import_deps);
15321564

15331565
let debug = if self.config.debug {
15341566
"
@@ -1548,55 +1580,101 @@ __wbg_set_wasm(wasm);"
15481580
}
15491581
self.expose_text_encoder()?;
15501582

1583+
let mut text_encoder = "cachedTextEncoder";
1584+
let mut mem_formatted = format!("{mem}()");
1585+
if matches!(self.config.mode, OutputMode::Emscripten) {
1586+
text_encoder = "textEncoder";
1587+
mem_formatted = "HEAP8".to_string();
1588+
};
15511589
// The first implementation we have for this is to use
15521590
// `TextEncoder#encode` which has been around for quite some time.
1553-
let encode = "function (arg, view) {
1554-
const buf = cachedTextEncoder.encode(arg);
1591+
let encode = format!(
1592+
"function (arg, view) {{
1593+
const buf = {text_encoder}.encode(arg);
15551594
view.set(buf);
1556-
return {
1595+
return {{
15571596
read: arg.length,
15581597
written: buf.length
1559-
};
1560-
}";
1598+
}};
1599+
}}"
1600+
);
15611601

15621602
// Another possibility is to use `TextEncoder#encodeInto` which is much
15631603
// newer and isn't implemented everywhere yet. It's more efficient,
15641604
// however, because it allows us to elide an intermediate allocation.
1565-
let encode_into = "function (arg, view) {
1566-
return cachedTextEncoder.encodeInto(arg, view);
1567-
}";
1605+
let encode_into = format!(
1606+
"function (arg, view) {{
1607+
return {text_encoder}.encodeInto(arg, view);
1608+
}}"
1609+
);
15681610

15691611
// Looks like `encodeInto` doesn't currently work when the memory passed
15701612
// in is backed by a `SharedArrayBuffer`, so force usage of `encode` if
15711613
// a `SharedArrayBuffer` is in use.
15721614
let shared = self.module.memories.get(memory).shared;
15731615

1574-
match self.config.encode_into {
1575-
EncodeInto::Always if !shared => {
1576-
self.global(&format!(
1577-
"
1578-
const encodeString = {};
1579-
",
1580-
encode_into
1581-
));
1582-
}
1583-
EncodeInto::Test if !shared => {
1584-
self.global(&format!(
1585-
"
1586-
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
1587-
? {}
1588-
: {});
1589-
",
1590-
encode_into, encode
1591-
));
1616+
if matches!(self.config.mode, OutputMode::Emscripten) {
1617+
match self.config.encode_into {
1618+
EncodeInto::Always if !shared => {
1619+
self.emscripten_library.push_str(&format!(
1620+
"
1621+
$encodeString : {},
1622+
",
1623+
encode_into
1624+
));
1625+
}
1626+
EncodeInto::Test if !shared => {
1627+
self.emscripten_library.push_str(&format!(
1628+
"
1629+
$encodeString : function (arg, view) {{
1630+
if (typeof TextEncoder.encodeInto === 'function') {{
1631+
return {}
1632+
}}
1633+
return {}
1634+
}},
1635+
",
1636+
encode_into, encode
1637+
));
1638+
}
1639+
_ => {
1640+
self.emscripten_library.push_str(&format!(
1641+
"
1642+
$encodeString : {},
1643+
",
1644+
encode
1645+
));
1646+
}
15921647
}
1593-
_ => {
1594-
self.global(&format!(
1595-
"
1596-
const encodeString = {};
1597-
",
1598-
encode
1599-
));
1648+
self.emscripten_library
1649+
.push_str("$encodeString__deps: ['$textEncoder'],\n");
1650+
} else {
1651+
match self.config.encode_into {
1652+
EncodeInto::Always if !shared => {
1653+
self.global(&format!(
1654+
"
1655+
const encodeString = {};
1656+
",
1657+
encode_into
1658+
));
1659+
}
1660+
EncodeInto::Test if !shared => {
1661+
self.global(&format!(
1662+
"
1663+
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
1664+
? {}
1665+
: {});
1666+
",
1667+
encode_into, encode
1668+
));
1669+
}
1670+
_ => {
1671+
self.global(&format!(
1672+
"
1673+
const encodeString = {};
1674+
",
1675+
encode
1676+
));
1677+
}
16001678
}
16011679
}
16021680

@@ -1612,17 +1690,17 @@ __wbg_set_wasm(wasm);"
16121690
let encode_as_ascii = format!(
16131691
"\
16141692
if (realloc === undefined) {{
1615-
const buf = cachedTextEncoder.encode(arg);
1693+
const buf = {text_encoder}.encode(arg);
16161694
const ptr = malloc(buf.length, 1) >>> 0;
1617-
{mem}().subarray(ptr, ptr + buf.length).set(buf);
1695+
{mem_formatted}.subarray(ptr, ptr + buf.length).set(buf);
16181696
WASM_VECTOR_LEN = buf.length;
16191697
return ptr;
16201698
}}
16211699
16221700
let len = arg.length;
16231701
let ptr = malloc(len, 1) >>> 0;
16241702
1625-
const mem = {mem}();
1703+
const mem = {mem_formatted};
16261704
16271705
let offset = 0;
16281706
@@ -1631,20 +1709,19 @@ __wbg_set_wasm(wasm);"
16311709
if (code > 0x7F) break;
16321710
mem[ptr + offset] = code;
16331711
}}
1634-
",
1635-
mem = mem,
1712+
"
16361713
);
1637-
1638-
self.global(&format!(
1639-
"function {name}(arg, malloc, realloc) {{
1714+
self.write_js_function(
1715+
&format!(
1716+
"
16401717
{debug}
16411718
{ascii}
16421719
if (offset !== len) {{
16431720
if (offset !== 0) {{
16441721
arg = arg.slice(offset);
16451722
}}
16461723
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
1647-
const view = {mem}().subarray(ptr + offset, ptr + len);
1724+
const view = {mem_formatted}.subarray(ptr + offset, ptr + len);
16481725
const ret = encodeString(arg, view);
16491726
{debug_end}
16501727
offset += ret.written;
@@ -1654,51 +1731,86 @@ __wbg_set_wasm(wasm);"
16541731
WASM_VECTOR_LEN = offset;
16551732
return ptr;
16561733
}}",
1657-
name = ret,
1658-
debug = debug,
1659-
ascii = encode_as_ascii,
1660-
mem = mem,
1661-
debug_end = if self.config.debug {
1662-
"if (ret.read !== arg.length) throw new Error('failed to pass whole string');"
1663-
} else {
1664-
""
1665-
},
1666-
));
1734+
debug = debug,
1735+
ascii = encode_as_ascii,
1736+
mem_formatted = mem_formatted,
1737+
debug_end = if self.config.debug {
1738+
"if (ret.read !== arg.length) throw new Error('failed to pass whole string');"
1739+
} else {
1740+
""
1741+
},
1742+
),
1743+
&format!("{ret}"),
1744+
"(arg, malloc, realloc)",
1745+
&vec![
1746+
format!("'$encodeString'"),
1747+
format!("'${text_encoder}'"),
1748+
format!("'$WASM_VECTOR_LEN'"),
1749+
],
1750+
);
16671751

16681752
Ok(ret)
16691753
}
16701754

1671-
fn expose_pass_array8_to_wasm(&mut self, memory: MemoryId) -> Result<MemView, Error> {
1755+
fn expose_pass_array8_to_wasm(
1756+
&mut self,
1757+
memory: MemoryId,
1758+
import_deps: &mut HashSet<String>,
1759+
) -> Result<MemView, Error> {
16721760
let view = self.expose_uint8_memory(memory);
1673-
self.pass_array_to_wasm("passArray8ToWasm", view, 1)
1761+
self.pass_array_to_wasm("passArray8ToWasm", view, 1, import_deps)
16741762
}
16751763

1676-
fn expose_pass_array16_to_wasm(&mut self, memory: MemoryId) -> Result<MemView, Error> {
1764+
fn expose_pass_array16_to_wasm(
1765+
&mut self,
1766+
memory: MemoryId,
1767+
import_deps: &mut HashSet<String>,
1768+
) -> Result<MemView, Error> {
16771769
let view = self.expose_uint16_memory(memory);
1678-
self.pass_array_to_wasm("passArray16ToWasm", view, 2)
1770+
self.pass_array_to_wasm("passArray16ToWasm", view, 2, import_deps)
16791771
}
16801772

1681-
fn expose_pass_array32_to_wasm(&mut self, memory: MemoryId) -> Result<MemView, Error> {
1773+
fn expose_pass_array32_to_wasm(
1774+
&mut self,
1775+
memory: MemoryId,
1776+
import_deps: &mut HashSet<String>,
1777+
) -> Result<MemView, Error> {
16821778
let view = self.expose_uint32_memory(memory);
1683-
self.pass_array_to_wasm("passArray32ToWasm", view, 4)
1779+
self.pass_array_to_wasm("passArray32ToWasm", view, 4, import_deps)
16841780
}
16851781

1686-
fn expose_pass_array64_to_wasm(&mut self, memory: MemoryId) -> Result<MemView, Error> {
1782+
fn expose_pass_array64_to_wasm(
1783+
&mut self,
1784+
memory: MemoryId,
1785+
import_deps: &mut HashSet<String>,
1786+
) -> Result<MemView, Error> {
16871787
let view = self.expose_uint64_memory(memory);
1688-
self.pass_array_to_wasm("passArray64ToWasm", view, 8)
1788+
self.pass_array_to_wasm("passArray64ToWasm", view, 8, import_deps)
16891789
}
16901790

1691-
fn expose_pass_array_f32_to_wasm(&mut self, memory: MemoryId) -> Result<MemView, Error> {
1791+
fn expose_pass_array_f32_to_wasm(
1792+
&mut self,
1793+
memory: MemoryId,
1794+
import_deps: &mut HashSet<String>,
1795+
) -> Result<MemView, Error> {
16921796
let view = self.expose_f32_memory(memory);
1693-
self.pass_array_to_wasm("passArrayF32ToWasm", view, 4)
1797+
self.pass_array_to_wasm("passArrayF32ToWasm", view, 4, import_deps)
16941798
}
16951799

1696-
fn expose_pass_array_f64_to_wasm(&mut self, memory: MemoryId) -> Result<MemView, Error> {
1800+
fn expose_pass_array_f64_to_wasm(
1801+
&mut self,
1802+
memory: MemoryId,
1803+
import_deps: &mut HashSet<String>,
1804+
) -> Result<MemView, Error> {
16971805
let view = self.expose_f64_memory(memory);
1698-
self.pass_array_to_wasm("passArrayF64ToWasm", view, 8)
1806+
self.pass_array_to_wasm("passArrayF64ToWasm", view, 8, import_deps)
16991807
}
17001808

1701-
fn expose_pass_array_jsvalue_to_wasm(&mut self, memory: MemoryId) -> Result<MemView, Error> {
1809+
fn expose_pass_array_jsvalue_to_wasm(
1810+
&mut self,
1811+
memory: MemoryId,
1812+
import_deps: &mut HashSet<String>,
1813+
) -> Result<MemView, Error> {
17021814
let mem = self.expose_dataview_memory(memory);
17031815
let ret = MemView {
17041816
name: "passArrayJsValueToWasm".into(),
@@ -1707,15 +1819,15 @@ __wbg_set_wasm(wasm);"
17071819
if !self.should_write_global(ret.to_string()) {
17081820
return Ok(ret);
17091821
}
1710-
self.expose_wasm_vector_len();
1822+
self.expose_wasm_vector_len(import_deps);
17111823
match (self.aux.externref_table, self.aux.externref_alloc) {
17121824
(Some(table), Some(alloc)) => {
17131825
// TODO: using `addToExternrefTable` goes back and forth between wasm
17141826
// and JS a lot, we should have a bulk operation for this.
1715-
let add = self.expose_add_to_externref_table(table, alloc)?;
1716-
self.global(&format!(
1717-
"
1718-
function {ret}(array, malloc) {{
1827+
let add = self.expose_add_to_externref_table(table, alloc, import_deps)?;
1828+
self.write_js_function(
1829+
&format!(
1830+
"
17191831
const ptr = malloc(array.length * 4, 4) >>> 0;
17201832
for (let i = 0; i < array.length; i++) {{
17211833
const add = {add}(array[i]);
@@ -1725,7 +1837,11 @@ __wbg_set_wasm(wasm);"
17251837
return ptr;
17261838
}}
17271839
",
1728-
));
1840+
),
1841+
&format!("{ret}"),
1842+
"(array, malloc)",
1843+
&vec![format!("'${add}'"), format!("'$WASM_VECTOR_LEN'")],
1844+
);
17291845
}
17301846
_ => {
17311847
self.expose_add_heap_object();
@@ -1752,6 +1868,7 @@ __wbg_set_wasm(wasm);"
17521868
name: &'static str,
17531869
view: MemView,
17541870
size: usize,
1871+
import_deps: &mut HashSet<String>,
17551872
) -> Result<MemView, Error> {
17561873
let ret = MemView {
17571874
name: name.into(),
@@ -1760,7 +1877,7 @@ __wbg_set_wasm(wasm);"
17601877
if !self.should_write_global(ret.to_string()) {
17611878
return Ok(ret);
17621879
}
1763-
self.expose_wasm_vector_len();
1880+
self.expose_wasm_vector_len(import_deps);
17641881
self.global(&format!(
17651882
"
17661883
function {}(arg, malloc) {{
@@ -1789,6 +1906,7 @@ __wbg_set_wasm(wasm);"
17891906
if !self.should_write_global("text_encoder") {
17901907
return Ok(());
17911908
}
1909+
self.emscripten_deps.insert("'$TextEncoder'".to_string());
17921910
self.expose_text_processor("TextEncoder", "encode", "('utf-8')", None)
17931911
}
17941912

@@ -2313,7 +2431,8 @@ __wbg_set_wasm(wasm);"
23132431
));
23142432
}
23152433

2316-
fn expose_handle_error(&mut self) -> Result<(), Error> {
2434+
fn expose_handle_error(&mut self, import_deps: &mut HashSet<String>) -> Result<(), Error> {
2435+
import_deps.insert("'$handleError'".to_string());
23172436
if !self.should_write_global("handle_error") {
23182437
return Ok(());
23192438
}
@@ -2324,10 +2443,10 @@ __wbg_set_wasm(wasm);"
23242443
let store = self.export_name_of(store);
23252444
match (self.aux.externref_table, self.aux.externref_alloc) {
23262445
(Some(table), Some(alloc)) => {
2327-
let add = self.expose_add_to_externref_table(table, alloc)?;
2328-
self.global(&format!(
2329-
"\
2330-
function handleError(f, args) {{
2446+
let add = self.expose_add_to_externref_table(table, alloc, import_deps)?;
2447+
self.write_js_function(
2448+
&format!(
2449+
"\
23312450
try {{
23322451
return f.apply(this, args);
23332452
}} catch (e) {{
@@ -2336,13 +2455,18 @@ __wbg_set_wasm(wasm);"
23362455
}}
23372456
}}
23382457
",
2339-
add, store,
2340-
));
2458+
add, store,
2459+
),
2460+
"handleError",
2461+
"(f, args)",
2462+
&vec![format!("'${add}'")],
2463+
);
23412464
}
23422465
_ => {
23432466
self.expose_add_heap_object();
2344-
self.global(&format!(
2345-
"\
2467+
self.write_js_function(
2468+
&format!(
2469+
"\
23462470
function handleError(f, args) {{
23472471
try {{
23482472
return f.apply(this, args);
@@ -2351,20 +2475,24 @@ __wbg_set_wasm(wasm);"
23512475
}}
23522476
}}
23532477
",
2354-
store,
2355-
));
2478+
store,
2479+
),
2480+
"handleError",
2481+
"(f, args)",
2482+
&vec![format!("'$addHeapObject'")],
2483+
);
23562484
}
23572485
}
23582486
Ok(())
23592487
}
23602488

2361-
fn expose_log_error(&mut self) {
2489+
fn expose_log_error(&mut self, import_deps: &mut HashSet<String>) {
2490+
import_deps.insert("'$logError'".to_string());
23622491
if !self.should_write_global("log_error") {
23632492
return;
23642493
}
2365-
self.global(
2494+
self.write_js_function(
23662495
"\
2367-
function logError(f, args) {
23682496
try {
23692497
return f.apply(this, args);
23702498
} catch (e) {
@@ -2384,22 +2512,38 @@ __wbg_set_wasm(wasm);"
23842512
}
23852513
}
23862514
",
2515+
"logError",
2516+
"(f, args)",
2517+
&Default::default(),
23872518
);
23882519
}
23892520

2390-
fn pass_to_wasm_function(&mut self, t: VectorKind, memory: MemoryId) -> Result<MemView, Error> {
2521+
fn pass_to_wasm_function(
2522+
&mut self,
2523+
t: VectorKind,
2524+
memory: MemoryId,
2525+
import_deps: &mut HashSet<String>,
2526+
) -> Result<MemView, Error> {
23912527
match t {
2392-
VectorKind::String => self.expose_pass_string_to_wasm(memory),
2528+
VectorKind::String => self.expose_pass_string_to_wasm(memory, import_deps),
23932529
VectorKind::I8 | VectorKind::U8 | VectorKind::ClampedU8 => {
2394-
self.expose_pass_array8_to_wasm(memory)
2530+
self.expose_pass_array8_to_wasm(memory, import_deps)
2531+
}
2532+
VectorKind::U16 | VectorKind::I16 => {
2533+
self.expose_pass_array16_to_wasm(memory, import_deps)
2534+
}
2535+
VectorKind::I32 | VectorKind::U32 => {
2536+
self.expose_pass_array32_to_wasm(memory, import_deps)
2537+
}
2538+
VectorKind::I64 | VectorKind::U64 => {
2539+
self.expose_pass_array64_to_wasm(memory, import_deps)
2540+
}
2541+
VectorKind::F32 => self.expose_pass_array_f32_to_wasm(memory, import_deps),
2542+
VectorKind::F64 => self.expose_pass_array_f64_to_wasm(memory, import_deps),
2543+
VectorKind::Externref => self.expose_pass_array_jsvalue_to_wasm(memory, import_deps),
2544+
VectorKind::NamedExternref(_) => {
2545+
self.expose_pass_array_jsvalue_to_wasm(memory, import_deps)
23952546
}
2396-
VectorKind::U16 | VectorKind::I16 => self.expose_pass_array16_to_wasm(memory),
2397-
VectorKind::I32 | VectorKind::U32 => self.expose_pass_array32_to_wasm(memory),
2398-
VectorKind::I64 | VectorKind::U64 => self.expose_pass_array64_to_wasm(memory),
2399-
VectorKind::F32 => self.expose_pass_array_f32_to_wasm(memory),
2400-
VectorKind::F64 => self.expose_pass_array_f64_to_wasm(memory),
2401-
VectorKind::Externref => self.expose_pass_array_jsvalue_to_wasm(memory),
2402-
VectorKind::NamedExternref(_) => self.expose_pass_array_jsvalue_to_wasm(memory),
24032547
}
24042548
}
24052549

@@ -2453,17 +2597,31 @@ __wbg_set_wasm(wasm);"
24532597
);
24542598
}
24552599

2456-
fn expose_is_like_none(&mut self) {
2600+
fn expose_is_like_none(&mut self, import_deps: &mut HashSet<String>) {
2601+
if matches!(self.config.mode, OutputMode::Emscripten) {
2602+
import_deps.insert("'$isLikeNone'".to_string());
2603+
}
24572604
if !self.should_write_global("is_like_none") {
24582605
return;
24592606
}
2460-
self.global(
2461-
"
2462-
function isLikeNone(x) {
2463-
return x === undefined || x === null;
2464-
}
2607+
2608+
if matches!(self.config.mode, OutputMode::Emscripten) {
2609+
self.emscripten_library.push_str(
2610+
"
2611+
$isLikeNone: function(x) {
2612+
return x == null;
2613+
},
24652614
",
2466-
);
2615+
);
2616+
} else {
2617+
self.global(
2618+
"
2619+
function isLikeNone(x) {
2620+
return x == null;
2621+
}
2622+
",
2623+
);
2624+
}
24672625
}
24682626

24692627
fn expose_assert_non_null(&mut self) {
@@ -2653,10 +2811,10 @@ __wbg_set_wasm(wasm);"
26532811
self.emscripten_library.push_str(
26542812
"
26552813
$CLOSURE_DTORS: `(typeof FinalizationRegistry === 'undefined')
2656-
? {{ register: () => {{}}, unregister: () => {{}} }}
2657-
: new FinalizationRegistry(state => {{
2814+
? { register: () => {}, unregister: () => {} }
2815+
: new FinalizationRegistry(state => {
26582816
wasmExports.__indirect_function_table.get(state.dtor)(state.a, state.b)
2659-
}})`,\n
2817+
})`,\n
26602818
",
26612819
);
26622820
} else {
@@ -2684,6 +2842,50 @@ __wbg_set_wasm(wasm);"
26842842
self.globals.push('\n');
26852843
}
26862844

2845+
fn emscripten_library(&mut self, s: &str) {
2846+
let s = s.trim();
2847+
2848+
// Ensure a blank line between adjacent items, and ensure everything is
2849+
// terminated with a newline.
2850+
while !self.emscripten_library.ends_with("\n\n\n")
2851+
&& !self.emscripten_library.ends_with("*/\n")
2852+
{
2853+
self.emscripten_library.push('\n');
2854+
}
2855+
self.emscripten_library.push_str(s);
2856+
self.emscripten_library.push('\n');
2857+
}
2858+
2859+
fn write_js_function(&mut self, body: &str, func_name: &str, args: &str, deps: &Vec<String>) {
2860+
if matches!(self.config.mode, OutputMode::Emscripten) {
2861+
self.emscripten_library(&format!(
2862+
"
2863+
${}: function{} {{
2864+
{},
2865+
",
2866+
func_name,
2867+
args,
2868+
body.trim().replace("wasm.", "wasmExports.")
2869+
));
2870+
if !deps.is_empty() {
2871+
self.emscripten_library.push_str(&format!(
2872+
"${}_deps: [{}],
2873+
",
2874+
func_name,
2875+
deps.join(",")
2876+
));
2877+
}
2878+
} else {
2879+
self.global(&format!(
2880+
"
2881+
function {}{} {{
2882+
{}
2883+
",
2884+
func_name, args, body
2885+
));
2886+
}
2887+
}
2888+
26872889
fn require_class_wrap(&mut self, name: &str) {
26882890
require_class(&mut self.exported_classes, name).wrap_needed = true;
26892891
}
@@ -2869,24 +3071,30 @@ __wbg_set_wasm(wasm);"
28693071
&mut self,
28703072
table: TableId,
28713073
alloc: FunctionId,
3074+
import_deps: &mut HashSet<String>,
28723075
) -> Result<MemView, Error> {
28733076
let view = self.memview_table("addToExternrefTable", table);
28743077
assert!(self.config.externref);
3078+
import_deps.insert(format!("'${}'", view).to_string());
28753079
if !self.should_write_global(view.to_string()) {
28763080
return Ok(view);
28773081
}
28783082
let alloc = self.export_name_of(alloc);
28793083
let table = self.export_name_of(table);
2880-
self.global(&format!(
2881-
"
2882-
function {}(obj) {{
3084+
self.write_js_function(
3085+
&format!(
3086+
"
28833087
const idx = wasm.{}();
28843088
wasm.{}.set(idx, obj);
28853089
return idx;
28863090
}}
28873091
",
2888-
view, alloc, table,
2889-
));
3092+
alloc, table,
3093+
),
3094+
&format!("{}", view),
3095+
"(obj)",
3096+
&Default::default(),
3097+
);
28903098

28913099
Ok(view)
28923100
}
@@ -3035,7 +3243,7 @@ __wbg_set_wasm(wasm);"
30353243
ContextAdapterKind::Export(e) => format!("`{}`", e.debug_name),
30363244
ContextAdapterKind::Adapter => format!("adapter {}", id.0),
30373245
};
3038-
let mut import_deps: Vec<String> = Default::default();
3246+
let mut import_deps: HashSet<String> = Default::default();
30393247
// Process the `binding` and generate a bunch of JS/TypeScript/etc.
30403248
let binding::JsFunction {
30413249
ts_sig,
@@ -3173,7 +3381,7 @@ __wbg_set_wasm(wasm);"
31733381
}
31743382
}
31753383
ContextAdapterKind::Import(core) => {
3176-
let code = if catch {
3384+
let mut code = if catch {
31773385
format!(
31783386
"function() {{ return handleError(function {}, arguments) }}",
31793387
code
@@ -3183,22 +3391,25 @@ __wbg_set_wasm(wasm);"
31833391
"function() {{ return logError(function {}, arguments) }}",
31843392
code
31853393
)
3186-
} else if (matches!(self.config.mode, OutputMode::Emscripten)
3187-
&& !import_deps.is_empty())
3188-
{
3189-
for dep in &import_deps {
3190-
self.emscripten_deps.insert(dep.clone());
3191-
}
3192-
format!(
3193-
"function{},\n{}__deps: [{}]",
3194-
code,
3195-
self.module.imports.get(core).name,
3196-
import_deps.join(",")
3197-
)
31983394
} else {
3199-
format!("function{}\n", code)
3395+
format!("function{}", code)
32003396
};
32013397

3398+
if matches!(self.config.mode, OutputMode::Emscripten) && !import_deps.is_empty() {
3399+
let mut import_deps_vec = import_deps
3400+
.iter()
3401+
.map(|s| s.as_str())
3402+
.collect::<Vec<&str>>();
3403+
// sort to generate deterministic output.
3404+
import_deps_vec.sort();
3405+
let deps: String = format!(
3406+
"{}__deps: [{}]\n",
3407+
self.module.imports.get(core).name,
3408+
import_deps_vec.join(",")
3409+
);
3410+
code = format!("{},\n{}\n", code, deps);
3411+
}
3412+
32023413
self.wasm_import_definitions.insert(core, code);
32033414
}
32043415
ContextAdapterKind::Adapter => {
@@ -3441,7 +3652,7 @@ __wbg_set_wasm(wasm);"
34413652
args: &[String],
34423653
variadic: bool,
34433654
prelude: &mut String,
3444-
import_deps: &mut Vec<String>,
3655+
import_deps: &mut HashSet<String>,
34453656
) -> Result<String, Error> {
34463657
let variadic_args = |js_arguments: &[String]| {
34473658
Ok(if !variadic {
@@ -3465,7 +3676,7 @@ __wbg_set_wasm(wasm);"
34653676
let re = Regex::new(r"([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(").unwrap();
34663677
for arg in args {
34673678
if let Some(result) = re.captures(arg) {
3468-
import_deps.push(format!("'${}'", &result[1]));
3679+
import_deps.insert(format!("'${}'", &result[1]));
34693680
}
34703681
}
34713682
}
@@ -3581,11 +3792,11 @@ __wbg_set_wasm(wasm);"
35813792
assert_eq!(args.len(), 3);
35823793

35833794
let call = self.adapter_name(*adapter);
3584-
import_deps.push(format!("'${}'", call));
3795+
import_deps.insert(format!("'${}'", call));
35853796
if *mutable {
35863797
self.expose_make_mut_closure()?;
35873798
if matches!(self.config.mode, OutputMode::Emscripten) {
3588-
import_deps.push("'$makeMutClosure'".to_string());
3799+
import_deps.insert("'$makeMutClosure'".to_string());
35893800
}
35903801
Ok(format!(
35913802
"makeMutClosure({arg0}, {arg1}, {dtor}, {call})",
@@ -3597,7 +3808,7 @@ __wbg_set_wasm(wasm);"
35973808
} else {
35983809
self.expose_make_closure()?;
35993810
if matches!(self.config.mode, OutputMode::Emscripten) {
3600-
import_deps.push("'$makeClosure'".to_string());
3811+
import_deps.insert("'$makeClosure'".to_string());
36013812
}
36023813
Ok(format!(
36033814
"makeClosure({arg0}, {arg1}, {dtor}, {call})",
@@ -3719,7 +3930,7 @@ __wbg_set_wasm(wasm);"
37193930
AuxImport::Intrinsic(intrinsic) => {
37203931
assert!(kind == AdapterJsImportKind::Normal);
37213932
assert!(!variadic);
3722-
self.invoke_intrinsic(intrinsic, args, prelude)
3933+
self.invoke_intrinsic(intrinsic, args, prelude, import_deps)
37233934
}
37243935

37253936
AuxImport::LinkTo(path, content) => {
@@ -3785,6 +3996,7 @@ __wbg_set_wasm(wasm);"
37853996
intrinsic: &Intrinsic,
37863997
args: &[String],
37873998
prelude: &mut String,
3999+
import_deps: &mut HashSet<String>,
37884000
) -> Result<String, Error> {
37894001
let expr = match intrinsic {
37904002
Intrinsic::JsvalEq => {
@@ -4121,6 +4333,7 @@ __wbg_set_wasm(wasm);"
41214333
Intrinsic::DebugString => {
41224334
assert_eq!(args.len(), 1);
41234335
self.expose_debug_string();
4336+
import_deps.insert("'$debugString'".to_string());
41244337
format!("debugString({})", args[0])
41254338
}
41264339

@@ -4395,9 +4608,8 @@ __wbg_set_wasm(wasm);"
43954608
return;
43964609
}
43974610

4398-
self.global(
4611+
self.write_js_function(
43994612
"
4400-
function debugString(val) {
44014613
// primitive types
44024614
const type = typeof val;
44034615
if (type == 'number' || type == 'boolean' || val == null) {
@@ -4462,6 +4674,9 @@ __wbg_set_wasm(wasm);"
44624674
return className;
44634675
}
44644676
",
4677+
"debugString",
4678+
"(val)",
4679+
&Default::default(),
44654680
);
44664681
}
44674682

0 commit comments

Comments
 (0)
Please sign in to comment.