xref: /wasmtime-44.0.1/tests/all/module.rs (revision dfd68853)
1 use anyhow::Result;
2 use wasmtime::*;
3 
4 #[test]
5 fn checks_incompatible_target() -> Result<()> {
6     let mut target = target_lexicon::Triple::host();
7     target.operating_system = target_lexicon::OperatingSystem::Unknown;
8     match Module::new(
9         &Engine::new(Config::new().target(&target.to_string())?)?,
10         "(module)",
11     ) {
12         Ok(_) => unreachable!(),
13         Err(e) => assert!(
14             format!("{:?}", e).contains("configuration does not match the host"),
15             "bad error: {:?}",
16             e
17         ),
18     }
19 
20     Ok(())
21 }
22 
23 #[test]
24 fn caches_across_engines() {
25     let c = Config::new();
26 
27     let bytes = Module::new(&Engine::new(&c).unwrap(), "(module)")
28         .unwrap()
29         .serialize()
30         .unwrap();
31 
32     unsafe {
33         let res = Module::deserialize(&Engine::default(), &bytes);
34         assert!(res.is_ok());
35 
36         // differ in runtime settings
37         let res = Module::deserialize(
38             &Engine::new(Config::new().static_memory_maximum_size(0)).unwrap(),
39             &bytes,
40         );
41         assert!(res.is_err());
42 
43         // differ in wasm features enabled (which can affect
44         // runtime/compilation settings)
45         let res = Module::deserialize(
46             &Engine::new(Config::new().wasm_simd(false)).unwrap(),
47             &bytes,
48         );
49         assert!(res.is_err());
50     }
51 }
52 
53 #[test]
54 #[cfg_attr(miri, ignore)]
55 fn aot_compiles() -> Result<()> {
56     let engine = Engine::default();
57     let bytes = engine.precompile_module(
58         "(module (func (export \"f\") (param i32) (result i32) local.get 0))".as_bytes(),
59     )?;
60 
61     let module = unsafe { Module::deserialize(&engine, &bytes)? };
62 
63     let mut store = Store::new(&engine, ());
64     let instance = Instance::new(&mut store, &module, &[])?;
65 
66     let f = instance.get_typed_func::<i32, i32>(&mut store, "f")?;
67     assert_eq!(f.call(&mut store, 101)?, 101);
68 
69     Ok(())
70 }
71 
72 #[test]
73 #[cfg_attr(miri, ignore)]
74 fn serialize_deterministic() {
75     let engine = Engine::default();
76 
77     let assert_deterministic = |wasm: &str| {
78         let p1 = engine.precompile_module(wasm.as_bytes()).unwrap();
79         let p2 = engine.precompile_module(wasm.as_bytes()).unwrap();
80         if p1 != p2 {
81             panic!("precompile_module not deterministic for:\n{}", wasm);
82         }
83 
84         let module1 = Module::new(&engine, wasm).unwrap();
85         let a1 = module1.serialize().unwrap();
86         let a2 = module1.serialize().unwrap();
87         if a1 != a2 {
88             panic!("Module::serialize not deterministic for:\n{}", wasm);
89         }
90 
91         let module2 = Module::new(&engine, wasm).unwrap();
92         let b1 = module2.serialize().unwrap();
93         let b2 = module2.serialize().unwrap();
94         if b1 != b2 {
95             panic!("Module::serialize not deterministic for:\n{}", wasm);
96         }
97 
98         if a1 != b2 {
99             panic!("not matching across modules:\n{}", wasm);
100         }
101         if b1 != p2 {
102             panic!("not matching across engine/module:\n{}", wasm);
103         }
104     };
105 
106     assert_deterministic("(module)");
107     assert_deterministic("(module (func))");
108     assert_deterministic("(module (func nop))");
109     assert_deterministic("(module (func) (func (param i32)))");
110     assert_deterministic("(module (func (export \"f\")) (func (export \"y\")))");
111     assert_deterministic("(module (func $f) (func $g))");
112     assert_deterministic("(module (data \"\") (data \"\"))");
113     assert_deterministic("(module (elem func) (elem func))");
114 }
115 
116 // This test asserts that the optimization to transform separate data segments
117 // into an initialization image doesn't unnecessarily create a massive module by
118 // accident with a very large initialization image in it.
119 #[test]
120 fn serialize_not_overly_massive() -> Result<()> {
121     let mut config = Config::new();
122     config.memory_guaranteed_dense_image_size(1 << 20);
123     let engine = Engine::new(&config)?;
124 
125     let assert_smaller_than_1mb = |module: &str| -> Result<()> {
126         println!("{}", module);
127         let bytes = Module::new(&engine, module)?.serialize()?;
128         assert!(bytes.len() < (1 << 20));
129         Ok(())
130     };
131 
132     // Tons of space between data segments should use sparse initialization,
133     // along with various permutations of empty and nonempty segments.
134     assert_smaller_than_1mb(
135         r#"(module
136             (memory 20000)
137             (data (i32.const 0) "a")
138             (data (i32.const 0x200000) "b")
139         )"#,
140     )?;
141     assert_smaller_than_1mb(
142         r#"(module
143             (memory 20000)
144             (data (i32.const 0) "a")
145             (data (i32.const 0x200000) "")
146         )"#,
147     )?;
148     assert_smaller_than_1mb(
149         r#"(module
150             (memory 20000)
151             (data (i32.const 0) "")
152             (data (i32.const 0x200000) "b")
153         )"#,
154     )?;
155     assert_smaller_than_1mb(
156         r#"(module
157             (memory 20000)
158             (data (i32.const 0) "")
159             (data (i32.const 0x200000) "")
160         )"#,
161     )?;
162 
163     // lone data segment
164     assert_smaller_than_1mb(
165         r#"(module
166             (memory 20000)
167             (data (i32.const 0x200000) "b")
168         )"#,
169     )?;
170 
171     Ok(())
172 }
173 
174 // This test specifically disables SSE4.1 in Cranelift which force wasm
175 // instructions like `f32.ceil` to go through libcalls instead of using native
176 // instructions. Note that SIMD is also disabled here because SIMD otherwise
177 // requires SSE4.1 to be enabled.
178 //
179 // This test then also tests that loading modules through various means, e.g.
180 // through precompiled artifacts, all works.
181 #[test]
182 #[cfg_attr(any(not(target_arch = "x86_64"), miri), ignore)]
183 fn missing_sse_and_floats_still_works() -> Result<()> {
184     let mut config = Config::new();
185     config.wasm_simd(false);
186     unsafe {
187         config.cranelift_flag_set("has_sse41", "false");
188     }
189     let engine = Engine::new(&config)?;
190     let module = Module::new(
191         &engine,
192         r#"
193             (module
194                 (func (export "f32.ceil") (param f32) (result f32)
195                     local.get 0
196                     f32.ceil)
197             )
198         "#,
199     )?;
200     let bytes = module.serialize()?;
201     let module2 = unsafe { Module::deserialize(&engine, &bytes)? };
202     let tmpdir = tempfile::TempDir::new()?;
203     let path = tmpdir.path().join("module.cwasm");
204     std::fs::write(&path, &bytes)?;
205     let module3 = unsafe { Module::deserialize_file(&engine, &path)? };
206 
207     for module in [module, module2, module3] {
208         let mut store = Store::new(&engine, ());
209         let instance = Instance::new(&mut store, &module, &[])?;
210         let ceil = instance.get_typed_func::<f32, f32>(&mut store, "f32.ceil")?;
211 
212         for f in [1.0, 2.3, -1.3] {
213             assert_eq!(ceil.call(&mut store, f)?, f.ceil());
214         }
215     }
216 
217     Ok(())
218 }
219