1use heck::*;
2use std::collections::BTreeMap;
3use std::io::{Read, Write};
4use std::mem;
5use std::process::{Command, Stdio};
6use wai_bindgen_gen_core::wai_parser::abi::{
7 AbiVariant, Bindgen, Instruction, LiftLower, WasmType,
8};
9use wai_bindgen_gen_core::{wai_parser::*, Direction, Files, Generator, Source, TypeInfo, Types};
10use wai_bindgen_gen_rust::{
11 int_repr, wasm_type, FnSig, RustFlagsRepr, RustFunctionGenerator, RustGenerator, TypeMode,
12};
13
14#[derive(Default)]
15pub struct RustWasm {
16 src: Source,
17 opts: Opts,
18 types: Types,
19 in_import: bool,
20 traits: BTreeMap<String, Trait>,
21 in_trait: bool,
22 trait_name: String,
23 return_pointer_area_size: usize,
24 return_pointer_area_align: usize,
25 sizes: SizeAlign,
26}
27
28#[derive(Default, Debug, Clone)]
29#[cfg_attr(feature = "structopt", derive(structopt::StructOpt))]
30pub struct Opts {
31 #[cfg_attr(feature = "structopt", structopt(long))]
33 pub rustfmt: bool,
34
35 #[cfg_attr(feature = "structopt", structopt(long))]
37 pub multi_module: bool,
38
39 #[cfg_attr(feature = "structopt", structopt(long))]
42 pub unchecked: bool,
43
44 #[cfg_attr(feature = "structopt", structopt(skip))]
47 pub symbol_namespace: String,
48
49 #[cfg_attr(feature = "structopt", structopt(skip))]
57 pub standalone: bool,
58
59 #[cfg_attr(feature = "structopt", structopt(long))]
61 pub force_generate_structs: bool,
62}
63
64#[derive(Default)]
65struct Trait {
66 methods: Vec<String>,
67 resource_methods: BTreeMap<ResourceId, Vec<String>>,
68}
69
70impl Opts {
71 pub fn build(self) -> RustWasm {
72 let mut r = RustWasm::new();
73 r.opts = self;
74 r
75 }
76}
77
78impl RustWasm {
79 pub fn new() -> RustWasm {
80 RustWasm::default()
81 }
82
83 fn abi_variant(dir: Direction) -> AbiVariant {
84 match dir {
86 Direction::Export => AbiVariant::GuestExport,
87 Direction::Import => AbiVariant::GuestImport,
88 }
89 }
90
91 fn ret_area_name(iface: &Interface) -> String {
92 format!("{}_RET_AREA", iface.name.to_shouty_snake_case())
93 }
94}
95
96impl RustGenerator for RustWasm {
97 fn always_generate_structs(&self) -> bool {
98 self.opts.force_generate_structs
99 }
100
101 fn default_param_mode(&self) -> TypeMode {
102 if self.in_import {
103 TypeMode::AllBorrowed("'a")
107 } else {
108 TypeMode::Owned
111 }
112 }
113
114 fn handle_projection(&self) -> Option<(&'static str, String)> {
115 None
116 }
117
118 fn handle_in_super(&self) -> bool {
119 !self.in_import
120 }
121
122 fn handle_wrapper(&self) -> Option<&'static str> {
123 if self.in_import {
124 None
125 } else {
126 Some("wai_bindgen_rust::Handle")
127 }
128 }
129
130 fn push_str(&mut self, s: &str) {
131 self.src.push_str(s);
132 }
133
134 fn info(&self, ty: TypeId) -> TypeInfo {
135 self.types.get(ty)
136 }
137
138 fn types_mut(&mut self) -> &mut Types {
139 &mut self.types
140 }
141
142 fn print_borrowed_slice(
143 &mut self,
144 iface: &Interface,
145 mutbl: bool,
146 ty: &Type,
147 lifetime: &'static str,
148 ) {
149 self.print_rust_slice(iface, mutbl, ty, lifetime);
150 }
151
152 fn print_borrowed_str(&mut self, lifetime: &'static str) {
153 self.push_str("&");
154 if lifetime != "'_" {
155 self.push_str(lifetime);
156 self.push_str(" ");
157 }
158 self.push_str(" str");
159 }
160}
161
162impl Generator for RustWasm {
163 fn preprocess_one(&mut self, iface: &Interface, dir: Direction) {
164 let variant = Self::abi_variant(dir);
165 self.in_import = variant == AbiVariant::GuestImport;
166 self.types.analyze(iface);
167 self.trait_name = iface.name.to_camel_case();
168
169 if !self.opts.standalone {
170 self.src.push_str(&format!(
171 "#[allow(clippy::all)]\nmod {} {{\n",
172 iface.name.to_snake_case(),
173 ));
174 }
175
176 self.sizes.fill(iface);
177 }
178
179 fn type_record(
180 &mut self,
181 iface: &Interface,
182 id: TypeId,
183 _name: &str,
184 record: &Record,
185 docs: &Docs,
186 ) {
187 self.print_typedef_record(iface, id, record, docs);
188 }
189
190 fn type_tuple(
191 &mut self,
192 iface: &Interface,
193 id: TypeId,
194 _name: &str,
195 tuple: &Tuple,
196 docs: &Docs,
197 ) {
198 self.print_typedef_tuple(iface, id, tuple, docs);
199 }
200
201 fn type_flags(
202 &mut self,
203 _iface: &Interface,
204 _id: TypeId,
205 name: &str,
206 flags: &Flags,
207 docs: &Docs,
208 ) {
209 self.src
210 .push_str("wai_bindgen_rust::bitflags::bitflags! {\n");
211 self.rustdoc(docs);
212 let repr = RustFlagsRepr::new(flags);
213 self.src
214 .push_str(&format!("pub struct {}: {repr} {{\n", name.to_camel_case(),));
215 for (i, flag) in flags.flags.iter().enumerate() {
216 self.rustdoc(&flag.docs);
217 self.src.push_str(&format!(
218 "const {} = 1 << {};\n",
219 flag.name.to_shouty_snake_case(),
220 i,
221 ));
222 }
223 self.src.push_str("}\n");
224 self.src.push_str("}\n");
225
226 self.src
228 .push_str(&format!("impl {} {{\n", name.to_camel_case()));
229 self.src
230 .push_str(" /// Convert from a raw integer, preserving any unknown bits. See\n");
231 self.src.push_str(
232 " /// <https://github.com/bitflags/bitflags/issues/263#issuecomment-957088321>\n",
233 );
234 self.src.push_str(&format!(
235 " pub fn from_bits_preserve(bits: {repr}) -> Self {{\n",
236 ));
237 self.src.push_str(" Self { bits }\n");
238 self.src.push_str(" }\n");
239 self.src.push_str("}\n");
240 }
241
242 fn type_variant(
243 &mut self,
244 iface: &Interface,
245 id: TypeId,
246 _name: &str,
247 variant: &Variant,
248 docs: &Docs,
249 ) {
250 self.print_typedef_variant(iface, id, variant, docs);
251 }
252
253 fn type_union(
254 &mut self,
255 iface: &Interface,
256 id: TypeId,
257 _name: &str,
258 union: &Union,
259 docs: &Docs,
260 ) {
261 self.print_typedef_union(iface, id, union, docs);
262 }
263
264 fn type_option(
265 &mut self,
266 iface: &Interface,
267 id: TypeId,
268 _name: &str,
269 payload: &Type,
270 docs: &Docs,
271 ) {
272 self.print_typedef_option(iface, id, payload, docs);
273 }
274
275 fn type_expected(
276 &mut self,
277 iface: &Interface,
278 id: TypeId,
279 _name: &str,
280 expected: &Expected,
281 docs: &Docs,
282 ) {
283 self.print_typedef_expected(iface, id, expected, docs);
284 }
285
286 fn type_enum(&mut self, _iface: &Interface, id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
287 self.print_typedef_enum(id, name, enum_, docs);
288 }
289
290 fn type_resource(&mut self, iface: &Interface, ty: ResourceId) {
291 if !self.in_import {
294 let panic = "
295 #[cfg(not(target_arch = \"wasm32\"))]
296 {
297 panic!(\"handles can only be used on wasm32\");
298 }
299 #[cfg(target_arch = \"wasm32\")]
300 ";
301 self.src.push_str(&format!(
302 "
303 unsafe impl wai_bindgen_rust::HandleType for super::{ty} {{
304 #[inline]
305 fn clone(_val: i32) -> i32 {{
306 {panic_not_wasm}
307 {{
308 #[link(wasm_import_module = \"canonical_abi\")]
309 extern \"C\" {{
310 #[link_name = \"resource_clone_{name}\"]
311 fn clone(val: i32) -> i32;
312 }}
313 unsafe {{ clone(_val) }}
314 }}
315 }}
316
317 #[inline]
318 fn drop(_val: i32) {{
319 {panic_not_wasm}
320 {{
321 #[link(wasm_import_module = \"canonical_abi\")]
322 extern \"C\" {{
323 #[link_name = \"resource_drop_{name}\"]
324 fn drop(val: i32);
325 }}
326 unsafe {{ drop(_val) }}
327 }}
328 }}
329 }}
330
331 unsafe impl wai_bindgen_rust::LocalHandle for super::{ty} {{
332 #[inline]
333 fn new(_val: i32) -> i32 {{
334 {panic_not_wasm}
335 {{
336 #[link(wasm_import_module = \"canonical_abi\")]
337 extern \"C\" {{
338 #[link_name = \"resource_new_{name}\"]
339 fn new(val: i32) -> i32;
340 }}
341 unsafe {{ new(_val) }}
342 }}
343 }}
344
345 #[inline]
346 fn get(_val: i32) -> i32 {{
347 {panic_not_wasm}
348 {{
349 #[link(wasm_import_module = \"canonical_abi\")]
350 extern \"C\" {{
351 #[link_name = \"resource_get_{name}\"]
352 fn get(val: i32) -> i32;
353 }}
354 unsafe {{ get(_val) }}
355 }}
356 }}
357 }}
358
359 const _: () = {{
360 #[export_name = \"{ns}canonical_abi_drop_{name}\"]
361 extern \"C\" fn drop(ty: Box<super::{ty}>) {{
362 <super::{iface} as {iface}>::drop_{name_snake}(*ty)
363 }}
364 }};
365 ",
366 ty = iface.resources[ty].name.to_camel_case(),
367 name = iface.resources[ty].name,
368 name_snake = iface.resources[ty].name.to_snake_case(),
369 iface = iface.name.to_camel_case(),
370 ns = self.opts.symbol_namespace,
371 panic_not_wasm = panic,
372 ));
373 let trait_ = self.traits.entry(iface.name.to_camel_case()).or_default();
374 trait_.methods.push(format!(
375 "
376 /// An optional callback invoked when a handle is finalized
377 /// and destroyed.
378 fn drop_{}(val: super::{}) {{
379 drop(val);
380 }}
381 ",
382 iface.resources[ty].name.to_snake_case(),
383 iface.resources[ty].name.to_camel_case(),
384 ));
385 return;
386 }
387
388 let resource = &iface.resources[ty];
389 let name = &resource.name;
390
391 self.rustdoc(&resource.docs);
392 self.src.push_str("#[derive(Debug)]\n");
393 self.src.push_str("#[repr(transparent)]\n");
394 self.src
395 .push_str(&format!("pub struct {}(i32);\n", name.to_camel_case()));
396 self.src.push_str("impl ");
397 self.src.push_str(&name.to_camel_case());
398 self.src.push_str(
399 " {
400 pub unsafe fn from_raw(raw: i32) -> Self {
401 Self(raw)
402 }
403
404 pub fn into_raw(self) -> i32 {
405 let ret = self.0;
406 core::mem::forget(self);
407 return ret;
408 }
409
410 pub fn as_raw(&self) -> i32 {
411 self.0
412 }
413 }\n",
414 );
415
416 self.src.push_str("impl Drop for ");
417 self.src.push_str(&name.to_camel_case());
418 self.src.push_str(&format!(
419 "{{
420 fn drop(&mut self) {{
421 #[link(wasm_import_module = \"canonical_abi\")]
422 extern \"C\" {{
423 #[link_name = \"resource_drop_{}\"]
424 fn close(fd: i32);
425 }}
426 unsafe {{
427 close(self.0);
428 }}
429 }}
430 }}\n",
431 name,
432 ));
433
434 self.src.push_str("impl Clone for ");
435 self.src.push_str(&name.to_camel_case());
436 self.src.push_str(&format!(
437 "{{
438 fn clone(&self) -> Self {{
439 #[link(wasm_import_module = \"canonical_abi\")]
440 extern \"C\" {{
441 #[link_name = \"resource_clone_{}\"]
442 fn clone(val: i32) -> i32;
443 }}
444 unsafe {{
445 Self(clone(self.0))
446 }}
447 }}
448 }}\n",
449 name,
450 ));
451 }
452
453 fn type_alias(&mut self, iface: &Interface, id: TypeId, _name: &str, ty: &Type, docs: &Docs) {
454 self.print_typedef_alias(iface, id, ty, docs);
455 }
456
457 fn type_list(&mut self, iface: &Interface, id: TypeId, _name: &str, ty: &Type, docs: &Docs) {
458 self.print_type_list(iface, id, ty, docs);
459 }
460
461 fn type_builtin(&mut self, iface: &Interface, _id: TypeId, name: &str, ty: &Type, docs: &Docs) {
462 self.rustdoc(docs);
463 self.src
464 .push_str(&format!("pub type {}", name.to_camel_case()));
465 self.src.push_str(" = ");
466 self.print_ty(iface, ty, TypeMode::Owned);
467 self.src.push_str(";\n");
468 }
469
470 fn preprocess_functions(&mut self, _iface: &Interface, dir: Direction) {
471 if self.opts.standalone && dir == Direction::Export {
472 self.src.push_str(
473 "/// Declares the export of the interface for the given type.\n\
474 #[macro_export]\n\
475 macro_rules! export(($t:ident) => {\n",
476 );
477 }
478 }
479
480 fn import(&mut self, iface: &Interface, func: &Function) {
481 let mut sig = FnSig::default();
482 let param_mode = TypeMode::AllBorrowed("'_");
483 sig.async_ = func.is_async;
484 match &func.kind {
485 FunctionKind::Freestanding => {}
486 FunctionKind::Static { resource, .. } | FunctionKind::Method { resource, .. } => {
487 sig.use_item_name = true;
488 self.src.push_str(&format!(
489 "impl {} {{\n",
490 iface.resources[*resource].name.to_camel_case()
491 ));
492 }
493 }
494 if let FunctionKind::Method { .. } = func.kind {
495 sig.self_arg = Some("&self".to_string());
496 sig.self_is_first_param = true;
497 }
498 let params = self.print_signature(iface, func, param_mode, &sig);
499 self.src.push_str("{\n");
500 self.src.push_str("unsafe {\n");
501
502 let mut f = FunctionBindgen::new(self, params);
503 iface.call(
504 AbiVariant::GuestImport,
505 LiftLower::LowerArgsLiftResults,
506 func,
507 &mut f,
508 );
509 let FunctionBindgen {
510 needs_cleanup_list,
511 src,
512 ..
513 } = f;
514
515 if needs_cleanup_list {
516 self.src.push_str("let mut cleanup_list = Vec::new();\n");
517 }
518 self.src.push_str(&String::from(src));
519
520 self.src.push_str("}\n");
521 self.src.push_str("}\n");
522
523 match &func.kind {
524 FunctionKind::Freestanding => {}
525 FunctionKind::Static { .. } | FunctionKind::Method { .. } => {
526 self.src.push_str("}\n");
527 }
528 }
529 }
530
531 fn export(&mut self, iface: &Interface, func: &Function) {
532 let iface_name = iface.name.to_snake_case();
533
534 self.src.push_str("#[export_name = \"");
535 match &iface.module {
536 Some(module) => {
537 self.src.push_str(module);
538 self.src.push_str("#");
539 self.src.push_str(&func.name);
540 }
541 None => {
542 self.src.push_str(&self.opts.symbol_namespace);
543 self.src.push_str(&func.name);
544 }
545 }
546 self.src.push_str("\"]\n");
547 self.src.push_str("unsafe extern \"C\" fn __wai_bindgen_");
548 self.src.push_str(&iface_name);
549 self.src.push_str("_");
550 self.src.push_str(&func.name.to_snake_case());
551 self.src.push_str("(");
552 let sig = iface.wasm_signature(AbiVariant::GuestExport, func);
553 let mut params = Vec::new();
554 for (i, param) in sig.params.iter().enumerate() {
555 let name = format!("arg{}", i);
556 self.src.push_str(&name);
557 self.src.push_str(": ");
558 self.wasm_type(*param);
559 self.src.push_str(", ");
560 params.push(name);
561 }
562 self.src.push_str(")");
563
564 match sig.results.len() {
565 0 => {}
566 1 => {
567 self.src.push_str(" -> ");
568 self.wasm_type(sig.results[0]);
569 }
570 _ => unimplemented!(),
571 }
572
573 self.push_str("{\n");
574
575 if self.opts.standalone {
576 self.src
579 .push_str("#[allow(unused_imports)]\nuse wai_bindgen_rust;\nuse ");
580 self.src.push_str(&iface_name);
581 self.src.push_str("::*;\n");
582 }
583
584 if func.is_async {
585 self.src.push_str("let future = async move {\n");
586 }
587
588 let mut f = FunctionBindgen::new(self, params);
589 iface.call(
590 AbiVariant::GuestExport,
591 LiftLower::LiftArgsLowerResults,
592 func,
593 &mut f,
594 );
595 let FunctionBindgen {
596 needs_cleanup_list,
597 src,
598 ..
599 } = f;
600 assert!(!needs_cleanup_list);
601 self.src.push_str(&String::from(src));
602 if func.is_async {
603 self.src.push_str("};\n");
604 self.src
605 .push_str("wai_bindgen_rust::rt::execute(Box::pin(future));\n");
606 }
607 self.src.push_str("}\n");
608
609 let prev = mem::take(&mut self.src);
610 self.in_trait = true;
611 let mut sig = FnSig::default();
612 sig.private = true;
613 sig.async_ = func.is_async;
614 match &func.kind {
615 FunctionKind::Freestanding => {}
616 FunctionKind::Static { .. } => sig.use_item_name = true,
617 FunctionKind::Method { .. } => {
618 sig.use_item_name = true;
619 sig.self_is_first_param = true;
620 sig.self_arg = Some("&self".to_string());
621 }
622 }
623 self.print_signature(iface, func, TypeMode::Owned, &sig);
624 self.src.push_str(";");
625 self.in_trait = false;
626 let trait_ = self.traits.entry(iface.name.to_camel_case()).or_default();
627 let dst = match &func.kind {
628 FunctionKind::Freestanding => &mut trait_.methods,
629 FunctionKind::Static { resource, .. } | FunctionKind::Method { resource, .. } => {
630 trait_.resource_methods.entry(*resource).or_default()
631 }
632 };
633 dst.push(mem::replace(&mut self.src, prev).into());
634 }
635
636 fn finish_functions(&mut self, iface: &Interface, dir: Direction) {
637 if self.return_pointer_area_align > 0 {
638 self.src.push_str(&format!(
639 "
640 #[repr(align({align}))]
641 struct RetArea([u8; {size}]);
642 static mut {name}: RetArea = RetArea([0; {size}]);
643 ",
644 name = Self::ret_area_name(iface),
645 align = self.return_pointer_area_align,
646 size = self.return_pointer_area_size,
647 ));
648 }
649
650 if self.opts.standalone && dir == Direction::Export {
652 self.src.push_str("});\n");
653 }
654 }
655
656 fn finish_one(&mut self, iface: &Interface, files: &mut Files) {
657 let mut src = mem::take(&mut self.src);
658
659 let any_async = iface.functions.iter().any(|f| f.is_async);
660 for (name, trait_) in self.traits.iter() {
661 if any_async {
662 src.push_str("#[wai_bindgen_rust::async_trait(?Send)]\n");
663 }
664 src.push_str("pub trait ");
665 src.push_str(name);
666 src.push_str(" {\n");
667 for f in trait_.methods.iter() {
668 src.push_str(f);
669 src.push_str("\n");
670 }
671 src.push_str("}\n");
672
673 for (id, methods) in trait_.resource_methods.iter() {
674 if any_async {
675 src.push_str("#[wai_bindgen_rust::async_trait(?Send)]\n");
676 }
677 src.push_str(&format!(
678 "pub trait {} {{\n",
679 iface.resources[*id].name.to_camel_case()
680 ));
681 for f in methods {
682 src.push_str(f);
683 src.push_str("\n");
684 }
685 src.push_str("}\n");
686 }
687 }
688
689 if !self.opts.standalone {
691 src.push_str("}\n");
692 }
693
694 if self.opts.rustfmt {
695 let mut child = Command::new("rustfmt")
696 .stdin(Stdio::piped())
697 .stdout(Stdio::piped())
698 .spawn()
699 .expect("failed to spawn `rustfmt`");
700 child
701 .stdin
702 .take()
703 .unwrap()
704 .write_all(src.as_bytes())
705 .unwrap();
706 src.as_mut_string().truncate(0);
707 child
708 .stdout
709 .take()
710 .unwrap()
711 .read_to_string(src.as_mut_string())
712 .unwrap();
713 let status = child.wait().unwrap();
714 assert!(status.success());
715 }
716
717 files.push("bindings.rs", src.as_bytes());
718 }
719}
720
721struct FunctionBindgen<'a> {
722 gen: &'a mut RustWasm,
723 params: Vec<String>,
724 src: Source,
725 blocks: Vec<String>,
726 block_storage: Vec<(Source, Vec<(String, String)>)>,
727 tmp: usize,
728 needs_cleanup_list: bool,
729 cleanup: Vec<(String, String)>,
730}
731
732impl FunctionBindgen<'_> {
733 fn new(gen: &mut RustWasm, params: Vec<String>) -> FunctionBindgen<'_> {
734 FunctionBindgen {
735 gen,
736 params,
737 src: Default::default(),
738 blocks: Vec::new(),
739 block_storage: Vec::new(),
740 tmp: 0,
741 needs_cleanup_list: false,
742 cleanup: Vec::new(),
743 }
744 }
745
746 fn emit_cleanup(&mut self) {
747 for (ptr, layout) in mem::take(&mut self.cleanup) {
748 self.push_str(&format!("std::alloc::dealloc({}, {});\n", ptr, layout));
749 }
750 if self.needs_cleanup_list {
751 self.push_str(
752 "for (ptr, layout) in cleanup_list {
753 std::alloc::dealloc(ptr, layout);
754 }\n",
755 );
756 }
757 }
758
759 fn declare_import(
760 &mut self,
761 iface: &Interface,
762 name: &str,
763 params: &[WasmType],
764 results: &[WasmType],
765 ) -> String {
766 let module = iface.module.as_deref().unwrap_or(&iface.name);
767
768 self.push_str("#[link(wasm_import_module = \"");
770 self.push_str(module);
771 self.push_str("\")]\n");
772 self.push_str("extern \"C\" {\n");
773 self.push_str("#[cfg_attr(target_arch = \"wasm32\", link_name = \"");
774 self.push_str(name);
775 self.push_str("\")]\n");
776 self.push_str("#[cfg_attr(not(target_arch = \"wasm32\"), link_name = \"");
777 self.push_str(module);
778 self.push_str("_");
779 self.push_str(name);
780 self.push_str("\")]\n");
781 self.push_str("fn wai_import(");
782 for param in params.iter() {
783 self.push_str("_: ");
784 self.push_str(wasm_type(*param));
785 self.push_str(", ");
786 }
787 self.push_str(")");
788 assert!(results.len() < 2);
789 for result in results.iter() {
790 self.push_str(" -> ");
791 self.push_str(wasm_type(*result));
792 }
793 self.push_str(";\n}\n");
794 "wai_import".to_string()
795 }
796}
797
798impl RustFunctionGenerator for FunctionBindgen<'_> {
799 fn push_str(&mut self, s: &str) {
800 self.src.push_str(s);
801 }
802
803 fn tmp(&mut self) -> usize {
804 let ret = self.tmp;
805 self.tmp += 1;
806 ret
807 }
808
809 fn rust_gen(&self) -> &dyn RustGenerator {
810 self.gen
811 }
812
813 fn lift_lower(&self) -> LiftLower {
814 if self.gen.in_import {
815 LiftLower::LowerArgsLiftResults
816 } else {
817 LiftLower::LiftArgsLowerResults
818 }
819 }
820}
821
822impl Bindgen for FunctionBindgen<'_> {
823 type Operand = String;
824
825 fn push_block(&mut self) {
826 let prev_src = mem::take(&mut self.src);
827 let prev_cleanup = mem::take(&mut self.cleanup);
828 self.block_storage.push((prev_src, prev_cleanup));
829 }
830
831 fn finish_block(&mut self, operands: &mut Vec<String>) {
832 if !self.cleanup.is_empty() {
833 self.needs_cleanup_list = true;
834 self.push_str("cleanup_list.extend_from_slice(&[");
835 for (ptr, layout) in mem::take(&mut self.cleanup) {
836 self.push_str("(");
837 self.push_str(&ptr);
838 self.push_str(", ");
839 self.push_str(&layout);
840 self.push_str("),");
841 }
842 self.push_str("]);\n");
843 }
844 let (prev_src, prev_cleanup) = self.block_storage.pop().unwrap();
845 let src = mem::replace(&mut self.src, prev_src);
846 self.cleanup = prev_cleanup;
847 let expr = match operands.len() {
848 0 => "()".to_string(),
849 1 => operands[0].clone(),
850 _ => format!("({})", operands.join(", ")),
851 };
852 if src.is_empty() {
853 self.blocks.push(expr);
854 } else if operands.is_empty() {
855 self.blocks.push(format!("{{\n{}\n}}", &src[..]));
856 } else {
857 self.blocks.push(format!("{{\n{}\n{}\n}}", &src[..], expr));
858 }
859 }
860
861 fn return_pointer(&mut self, iface: &Interface, size: usize, align: usize) -> String {
862 self.gen.return_pointer_area_size = self.gen.return_pointer_area_size.max(size);
863 self.gen.return_pointer_area_align = self.gen.return_pointer_area_align.max(align);
864 let tmp = self.tmp();
865
866 self.push_str(&format!(
867 "let ptr{} = {}.0.as_mut_ptr() as i32;\n",
868 tmp,
869 RustWasm::ret_area_name(iface),
870 ));
871 format!("ptr{}", tmp)
872 }
873
874 fn sizes(&self) -> &SizeAlign {
875 &self.gen.sizes
876 }
877
878 fn is_list_canonical(&self, iface: &Interface, ty: &Type) -> bool {
879 iface.all_bits_valid(ty)
880 }
881
882 fn emit(
883 &mut self,
884 iface: &Interface,
885 inst: &Instruction<'_>,
886 operands: &mut Vec<String>,
887 results: &mut Vec<String>,
888 ) {
889 let unchecked = self.gen.opts.unchecked;
890 let mut top_as = |cvt: &str| {
891 let mut s = operands.pop().unwrap();
892 s.push_str(" as ");
893 s.push_str(cvt);
894 results.push(s);
895 };
896
897 match inst {
898 Instruction::GetArg { nth } => results.push(self.params[*nth].clone()),
899 Instruction::I32Const { val } => results.push(format!("{}i32", val)),
900 Instruction::ConstZero { tys } => {
901 for ty in tys.iter() {
902 match ty {
903 WasmType::I32 => results.push("0i32".to_string()),
904 WasmType::I64 => results.push("0i64".to_string()),
905 WasmType::F32 => results.push("0.0f32".to_string()),
906 WasmType::F64 => results.push("0.0f64".to_string()),
907 }
908 }
909 }
910
911 Instruction::I64FromU64 | Instruction::I64FromS64 => {
912 let s = operands.pop().unwrap();
913 results.push(format!("wai_bindgen_rust::rt::as_i64({})", s));
914 }
915 Instruction::I32FromChar
916 | Instruction::I32FromU8
917 | Instruction::I32FromS8
918 | Instruction::I32FromU16
919 | Instruction::I32FromS16
920 | Instruction::I32FromU32
921 | Instruction::I32FromS32 => {
922 let s = operands.pop().unwrap();
923 results.push(format!("wai_bindgen_rust::rt::as_i32({})", s));
924 }
925
926 Instruction::F32FromFloat32 => {
927 let s = operands.pop().unwrap();
928 results.push(format!("wai_bindgen_rust::rt::as_f32({})", s));
929 }
930 Instruction::F64FromFloat64 => {
931 let s = operands.pop().unwrap();
932 results.push(format!("wai_bindgen_rust::rt::as_f64({})", s));
933 }
934 Instruction::Float32FromF32
935 | Instruction::Float64FromF64
936 | Instruction::S32FromI32
937 | Instruction::S64FromI64 => {
938 results.push(operands.pop().unwrap());
939 }
940 Instruction::S8FromI32 => top_as("i8"),
941 Instruction::U8FromI32 => top_as("u8"),
942 Instruction::S16FromI32 => top_as("i16"),
943 Instruction::U16FromI32 => top_as("u16"),
944 Instruction::U32FromI32 => top_as("u32"),
945 Instruction::U64FromI64 => top_as("u64"),
946 Instruction::CharFromI32 => {
947 if unchecked {
948 results.push(format!(
949 "core::char::from_u32_unchecked({} as u32)",
950 operands[0]
951 ));
952 } else {
953 results.push(format!(
954 "core::char::from_u32({} as u32).unwrap()",
955 operands[0]
956 ));
957 }
958 }
959
960 Instruction::Bitcasts { casts } => {
961 wai_bindgen_gen_rust::bitcast(casts, operands, results)
962 }
963
964 Instruction::UnitLower => {
965 self.push_str(&format!("let () = {};\n", operands[0]));
966 }
967 Instruction::UnitLift => {
968 results.push("()".to_string());
969 }
970
971 Instruction::I32FromBool => {
972 results.push(format!("match {} {{ true => 1, false => 0 }}", operands[0]));
973 }
974 Instruction::BoolFromI32 => {
975 if unchecked {
976 results.push(format!(
977 "core::mem::transmute::<u8, bool>({} as u8)",
978 operands[0],
979 ));
980 } else {
981 results.push(format!(
982 "match {} {{
983 0 => false,
984 1 => true,
985 _ => panic!(\"invalid bool discriminant\"),
986 }}",
987 operands[0],
988 ));
989 }
990 }
991
992 Instruction::I32FromOwnedHandle { .. } => {
994 results.push(format!(
995 "wai_bindgen_rust::Handle::into_raw({})",
996 operands[0]
997 ));
998 }
999 Instruction::HandleBorrowedFromI32 { .. } => {
1000 results.push(format!(
1001 "wai_bindgen_rust::Handle::from_raw({})",
1002 operands[0],
1003 ));
1004 }
1005
1006 Instruction::I32FromBorrowedHandle { .. } => {
1008 results.push(format!("{}.0", operands[0]));
1009 }
1010 Instruction::HandleOwnedFromI32 { ty } => {
1011 results.push(format!(
1012 "{}({})",
1013 iface.resources[*ty].name.to_camel_case(),
1014 operands[0]
1015 ));
1016 }
1017
1018 Instruction::FlagsLower { flags, .. } => {
1019 let tmp = self.tmp();
1020 self.push_str(&format!("let flags{} = {};\n", tmp, operands[0]));
1021 for i in 0..flags.repr().count() {
1022 results.push(format!("(flags{}.bits() >> {}) as i32", tmp, i * 32));
1023 }
1024 }
1025 Instruction::FlagsLift { name, flags, .. } => {
1026 let repr = RustFlagsRepr::new(flags);
1027 let name = name.to_camel_case();
1028 let mut result = format!("{}::empty()", name);
1029 for (i, op) in operands.iter().enumerate() {
1030 result.push_str(&format!(
1031 " | {}::from_bits_preserve((({} as {repr}) << {}) as _)",
1032 name,
1033 op,
1034 i * 32
1035 ));
1036 }
1037 results.push(result);
1038 }
1039
1040 Instruction::RecordLower { ty, record, .. } => {
1041 self.record_lower(iface, *ty, record, &operands[0], results);
1042 }
1043 Instruction::RecordLift { ty, record, .. } => {
1044 self.record_lift(iface, *ty, record, operands, results);
1045 }
1046
1047 Instruction::TupleLower { tuple, .. } => {
1048 self.tuple_lower(tuple, &operands[0], results);
1049 }
1050 Instruction::TupleLift { .. } => {
1051 self.tuple_lift(operands, results);
1052 }
1053
1054 Instruction::VariantPayloadName => results.push("e".to_string()),
1055
1056 Instruction::VariantLower {
1057 variant,
1058 results: result_types,
1059 ty,
1060 ..
1061 } => {
1062 let blocks = self
1063 .blocks
1064 .drain(self.blocks.len() - variant.cases.len()..)
1065 .collect::<Vec<_>>();
1066 self.let_results(result_types.len(), results);
1067 let op0 = &operands[0];
1068 self.push_str(&format!("match {op0} {{\n"));
1069 let name = self.typename_lower(iface, *ty);
1070 for (case, block) in variant.cases.iter().zip(blocks) {
1071 let case_name = case.name.to_camel_case();
1072 self.push_str(&format!("{name}::{case_name}"));
1073 if case.ty == Type::Unit {
1074 self.push_str(&format!(" => {{\nlet e = ();\n{block}\n}}\n"));
1075 } else {
1076 self.push_str(&format!("(e) => {block},\n"));
1077 }
1078 }
1079 self.push_str("};\n");
1080 }
1081
1082 Instruction::VariantLift { name, variant, .. }
1085 if variant.cases.iter().all(|c| c.ty == Type::Unit) && unchecked =>
1086 {
1087 self.blocks.drain(self.blocks.len() - variant.cases.len()..);
1088 let mut result = "core::mem::transmute::<_, ".to_string();
1089 result.push_str(&name.to_camel_case());
1090 result.push_str(">(");
1091 result.push_str(&operands[0]);
1092 result.push_str(" as ");
1093 result.push_str(int_repr(variant.tag()));
1094 result.push(')');
1095 results.push(result);
1096 }
1097
1098 Instruction::VariantLift { variant, ty, .. } => {
1099 let blocks = self
1100 .blocks
1101 .drain(self.blocks.len() - variant.cases.len()..)
1102 .collect::<Vec<_>>();
1103 let op0 = &operands[0];
1104 let mut result = format!("match {op0} {{\n");
1105 let name = self.typename_lift(iface, *ty);
1106 for (i, (case, block)) in variant.cases.iter().zip(blocks).enumerate() {
1107 let pat = if i == variant.cases.len() - 1 && unchecked {
1108 String::from("_")
1109 } else {
1110 i.to_string()
1111 };
1112 let block = if case.ty != Type::Unit {
1113 format!("({block})")
1114 } else {
1115 String::new()
1116 };
1117 let case = case.name.to_camel_case();
1118 result.push_str(&format!("{pat} => {name}::{case}{block},\n"));
1119 }
1120 if !unchecked {
1121 result.push_str("_ => panic!(\"invalid enum discriminant\"),\n");
1122 }
1123 result.push('}');
1124 results.push(result);
1125 }
1126
1127 Instruction::UnionLower {
1128 union,
1129 results: result_types,
1130 ty,
1131 ..
1132 } => {
1133 let blocks = self
1134 .blocks
1135 .drain(self.blocks.len() - union.cases.len()..)
1136 .collect::<Vec<_>>();
1137 self.let_results(result_types.len(), results);
1138 let op0 = &operands[0];
1139 self.push_str(&format!("match {op0} {{\n"));
1140 let name = self.typename_lower(iface, *ty);
1141 for (case_name, block) in self
1142 .gen
1143 .union_case_names(iface, union)
1144 .into_iter()
1145 .zip(blocks)
1146 {
1147 self.push_str(&format!("{name}::{case_name}(e) => {block},\n"));
1148 }
1149 self.push_str("};\n");
1150 }
1151
1152 Instruction::UnionLift { union, ty, .. } => {
1153 let blocks = self
1154 .blocks
1155 .drain(self.blocks.len() - union.cases.len()..)
1156 .collect::<Vec<_>>();
1157 let op0 = &operands[0];
1158 let mut result = format!("match {op0} {{\n");
1159 for (i, (case_name, block)) in self
1160 .gen
1161 .union_case_names(iface, union)
1162 .into_iter()
1163 .zip(blocks)
1164 .enumerate()
1165 {
1166 let pat = if i == union.cases.len() - 1 && unchecked {
1167 String::from("_")
1168 } else {
1169 i.to_string()
1170 };
1171 let name = self.typename_lift(iface, *ty);
1172 result.push_str(&format!("{pat} => {name}::{case_name}({block}),\n"));
1173 }
1174 if !unchecked {
1175 result.push_str("_ => panic!(\"invalid union discriminant\"),\n");
1176 }
1177 result.push('}');
1178 results.push(result);
1179 }
1180
1181 Instruction::OptionLower {
1182 results: result_types,
1183 ..
1184 } => {
1185 let some = self.blocks.pop().unwrap();
1186 let none = self.blocks.pop().unwrap();
1187 self.let_results(result_types.len(), results);
1188 let operand = &operands[0];
1189 self.push_str(&format!(
1190 "match {operand} {{
1191 Some(e) => {some},
1192 None => {{\nlet e = ();\n{none}\n}},
1193 }};"
1194 ));
1195 }
1196
1197 Instruction::OptionLift { .. } => {
1198 let some = self.blocks.pop().unwrap();
1199 let none = self.blocks.pop().unwrap();
1200 assert_eq!(none, "()");
1201 let operand = &operands[0];
1202 let invalid = if unchecked {
1203 "std::hint::unreachable_unchecked()"
1204 } else {
1205 "panic!(\"invalid enum discriminant\")"
1206 };
1207 results.push(format!(
1208 "match {operand} {{
1209 0 => None,
1210 1 => Some({some}),
1211 _ => {invalid},
1212 }}"
1213 ));
1214 }
1215
1216 Instruction::ExpectedLower {
1217 results: result_types,
1218 ..
1219 } => {
1220 let err = self.blocks.pop().unwrap();
1221 let ok = self.blocks.pop().unwrap();
1222 self.let_results(result_types.len(), results);
1223 let operand = &operands[0];
1224 self.push_str(&format!(
1225 "match {operand} {{
1226 Ok(e) => {{ {ok} }},
1227 Err(e) => {{ {err} }},
1228 }};"
1229 ));
1230 }
1231
1232 Instruction::ExpectedLift { .. } => {
1233 let err = self.blocks.pop().unwrap();
1234 let ok = self.blocks.pop().unwrap();
1235 let operand = &operands[0];
1236 let invalid = if unchecked {
1237 "std::hint::unreachable_unchecked()"
1238 } else {
1239 "panic!(\"invalid enum discriminant\")"
1240 };
1241 results.push(format!(
1242 "match {operand} {{
1243 0 => Ok({ok}),
1244 1 => Err({err}),
1245 _ => {invalid},
1246 }}"
1247 ));
1248 }
1249
1250 Instruction::EnumLower { enum_, name, .. } => {
1251 let mut result = format!("match {} {{\n", operands[0]);
1252 let name = name.to_camel_case();
1253 for (i, case) in enum_.cases.iter().enumerate() {
1254 let case = case.name.to_camel_case();
1255 result.push_str(&format!("{name}::{case} => {i},\n"));
1256 }
1257 result.push('}');
1258 results.push(result);
1259 }
1260
1261 Instruction::EnumLift { enum_, name, .. } if unchecked => {
1264 let mut result = "core::mem::transmute::<_, ".to_string();
1265 result.push_str(&name.to_camel_case());
1266 result.push_str(">(");
1267 result.push_str(&operands[0]);
1268 result.push_str(" as ");
1269 result.push_str(int_repr(enum_.tag()));
1270 result.push(')');
1271 results.push(result);
1272 }
1273
1274 Instruction::EnumLift { enum_, name, .. } => {
1275 let mut result = "match ".to_string();
1276 result.push_str(&operands[0]);
1277 result.push_str(" {\n");
1278 let name = name.to_camel_case();
1279 for (i, case) in enum_.cases.iter().enumerate() {
1280 let case = case.name.to_camel_case();
1281 result.push_str(&format!("{i} => {name}::{case},\n"));
1282 }
1283 result.push_str("_ => panic!(\"invalid enum discriminant\"),\n");
1284 result.push('}');
1285 results.push(result);
1286 }
1287
1288 Instruction::ListCanonLower { realloc, .. } => {
1289 let tmp = self.tmp();
1290 let val = format!("vec{}", tmp);
1291 let ptr = format!("ptr{}", tmp);
1292 let len = format!("len{}", tmp);
1293 if realloc.is_none() {
1294 self.push_str(&format!("let {} = {};\n", val, operands[0]));
1295 } else {
1296 let op0 = operands.pop().unwrap();
1297 self.push_str(&format!("let {} = ({}).into_boxed_slice();\n", val, op0));
1298 }
1299 self.push_str(&format!("let {} = {}.as_ptr() as i32;\n", ptr, val));
1300 self.push_str(&format!("let {} = {}.len() as i32;\n", len, val));
1301 if realloc.is_some() {
1302 self.push_str(&format!("core::mem::forget({});\n", val));
1303 }
1304 results.push(ptr);
1305 results.push(len);
1306 }
1307
1308 Instruction::ListCanonLift { free, .. } => {
1309 assert!(free.is_some());
1312 let tmp = self.tmp();
1313 let len = format!("len{}", tmp);
1314 self.push_str(&format!("let {} = {} as usize;\n", len, operands[1]));
1315 let result = format!(
1316 "Vec::from_raw_parts({} as *mut _, {1}, {1})",
1317 operands[0], len
1318 );
1319 results.push(result);
1320 }
1321
1322 Instruction::StringLower { realloc } => {
1323 let tmp = self.tmp();
1324 let val = format!("vec{}", tmp);
1325 let ptr = format!("ptr{}", tmp);
1326 let len = format!("len{}", tmp);
1327 if realloc.is_none() {
1328 self.push_str(&format!("let {} = {};\n", val, operands[0]));
1329 } else {
1330 let op0 = format!("{}.into_bytes()", operands[0]);
1331 self.push_str(&format!("let {} = ({}).into_boxed_slice();\n", val, op0));
1332 }
1333 self.push_str(&format!("let {} = {}.as_ptr() as i32;\n", ptr, val));
1334 self.push_str(&format!("let {} = {}.len() as i32;\n", len, val));
1335 if realloc.is_some() {
1336 self.push_str(&format!("core::mem::forget({});\n", val));
1337 }
1338 results.push(ptr);
1339 results.push(len);
1340 }
1341
1342 Instruction::StringLift { free, .. } => {
1343 assert!(free.is_some());
1346 let tmp = self.tmp();
1347 let len = format!("len{}", tmp);
1348 self.push_str(&format!("let {} = {} as usize;\n", len, operands[1]));
1349 let result = format!(
1350 "Vec::from_raw_parts({} as *mut _, {1}, {1})",
1351 operands[0], len
1352 );
1353 if unchecked {
1354 results.push(format!("String::from_utf8_unchecked({})", result));
1355 } else {
1356 results.push(format!("String::from_utf8({}).unwrap()", result));
1357 }
1358 }
1359
1360 Instruction::ListLower { element, realloc } => {
1361 let body = self.blocks.pop().unwrap();
1362 let tmp = self.tmp();
1363 let vec = format!("vec{}", tmp);
1364 let result = format!("result{}", tmp);
1365 let layout = format!("layout{}", tmp);
1366 let len = format!("len{}", tmp);
1367 self.push_str(&format!("let {} = {};\n", vec, operands[0]));
1368 self.push_str(&format!("let {} = {}.len() as i32;\n", len, vec));
1369 let size = self.gen.sizes.size(element);
1370 let align = self.gen.sizes.align(element);
1371 self.push_str(&format!(
1372 "let {} = core::alloc::Layout::from_size_align_unchecked({}.len() * {}, {});\n",
1373 layout, vec, size, align,
1374 ));
1375 self.push_str(&format!(
1376 "let {} = std::alloc::alloc({});\n",
1377 result, layout,
1378 ));
1379 self.push_str(&format!(
1380 "if {}.is_null() {{ std::alloc::handle_alloc_error({}); }}\n",
1381 result, layout,
1382 ));
1383 self.push_str(&format!(
1384 "for (i, e) in {}.into_iter().enumerate() {{\n",
1385 vec
1386 ));
1387 self.push_str(&format!(
1388 "let base = {} as i32 + (i as i32) * {};\n",
1389 result, size,
1390 ));
1391 self.push_str(&body);
1392 self.push_str("}\n");
1393 results.push(format!("{} as i32", result));
1394 results.push(len);
1395
1396 if realloc.is_none() {
1397 self.cleanup.push((result, layout));
1401 }
1402 }
1403
1404 Instruction::ListLift { element, free, .. } => {
1405 assert!(free.is_some());
1408 let body = self.blocks.pop().unwrap();
1409 let tmp = self.tmp();
1410 let size = self.gen.sizes.size(element);
1411 let align = self.gen.sizes.align(element);
1412 let len = format!("len{}", tmp);
1413 let base = format!("base{}", tmp);
1414 let result = format!("result{}", tmp);
1415 self.push_str(&format!("let {} = {};\n", base, operands[0]));
1416 self.push_str(&format!("let {} = {};\n", len, operands[1],));
1417 self.push_str(&format!(
1418 "let mut {} = Vec::with_capacity({} as usize);\n",
1419 result, len,
1420 ));
1421
1422 self.push_str("for i in 0..");
1423 self.push_str(&len);
1424 self.push_str(" {\n");
1425 self.push_str("let base = ");
1426 self.push_str(&base);
1427 self.push_str(" + i *");
1428 self.push_str(&size.to_string());
1429 self.push_str(";\n");
1430 self.push_str(&result);
1431 self.push_str(".push(");
1432 self.push_str(&body);
1433 self.push_str(");\n");
1434 self.push_str("}\n");
1435 results.push(result);
1436 self.push_str(&format!(
1437 "std::alloc::dealloc(
1438 {} as *mut _,
1439 std::alloc::Layout::from_size_align_unchecked(
1440 ({} as usize) * {},
1441 {},
1442 ),
1443 );\n",
1444 base, len, size, align
1445 ));
1446 }
1447
1448 Instruction::IterElem { .. } => results.push("e".to_string()),
1449
1450 Instruction::IterBasePointer => results.push("base".to_string()),
1451
1452 Instruction::CallWasm { iface, name, sig } => {
1453 let func = self.declare_import(iface, name, &sig.params, &sig.results);
1454
1455 if !sig.results.is_empty() {
1457 self.push_str("let ret = ");
1458 results.push("ret".to_string());
1459 }
1460 self.push_str(&func);
1461 self.push_str("(");
1462 self.push_str(&operands.join(", "));
1463 self.push_str(");\n");
1464 }
1465
1466 Instruction::CallWasmAsyncImport {
1467 iface,
1468 name,
1469 params: wasm_params,
1470 results: wasm_results,
1471 } => {
1472 self.push_str("unsafe extern \"C\" fn completion_callback(sender: usize");
1480 for (i, result) in wasm_results.iter().enumerate() {
1481 self.push_str(", ");
1482 self.push_str(&format!("ret{}: ", i));
1483 self.push_str(wasm_type(*result));
1484 }
1485 self.push_str(") {\n");
1486 self.push_str("wai_bindgen_rust::rt::Sender::from_usize(sender).send((");
1487 for i in 0..wasm_results.len() {
1488 self.push_str(&format!("ret{},", i));
1489 }
1490 self.push_str("));\n");
1491 self.push_str("}\n");
1492
1493 self.push_str("let (rx, tx) = wai_bindgen_rust::rt::Oneshot::<(");
1499 for ty in *wasm_results {
1500 self.push_str(wasm_type(*ty));
1501 self.push_str(", ");
1502 }
1503 self.push_str(")>::new();\n");
1504
1505 let func = self.declare_import(iface, name, wasm_params, &[]);
1511 self.push_str(&func);
1512 self.push_str("(");
1513 for op in operands {
1514 self.push_str(op);
1515 self.push_str(", ");
1516 }
1517 self.push_str("completion_callback as i32, ");
1518 self.push_str("tx.into_usize() as i32");
1519 self.push_str(");\n");
1520
1521 let tmp = self.tmp();
1527 self.push_str("let (");
1528 for i in 0..wasm_results.len() {
1529 let name = format!("ret{}_{}", tmp, i);
1530 self.push_str(&name);
1531 self.push_str(",");
1532 results.push(name);
1533 }
1534 self.push_str(") = rx.await;\n");
1535 }
1536
1537 Instruction::CallWasmAsyncExport { .. } => unreachable!(),
1538
1539 Instruction::CallInterface { module, func } => {
1540 self.push_str("let result = ");
1541 results.push("result".to_string());
1542 match &func.kind {
1543 FunctionKind::Freestanding => {
1544 if self.gen.opts.standalone {
1545 self.push_str(&format!(
1547 "<$t as {t}>::{}",
1548 func.name.to_snake_case(),
1549 t = module.to_camel_case(),
1550 ));
1551 } else {
1552 self.push_str(&format!(
1553 "<super::{m} as {m}>::{}",
1554 func.name.to_snake_case(),
1555 m = module.to_camel_case()
1556 ));
1557 }
1558 }
1559 FunctionKind::Static { resource, name }
1560 | FunctionKind::Method { resource, name } => {
1561 self.push_str(&format!(
1562 "<super::{r} as {r}>::{}",
1563 name.to_snake_case(),
1564 r = iface.resources[*resource].name.to_camel_case(),
1565 ));
1566 }
1567 }
1568 self.push_str("(");
1569 if let FunctionKind::Method { .. } = func.kind {
1570 self.push_str("&");
1571 }
1572 self.push_str(&operands.join(", "));
1573 self.push_str(")");
1574 if func.is_async {
1575 self.push_str(".await");
1576 }
1577 self.push_str(";\n");
1578 }
1579
1580 Instruction::Return { amt, .. } => {
1581 self.emit_cleanup();
1582 match amt {
1583 0 => {}
1584 1 => {
1585 self.push_str(&operands[0]);
1586 self.push_str("\n");
1587 }
1588 _ => {
1589 self.push_str("(");
1590 self.push_str(&operands.join(", "));
1591 self.push_str(")\n");
1592 }
1593 }
1594 }
1595
1596 Instruction::ReturnAsyncExport { .. } => {
1597 self.emit_cleanup();
1598 self.push_str(&format!(
1599 "wai_bindgen_rust::rt::async_export_done({}, {});\n",
1600 operands[0], operands[1]
1601 ));
1602 }
1603 Instruction::ReturnAsyncImport { .. } => unreachable!(),
1604
1605 Instruction::I32Load { offset } => {
1606 results.push(format!("*(({} + {}) as *const i32)", operands[0], offset));
1607 }
1608 Instruction::I32Load8U { offset } => {
1609 results.push(format!(
1610 "i32::from(*(({} + {}) as *const u8))",
1611 operands[0], offset
1612 ));
1613 }
1614 Instruction::I32Load8S { offset } => {
1615 results.push(format!(
1616 "i32::from(*(({} + {}) as *const i8))",
1617 operands[0], offset
1618 ));
1619 }
1620 Instruction::I32Load16U { offset } => {
1621 results.push(format!(
1622 "i32::from(*(({} + {}) as *const u16))",
1623 operands[0], offset
1624 ));
1625 }
1626 Instruction::I32Load16S { offset } => {
1627 results.push(format!(
1628 "i32::from(*(({} + {}) as *const i16))",
1629 operands[0], offset
1630 ));
1631 }
1632 Instruction::I64Load { offset } => {
1633 results.push(format!("*(({} + {}) as *const i64)", operands[0], offset));
1634 }
1635 Instruction::F32Load { offset } => {
1636 results.push(format!("*(({} + {}) as *const f32)", operands[0], offset));
1637 }
1638 Instruction::F64Load { offset } => {
1639 results.push(format!("*(({} + {}) as *const f64)", operands[0], offset));
1640 }
1641 Instruction::I32Store { offset } => {
1642 self.push_str(&format!(
1643 "*(({} + {}) as *mut i32) = {};\n",
1644 operands[1], offset, operands[0]
1645 ));
1646 }
1647 Instruction::I32Store8 { offset } => {
1648 self.push_str(&format!(
1649 "*(({} + {}) as *mut u8) = ({}) as u8;\n",
1650 operands[1], offset, operands[0]
1651 ));
1652 }
1653 Instruction::I32Store16 { offset } => {
1654 self.push_str(&format!(
1655 "*(({} + {}) as *mut u16) = ({}) as u16;\n",
1656 operands[1], offset, operands[0]
1657 ));
1658 }
1659 Instruction::I64Store { offset } => {
1660 self.push_str(&format!(
1661 "*(({} + {}) as *mut i64) = {};\n",
1662 operands[1], offset, operands[0]
1663 ));
1664 }
1665 Instruction::F32Store { offset } => {
1666 self.push_str(&format!(
1667 "*(({} + {}) as *mut f32) = {};\n",
1668 operands[1], offset, operands[0]
1669 ));
1670 }
1671 Instruction::F64Store { offset } => {
1672 self.push_str(&format!(
1673 "*(({} + {}) as *mut f64) = {};\n",
1674 operands[1], offset, operands[0]
1675 ));
1676 }
1677
1678 Instruction::Malloc { .. } => unimplemented!(),
1679 Instruction::Free {
1680 free: _,
1681 size,
1682 align,
1683 } => {
1684 self.push_str(&format!(
1685 "wai_bindgen_rust::rt::canonical_abi_free({} as *mut u8, {}, {});\n",
1686 operands[0], size, align
1687 ));
1688 }
1689 }
1690 }
1691}