@@ -9,6 +9,7 @@ use crate::wit::InstructionData;
9
9
use crate :: wit:: {
10
10
Adapter , AdapterId , AdapterKind , AdapterType , AuxFunctionArgumentData , Instruction ,
11
11
} ;
12
+ use crate :: OutputMode ;
12
13
use anyhow:: { anyhow, bail, Error } ;
13
14
use std:: collections:: HashSet ;
14
15
use std:: fmt:: Write ;
@@ -130,7 +131,7 @@ impl<'a, 'b> Builder<'a, 'b> {
130
131
debug_name : & str ,
131
132
ret_ty_override : & Option < String > ,
132
133
ret_desc : & Option < String > ,
133
- import_deps : & mut Vec < String > ,
134
+ import_deps : & mut HashSet < String > ,
134
135
) -> Result < JsFunction , Error > {
135
136
if self
136
137
. cx
@@ -257,15 +258,15 @@ impl<'a, 'b> Builder<'a, 'b> {
257
258
} ;
258
259
259
260
if self . catch {
260
- js. cx . expose_handle_error ( ) ?;
261
+ js. cx . expose_handle_error ( import_deps ) ?;
261
262
}
262
263
263
264
// Generate a try/catch block in debug mode which handles unexpected and
264
265
// unhandled exceptions, typically used on imports. This currently just
265
266
// logs what happened, but keeps the exception being thrown to propagate
266
267
// elsewhere.
267
268
if self . log_error {
268
- js. cx . expose_log_error ( ) ;
269
+ js. cx . expose_log_error ( import_deps ) ;
269
270
}
270
271
271
272
code. push_str ( & call) ;
@@ -641,11 +642,11 @@ impl<'a, 'b> JsBuilder<'a, 'b> {
641
642
self . prelude ( & format ! ( "_assertBoolean({});" , arg) ) ;
642
643
}
643
644
644
- fn assert_optional_number ( & mut self , arg : & str ) {
645
+ fn assert_optional_number ( & mut self , arg : & str , import_deps : & mut HashSet < String > ) {
645
646
if !self . cx . config . debug {
646
647
return ;
647
648
}
648
- self . cx . expose_is_like_none ( ) ;
649
+ self . cx . expose_is_like_none ( import_deps ) ;
649
650
self . prelude ( & format ! ( "if (!isLikeNone({})) {{" , arg) ) ;
650
651
self . assert_number ( arg) ;
651
652
self . prelude ( "}" ) ;
@@ -661,21 +662,21 @@ impl<'a, 'b> JsBuilder<'a, 'b> {
661
662
self . prelude ( & format ! ( "_assertChar({});" , arg) ) ;
662
663
}
663
664
664
- fn assert_optional_bigint ( & mut self , arg : & str ) {
665
+ fn assert_optional_bigint ( & mut self , arg : & str , import_deps : & mut HashSet < String > ) {
665
666
if !self . cx . config . debug {
666
667
return ;
667
668
}
668
- self . cx . expose_is_like_none ( ) ;
669
+ self . cx . expose_is_like_none ( import_deps ) ;
669
670
self . prelude ( & format ! ( "if (!isLikeNone({})) {{" , arg) ) ;
670
671
self . assert_bigint ( arg) ;
671
672
self . prelude ( "}" ) ;
672
673
}
673
674
674
- fn assert_optional_bool ( & mut self , arg : & str ) {
675
+ fn assert_optional_bool ( & mut self , arg : & str , import_deps : & mut HashSet < String > ) {
675
676
if !self . cx . config . debug {
676
677
return ;
677
678
}
678
- self . cx . expose_is_like_none ( ) ;
679
+ self . cx . expose_is_like_none ( import_deps ) ;
679
680
self . prelude ( & format ! ( "if (!isLikeNone({})) {{" , arg) ) ;
680
681
self . assert_bool ( arg) ;
681
682
self . prelude ( "}" ) ;
@@ -700,8 +701,9 @@ impl<'a, 'b> JsBuilder<'a, 'b> {
700
701
mem : walrus:: MemoryId ,
701
702
malloc : walrus:: FunctionId ,
702
703
realloc : Option < walrus:: FunctionId > ,
704
+ import_deps : & mut HashSet < String > ,
703
705
) -> 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 ) ?;
705
707
let val = self . pop ( ) ;
706
708
let malloc = self . cx . export_name_of ( malloc) ;
707
709
let i = self . tmp ( ) ;
@@ -720,6 +722,7 @@ impl<'a, 'b> JsBuilder<'a, 'b> {
720
722
self . prelude ( & format ! ( "const len{} = WASM_VECTOR_LEN;" , i) ) ;
721
723
self . push ( format ! ( "ptr{}" , i) ) ;
722
724
self . push ( format ! ( "len{}" , i) ) ;
725
+ import_deps. insert ( format ! ( "'${}'" , pass) ) ;
723
726
Ok ( ( ) )
724
727
}
725
728
}
@@ -729,7 +732,7 @@ fn instruction(
729
732
instr : & Instruction ,
730
733
log_error : & mut bool ,
731
734
constructor : & Option < String > ,
732
- import_deps : & mut Vec < String > ,
735
+ import_deps : & mut HashSet < String > ,
733
736
) -> Result < ( ) , Error > {
734
737
fn wasm_to_string_enum ( name : & str , index : & str ) -> String {
735
738
// e.g. ["a","b","c"][someIndex]
@@ -880,8 +883,8 @@ fn instruction(
880
883
881
884
Instruction :: OptionInt128ToWasm => {
882
885
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 ) ;
885
888
let ( low, high) = int128_to_int64x2 ( & val) ;
886
889
js. push ( format ! ( "!isLikeNone({val})" ) ) ;
887
890
js. push ( format ! ( "isLikeNone({val}) ? BigInt(0) : {low}" ) ) ;
@@ -924,7 +927,7 @@ fn instruction(
924
927
let enum_val = js. pop ( ) ;
925
928
js. cx . expose_string_enum ( name) ;
926
929
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 ) ;
928
931
929
932
// e.g. isLikeNone(someEnumVal) ? 4 : (string_enum_to_wasm(someEnumVal))
930
933
js. push ( format ! (
@@ -944,7 +947,7 @@ fn instruction(
944
947
malloc,
945
948
realloc,
946
949
} => {
947
- js. string_to_memory ( * mem, * malloc, * realloc) ?;
950
+ js. string_to_memory ( * mem, * malloc, * realloc, import_deps ) ?;
948
951
}
949
952
950
953
Instruction :: Retptr { size } => {
@@ -969,7 +972,7 @@ fn instruction(
969
972
// Note that we always assume the return pointer is argument 0,
970
973
// which is currently the case for LLVM.
971
974
let val = js. pop ( ) ;
972
- let expr = format ! (
975
+ let mut expr = format ! (
973
976
"{}().{}({} + {} * {}, {}, true);" ,
974
977
mem,
975
978
method,
@@ -978,6 +981,16 @@ fn instruction(
978
981
offset,
979
982
val,
980
983
) ;
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
+ }
981
994
js. prelude ( & expr) ;
982
995
}
983
996
@@ -997,10 +1010,18 @@ fn instruction(
997
1010
// If we're loading from the return pointer then we must have pushed
998
1011
// it earlier, and we always push the same value, so load that value
999
1012
// here
1000
- let expr = format ! (
1013
+ let mut expr = format ! (
1001
1014
"{}().{}(retptr + {} * {}, true)" ,
1002
1015
mem, method, size, scaled_offset
1003
1016
) ;
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
+
1004
1025
js. prelude ( & format ! ( "var r{} = {};" , offset, expr) ) ;
1005
1026
js. push ( format ! ( "r{}" , offset) ) ;
1006
1027
}
@@ -1053,7 +1074,7 @@ fn instruction(
1053
1074
1054
1075
Instruction :: I32FromOptionRust { class } => {
1055
1076
let val = js. pop ( ) ;
1056
- js. cx . expose_is_like_none ( ) ;
1077
+ js. cx . expose_is_like_none ( import_deps ) ;
1057
1078
let i = js. tmp ( ) ;
1058
1079
js. prelude ( & format ! ( "let ptr{} = 0;" , i) ) ;
1059
1080
js. prelude ( & format ! ( "if (!isLikeNone({0})) {{" , val) ) ;
@@ -1066,10 +1087,12 @@ fn instruction(
1066
1087
1067
1088
Instruction :: I32FromOptionExternref { table_and_alloc } => {
1068
1089
let val = js. pop ( ) ;
1069
- js. cx . expose_is_like_none ( ) ;
1090
+ js. cx . expose_is_like_none ( import_deps ) ;
1070
1091
match table_and_alloc {
1071
1092
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) ?;
1073
1096
js. push ( format ! ( "isLikeNone({0}) ? 0 : {1}({0})" , val, alloc) ) ;
1074
1097
}
1075
1098
None => {
@@ -1081,22 +1104,22 @@ fn instruction(
1081
1104
1082
1105
Instruction :: I32FromOptionU32Sentinel => {
1083
1106
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 ) ;
1086
1109
js. push ( format ! ( "isLikeNone({0}) ? 0xFFFFFF : {0}" , val) ) ;
1087
1110
}
1088
1111
1089
1112
Instruction :: I32FromOptionBool => {
1090
1113
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 ) ;
1093
1116
js. push ( format ! ( "isLikeNone({0}) ? 0xFFFFFF : {0} ? 1 : 0" , val) ) ;
1094
1117
}
1095
1118
1096
1119
Instruction :: I32FromOptionChar => {
1097
1120
let val = js. pop ( ) ;
1098
1121
let i = js. tmp ( ) ;
1099
- js. cx . expose_is_like_none ( ) ;
1122
+ js. cx . expose_is_like_none ( import_deps ) ;
1100
1123
js. prelude ( & format ! (
1101
1124
"const char{i} = isLikeNone({0}) ? 0xFFFFFF : {0}.codePointAt(0);" ,
1102
1125
val
@@ -1111,15 +1134,15 @@ fn instruction(
1111
1134
1112
1135
Instruction :: I32FromOptionEnum { hole } => {
1113
1136
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 ) ;
1116
1139
js. push ( format ! ( "isLikeNone({0}) ? {1} : {0}" , val, hole) ) ;
1117
1140
}
1118
1141
1119
1142
Instruction :: F64FromOptionSentinelInt { signed } => {
1120
1143
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 ) ;
1123
1146
1124
1147
// We need to convert the given number to a 32-bit integer before
1125
1148
// passing it to the ABI for 2 reasons:
@@ -1141,8 +1164,8 @@ fn instruction(
1141
1164
}
1142
1165
Instruction :: F64FromOptionSentinelF32 => {
1143
1166
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 ) ;
1146
1169
1147
1170
// Similar to the above 32-bit integer variant, we convert the
1148
1171
// number to a 32-bit *float* before passing it to the ABI. This
@@ -1156,11 +1179,11 @@ fn instruction(
1156
1179
1157
1180
Instruction :: FromOptionNative { ty } => {
1158
1181
let val = js. pop ( ) ;
1159
- js. cx . expose_is_like_none ( ) ;
1182
+ js. cx . expose_is_like_none ( import_deps ) ;
1160
1183
if * ty == ValType :: I64 {
1161
- js. assert_optional_bigint ( & val) ;
1184
+ js. assert_optional_bigint ( & val, import_deps ) ;
1162
1185
} else {
1163
- js. assert_optional_number ( & val) ;
1186
+ js. assert_optional_number ( & val, import_deps ) ;
1164
1187
}
1165
1188
js. push ( format ! ( "!isLikeNone({0})" , val) ) ;
1166
1189
js. push ( format ! (
@@ -1177,7 +1200,9 @@ fn instruction(
1177
1200
1178
1201
Instruction :: VectorToMemory { kind, malloc, mem } => {
1179
1202
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) ?;
1181
1206
let malloc = js. cx . export_name_of ( * malloc) ;
1182
1207
let i = js. tmp ( ) ;
1183
1208
js. prelude ( & format ! (
@@ -1190,6 +1215,7 @@ fn instruction(
1190
1215
js. prelude ( & format ! ( "const len{} = WASM_VECTOR_LEN;" , i) ) ;
1191
1216
js. push ( format ! ( "ptr{}" , i) ) ;
1192
1217
js. push ( format ! ( "len{}" , i) ) ;
1218
+ import_deps. insert ( format ! ( "'${}'" , func) ) ;
1193
1219
}
1194
1220
1195
1221
Instruction :: UnwrapResult { table_and_drop } => {
@@ -1260,8 +1286,8 @@ fn instruction(
1260
1286
malloc,
1261
1287
realloc,
1262
1288
} => {
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 ) ;
1265
1291
let i = js. tmp ( ) ;
1266
1292
let malloc = js. cx . export_name_of ( * malloc) ;
1267
1293
let val = js. pop ( ) ;
@@ -1280,11 +1306,14 @@ fn instruction(
1280
1306
js. prelude ( & format ! ( "var len{} = WASM_VECTOR_LEN;" , i) ) ;
1281
1307
js. push ( format ! ( "ptr{}" , i) ) ;
1282
1308
js. push ( format ! ( "len{}" , i) ) ;
1309
+ import_deps. insert ( format ! ( "'${}'" , func) ) ;
1283
1310
}
1284
1311
1285
1312
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) ;
1288
1317
let i = js. tmp ( ) ;
1289
1318
let malloc = js. cx . export_name_of ( * malloc) ;
1290
1319
let val = js. pop ( ) ;
@@ -1298,12 +1327,15 @@ fn instruction(
1298
1327
js. prelude ( & format ! ( "var len{} = WASM_VECTOR_LEN;" , i) ) ;
1299
1328
js. push ( format ! ( "ptr{}" , i) ) ;
1300
1329
js. push ( format ! ( "len{}" , i) ) ;
1330
+ import_deps. insert ( format ! ( "'${}'" , func) ) ;
1301
1331
}
1302
1332
1303
1333
Instruction :: MutableSliceToMemory { kind, malloc, mem } => {
1304
1334
// Copy the contents of the typed array into wasm.
1305
1335
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) ?;
1307
1339
let malloc = js. cx . export_name_of ( * malloc) ;
1308
1340
let i = js. tmp ( ) ;
1309
1341
js. prelude ( & format ! (
@@ -1320,6 +1352,7 @@ fn instruction(
1320
1352
// Then we give Wasm a reference to the original typed array, so that it can
1321
1353
// update it with modifications made on the Wasm side before returning.
1322
1354
js. push ( val) ;
1355
+ import_deps. insert ( format ! ( "'${}'" , func) ) ;
1323
1356
}
1324
1357
1325
1358
Instruction :: BoolFromI32 => {
@@ -1421,6 +1454,7 @@ fn instruction(
1421
1454
. collect :: < Vec < _ > > ( )
1422
1455
. join ( ", " ) ;
1423
1456
let wrapper = js. cx . adapter_name ( * adapter) ;
1457
+ import_deps. insert ( format ! ( "'${}'" , wrapper) ) ;
1424
1458
if * mutable {
1425
1459
// Mutable closures need protection against being called
1426
1460
// recursively, so ensure that we clear out one of the
@@ -1566,8 +1600,8 @@ fn instruction(
1566
1600
1567
1601
Instruction :: I32FromOptionNonNull => {
1568
1602
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 ) ;
1571
1605
js. push ( format ! ( "isLikeNone({0}) ? 0 : {0}" , val) ) ;
1572
1606
}
1573
1607
@@ -1640,7 +1674,7 @@ impl Invocation {
1640
1674
args : & [ String ] ,
1641
1675
prelude : & mut String ,
1642
1676
log_error : & mut bool ,
1643
- import_deps : & mut Vec < String > ,
1677
+ import_deps : & mut HashSet < String > ,
1644
1678
) -> Result < String , Error > {
1645
1679
match self {
1646
1680
Invocation :: Core { id, .. } => {
0 commit comments