1use heck::{ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
2use std::{
3 collections::{HashMap, HashSet},
4 fmt::Write,
5 iter, mem,
6 ops::Deref,
7};
8use wit_bindgen_core::{
9 uwrite, uwriteln,
10 wit_parser::{
11 abi::{AbiVariant, Bindgen, Bitcast, Instruction, LiftLower, WasmType},
12 Case, Docs, Enum, Flags, FlagsRepr, Function, FunctionKind, Int, InterfaceId, Record,
13 Resolve, Result_, SizeAlign, Tuple, Type, TypeDef, TypeDefKind, TypeId, TypeOwner, Union,
14 Variant, WorldId,
15 },
16 Files, InterfaceGenerator as _, Ns, WorldGenerator,
17};
18
19const IMPORTS: &str = "\
20import java.nio.charset.StandardCharsets;
21import java.util.ArrayList;
22
23import org.teavm.interop.Memory;
24import org.teavm.interop.Address;
25import org.teavm.interop.Import;
26import org.teavm.interop.Export;\
27";
28
29#[derive(Default, Debug, Clone)]
30#[cfg_attr(feature = "clap", derive(clap::Args))]
31pub struct Opts {
32 #[cfg_attr(feature = "clap", arg(long))]
34 pub generate_stub: bool,
35}
36
37impl Opts {
38 pub fn build(&self) -> Box<dyn WorldGenerator> {
39 Box::new(TeaVmJava {
40 opts: self.clone(),
41 ..TeaVmJava::default()
42 })
43 }
44}
45
46struct InterfaceFragment {
47 src: String,
48 stub: String,
49}
50
51#[derive(Default)]
52pub struct TeaVmJava {
53 opts: Opts,
54 name: String,
55 return_area_size: usize,
56 return_area_align: usize,
57 tuple_counts: HashSet<usize>,
58 needs_cleanup: bool,
59 needs_result: bool,
60 interface_fragments: HashMap<String, Vec<InterfaceFragment>>,
61 world_fragments: Vec<InterfaceFragment>,
62 sizes: SizeAlign,
63 interface_names: HashMap<InterfaceId, String>,
64}
65
66impl TeaVmJava {
67 fn qualifier(&self) -> String {
68 let world = self.name.to_upper_camel_case();
69 format!("{world}World.")
70 }
71
72 fn interface<'a>(&'a mut self, resolve: &'a Resolve, name: &'a str) -> InterfaceGenerator<'a> {
73 InterfaceGenerator {
74 src: String::new(),
75 stub: String::new(),
76 gen: self,
77 resolve,
78 name,
79 }
80 }
81}
82
83impl WorldGenerator for TeaVmJava {
84 fn preprocess(&mut self, resolve: &Resolve, world: WorldId) {
85 let name = &resolve.worlds[world].name;
86 self.name = name.to_string();
87 self.sizes.fill(resolve);
88 }
89
90 fn import_interface(
91 &mut self,
92 resolve: &Resolve,
93 name: &str,
94 id: InterfaceId,
95 _files: &mut Files,
96 ) {
97 self.interface_names.insert(id, name.to_owned());
98 let mut gen = self.interface(resolve, name);
99 gen.types(id);
100
101 for (_, func) in resolve.interfaces[id].functions.iter() {
102 gen.import(name, func);
103 }
104
105 gen.add_interface_fragment();
106 }
107
108 fn import_funcs(
109 &mut self,
110 resolve: &Resolve,
111 world: WorldId,
112 funcs: &[(&str, &Function)],
113 _files: &mut Files,
114 ) {
115 let name = &format!("{}-world", resolve.worlds[world].name);
116 let mut gen = self.interface(resolve, name);
117
118 for (_, func) in funcs {
119 gen.import(name, func);
120 }
121
122 gen.add_world_fragment();
123 }
124
125 fn export_interface(
126 &mut self,
127 resolve: &Resolve,
128 name: &str,
129 id: InterfaceId,
130 _files: &mut Files,
131 ) {
132 self.interface_names.insert(id, name.to_owned());
133 let mut gen = self.interface(resolve, name);
134 gen.types(id);
135
136 for (_, func) in resolve.interfaces[id].functions.iter() {
137 gen.export(func, Some(name));
138 }
139
140 gen.add_interface_fragment();
141 }
142
143 fn export_funcs(
144 &mut self,
145 resolve: &Resolve,
146 world: WorldId,
147 funcs: &[(&str, &Function)],
148 _files: &mut Files,
149 ) {
150 let name = &format!("{}-world", resolve.worlds[world].name);
151 let mut gen = self.interface(resolve, name);
152
153 for (_, func) in funcs {
154 gen.export(func, None);
155 }
156
157 gen.add_world_fragment();
158 }
159
160 fn export_types(
161 &mut self,
162 resolve: &Resolve,
163 world: WorldId,
164 types: &[(&str, TypeId)],
165 _files: &mut Files,
166 ) {
167 let name = &format!("{}-world", resolve.worlds[world].name);
168 let mut gen = self.interface(resolve, name);
169
170 for (ty_name, ty) in types {
171 gen.define_type(ty_name, *ty);
172 }
173
174 gen.add_world_fragment();
175 }
176
177 fn finish(&mut self, resolve: &Resolve, id: WorldId, files: &mut Files) {
178 let world = &resolve.worlds[id];
179 let package = format!("wit_{}", world.name.to_snake_case());
180 let name = world.name.to_upper_camel_case();
181
182 let mut src = String::new();
183
184 uwrite!(
185 src,
186 "package {package};
187
188 {IMPORTS}
189 import org.teavm.interop.CustomSection;
190
191 public final class {name}World {{
192 private {name}World() {{}}
193 "
194 );
195
196 src.push_str(
197 &self
198 .world_fragments
199 .iter()
200 .map(|f| f.src.deref())
201 .collect::<Vec<_>>()
202 .join("\n"),
203 );
204
205 let component_type =
206 wit_component::metadata::encode(resolve, id, wit_component::StringEncoding::UTF8)
207 .unwrap()
208 .into_iter()
209 .map(|byte| format!("{byte:02x}"))
210 .collect::<Vec<_>>()
211 .concat();
212
213 uwriteln!(
214 src,
215 r#"
216 @CustomSection(name = "component-type:{name}")
217 private static final String __WIT_BINDGEN_COMPONENT_TYPE = "{component_type}";
218 "#
219 );
220
221 for &count in &self.tuple_counts {
222 let (type_params, instance) = if count == 0 {
223 (
224 String::new(),
225 "public static final Tuple0 INSTANCE = new Tuple0();",
226 )
227 } else {
228 (
229 format!(
230 "<{}>",
231 (0..count)
232 .map(|index| format!("T{index}"))
233 .collect::<Vec<_>>()
234 .join(", ")
235 ),
236 "",
237 )
238 };
239 let value_params = (0..count)
240 .map(|index| format!("T{index} f{index}"))
241 .collect::<Vec<_>>()
242 .join(", ");
243 let fields = (0..count)
244 .map(|index| format!("public final T{index} f{index};"))
245 .collect::<Vec<_>>()
246 .join("\n");
247 let inits = (0..count)
248 .map(|index| format!("this.f{index} = f{index};"))
249 .collect::<Vec<_>>()
250 .join("\n");
251
252 uwrite!(
253 src,
254 "
255 public static final class Tuple{count}{type_params} {{
256 {fields}
257
258 public Tuple{count}({value_params}) {{
259 {inits}
260 }}
261
262 {instance}
263 }}
264 "
265 )
266 }
267
268 if self.needs_result {
269 src.push_str(
270 r#"
271 public static final class Result<Ok, Err> {
272 public final byte tag;
273 private final Object value;
274
275 private Result(byte tag, Object value) {
276 this.tag = tag;
277 this.value = value;
278 }
279
280 public static <Ok, Err> Result<Ok, Err> ok(Ok ok) {
281 return new Result<>(OK, ok);
282 }
283
284 public static <Ok, Err> Result<Ok, Err> err(Err err) {
285 return new Result<>(ERR, err);
286 }
287
288 public Ok getOk() {
289 if (this.tag == OK) {
290 return (Ok) this.value;
291 } else {
292 throw new RuntimeException("expected OK, got " + this.tag);
293 }
294 }
295
296 public Err getErr() {
297 if (this.tag == ERR) {
298 return (Err) this.value;
299 } else {
300 throw new RuntimeException("expected ERR, got " + this.tag);
301 }
302 }
303
304 public static final byte OK = 0;
305 public static final byte ERR = 1;
306 }
307 "#,
308 )
309 }
310
311 if self.needs_cleanup {
312 src.push_str(
313 "
314 public static final class Cleanup {
315 public final int address;
316 public final int size;
317 public final int align;
318
319 public Cleanup(int address, int size, int align) {
320 this.address = address;
321 this.size = size;
322 this.align = align;
323 }
324 }
325 ",
326 );
327 }
328
329 if self.return_area_align > 0 {
330 let size = self.return_area_size;
331 let align = self.return_area_align;
332
333 uwriteln!(
334 src,
335 "public static final int RETURN_AREA = Memory.malloc({size}, {align}).toInt();",
336 );
337 }
338
339 src.push_str("}\n");
340
341 files.push(&format!("{name}World.java"), indent(&src).as_bytes());
342
343 let generate_stub = |name, fragments: &[InterfaceFragment], files: &mut Files| {
344 let body = fragments
345 .iter()
346 .map(|f| f.stub.deref())
347 .collect::<Vec<_>>()
348 .join("\n");
349
350 let body = format!(
351 "package {package};
352
353 {IMPORTS}
354
355 public class {name} {{
356 {body}
357 }}
358 "
359 );
360
361 files.push(&format!("{name}.java"), indent(&body).as_bytes());
362 };
363
364 if self.opts.generate_stub {
365 generate_stub(format!("{name}WorldImpl"), &self.world_fragments, files);
366 }
367
368 for (name, fragments) in &self.interface_fragments {
369 let body = fragments
370 .iter()
371 .map(|f| f.src.deref())
372 .collect::<Vec<_>>()
373 .join("\n");
374
375 let body = format!(
376 "package {package};
377
378 {IMPORTS}
379
380 public final class {name} {{
381 private {name}() {{}}
382
383 {body}
384 }}
385 "
386 );
387
388 files.push(&format!("{name}.java"), indent(&body).as_bytes());
389
390 if self.opts.generate_stub {
391 generate_stub(format!("{name}Impl"), fragments, files);
392 }
393 }
394 }
395}
396
397struct InterfaceGenerator<'a> {
398 src: String,
399 stub: String,
400 gen: &'a mut TeaVmJava,
401 resolve: &'a Resolve,
402 name: &'a str,
403}
404
405impl InterfaceGenerator<'_> {
406 fn qualifier(&self, when: bool, ty: &TypeDef) -> String {
407 if let TypeOwner::Interface(id) = &ty.owner {
408 if let Some(name) = self.gen.interface_names.get(id) {
409 if name != self.name {
410 return format!("{}.", name.to_upper_camel_case());
411 }
412 }
413 }
414
415 if when {
416 let name = self.name.to_upper_camel_case();
417 format!("{name}.")
418 } else {
419 String::new()
420 }
421 }
422
423 fn add_interface_fragment(self) {
424 self.gen
425 .interface_fragments
426 .entry(self.name.to_upper_camel_case())
427 .or_default()
428 .push(InterfaceFragment {
429 src: self.src,
430 stub: self.stub,
431 });
432 }
433
434 fn add_world_fragment(self) {
435 self.gen.world_fragments.push(InterfaceFragment {
436 src: self.src,
437 stub: self.stub,
438 });
439 }
440
441 fn import(&mut self, module: &str, func: &Function) {
442 if func.kind != FunctionKind::Freestanding {
443 todo!("resources");
444 }
445
446 let mut bindgen = FunctionBindgen::new(
447 self,
448 &func.name,
449 func.params
450 .iter()
451 .map(|(name, _)| name.to_java_ident())
452 .collect(),
453 );
454
455 bindgen.gen.resolve.call(
456 AbiVariant::GuestImport,
457 LiftLower::LowerArgsLiftResults,
458 func,
459 &mut bindgen,
460 );
461
462 let src = bindgen.src;
463
464 let cleanup_list = if bindgen.needs_cleanup_list {
465 self.gen.needs_cleanup = true;
466
467 format!(
468 "ArrayList<{}Cleanup> cleanupList = new ArrayList<>();\n",
469 self.gen.qualifier()
470 )
471 } else {
472 String::new()
473 };
474
475 let name = &func.name;
476
477 let sig = self.resolve.wasm_signature(AbiVariant::GuestImport, func);
478
479 let result_type = match &sig.results[..] {
480 [] => "void",
481 [result] => wasm_type(*result),
482 _ => unreachable!(),
483 };
484
485 let camel_name = func.name.to_upper_camel_case();
486
487 let params = sig
488 .params
489 .iter()
490 .enumerate()
491 .map(|(i, param)| {
492 let ty = wasm_type(*param);
493 format!("{ty} p{i}")
494 })
495 .collect::<Vec<_>>()
496 .join(", ");
497
498 let sig = self.sig_string(func, false);
499
500 uwrite!(
501 self.src,
502 r#"@Import(name = "{name}", module = "{module}")
503 private static native {result_type} wasmImport{camel_name}({params});
504
505 {sig} {{
506 {cleanup_list} {src}
507 }}
508 "#
509 );
510 }
511
512 fn export(&mut self, func: &Function, interface_name: Option<&str>) {
513 let sig = self.resolve.wasm_signature(AbiVariant::GuestExport, func);
514
515 let export_name = func.core_export_name(interface_name);
516
517 let mut bindgen = FunctionBindgen::new(
518 self,
519 &func.name,
520 (0..sig.params.len()).map(|i| format!("p{i}")).collect(),
521 );
522
523 bindgen.gen.resolve.call(
524 AbiVariant::GuestExport,
525 LiftLower::LiftArgsLowerResults,
526 func,
527 &mut bindgen,
528 );
529
530 assert!(!bindgen.needs_cleanup_list);
531
532 let src = bindgen.src;
533
534 let result_type = match &sig.results[..] {
535 [] => "void",
536 [result] => wasm_type(*result),
537 _ => unreachable!(),
538 };
539
540 let camel_name = func.name.to_upper_camel_case();
541
542 let params = sig
543 .params
544 .iter()
545 .enumerate()
546 .map(|(i, param)| {
547 let ty = wasm_type(*param);
548 format!("{ty} p{i}")
549 })
550 .collect::<Vec<_>>()
551 .join(", ");
552
553 uwrite!(
554 self.src,
555 r#"
556 @Export(name = "{export_name}")
557 private static {result_type} wasmExport{camel_name}({params}) {{
558 {src}
559 }}
560 "#
561 );
562
563 if self.resolve.guest_export_needs_post_return(func) {
564 let params = sig
565 .results
566 .iter()
567 .enumerate()
568 .map(|(i, param)| {
569 let ty = wasm_type(*param);
570 format!("{ty} p{i}")
571 })
572 .collect::<Vec<_>>()
573 .join(", ");
574
575 let mut bindgen = FunctionBindgen::new(
576 self,
577 "INVALID",
578 (0..sig.results.len()).map(|i| format!("p{i}")).collect(),
579 );
580
581 bindgen.gen.resolve.post_return(func, &mut bindgen);
582
583 let src = bindgen.src;
584
585 uwrite!(
586 self.src,
587 r#"
588 @Export(name = "cabi_post_{export_name}")
589 private static void wasmExport{camel_name}PostReturn({params}) {{
590 {src}
591 }}
592 "#
593 );
594 }
595
596 if self.gen.opts.generate_stub {
597 let sig = self.sig_string(func, true);
598
599 uwrite!(
600 self.stub,
601 r#"
602 {sig} {{
603 throw new RuntimeException("todo");
604 }}
605 "#
606 );
607 }
608 }
609
610 fn type_name(&mut self, ty: &Type) -> String {
611 self.type_name_with_qualifier(ty, false)
612 }
613
614 fn type_name_with_qualifier(&mut self, ty: &Type, qualifier: bool) -> String {
615 match ty {
616 Type::Bool => "boolean".into(),
617 Type::U8 | Type::S8 => "byte".into(),
618 Type::U16 | Type::S16 => "short".into(),
619 Type::U32 | Type::S32 | Type::Char => "int".into(),
620 Type::U64 | Type::S64 => "long".into(),
621 Type::Float32 => "float".into(),
622 Type::Float64 => "double".into(),
623 Type::String => "String".into(),
624 Type::Id(id) => {
625 let ty = &self.resolve.types[*id];
626 match &ty.kind {
627 TypeDefKind::Type(ty) => self.type_name_with_qualifier(ty, qualifier),
628 TypeDefKind::List(ty) => {
629 if is_primitive(ty) {
630 format!("{}[]", self.type_name(ty))
631 } else {
632 format!("ArrayList<{}>", self.type_name_boxed(ty, qualifier))
633 }
634 }
635 TypeDefKind::Tuple(tuple) => {
636 let count = tuple.types.len();
637 self.gen.tuple_counts.insert(count);
638
639 let params = if count == 0 {
640 String::new()
641 } else {
642 format!(
643 "<{}>",
644 tuple
645 .types
646 .iter()
647 .map(|ty| self.type_name_boxed(ty, qualifier))
648 .collect::<Vec<_>>()
649 .join(", ")
650 )
651 };
652
653 format!("{}Tuple{count}{params}", self.gen.qualifier())
654 }
655 TypeDefKind::Option(ty) => self.type_name_boxed(ty, qualifier),
656 TypeDefKind::Result(result) => {
657 self.gen.needs_result = true;
658 let mut name = |ty: &Option<Type>| {
659 ty.as_ref()
660 .map(|ty| self.type_name_boxed(ty, qualifier))
661 .unwrap_or_else(|| {
662 self.gen.tuple_counts.insert(0);
663
664 format!("{}Tuple0", self.gen.qualifier())
665 })
666 };
667 let ok = name(&result.ok);
668 let err = name(&result.err);
669
670 format!("{}Result<{ok}, {err}>", self.gen.qualifier())
671 }
672 _ => {
673 if let Some(name) = &ty.name {
674 format!(
675 "{}{}",
676 self.qualifier(qualifier, ty),
677 name.to_upper_camel_case()
678 )
679 } else {
680 unreachable!()
681 }
682 }
683 }
684 }
685 }
686 }
687
688 fn type_name_boxed(&mut self, ty: &Type, qualifier: bool) -> String {
689 match ty {
690 Type::Bool => "Boolean".into(),
691 Type::U8 | Type::S8 => "Byte".into(),
692 Type::U16 | Type::S16 => "Short".into(),
693 Type::U32 | Type::S32 | Type::Char => "Integer".into(),
694 Type::U64 | Type::S64 => "Long".into(),
695 Type::Float32 => "Float".into(),
696 Type::Float64 => "Double".into(),
697 Type::Id(id) => {
698 let def = &self.resolve.types[*id];
699 match &def.kind {
700 TypeDefKind::Type(ty) => self.type_name_boxed(ty, qualifier),
701 _ => self.type_name_with_qualifier(ty, qualifier),
702 }
703 }
704 _ => self.type_name_with_qualifier(ty, qualifier),
705 }
706 }
707
708 fn print_docs(&mut self, docs: &Docs) {
709 if let Some(docs) = &docs.contents {
710 let lines = docs
711 .trim()
712 .lines()
713 .map(|line| format!("* {line}"))
714 .collect::<Vec<_>>()
715 .join("\n");
716
717 uwrite!(
718 self.src,
719 "
720 /**
721 {lines}
722 */
723 "
724 )
725 }
726 }
727
728 fn non_empty_type<'a>(&self, ty: Option<&'a Type>) -> Option<&'a Type> {
729 if let Some(ty) = ty {
730 let id = match ty {
731 Type::Id(id) => *id,
732 _ => return Some(ty),
733 };
734 match &self.resolve.types[id].kind {
735 TypeDefKind::Type(t) => self.non_empty_type(Some(t)).map(|_| ty),
736 TypeDefKind::Record(r) => (!r.fields.is_empty()).then_some(ty),
737 TypeDefKind::Tuple(t) => (!t.types.is_empty()).then_some(ty),
738 _ => Some(ty),
739 }
740 } else {
741 None
742 }
743 }
744
745 fn sig_string(&mut self, func: &Function, qualifier: bool) -> String {
746 let name = func.name.to_java_ident();
747
748 let result_type = match func.results.len() {
749 0 => "void".into(),
750 1 => {
751 self.type_name_with_qualifier(func.results.iter_types().next().unwrap(), qualifier)
752 }
753 count => {
754 self.gen.tuple_counts.insert(count);
755 format!(
756 "{}Tuple{count}<{}>",
757 self.gen.qualifier(),
758 func.results
759 .iter_types()
760 .map(|ty| self.type_name_boxed(ty, qualifier))
761 .collect::<Vec<_>>()
762 .join(", ")
763 )
764 }
765 };
766
767 let params = func
768 .params
769 .iter()
770 .map(|(name, ty)| {
771 let ty = self.type_name_with_qualifier(ty, qualifier);
772 let name = name.to_java_ident();
773 format!("{ty} {name}")
774 })
775 .collect::<Vec<_>>()
776 .join(", ");
777
778 format!("public static {result_type} {name}({params})")
779 }
780}
781
782impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
783 fn resolve(&self) -> &'a Resolve {
784 self.resolve
785 }
786
787 fn type_record(&mut self, _id: TypeId, name: &str, record: &Record, docs: &Docs) {
788 self.print_docs(docs);
789
790 let name = name.to_upper_camel_case();
791
792 let parameters = record
793 .fields
794 .iter()
795 .map(|field| {
796 format!(
797 "{} {}",
798 self.type_name(&field.ty),
799 field.name.to_java_ident()
800 )
801 })
802 .collect::<Vec<_>>()
803 .join(", ");
804
805 let assignments = record
806 .fields
807 .iter()
808 .map(|field| {
809 let name = field.name.to_java_ident();
810 format!("this.{name} = {name};")
811 })
812 .collect::<Vec<_>>()
813 .join("\n");
814
815 let fields = if record.fields.is_empty() {
816 format!("public static final {name} INSTANCE = new {name}();")
817 } else {
818 record
819 .fields
820 .iter()
821 .map(|field| {
822 format!(
823 "public final {} {};",
824 self.type_name(&field.ty),
825 field.name.to_java_ident()
826 )
827 })
828 .collect::<Vec<_>>()
829 .join("\n")
830 };
831
832 uwrite!(
833 self.src,
834 "
835 public static final class {name} {{
836 {fields}
837
838 public {name}({parameters}) {{
839 {assignments}
840 }}
841 }}
842 "
843 );
844 }
845
846 fn type_flags(&mut self, _id: TypeId, name: &str, flags: &Flags, docs: &Docs) {
847 self.print_docs(docs);
848
849 let name = name.to_upper_camel_case();
850
851 let ty = match flags.repr() {
852 FlagsRepr::U8 => "byte",
853 FlagsRepr::U16 => "short",
854 FlagsRepr::U32(1) => "int",
855 FlagsRepr::U32(2) => "long",
856 repr => todo!("flags {repr:?}"),
857 };
858
859 let flags = flags
860 .flags
861 .iter()
862 .enumerate()
863 .map(|(i, flag)| {
864 let flag_name = flag.name.to_shouty_snake_case();
865 let suffix = if matches!(flags.repr(), FlagsRepr::U32(2)) {
866 "L"
867 } else {
868 ""
869 };
870 format!(
871 "public static final {name} {flag_name} = new {name}(({ty}) (1{suffix} << {i}));"
872 )
873 })
874 .collect::<Vec<_>>()
875 .join("\n");
876
877 uwrite!(
878 self.src,
879 "
880 public static final class {name} {{
881 public final {ty} value;
882
883 public {name}({ty} value) {{
884 this.value = value;
885 }}
886
887 {flags}
888 }}
889 "
890 );
891 }
892
893 fn type_tuple(&mut self, id: TypeId, _name: &str, _tuple: &Tuple, _docs: &Docs) {
894 self.type_name(&Type::Id(id));
895 }
896
897 fn type_variant(&mut self, _id: TypeId, name: &str, variant: &Variant, docs: &Docs) {
898 self.print_docs(docs);
899
900 let name = name.to_upper_camel_case();
901 let tag_type = int_type(variant.tag());
902
903 let constructors = variant
904 .cases
905 .iter()
906 .map(|case| {
907 let case_name = case.name.to_java_ident();
908 let tag = case.name.to_shouty_snake_case();
909 let (parameter, argument) = if let Some(ty) = self.non_empty_type(case.ty.as_ref())
910 {
911 (
912 format!("{} {case_name}", self.type_name(ty)),
913 case_name.deref(),
914 )
915 } else {
916 (String::new(), "null")
917 };
918
919 format!(
920 "public static {name} {case_name}({parameter}) {{
921 return new {name}({tag}, {argument});
922 }}
923 "
924 )
925 })
926 .collect::<Vec<_>>()
927 .join("\n");
928
929 let accessors = variant
930 .cases
931 .iter()
932 .filter_map(|case| {
933 self.non_empty_type(case.ty.as_ref()).map(|ty| {
934 let case_name = case.name.to_upper_camel_case();
935 let tag = case.name.to_shouty_snake_case();
936 let ty = self.type_name(ty);
937 format!(
938 r#"public {ty} get{case_name}() {{
939 if (this.tag == {tag}) {{
940 return ({ty}) this.value;
941 }} else {{
942 throw new RuntimeException("expected {tag}, got " + this.tag);
943 }}
944 }}
945 "#
946 )
947 })
948 })
949 .collect::<Vec<_>>()
950 .join("\n");
951
952 let tags = variant
953 .cases
954 .iter()
955 .enumerate()
956 .map(|(i, case)| {
957 let tag = case.name.to_shouty_snake_case();
958 format!("public static final {tag_type} {tag} = {i};")
959 })
960 .collect::<Vec<_>>()
961 .join("\n");
962
963 uwrite!(
964 self.src,
965 "
966 public static final class {name} {{
967 public final {tag_type} tag;
968 private final Object value;
969
970 private {name}({tag_type} tag, Object value) {{
971 this.tag = tag;
972 this.value = value;
973 }}
974
975 {constructors}
976 {accessors}
977 {tags}
978 }}
979 "
980 );
981 }
982
983 fn type_option(&mut self, id: TypeId, _name: &str, _payload: &Type, _docs: &Docs) {
984 self.type_name(&Type::Id(id));
985 }
986
987 fn type_result(&mut self, id: TypeId, _name: &str, _result: &Result_, _docs: &Docs) {
988 self.type_name(&Type::Id(id));
989 }
990
991 fn type_union(&mut self, id: TypeId, name: &str, union: &Union, docs: &Docs) {
992 self.type_variant(
993 id,
994 name,
995 &Variant {
996 cases: union
997 .cases
998 .iter()
999 .enumerate()
1000 .map(|(i, case)| Case {
1001 docs: case.docs.clone(),
1002 name: format!("f{i}"),
1003 ty: Some(case.ty),
1004 })
1005 .collect(),
1006 },
1007 docs,
1008 )
1009 }
1010
1011 fn type_enum(&mut self, _id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
1012 self.print_docs(docs);
1013
1014 let name = name.to_upper_camel_case();
1015
1016 let cases = enum_
1017 .cases
1018 .iter()
1019 .map(|case| case.name.to_shouty_snake_case())
1020 .collect::<Vec<_>>()
1021 .join(", ");
1022
1023 uwrite!(
1024 self.src,
1025 "
1026 public static enum {name} {{
1027 {cases}
1028 }}
1029 "
1030 );
1031 }
1032
1033 fn type_alias(&mut self, id: TypeId, _name: &str, _ty: &Type, _docs: &Docs) {
1034 self.type_name(&Type::Id(id));
1035 }
1036
1037 fn type_list(&mut self, id: TypeId, _name: &str, _ty: &Type, _docs: &Docs) {
1038 self.type_name(&Type::Id(id));
1039 }
1040
1041 fn type_builtin(&mut self, _id: TypeId, _name: &str, _ty: &Type, _docs: &Docs) {
1042 unimplemented!();
1043 }
1044}
1045
1046struct Block {
1047 body: String,
1048 results: Vec<String>,
1049 element: String,
1050 base: String,
1051}
1052
1053struct Cleanup {
1054 address: String,
1055 size: String,
1056 align: usize,
1057}
1058
1059struct BlockStorage {
1060 body: String,
1061 element: String,
1062 base: String,
1063 cleanup: Vec<Cleanup>,
1064}
1065
1066struct FunctionBindgen<'a, 'b> {
1067 gen: &'b mut InterfaceGenerator<'a>,
1068 func_name: &'b str,
1069 params: Box<[String]>,
1070 src: String,
1071 locals: Ns,
1072 block_storage: Vec<BlockStorage>,
1073 blocks: Vec<Block>,
1074 payloads: Vec<String>,
1075 cleanup: Vec<Cleanup>,
1076 needs_cleanup_list: bool,
1077}
1078
1079impl<'a, 'b> FunctionBindgen<'a, 'b> {
1080 fn new(
1081 gen: &'b mut InterfaceGenerator<'a>,
1082 func_name: &'b str,
1083 params: Box<[String]>,
1084 ) -> FunctionBindgen<'a, 'b> {
1085 Self {
1086 gen,
1087 func_name,
1088 params,
1089 src: String::new(),
1090 locals: Ns::default(),
1091 block_storage: Vec::new(),
1092 blocks: Vec::new(),
1093 payloads: Vec::new(),
1094 cleanup: Vec::new(),
1095 needs_cleanup_list: false,
1096 }
1097 }
1098
1099 fn lower_variant(
1100 &mut self,
1101 cases: &[(&str, Option<Type>)],
1102 lowered_types: &[WasmType],
1103 op: &str,
1104 results: &mut Vec<String>,
1105 ) {
1106 let blocks = self
1107 .blocks
1108 .drain(self.blocks.len() - cases.len()..)
1109 .collect::<Vec<_>>();
1110
1111 let payloads = self
1112 .payloads
1113 .drain(self.payloads.len() - cases.len()..)
1114 .collect::<Vec<_>>();
1115
1116 let lowered = lowered_types
1117 .iter()
1118 .map(|_| self.locals.tmp("lowered"))
1119 .collect::<Vec<_>>();
1120
1121 results.extend(lowered.iter().cloned());
1122
1123 let declarations = lowered
1124 .iter()
1125 .zip(lowered_types)
1126 .map(|(lowered, ty)| format!("{} {lowered};", wasm_type(*ty)))
1127 .collect::<Vec<_>>()
1128 .join("\n");
1129
1130 let cases = cases
1131 .iter()
1132 .zip(blocks)
1133 .zip(payloads)
1134 .enumerate()
1135 .map(
1136 |(i, (((name, ty), Block { body, results, .. }), payload))| {
1137 let payload = if let Some(ty) = self.gen.non_empty_type(ty.as_ref()) {
1138 let ty = self.gen.type_name(ty);
1139 let name = name.to_upper_camel_case();
1140
1141 format!("{ty} {payload} = ({op}).get{name}();")
1142 } else {
1143 String::new()
1144 };
1145
1146 let assignments = lowered
1147 .iter()
1148 .zip(&results)
1149 .map(|(lowered, result)| format!("{lowered} = {result};\n"))
1150 .collect::<Vec<_>>()
1151 .concat();
1152
1153 format!(
1154 "case {i}: {{
1155 {payload}
1156 {body}
1157 {assignments}
1158 break;
1159 }}"
1160 )
1161 },
1162 )
1163 .collect::<Vec<_>>()
1164 .join("\n");
1165
1166 uwrite!(
1167 self.src,
1168 r#"
1169 {declarations}
1170
1171 switch (({op}).tag) {{
1172 {cases}
1173
1174 default: throw new AssertionError("invalid discriminant: " + ({op}).tag);
1175 }}
1176 "#
1177 );
1178 }
1179
1180 fn lift_variant(
1181 &mut self,
1182 ty: &Type,
1183 cases: &[(&str, Option<Type>)],
1184 op: &str,
1185 results: &mut Vec<String>,
1186 ) {
1187 let blocks = self
1188 .blocks
1189 .drain(self.blocks.len() - cases.len()..)
1190 .collect::<Vec<_>>();
1191
1192 let ty = self.gen.type_name(ty);
1193 let generics_position = ty.find('<');
1194 let lifted = self.locals.tmp("lifted");
1195
1196 let cases = cases
1197 .iter()
1198 .zip(blocks)
1199 .enumerate()
1200 .map(|(i, ((case_name, case_ty), Block { body, results, .. }))| {
1201 let payload = if self.gen.non_empty_type(case_ty.as_ref()).is_some() {
1202 results.into_iter().next().unwrap()
1203 } else if generics_position.is_some() {
1204 if let Some(ty) = case_ty.as_ref() {
1205 format!("{}.INSTANCE", self.gen.type_name(ty))
1206 } else {
1207 format!("{}Tuple0.INSTANCE", self.gen.gen.qualifier())
1208 }
1209 } else {
1210 String::new()
1211 };
1212
1213 let method = case_name.to_java_ident();
1214
1215 let call = if let Some(position) = generics_position {
1216 let (ty, generics) = ty.split_at(position);
1217 format!("{ty}.{generics}{method}")
1218 } else {
1219 format!("{ty}.{method}")
1220 };
1221
1222 format!(
1223 "case {i}: {{
1224 {body}
1225 {lifted} = {call}({payload});
1226 break;
1227 }}"
1228 )
1229 })
1230 .collect::<Vec<_>>()
1231 .join("\n");
1232
1233 uwrite!(
1234 self.src,
1235 r#"
1236 {ty} {lifted};
1237
1238 switch ({op}) {{
1239 {cases}
1240
1241 default: throw new AssertionError("invalid discriminant: " + ({op}));
1242 }}
1243 "#
1244 );
1245
1246 results.push(lifted);
1247 }
1248}
1249
1250impl Bindgen for FunctionBindgen<'_, '_> {
1251 type Operand = String;
1252
1253 fn emit(
1254 &mut self,
1255 _resolve: &Resolve,
1256 inst: &Instruction<'_>,
1257 operands: &mut Vec<String>,
1258 results: &mut Vec<String>,
1259 ) {
1260 match inst {
1261 Instruction::GetArg { nth } => results.push(self.params[*nth].clone()),
1262 Instruction::I32Const { val } => results.push(val.to_string()),
1263 Instruction::ConstZero { tys } => results.extend(tys.iter().map(|ty| {
1264 match ty {
1265 WasmType::I32 => "0",
1266 WasmType::I64 => "0L",
1267 WasmType::F32 => "0.0F",
1268 WasmType::F64 => "0.0D",
1269 }
1270 .to_owned()
1271 })),
1272
1273 Instruction::U8FromI32 => results.push(format!("(byte) ({})", operands[0])),
1275 Instruction::S8FromI32 => results.push(format!("(byte) ({})", operands[0])),
1276 Instruction::U16FromI32 => results.push(format!("(short) ({})", operands[0])),
1277 Instruction::S16FromI32 => results.push(format!("(short) ({})", operands[0])),
1278
1279 Instruction::I32FromU8 => results.push(format!("((int) ({})) & 0xFF", operands[0])),
1280 Instruction::I32FromU16 => results.push(format!("((int) ({})) & 0xFFFF", operands[0])),
1281
1282 Instruction::I32FromS8 | Instruction::I32FromS16 => {
1283 results.push(format!("(int) ({})", operands[0]))
1284 }
1285
1286 Instruction::CharFromI32
1287 | Instruction::I32FromChar
1288 | Instruction::U32FromI32
1289 | Instruction::S32FromI32
1290 | Instruction::S64FromI64
1291 | Instruction::U64FromI64
1292 | Instruction::I32FromU32
1293 | Instruction::I32FromS32
1294 | Instruction::I64FromS64
1295 | Instruction::I64FromU64
1296 | Instruction::F32FromFloat32
1297 | Instruction::F64FromFloat64
1298 | Instruction::Float32FromF32
1299 | Instruction::Float64FromF64 => results.push(operands[0].clone()),
1300
1301 Instruction::Bitcasts { casts } => {
1302 results.extend(casts.iter().zip(operands).map(|(cast, op)| match cast {
1303 Bitcast::I32ToF32 => format!("Float.intBitsToFloat({op})"),
1304 Bitcast::I64ToF32 => format!("Float.intBitsToFloat((int) ({op}))"),
1305 Bitcast::F32ToI32 => format!("Float.floatToIntBits({op})"),
1306 Bitcast::F32ToI64 => format!("(long) Float.floatToIntBits({op})"),
1307 Bitcast::I64ToF64 => format!("Double.longBitsToDouble({op})"),
1308 Bitcast::F64ToI64 => format!("Double.doubleToLongBits({op})"),
1309 Bitcast::I32ToI64 => format!("(long) ({op})"),
1310 Bitcast::I64ToI32 => format!("(int) ({op})"),
1311 Bitcast::None => op.to_owned(),
1312 }))
1313 }
1314
1315 Instruction::I32FromBool => {
1316 results.push(format!("({} ? 1 : 0)", operands[0]));
1317 }
1318 Instruction::BoolFromI32 => results.push(format!("({} != 0)", operands[0])),
1319
1320 Instruction::FlagsLower { flags, .. } => match flags_repr(flags) {
1322 Int::U8 | Int::U16 | Int::U32 => {
1323 results.push(format!("({}).value", operands[0]));
1324 }
1325 Int::U64 => {
1326 let op = &operands[0];
1327 results.push(format!("(int) (({op}).value & 0xffffffffL)"));
1328 results.push(format!("(int) ((({op}).value >>> 32) & 0xffffffffL)"));
1329 }
1330 },
1331
1332 Instruction::FlagsLift { name, flags, .. } => match flags_repr(flags) {
1333 Int::U8 | Int::U16 | Int::U32 => {
1334 results.push(format!(
1335 "new {}(({}) {})",
1336 name.to_upper_camel_case(),
1337 int_type(flags_repr(flags)),
1338 operands[0]
1339 ));
1340 }
1341 Int::U64 => {
1342 results.push(format!(
1343 "new {}(((long) ({})) | (((long) ({})) << 32))",
1344 name.to_upper_camel_case(),
1345 operands[0],
1346 operands[1]
1347 ));
1348 }
1349 },
1350
1351 Instruction::RecordLower { record, .. } => {
1352 let op = &operands[0];
1353 for field in record.fields.iter() {
1354 results.push(format!("({op}).{}", field.name.to_java_ident()));
1355 }
1356 }
1357 Instruction::RecordLift { ty, .. } | Instruction::TupleLift { ty, .. } => {
1358 let ops = operands
1359 .iter()
1360 .map(|op| op.to_string())
1361 .collect::<Vec<_>>()
1362 .join(", ");
1363
1364 results.push(format!("new {}({ops})", self.gen.type_name(&Type::Id(*ty))));
1365 }
1366
1367 Instruction::TupleLower { tuple, .. } => {
1368 let op = &operands[0];
1369 for i in 0..tuple.types.len() {
1370 results.push(format!("({op}).f{i}"));
1371 }
1372 }
1373
1374 Instruction::VariantPayloadName => {
1375 let payload = self.locals.tmp("payload");
1376 results.push(payload.clone());
1377 self.payloads.push(payload);
1378 }
1379
1380 Instruction::VariantLower {
1381 variant,
1382 results: lowered_types,
1383 ..
1384 } => self.lower_variant(
1385 &variant
1386 .cases
1387 .iter()
1388 .map(|case| (case.name.deref(), case.ty))
1389 .collect::<Vec<_>>(),
1390 lowered_types,
1391 &operands[0],
1392 results,
1393 ),
1394
1395 Instruction::VariantLift { variant, ty, .. } => self.lift_variant(
1396 &Type::Id(*ty),
1397 &variant
1398 .cases
1399 .iter()
1400 .map(|case| (case.name.deref(), case.ty))
1401 .collect::<Vec<_>>(),
1402 &operands[0],
1403 results,
1404 ),
1405
1406 Instruction::UnionLower {
1407 union,
1408 results: lowered_types,
1409 ..
1410 } => {
1411 let cases = union
1412 .cases
1413 .iter()
1414 .enumerate()
1415 .map(|(i, case)| (format!("f{i}"), case.ty))
1416 .collect::<Vec<_>>();
1417
1418 self.lower_variant(
1419 &cases
1420 .iter()
1421 .map(|(name, ty)| (name.deref(), Some(*ty)))
1422 .collect::<Vec<_>>(),
1423 lowered_types,
1424 &operands[0],
1425 results,
1426 )
1427 }
1428
1429 Instruction::UnionLift { union, ty, .. } => {
1430 let cases = union
1431 .cases
1432 .iter()
1433 .enumerate()
1434 .map(|(i, case)| (format!("f{i}"), case.ty))
1435 .collect::<Vec<_>>();
1436
1437 self.lift_variant(
1438 &Type::Id(*ty),
1439 &cases
1440 .iter()
1441 .map(|(name, ty)| (name.deref(), Some(*ty)))
1442 .collect::<Vec<_>>(),
1443 &operands[0],
1444 results,
1445 )
1446 }
1447
1448 Instruction::OptionLower {
1449 results: lowered_types,
1450 payload,
1451 ..
1452 } => {
1453 let some = self.blocks.pop().unwrap();
1454 let none = self.blocks.pop().unwrap();
1455 let some_payload = self.payloads.pop().unwrap();
1456 let none_payload = self.payloads.pop().unwrap();
1457
1458 let lowered = lowered_types
1459 .iter()
1460 .map(|_| self.locals.tmp("lowered"))
1461 .collect::<Vec<_>>();
1462
1463 results.extend(lowered.iter().cloned());
1464
1465 let declarations = lowered
1466 .iter()
1467 .zip(lowered_types.iter())
1468 .map(|(lowered, ty)| format!("{} {lowered};", wasm_type(*ty)))
1469 .collect::<Vec<_>>()
1470 .join("\n");
1471
1472 let op = &operands[0];
1473
1474 let mut block = |ty: Option<&Type>, Block { body, results, .. }, payload| {
1475 let payload = if let Some(ty) = self.gen.non_empty_type(ty) {
1476 let ty = self.gen.type_name(ty);
1477
1478 format!("{ty} {payload} = ({ty}) ({op});")
1479 } else {
1480 String::new()
1481 };
1482
1483 let assignments = lowered
1484 .iter()
1485 .zip(&results)
1486 .map(|(lowered, result)| format!("{lowered} = {result};\n"))
1487 .collect::<Vec<_>>()
1488 .concat();
1489
1490 format!(
1491 "{payload}
1492 {body}
1493 {assignments}"
1494 )
1495 };
1496
1497 let none = block(None, none, none_payload);
1498 let some = block(Some(payload), some, some_payload);
1499
1500 uwrite!(
1501 self.src,
1502 r#"
1503 {declarations}
1504
1505 if (({op}) == null) {{
1506 {none}
1507 }} else {{
1508 {some}
1509 }}
1510 "#
1511 );
1512 }
1513
1514 Instruction::OptionLift { payload, ty } => {
1515 let some = self.blocks.pop().unwrap();
1516 let _none = self.blocks.pop().unwrap();
1517
1518 let ty = self.gen.type_name(&Type::Id(*ty));
1519 let lifted = self.locals.tmp("lifted");
1520 let op = &operands[0];
1521
1522 let payload = if self.gen.non_empty_type(Some(*payload)).is_some() {
1523 some.results.into_iter().next().unwrap()
1524 } else {
1525 "null".into()
1526 };
1527
1528 let some = some.body;
1529
1530 uwrite!(
1531 self.src,
1532 r#"
1533 {ty} {lifted};
1534
1535 switch ({op}) {{
1536 case 0: {{
1537 {lifted} = null;
1538 break;
1539 }}
1540
1541 case 1: {{
1542 {some}
1543 {lifted} = {payload};
1544 break;
1545 }}
1546
1547 default: throw new AssertionError("invalid discriminant: " + ({op}));
1548 }}
1549 "#
1550 );
1551
1552 results.push(lifted);
1553 }
1554
1555 Instruction::ResultLower {
1556 results: lowered_types,
1557 result,
1558 ..
1559 } => self.lower_variant(
1560 &[("ok", result.ok), ("err", result.err)],
1561 lowered_types,
1562 &operands[0],
1563 results,
1564 ),
1565
1566 Instruction::ResultLift { result, ty } => self.lift_variant(
1567 &Type::Id(*ty),
1568 &[("ok", result.ok), ("err", result.err)],
1569 &operands[0],
1570 results,
1571 ),
1572
1573 Instruction::EnumLower { .. } => results.push(format!("{}.ordinal()", operands[0])),
1574
1575 Instruction::EnumLift { name, .. } => results.push(format!(
1576 "{}.values()[{}]",
1577 name.to_upper_camel_case(),
1578 operands[0]
1579 )),
1580
1581 Instruction::ListCanonLower { element, realloc } => {
1582 let op = &operands[0];
1583 let (size, ty) = list_element_info(element);
1584
1585 if realloc.is_none() && size <= 4 {
1588 results.push(format!("Address.ofData({op}).toInt()"));
1589 } else {
1590 let address = self.locals.tmp("address");
1591 let ty = ty.to_upper_camel_case();
1592
1593 uwrite!(
1594 self.src,
1595 "
1596 Address {address} = Memory.malloc({size} * ({op}).length, {size});
1597 Memory.put{ty}s({address}, {op}, 0, ({op}).length);
1598 "
1599 );
1600
1601 if realloc.is_none() {
1602 self.cleanup.push(Cleanup {
1603 address: format!("{address}.toInt()"),
1604 size: format!("{size} * ({op}).length"),
1605 align: size,
1606 });
1607 }
1608
1609 results.push(format!("{address}.toInt()"));
1610 }
1611 results.push(format!("({op}).length"));
1612 }
1613
1614 Instruction::ListCanonLift { element, .. } => {
1615 let (_, ty) = list_element_info(element);
1616 let ty_upper = ty.to_upper_camel_case();
1617 let array = self.locals.tmp("array");
1618 let address = &operands[0];
1619 let length = &operands[1];
1620
1621 uwrite!(
1622 self.src,
1623 "
1624 {ty}[] {array} = new {ty}[{length}];
1625 Memory.get{ty_upper}s(Address.fromInt({address}), {array}, 0, ({array}).length);
1626 "
1627 );
1628
1629 results.push(array);
1630 }
1631
1632 Instruction::StringLower { realloc } => {
1633 let op = &operands[0];
1634 let bytes = self.locals.tmp("bytes");
1635 uwriteln!(
1636 self.src,
1637 "byte[] {bytes} = ({op}).getBytes(StandardCharsets.UTF_8);"
1638 );
1639
1640 if realloc.is_none() {
1641 results.push(format!("Address.ofData({bytes}).toInt()"));
1642 } else {
1643 let address = self.locals.tmp("address");
1644
1645 uwrite!(
1646 self.src,
1647 "
1648 Address {address} = Memory.malloc({bytes}.length, 1);
1649 Memory.putBytes({address}, {bytes}, 0, {bytes}.length);
1650 "
1651 );
1652
1653 results.push(format!("{address}.toInt()"));
1654 }
1655 results.push(format!("{bytes}.length"));
1656 }
1657
1658 Instruction::StringLift { .. } => {
1659 let bytes = self.locals.tmp("bytes");
1660 let address = &operands[0];
1661 let length = &operands[1];
1662
1663 uwrite!(
1664 self.src,
1665 "
1666 byte[] {bytes} = new byte[{length}];
1667 Memory.getBytes(Address.fromInt({address}), {bytes}, 0, {length});
1668 "
1669 );
1670
1671 results.push(format!("new String({bytes}, StandardCharsets.UTF_8)"));
1672 }
1673
1674 Instruction::ListLower { element, realloc } => {
1675 let Block {
1676 body,
1677 results: block_results,
1678 element: block_element,
1679 base,
1680 } = self.blocks.pop().unwrap();
1681 assert!(block_results.is_empty());
1682
1683 let op = &operands[0];
1684 let size = self.gen.gen.sizes.size(element);
1685 let align = self.gen.gen.sizes.align(element);
1686 let address = self.locals.tmp("address");
1687 let ty = self.gen.type_name(element);
1688 let index = self.locals.tmp("index");
1689
1690 uwrite!(
1691 self.src,
1692 "
1693 int {address} = Memory.malloc(({op}).size() * {size}, {align}).toInt();
1694 for (int {index} = 0; {index} < ({op}).size(); ++{index}) {{
1695 {ty} {block_element} = ({op}).get({index});
1696 int {base} = {address} + ({index} * {size});
1697 {body}
1698 }}
1699 "
1700 );
1701
1702 if realloc.is_none() {
1703 self.cleanup.push(Cleanup {
1704 address: address.clone(),
1705 size: format!("({op}).size() * {size}"),
1706 align,
1707 });
1708 }
1709
1710 results.push(address);
1711 results.push(format!("({op}).size()"));
1712 }
1713
1714 Instruction::ListLift { element, .. } => {
1715 let Block {
1716 body,
1717 results: block_results,
1718 base,
1719 ..
1720 } = self.blocks.pop().unwrap();
1721 let address = &operands[0];
1722 let length = &operands[1];
1723 let array = self.locals.tmp("array");
1724 let ty = self.gen.type_name(element);
1725 let size = self.gen.gen.sizes.size(element);
1726 let align = self.gen.gen.sizes.align(element);
1727 let index = self.locals.tmp("index");
1728
1729 let result = match &block_results[..] {
1730 [result] => result,
1731 _ => todo!("result count == {}", results.len()),
1732 };
1733
1734 uwrite!(
1735 self.src,
1736 "
1737 ArrayList<{ty}> {array} = new ArrayList<>({length});
1738 for (int {index} = 0; {index} < ({length}); ++{index}) {{
1739 int {base} = ({address}) + ({index} * {size});
1740 {body}
1741 {array}.add({result});
1742 }}
1743 Memory.free(Address.fromInt({address}), ({length}) * {size}, {align});
1744 "
1745 );
1746
1747 results.push(array);
1748 }
1749
1750 Instruction::IterElem { .. } => {
1751 results.push(self.block_storage.last().unwrap().element.clone())
1752 }
1753
1754 Instruction::IterBasePointer => {
1755 results.push(self.block_storage.last().unwrap().base.clone())
1756 }
1757
1758 Instruction::CallWasm { sig, .. } => {
1759 let assignment = match &sig.results[..] {
1760 [result] => {
1761 let ty = wasm_type(*result);
1762 let result = self.locals.tmp("result");
1763 let assignment = format!("{ty} {result} = ");
1764 results.push(result);
1765 assignment
1766 }
1767
1768 [] => String::new(),
1769
1770 _ => unreachable!(),
1771 };
1772
1773 let func_name = self.func_name.to_upper_camel_case();
1774
1775 let operands = operands.join(", ");
1776
1777 uwriteln!(self.src, "{assignment} wasmImport{func_name}({operands});");
1778 }
1779
1780 Instruction::CallInterface { func, .. } => {
1781 let (assignment, destructure) = match func.results.len() {
1782 0 => (String::new(), String::new()),
1783 1 => {
1784 let ty = self
1785 .gen
1786 .type_name(func.results.iter_types().next().unwrap());
1787 let result = self.locals.tmp("result");
1788 let assignment = format!("{ty} {result} = ");
1789 results.push(result);
1790 (assignment, String::new())
1791 }
1792 count => {
1793 self.gen.gen.tuple_counts.insert(count);
1794 let ty = format!(
1795 "{}Tuple{count}<{}>",
1796 self.gen.gen.qualifier(),
1797 func.results
1798 .iter_types()
1799 .map(|ty| self.gen.type_name_boxed(ty, false))
1800 .collect::<Vec<_>>()
1801 .join(", ")
1802 );
1803
1804 let result = self.locals.tmp("result");
1805 let assignment = format!("{ty} {result} = ");
1806
1807 let destructure = func
1808 .results
1809 .iter_types()
1810 .enumerate()
1811 .map(|(index, ty)| {
1812 let ty = self.gen.type_name(ty);
1813 let my_result = self.locals.tmp("result");
1814 let assignment = format!("{ty} {my_result} = {result}.f{index};");
1815 results.push(my_result);
1816 assignment
1817 })
1818 .collect::<Vec<_>>()
1819 .join("\n");
1820
1821 (assignment, destructure)
1822 }
1823 };
1824
1825 let module = self.gen.name.to_upper_camel_case();
1826 let name = func.name.to_java_ident();
1827
1828 let args = operands.join(", ");
1829
1830 uwrite!(
1831 self.src,
1832 "
1833 {assignment}{module}Impl.{name}({args});
1834 {destructure}
1835 "
1836 );
1837 }
1838
1839 Instruction::Return { amt, .. } => {
1840 for Cleanup {
1841 address,
1842 size,
1843 align,
1844 } in &self.cleanup
1845 {
1846 uwriteln!(
1847 self.src,
1848 "Memory.free(Address.fromInt({address}), {size}, {align});"
1849 );
1850 }
1851
1852 if self.needs_cleanup_list {
1853 uwrite!(
1854 self.src,
1855 "
1856 for ({}Cleanup cleanup : cleanupList) {{
1857 Memory.free(Address.fromInt(cleanup.address), cleanup.size, cleanup.align);
1858 }}
1859 ",
1860 self.gen.gen.qualifier()
1861 );
1862 }
1863
1864 match *amt {
1865 0 => (),
1866 1 => uwriteln!(self.src, "return {};", operands[0]),
1867 count => {
1868 let results = operands.join(", ");
1869 uwriteln!(
1870 self.src,
1871 "return new {}Tuple{count}<>({results});",
1872 self.gen.gen.qualifier()
1873 )
1874 }
1875 }
1876 }
1877
1878 Instruction::I32Load { offset } => results.push(format!(
1879 "Address.fromInt(({}) + {offset}).getInt()",
1880 operands[0]
1881 )),
1882
1883 Instruction::I32Load8U { offset } => results.push(format!(
1884 "(((int) Address.fromInt(({}) + {offset}).getByte()) & 0xFF)",
1885 operands[0]
1886 )),
1887
1888 Instruction::I32Load8S { offset } => results.push(format!(
1889 "((int) Address.fromInt(({}) + {offset}).getByte())",
1890 operands[0]
1891 )),
1892
1893 Instruction::I32Load16U { offset } => results.push(format!(
1894 "(((int) Address.fromInt(({}) + {offset}).getShort()) & 0xFFFF)",
1895 operands[0]
1896 )),
1897
1898 Instruction::I32Load16S { offset } => results.push(format!(
1899 "((int) Address.fromInt(({}) + {offset}).getShort())",
1900 operands[0]
1901 )),
1902
1903 Instruction::I64Load { offset } => results.push(format!(
1904 "Address.fromInt(({}) + {offset}).getLong()",
1905 operands[0]
1906 )),
1907
1908 Instruction::F32Load { offset } => results.push(format!(
1909 "Address.fromInt(({}) + {offset}).getFloat()",
1910 operands[0]
1911 )),
1912
1913 Instruction::F64Load { offset } => results.push(format!(
1914 "Address.fromInt(({}) + {offset}).getDouble()",
1915 operands[0]
1916 )),
1917
1918 Instruction::I32Store { offset } => uwriteln!(
1919 self.src,
1920 "Address.fromInt(({}) + {offset}).putInt({});",
1921 operands[1],
1922 operands[0]
1923 ),
1924
1925 Instruction::I32Store8 { offset } => uwriteln!(
1926 self.src,
1927 "Address.fromInt(({}) + {offset}).putByte((byte) ({}));",
1928 operands[1],
1929 operands[0]
1930 ),
1931
1932 Instruction::I32Store16 { offset } => uwriteln!(
1933 self.src,
1934 "Address.fromInt(({}) + {offset}).putShort((short) ({}));",
1935 operands[1],
1936 operands[0]
1937 ),
1938
1939 Instruction::I64Store { offset } => uwriteln!(
1940 self.src,
1941 "Address.fromInt(({}) + {offset}).putLong({});",
1942 operands[1],
1943 operands[0]
1944 ),
1945
1946 Instruction::F32Store { offset } => uwriteln!(
1947 self.src,
1948 "Address.fromInt(({}) + {offset}).putFloat({});",
1949 operands[1],
1950 operands[0]
1951 ),
1952
1953 Instruction::F64Store { offset } => uwriteln!(
1954 self.src,
1955 "Address.fromInt(({}) + {offset}).putDouble({});",
1956 operands[1],
1957 operands[0]
1958 ),
1959
1960 Instruction::Malloc { .. } => unimplemented!(),
1961
1962 Instruction::GuestDeallocate { size, align } => {
1963 uwriteln!(
1964 self.src,
1965 "Memory.free(Address.fromInt({}), {size}, {align});",
1966 operands[0]
1967 )
1968 }
1969
1970 Instruction::GuestDeallocateString => uwriteln!(
1971 self.src,
1972 "Memory.free(Address.fromInt({}), {}, 1);",
1973 operands[0],
1974 operands[1]
1975 ),
1976
1977 Instruction::GuestDeallocateVariant { blocks } => {
1978 let cases = self
1979 .blocks
1980 .drain(self.blocks.len() - blocks..)
1981 .enumerate()
1982 .map(|(i, Block { body, results, .. })| {
1983 assert!(results.is_empty());
1984
1985 format!(
1986 "case {i}: {{
1987 {body}
1988 break;
1989 }}"
1990 )
1991 })
1992 .collect::<Vec<_>>()
1993 .join("\n");
1994
1995 let op = &operands[0];
1996
1997 uwrite!(
1998 self.src,
1999 "
2000 switch ({op}) {{
2001 {cases}
2002 }}
2003 "
2004 );
2005 }
2006
2007 Instruction::GuestDeallocateList { element } => {
2008 let Block {
2009 body,
2010 results,
2011 base,
2012 ..
2013 } = self.blocks.pop().unwrap();
2014 assert!(results.is_empty());
2015
2016 let address = &operands[0];
2017 let length = &operands[1];
2018
2019 let size = self.gen.gen.sizes.size(element);
2020 let align = self.gen.gen.sizes.align(element);
2021
2022 if !body.trim().is_empty() {
2023 let index = self.locals.tmp("index");
2024
2025 uwrite!(
2026 self.src,
2027 "
2028 for (int {index} = 0; {index} < ({length}); ++{index}) {{
2029 int {base} = ({address}) + ({index} * {size});
2030 {body}
2031 }}
2032 "
2033 );
2034 }
2035
2036 uwriteln!(
2037 self.src,
2038 "Memory.free(Address.fromInt({address}), ({length}) * {size}, {align});"
2039 );
2040 }
2041 }
2042 }
2043
2044 fn return_pointer(&mut self, size: usize, align: usize) -> String {
2045 self.gen.gen.return_area_size = self.gen.gen.return_area_size.max(size);
2046 self.gen.gen.return_area_align = self.gen.gen.return_area_align.max(align);
2047 format!("{}RETURN_AREA", self.gen.gen.qualifier())
2048 }
2049
2050 fn push_block(&mut self) {
2051 self.block_storage.push(BlockStorage {
2052 body: mem::take(&mut self.src),
2053 element: self.locals.tmp("element"),
2054 base: self.locals.tmp("base"),
2055 cleanup: mem::take(&mut self.cleanup),
2056 });
2057 }
2058
2059 fn finish_block(&mut self, operands: &mut Vec<String>) {
2060 let BlockStorage {
2061 body,
2062 element,
2063 base,
2064 cleanup,
2065 } = self.block_storage.pop().unwrap();
2066
2067 if !self.cleanup.is_empty() {
2068 self.needs_cleanup_list = true;
2069
2070 for Cleanup {
2071 address,
2072 size,
2073 align,
2074 } in &self.cleanup
2075 {
2076 uwriteln!(
2077 self.src,
2078 "cleanupList.add(new {}Cleanup({address}, {size}, {align}));",
2079 self.gen.gen.qualifier()
2080 );
2081 }
2082 }
2083
2084 self.cleanup = cleanup;
2085
2086 self.blocks.push(Block {
2087 body: mem::replace(&mut self.src, body),
2088 results: mem::take(operands),
2089 element,
2090 base,
2091 });
2092 }
2093
2094 fn sizes(&self) -> &SizeAlign {
2095 &self.gen.gen.sizes
2096 }
2097
2098 fn is_list_canonical(&self, _resolve: &Resolve, element: &Type) -> bool {
2099 is_primitive(element)
2100 }
2101}
2102
2103fn int_type(int: Int) -> &'static str {
2104 match int {
2105 Int::U8 => "byte",
2106 Int::U16 => "short",
2107 Int::U32 => "int",
2108 Int::U64 => "long",
2109 }
2110}
2111
2112fn wasm_type(ty: WasmType) -> &'static str {
2113 match ty {
2114 WasmType::I32 => "int",
2115 WasmType::I64 => "long",
2116 WasmType::F32 => "float",
2117 WasmType::F64 => "double",
2118 }
2119}
2120
2121fn flags_repr(flags: &Flags) -> Int {
2122 match flags.repr() {
2123 FlagsRepr::U8 => Int::U8,
2124 FlagsRepr::U16 => Int::U16,
2125 FlagsRepr::U32(1) => Int::U32,
2126 FlagsRepr::U32(2) => Int::U64,
2127 repr => panic!("unimplemented flags {repr:?}"),
2128 }
2129}
2130
2131fn list_element_info(ty: &Type) -> (usize, &'static str) {
2132 match ty {
2133 Type::U8 | Type::S8 => (1, "byte"),
2134 Type::U16 | Type::S16 => (2, "short"),
2135 Type::U32 | Type::S32 => (4, "int"),
2136 Type::U64 | Type::S64 => (8, "long"),
2137 Type::Float32 => (4, "float"),
2138 Type::Float64 => (8, "double"),
2139 _ => unreachable!(),
2140 }
2141}
2142
2143fn indent(code: &str) -> String {
2144 let mut indented = String::with_capacity(code.len());
2145 let mut indent = 0;
2146 let mut was_empty = false;
2147 for line in code.lines() {
2148 let trimmed = line.trim();
2149 if trimmed.is_empty() {
2150 if was_empty {
2151 continue;
2152 }
2153 was_empty = true;
2154 } else {
2155 was_empty = false;
2156 }
2157
2158 if trimmed.starts_with('}') {
2159 indent -= 1;
2160 }
2161 indented.extend(iter::repeat(' ').take(indent * 4));
2162 indented.push_str(trimmed);
2163 if trimmed.ends_with('{') {
2164 indent += 1;
2165 }
2166 indented.push('\n');
2167 }
2168 indented
2169}
2170
2171fn is_primitive(ty: &Type) -> bool {
2172 matches!(
2173 ty,
2174 Type::U8
2175 | Type::S8
2176 | Type::U16
2177 | Type::S16
2178 | Type::U32
2179 | Type::S32
2180 | Type::U64
2181 | Type::S64
2182 | Type::Float32
2183 | Type::Float64
2184 )
2185}
2186
2187trait ToJavaIdent: ToOwned {
2188 fn to_java_ident(&self) -> Self::Owned;
2189}
2190
2191impl ToJavaIdent for str {
2192 fn to_java_ident(&self) -> String {
2193 match self {
2196 "abstract" | "continue" | "for" | "new" | "switch" | "assert" | "default" | "goto"
2197 | "package" | "synchronized" | "boolean" | "do" | "if" | "private" | "this"
2198 | "break" | "double" | "implements" | "protected" | "throw" | "byte" | "else"
2199 | "import" | "public" | "throws" | "case" | "enum" | "instanceof" | "return"
2200 | "transient" | "catch" | "extends" | "int" | "short" | "try" | "char" | "final"
2201 | "interface" | "static" | "void" | "class" | "finally" | "long" | "strictfp"
2202 | "volatile" | "const" | "float" | "native" | "super" | "while" => format!("{self}_"),
2203 _ => self.to_lower_camel_case(),
2204 }
2205 }
2206}