wit_bindgen_gen_guest_teavm_java/
lib.rs

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    /// Whether or not to generate a stub class for exported functions
33    #[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            // TODO: checked
1274            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            // TODO: checked
1321            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                // Note that we can only reliably use `Address.ofData` for elements with alignment <= 4 because as
1586                // of this writing TeaVM does not guarantee 64 bit items are aligned on 8 byte boundaries.
1587                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        // Escape Java keywords
2194        // Source: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html
2195        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}