Skip to main content

oxilean_codegen/wasm_component_backend/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use std::collections::HashMap;
6
7use super::types::{
8    CanonicalOptions, ComponentExport, ComponentImport, ComponentInstance, CoreModule,
9    WCAnalysisCache, WCConstantFoldingHelper, WCDepGraph, WCDominatorTree, WCLivenessInfo,
10    WCPassConfig, WCPassPhase, WCPassRegistry, WCPassStats, WCWorklist, WasmCExtCache,
11    WasmCExtConstFolder, WasmCExtDepGraph, WasmCExtDomTree, WasmCExtLiveness, WasmCExtPassConfig,
12    WasmCExtPassPhase, WasmCExtPassRegistry, WasmCExtPassStats, WasmCExtWorklist,
13    WasmCompExtConfig, WasmCompExtDiagCollector, WasmCompExtDiagMsg, WasmCompExtEmitStats,
14    WasmCompExtEventLog, WasmCompExtFeatures, WasmCompExtIdGen, WasmCompExtIncrKey,
15    WasmCompExtNameScope, WasmCompExtPassTiming, WasmCompExtProfiler, WasmCompExtSourceBuffer,
16    WasmCompExtVersion, WasmComponentBackend, WasmComponentExpr, WasmComponentType, WitInterface,
17    WitResource,
18};
19
20/// Build a simple WIT interface for math operations.
21pub fn build_math_interface() -> WitInterface {
22    let mut iface = WitInterface::new("oxilean:math/", "arithmetic");
23    iface.add_type("num", WasmComponentType::F64);
24    iface.add_function(
25        "add",
26        WasmComponentType::Func(
27            vec![
28                ("a".to_string(), WasmComponentType::F64),
29                ("b".to_string(), WasmComponentType::F64),
30            ],
31            vec![("result".to_string(), WasmComponentType::F64)],
32        ),
33    );
34    iface.add_function(
35        "sqrt",
36        WasmComponentType::Func(
37            vec![("x".to_string(), WasmComponentType::F64)],
38            vec![(
39                "result".to_string(),
40                WasmComponentType::Option(Box::new(WasmComponentType::F64)),
41            )],
42        ),
43    );
44    iface
45}
46/// Build a simple WASI-like streams interface for demonstration.
47pub fn build_streams_interface() -> WitInterface {
48    let mut iface = WitInterface::new("wasi:io/", "streams");
49    iface.add_resource(
50        WitResource::new("output-stream")
51            .with_constructor(vec![])
52            .with_method(
53                "write",
54                WasmComponentType::Func(
55                    vec![(
56                        "bytes".to_string(),
57                        WasmComponentType::List(Box::new(WasmComponentType::U8)),
58                    )],
59                    vec![(
60                        "result".to_string(),
61                        WasmComponentType::Result(
62                            Box::new(None),
63                            Box::new(Some(WasmComponentType::TypeRef("stream-error".to_string()))),
64                        ),
65                    )],
66                ),
67            ),
68    );
69    iface.add_type(
70        "stream-error",
71        WasmComponentType::Variant(vec![
72            ("last-operation-failed".to_string(), None),
73            ("closed".to_string(), None),
74        ]),
75    );
76    iface
77}
78#[cfg(test)]
79mod tests {
80    use super::*;
81    #[test]
82    pub(super) fn test_component_type_display_primitives() {
83        assert_eq!(WasmComponentType::Bool.to_string(), "bool");
84        assert_eq!(WasmComponentType::U32.to_string(), "u32");
85        assert_eq!(WasmComponentType::S64.to_string(), "s64");
86        assert_eq!(WasmComponentType::F32.to_string(), "f32");
87        assert_eq!(WasmComponentType::String.to_string(), "string");
88        assert_eq!(WasmComponentType::Char.to_string(), "char");
89    }
90    #[test]
91    pub(super) fn test_component_type_display_compound() {
92        let list_ty = WasmComponentType::List(Box::new(WasmComponentType::U8));
93        assert_eq!(list_ty.to_string(), "list<u8>");
94        let opt_ty = WasmComponentType::Option(Box::new(WasmComponentType::String));
95        assert_eq!(opt_ty.to_string(), "option<string>");
96        let res_ty = WasmComponentType::Result(
97            Box::new(Some(WasmComponentType::U32)),
98            Box::new(Some(WasmComponentType::String)),
99        );
100        assert_eq!(res_ty.to_string(), "result<u32, string>");
101        let result_no_err =
102            WasmComponentType::Result(Box::new(Some(WasmComponentType::Bool)), Box::new(None));
103        assert_eq!(result_no_err.to_string(), "result<bool>");
104    }
105    #[test]
106    pub(super) fn test_component_type_display_record() {
107        let record = WasmComponentType::Record(vec![
108            ("x".to_string(), WasmComponentType::F32),
109            ("y".to_string(), WasmComponentType::F32),
110        ]);
111        let s = record.to_string();
112        assert!(s.starts_with("record {"));
113        assert!(s.contains("x: f32"));
114        assert!(s.contains("y: f32"));
115    }
116    #[test]
117    pub(super) fn test_component_type_display_variant() {
118        let variant = WasmComponentType::Variant(vec![
119            ("none".to_string(), None),
120            ("some".to_string(), Some(WasmComponentType::U32)),
121        ]);
122        let s = variant.to_string();
123        assert!(s.starts_with("variant {"));
124        assert!(s.contains("none"));
125        assert!(s.contains("some(u32)"));
126    }
127    #[test]
128    pub(super) fn test_component_type_display_enum_flags() {
129        let enum_ty = WasmComponentType::Enum(vec![
130            "red".to_string(),
131            "green".to_string(),
132            "blue".to_string(),
133        ]);
134        let s = enum_ty.to_string();
135        assert!(s.contains("red"));
136        assert!(s.contains("green"));
137        let flags_ty = WasmComponentType::Flags(vec![
138            "read".to_string(),
139            "write".to_string(),
140            "exec".to_string(),
141        ]);
142        let fs = flags_ty.to_string();
143        assert!(fs.contains("read"));
144        assert!(fs.contains("write"));
145    }
146    #[test]
147    pub(super) fn test_component_export_emit() {
148        let export = ComponentExport::func("my-func", "my_func_impl");
149        let s = export.emit();
150        assert!(s.contains("my-func"));
151        assert!(s.contains("func"));
152        assert!(s.contains("my_func_impl"));
153    }
154    #[test]
155    pub(super) fn test_component_instance_construction() {
156        let mut inst = ComponentInstance::new("my-component");
157        assert_eq!(inst.export_count(), 0);
158        assert_eq!(inst.import_count(), 0);
159        inst.add_export(ComponentExport::func("greet", "greet_impl"));
160        inst.add_import(ComponentImport::func(
161            "wasi:io/",
162            "write",
163            vec![(
164                "data".to_string(),
165                WasmComponentType::List(Box::new(WasmComponentType::U8)),
166            )],
167            vec![],
168        ));
169        assert_eq!(inst.export_count(), 1);
170        assert_eq!(inst.import_count(), 1);
171    }
172    #[test]
173    pub(super) fn test_wit_interface_emit() {
174        let mut iface = WitInterface::new("oxilean:core/", "types");
175        iface.add_type("idx", WasmComponentType::U32);
176        iface.add_function(
177            "identity",
178            WasmComponentType::Func(
179                vec![("x".to_string(), WasmComponentType::U32)],
180                vec![("result".to_string(), WasmComponentType::U32)],
181            ),
182        );
183        let wit = iface.emit_wit();
184        assert!(wit.contains("interface types {"));
185        assert!(wit.contains("type idx = u32"));
186        assert!(wit.contains("identity:"));
187        assert!(wit.contains("func(x: u32)"));
188    }
189    #[test]
190    pub(super) fn test_backend_emit_component_wat() {
191        let mut backend = WasmComponentBackend::new("my-app");
192        backend.define_type("size", WasmComponentType::U64);
193        backend.add_export(ComponentExport::func("run", "run_impl"));
194        let wat = backend.emit_component_wat();
195        assert!(wat.contains("(component $my-app"));
196        assert!(wat.contains("$size"));
197        assert!(wat.contains("run"));
198    }
199    #[test]
200    pub(super) fn test_backend_wit_package() {
201        let mut backend = WasmComponentBackend::new("math-lib");
202        backend.add_interface(build_math_interface());
203        let pkg = backend.emit_wit_package("oxilean:math", Some("0.1.0"));
204        assert!(pkg.contains("package oxilean:math@0.1.0"));
205        assert!(pkg.contains("interface arithmetic {"));
206        assert!(pkg.contains("type num = f64"));
207    }
208    #[test]
209    pub(super) fn test_core_module_inline() {
210        let module =
211            CoreModule::inline_text("core", "(module (func $add (param i32 i32) (result i32)))");
212        let s = module.emit();
213        assert!(s.contains("(core module $core"));
214        assert!(s.contains("func $add"));
215    }
216    #[test]
217    pub(super) fn test_canonical_options_emit() {
218        let opts = CanonicalOptions::with_memory_and_realloc("$mem", "$realloc");
219        let s = opts.emit();
220        assert!(s.contains("(memory $mem)"));
221        assert!(s.contains("(realloc $realloc)"));
222    }
223    #[test]
224    pub(super) fn test_wit_resource_emit() {
225        let resource = WitResource::new("connection")
226            .with_constructor(vec![
227                ("host".to_string(), WasmComponentType::String),
228                ("port".to_string(), WasmComponentType::U16),
229            ])
230            .with_method(
231                "send",
232                WasmComponentType::Func(
233                    vec![(
234                        "data".to_string(),
235                        WasmComponentType::List(Box::new(WasmComponentType::U8)),
236                    )],
237                    vec![(
238                        "n".to_string(),
239                        WasmComponentType::Result(
240                            Box::new(Some(WasmComponentType::U32)),
241                            Box::new(None),
242                        ),
243                    )],
244                ),
245            );
246        let s = resource.emit_wit();
247        assert!(s.contains("resource connection {"));
248        assert!(s.contains("constructor(host: string, port: u16)"));
249        assert!(s.contains("send:"));
250    }
251    #[test]
252    pub(super) fn test_component_expr_display() {
253        let expr = WasmComponentExpr::Call {
254            instance: "wasi-io".to_string(),
255            func: "write".to_string(),
256            args: vec![
257                WasmComponentExpr::Var("buf".to_string()),
258                WasmComponentExpr::IntLit(1024),
259            ],
260        };
261        let s = expr.to_string();
262        assert!(s.contains("wasi-io.write"));
263        assert!(s.contains("buf"));
264        assert!(s.contains("1024"));
265        let some_expr = WasmComponentExpr::OptionSome(Box::new(WasmComponentExpr::BoolLit(true)));
266        assert_eq!(some_expr.to_string(), "(some true)");
267        let none_expr = WasmComponentExpr::OptionNone;
268        assert_eq!(none_expr.to_string(), "none");
269    }
270    #[test]
271    pub(super) fn test_streams_interface() {
272        let iface = build_streams_interface();
273        let wit = iface.emit_wit();
274        assert!(wit.contains("interface streams {"));
275        assert!(wit.contains("resource output-stream {"));
276        assert!(wit.contains("stream-error"));
277    }
278    #[test]
279    pub(super) fn test_backend_add_lifted_func() {
280        let mut backend = WasmComponentBackend::new("compute");
281        backend.set_canonical_opts("$memory", "$realloc");
282        backend.add_lifted_func(
283            "compute-sum",
284            "core_compute_sum",
285            vec![
286                ("a".to_string(), WasmComponentType::S64),
287                ("b".to_string(), WasmComponentType::S64),
288            ],
289            vec![("result".to_string(), WasmComponentType::S64)],
290        );
291        assert_eq!(backend.func_count(), 1);
292        let wat = backend.emit_component_wat();
293        assert!(wat.contains("canon lift"));
294        assert!(wat.contains("core_compute_sum"));
295    }
296}
297#[cfg(test)]
298mod tests_wasm_comp_ext_extra {
299    use super::*;
300    #[test]
301    pub(super) fn test_wasm_comp_ext_config() {
302        let mut cfg = WasmCompExtConfig::new();
303        cfg.set("mode", "release");
304        cfg.set("verbose", "true");
305        assert_eq!(cfg.get("mode"), Some("release"));
306        assert!(cfg.get_bool("verbose"));
307        assert!(cfg.get_int("mode").is_none());
308        assert_eq!(cfg.len(), 2);
309    }
310    #[test]
311    pub(super) fn test_wasm_comp_ext_source_buffer() {
312        let mut buf = WasmCompExtSourceBuffer::new();
313        buf.push_line("fn main() {");
314        buf.indent();
315        buf.push_line("println!(\"hello\");");
316        buf.dedent();
317        buf.push_line("}");
318        assert!(buf.as_str().contains("fn main()"));
319        assert!(buf.as_str().contains("    println!"));
320        assert_eq!(buf.line_count(), 3);
321        buf.reset();
322        assert!(buf.is_empty());
323    }
324    #[test]
325    pub(super) fn test_wasm_comp_ext_name_scope() {
326        let mut scope = WasmCompExtNameScope::new();
327        assert!(scope.declare("x"));
328        assert!(!scope.declare("x"));
329        assert!(scope.is_declared("x"));
330        let scope = scope.push_scope();
331        assert_eq!(scope.depth(), 1);
332        let mut scope = scope.pop_scope();
333        assert_eq!(scope.depth(), 0);
334        scope.declare("y");
335        assert_eq!(scope.len(), 2);
336    }
337    #[test]
338    pub(super) fn test_wasm_comp_ext_diag_collector() {
339        let mut col = WasmCompExtDiagCollector::new();
340        col.emit(WasmCompExtDiagMsg::warning("pass_a", "slow"));
341        col.emit(WasmCompExtDiagMsg::error("pass_b", "fatal"));
342        assert!(col.has_errors());
343        assert_eq!(col.errors().len(), 1);
344        assert_eq!(col.warnings().len(), 1);
345        col.clear();
346        assert!(col.is_empty());
347    }
348    #[test]
349    pub(super) fn test_wasm_comp_ext_id_gen() {
350        let mut gen = WasmCompExtIdGen::new();
351        assert_eq!(gen.next_id(), 0);
352        assert_eq!(gen.next_id(), 1);
353        gen.skip(10);
354        assert_eq!(gen.next_id(), 12);
355        gen.reset();
356        assert_eq!(gen.peek_next(), 0);
357    }
358    #[test]
359    pub(super) fn test_wasm_comp_ext_incr_key() {
360        let k1 = WasmCompExtIncrKey::new(100, 200);
361        let k2 = WasmCompExtIncrKey::new(100, 200);
362        let k3 = WasmCompExtIncrKey::new(999, 200);
363        assert!(k1.matches(&k2));
364        assert!(!k1.matches(&k3));
365    }
366    #[test]
367    pub(super) fn test_wasm_comp_ext_profiler() {
368        let mut p = WasmCompExtProfiler::new();
369        p.record(WasmCompExtPassTiming::new("pass_a", 1000, 50, 200, 100));
370        p.record(WasmCompExtPassTiming::new("pass_b", 500, 30, 100, 200));
371        assert_eq!(p.total_elapsed_us(), 1500);
372        assert_eq!(
373            p.slowest_pass()
374                .expect("slowest pass should exist")
375                .pass_name,
376            "pass_a"
377        );
378        assert_eq!(p.profitable_passes().len(), 1);
379    }
380    #[test]
381    pub(super) fn test_wasm_comp_ext_event_log() {
382        let mut log = WasmCompExtEventLog::new(3);
383        log.push("event1");
384        log.push("event2");
385        log.push("event3");
386        assert_eq!(log.len(), 3);
387        log.push("event4");
388        assert_eq!(log.len(), 3);
389        assert_eq!(
390            log.iter()
391                .next()
392                .expect("iterator should have next element"),
393            "event2"
394        );
395    }
396    #[test]
397    pub(super) fn test_wasm_comp_ext_version() {
398        let v = WasmCompExtVersion::new(1, 2, 3).with_pre("alpha");
399        assert!(!v.is_stable());
400        assert_eq!(format!("{}", v), "1.2.3-alpha");
401        let stable = WasmCompExtVersion::new(2, 0, 0);
402        assert!(stable.is_stable());
403        assert!(stable.is_compatible_with(&WasmCompExtVersion::new(2, 0, 0)));
404        assert!(!stable.is_compatible_with(&WasmCompExtVersion::new(3, 0, 0)));
405    }
406    #[test]
407    pub(super) fn test_wasm_comp_ext_features() {
408        let mut f = WasmCompExtFeatures::new();
409        f.enable("sse2");
410        f.enable("avx2");
411        assert!(f.is_enabled("sse2"));
412        assert!(!f.is_enabled("avx512"));
413        f.disable("avx2");
414        assert!(!f.is_enabled("avx2"));
415        let mut g = WasmCompExtFeatures::new();
416        g.enable("sse2");
417        g.enable("neon");
418        let union = f.union(&g);
419        assert!(union.is_enabled("sse2") && union.is_enabled("neon"));
420        let inter = f.intersection(&g);
421        assert!(inter.is_enabled("sse2"));
422    }
423    #[test]
424    pub(super) fn test_wasm_comp_ext_emit_stats() {
425        let mut s = WasmCompExtEmitStats::new();
426        s.bytes_emitted = 50_000;
427        s.items_emitted = 500;
428        s.elapsed_ms = 100;
429        assert!(s.is_clean());
430        assert!((s.throughput_bps() - 500_000.0).abs() < 1.0);
431        let disp = format!("{}", s);
432        assert!(disp.contains("bytes=50000"));
433    }
434}
435#[cfg(test)]
436mod WC_infra_tests {
437    use super::*;
438    #[test]
439    pub(super) fn test_pass_config() {
440        let config = WCPassConfig::new("test_pass", WCPassPhase::Transformation);
441        assert!(config.enabled);
442        assert!(config.phase.is_modifying());
443        assert_eq!(config.phase.name(), "transformation");
444    }
445    #[test]
446    pub(super) fn test_pass_stats() {
447        let mut stats = WCPassStats::new();
448        stats.record_run(10, 100, 3);
449        stats.record_run(20, 200, 5);
450        assert_eq!(stats.total_runs, 2);
451        assert!((stats.average_changes_per_run() - 15.0).abs() < 0.01);
452        assert!((stats.success_rate() - 1.0).abs() < 0.01);
453        let s = stats.format_summary();
454        assert!(s.contains("Runs: 2/2"));
455    }
456    #[test]
457    pub(super) fn test_pass_registry() {
458        let mut reg = WCPassRegistry::new();
459        reg.register(WCPassConfig::new("pass_a", WCPassPhase::Analysis));
460        reg.register(WCPassConfig::new("pass_b", WCPassPhase::Transformation).disabled());
461        assert_eq!(reg.total_passes(), 2);
462        assert_eq!(reg.enabled_count(), 1);
463        reg.update_stats("pass_a", 5, 50, 2);
464        let stats = reg.get_stats("pass_a").expect("stats should exist");
465        assert_eq!(stats.total_changes, 5);
466    }
467    #[test]
468    pub(super) fn test_analysis_cache() {
469        let mut cache = WCAnalysisCache::new(10);
470        cache.insert("key1".to_string(), vec![1, 2, 3]);
471        assert!(cache.get("key1").is_some());
472        assert!(cache.get("key2").is_none());
473        assert!((cache.hit_rate() - 0.5).abs() < 0.01);
474        cache.invalidate("key1");
475        assert!(!cache.entries["key1"].valid);
476        assert_eq!(cache.size(), 1);
477    }
478    #[test]
479    pub(super) fn test_worklist() {
480        let mut wl = WCWorklist::new();
481        assert!(wl.push(1));
482        assert!(wl.push(2));
483        assert!(!wl.push(1));
484        assert_eq!(wl.len(), 2);
485        assert_eq!(wl.pop(), Some(1));
486        assert!(!wl.contains(1));
487        assert!(wl.contains(2));
488    }
489    #[test]
490    pub(super) fn test_dominator_tree() {
491        let mut dt = WCDominatorTree::new(5);
492        dt.set_idom(1, 0);
493        dt.set_idom(2, 0);
494        dt.set_idom(3, 1);
495        assert!(dt.dominates(0, 3));
496        assert!(dt.dominates(1, 3));
497        assert!(!dt.dominates(2, 3));
498        assert!(dt.dominates(3, 3));
499    }
500    #[test]
501    pub(super) fn test_liveness() {
502        let mut liveness = WCLivenessInfo::new(3);
503        liveness.add_def(0, 1);
504        liveness.add_use(1, 1);
505        assert!(liveness.defs[0].contains(&1));
506        assert!(liveness.uses[1].contains(&1));
507    }
508    #[test]
509    pub(super) fn test_constant_folding() {
510        assert_eq!(WCConstantFoldingHelper::fold_add_i64(3, 4), Some(7));
511        assert_eq!(WCConstantFoldingHelper::fold_div_i64(10, 0), None);
512        assert_eq!(WCConstantFoldingHelper::fold_div_i64(10, 2), Some(5));
513        assert_eq!(
514            WCConstantFoldingHelper::fold_bitand_i64(0b1100, 0b1010),
515            0b1000
516        );
517        assert_eq!(WCConstantFoldingHelper::fold_bitnot_i64(0), -1);
518    }
519    #[test]
520    pub(super) fn test_dep_graph() {
521        let mut g = WCDepGraph::new();
522        g.add_dep(1, 2);
523        g.add_dep(2, 3);
524        g.add_dep(1, 3);
525        assert_eq!(g.dependencies_of(2), vec![1]);
526        let topo = g.topological_sort();
527        assert_eq!(topo.len(), 3);
528        assert!(!g.has_cycle());
529        let pos: std::collections::HashMap<u32, usize> =
530            topo.iter().enumerate().map(|(i, &n)| (n, i)).collect();
531        assert!(pos[&1] < pos[&2]);
532        assert!(pos[&1] < pos[&3]);
533        assert!(pos[&2] < pos[&3]);
534    }
535}
536#[cfg(test)]
537mod wasmcext_pass_tests {
538    use super::*;
539    #[test]
540    pub(super) fn test_wasmcext_phase_order() {
541        assert_eq!(WasmCExtPassPhase::Early.order(), 0);
542        assert_eq!(WasmCExtPassPhase::Middle.order(), 1);
543        assert_eq!(WasmCExtPassPhase::Late.order(), 2);
544        assert_eq!(WasmCExtPassPhase::Finalize.order(), 3);
545        assert!(WasmCExtPassPhase::Early.is_early());
546        assert!(!WasmCExtPassPhase::Early.is_late());
547    }
548    #[test]
549    pub(super) fn test_wasmcext_config_builder() {
550        let c = WasmCExtPassConfig::new("p")
551            .with_phase(WasmCExtPassPhase::Late)
552            .with_max_iter(50)
553            .with_debug(1);
554        assert_eq!(c.name, "p");
555        assert_eq!(c.max_iterations, 50);
556        assert!(c.is_debug_enabled());
557        assert!(c.enabled);
558        let c2 = c.disabled();
559        assert!(!c2.enabled);
560    }
561    #[test]
562    pub(super) fn test_wasmcext_stats() {
563        let mut s = WasmCExtPassStats::new();
564        s.visit();
565        s.visit();
566        s.modify();
567        s.iterate();
568        assert_eq!(s.nodes_visited, 2);
569        assert_eq!(s.nodes_modified, 1);
570        assert!(s.changed);
571        assert_eq!(s.iterations, 1);
572        let e = s.efficiency();
573        assert!((e - 0.5).abs() < 1e-9);
574    }
575    #[test]
576    pub(super) fn test_wasmcext_registry() {
577        let mut r = WasmCExtPassRegistry::new();
578        r.register(WasmCExtPassConfig::new("a").with_phase(WasmCExtPassPhase::Early));
579        r.register(WasmCExtPassConfig::new("b").disabled());
580        assert_eq!(r.len(), 2);
581        assert_eq!(r.enabled_passes().len(), 1);
582        assert_eq!(r.passes_in_phase(&WasmCExtPassPhase::Early).len(), 1);
583    }
584    #[test]
585    pub(super) fn test_wasmcext_cache() {
586        let mut c = WasmCExtCache::new(4);
587        assert!(c.get(99).is_none());
588        c.put(99, vec![1, 2, 3]);
589        let v = c.get(99).expect("v should be present in map");
590        assert_eq!(v, &[1u8, 2, 3]);
591        assert!(c.hit_rate() > 0.0);
592        assert_eq!(c.live_count(), 1);
593    }
594    #[test]
595    pub(super) fn test_wasmcext_worklist() {
596        let mut w = WasmCExtWorklist::new(10);
597        w.push(5);
598        w.push(3);
599        w.push(5);
600        assert_eq!(w.len(), 2);
601        assert!(w.contains(5));
602        let first = w.pop().expect("first should be available to pop");
603        assert!(!w.contains(first));
604    }
605    #[test]
606    pub(super) fn test_wasmcext_dom_tree() {
607        let mut dt = WasmCExtDomTree::new(5);
608        dt.set_idom(1, 0);
609        dt.set_idom(2, 0);
610        dt.set_idom(3, 1);
611        dt.set_idom(4, 1);
612        assert!(dt.dominates(0, 3));
613        assert!(dt.dominates(1, 4));
614        assert!(!dt.dominates(2, 3));
615        assert_eq!(dt.depth_of(3), 2);
616    }
617    #[test]
618    pub(super) fn test_wasmcext_liveness() {
619        let mut lv = WasmCExtLiveness::new(3);
620        lv.add_def(0, 1);
621        lv.add_use(1, 1);
622        assert!(lv.var_is_def_in_block(0, 1));
623        assert!(lv.var_is_used_in_block(1, 1));
624        assert!(!lv.var_is_def_in_block(1, 1));
625    }
626    #[test]
627    pub(super) fn test_wasmcext_const_folder() {
628        let mut cf = WasmCExtConstFolder::new();
629        assert_eq!(cf.add_i64(3, 4), Some(7));
630        assert_eq!(cf.div_i64(10, 0), None);
631        assert_eq!(cf.mul_i64(6, 7), Some(42));
632        assert_eq!(cf.and_i64(0b1100, 0b1010), 0b1000);
633        assert_eq!(cf.fold_count(), 3);
634        assert_eq!(cf.failure_count(), 1);
635    }
636    #[test]
637    pub(super) fn test_wasmcext_dep_graph() {
638        let mut g = WasmCExtDepGraph::new(4);
639        g.add_edge(0, 1);
640        g.add_edge(1, 2);
641        g.add_edge(2, 3);
642        assert!(!g.has_cycle());
643        assert_eq!(g.topo_sort(), Some(vec![0, 1, 2, 3]));
644        assert_eq!(g.reachable(0).len(), 4);
645        let sccs = g.scc();
646        assert_eq!(sccs.len(), 4);
647    }
648}