1pub mod aot;
6pub mod async_exec;
7pub mod cache;
8pub mod component;
9pub mod debug;
10pub mod deterministic;
11pub mod executor;
12pub mod extensions;
13pub mod filesystem;
14pub mod host;
15pub mod jit;
16pub mod memory;
17pub mod module;
18pub mod network;
19pub mod resource;
20pub mod runtime;
21pub mod sandbox;
22pub mod security;
23pub mod system;
24pub mod validation;
25pub mod verification;
26pub mod wasi;
27pub mod wasi_debug;
28
29use thiserror::Error;
30
31#[derive(Debug, Error)]
32pub enum WasmError {
33 #[error("Compilation failed: {0}")]
34 CompilationFailed(String),
35 #[error("Execution failed: {0}")]
36 ExecutionFailed(String),
37 #[error("Invalid module: {0}")]
38 InvalidModule(String),
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44 use crate::executor::WasmExecutor;
45 use mielin_hal::capabilities::HardwareCapabilities;
46
47 #[test]
48 fn test_wasm_error_types() {
49 let err = WasmError::InvalidModule("test".to_string());
50 assert!(err.to_string().contains("Invalid module"));
51 }
52
53 #[test]
54 fn test_tensor_host_functions() {
55 let executor = WasmExecutor::with_capabilities(HardwareCapabilities::NEON).unwrap();
57
58 let wasm = wat::parse_str(
60 r#"
61 (module
62 (import "mielin" "tensor_supports_neon" (func $tensor_supports_neon (result i32)))
63 (import "mielin" "tensor_zeros" (func $tensor_zeros (param i32 i32) (result i32)))
64 (import "mielin" "tensor_free" (func $tensor_free (param i32) (result i32)))
65 (memory (export "memory") 1)
66 (func (export "_start")
67 ;; Check NEON support
68 call $tensor_supports_neon
69 drop
70
71 ;; Create a 2x2 tensor - shape is at offset 0
72 i32.const 0
73 i32.const 2
74 i32.store
75 i32.const 4
76 i32.const 2
77 i32.store
78
79 ;; Call tensor_zeros with shape pointer and length
80 i32.const 0
81 i32.const 2
82 call $tensor_zeros
83
84 ;; Free the tensor
85 call $tensor_free
86 drop
87 )
88 )
89 "#,
90 )
91 .unwrap();
92
93 let module = executor.compile_module(&wasm).unwrap();
94 let (instance, mut store) = executor
95 .instantiate(&module, HardwareCapabilities::NEON)
96 .unwrap();
97
98 let start = instance.get_func(&mut store, "_start").unwrap();
100 start.call(&mut store, &[], &mut []).unwrap();
101
102 assert!(store.data().tensor_runtime().supports_neon());
104 }
105
106 #[test]
107 fn test_tensor_operations_integration() {
108 let wasm = wat::parse_str(
110 r#"
111 (module
112 (import "mielin" "tensor_zeros" (func $tensor_zeros (param i32 i32) (result i32)))
113 (import "mielin" "tensor_ones" (func $tensor_ones (param i32 i32) (result i32)))
114 (import "mielin" "tensor_add" (func $tensor_add (param i32 i32) (result i32)))
115 (import "mielin" "tensor_free" (func $tensor_free (param i32) (result i32)))
116 (memory (export "memory") 1)
117 (func (export "_start") (local i32) (local i32) (local i32)
118 ;; Setup shape [3] at offset 0
119 i32.const 0
120 i32.const 3
121 i32.store
122
123 ;; Create zeros tensor
124 i32.const 0
125 i32.const 1
126 call $tensor_zeros
127 local.set 0
128
129 ;; Create ones tensor
130 i32.const 0
131 i32.const 1
132 call $tensor_ones
133 local.set 1
134
135 ;; Add them
136 local.get 0
137 local.get 1
138 call $tensor_add
139 local.set 2
140
141 ;; Free all tensors
142 local.get 0
143 call $tensor_free
144 drop
145 local.get 1
146 call $tensor_free
147 drop
148 local.get 2
149 call $tensor_free
150 drop
151 )
152 )
153 "#,
154 )
155 .unwrap();
156
157 let executor = WasmExecutor::new().unwrap();
158 let module = executor.compile_module(&wasm).unwrap();
159 let (instance, mut store) = executor
160 .instantiate(&module, HardwareCapabilities::NONE)
161 .unwrap();
162
163 let start = instance.get_func(&mut store, "_start").unwrap();
164 start.call(&mut store, &[], &mut []).unwrap();
165
166 let tensors = store.data().tensors().lock().unwrap();
168 assert!(tensors.is_empty());
169 }
170
171 #[test]
172 fn test_time_host_functions() {
173 let wasm = wat::parse_str(
175 r#"
176 (module
177 (import "mielin" "time_now_millis" (func $time_now_millis (result i64)))
178 (import "mielin" "time_monotonic_nanos" (func $time_monotonic_nanos (result i64)))
179 (memory (export "memory") 1)
180 (global $time1 (mut i64) (i64.const 0))
181 (global $time2 (mut i64) (i64.const 0))
182 (func (export "_start")
183 ;; Get current time in millis (should be non-zero)
184 call $time_now_millis
185 global.set $time1
186
187 ;; Get monotonic time (should be small positive)
188 call $time_monotonic_nanos
189 global.set $time2
190 )
191 (func (export "get_time1") (result i64)
192 global.get $time1
193 )
194 (func (export "get_time2") (result i64)
195 global.get $time2
196 )
197 )
198 "#,
199 )
200 .unwrap();
201
202 let executor = WasmExecutor::new().unwrap();
203 let module = executor.compile_module(&wasm).unwrap();
204 let (instance, mut store) = executor
205 .instantiate(&module, HardwareCapabilities::NONE)
206 .unwrap();
207
208 let start = instance.get_func(&mut store, "_start").unwrap();
209 start.call(&mut store, &[], &mut []).unwrap();
210
211 let get_time1 = instance
213 .get_typed_func::<(), i64>(&mut store, "get_time1")
214 .unwrap();
215 let time1 = get_time1.call(&mut store, ()).unwrap();
216 assert!(time1 > 0, "time_now_millis should return positive value");
217
218 let get_time2 = instance
219 .get_typed_func::<(), i64>(&mut store, "get_time2")
220 .unwrap();
221 let time2 = get_time2.call(&mut store, ()).unwrap();
222 assert!(
223 time2 >= 0,
224 "time_monotonic_nanos should return non-negative"
225 );
226 }
227
228 #[test]
229 fn test_random_host_functions() {
230 let wasm = wat::parse_str(
232 r#"
233 (module
234 (import "mielin" "random_u32" (func $random_u32 (result i32)))
235 (import "mielin" "random_f32" (func $random_f32 (result f32)))
236 (import "mielin" "random_bytes" (func $random_bytes (param i32 i32) (result i32)))
237 (memory (export "memory") 1)
238 (global $rand1 (mut i32) (i32.const 0))
239 (global $rand2 (mut i32) (i32.const 0))
240 (global $randf (mut f32) (f32.const 0))
241 (func (export "_start")
242 ;; Get two random u32 values
243 call $random_u32
244 global.set $rand1
245 call $random_u32
246 global.set $rand2
247
248 ;; Get random f32
249 call $random_f32
250 global.set $randf
251
252 ;; Fill 16 bytes with random data at offset 100
253 i32.const 100
254 i32.const 16
255 call $random_bytes
256 drop
257 )
258 (func (export "get_rand1") (result i32)
259 global.get $rand1
260 )
261 (func (export "get_rand2") (result i32)
262 global.get $rand2
263 )
264 (func (export "get_randf") (result f32)
265 global.get $randf
266 )
267 )
268 "#,
269 )
270 .unwrap();
271
272 let executor = WasmExecutor::new().unwrap();
273 let module = executor.compile_module(&wasm).unwrap();
274 let (instance, mut store) = executor
275 .instantiate(&module, HardwareCapabilities::NONE)
276 .unwrap();
277
278 let start = instance.get_func(&mut store, "_start").unwrap();
279 start.call(&mut store, &[], &mut []).unwrap();
280
281 let get_rand1 = instance
283 .get_typed_func::<(), i32>(&mut store, "get_rand1")
284 .unwrap();
285 let get_rand2 = instance
286 .get_typed_func::<(), i32>(&mut store, "get_rand2")
287 .unwrap();
288 let r1 = get_rand1.call(&mut store, ()).unwrap();
289 let r2 = get_rand2.call(&mut store, ()).unwrap();
290
291 assert!(
294 r1 != r2 || r1 == 0,
295 "Two random values should likely differ"
296 );
297
298 let get_randf = instance
300 .get_typed_func::<(), f32>(&mut store, "get_randf")
301 .unwrap();
302 let f = get_randf.call(&mut store, ()).unwrap();
303 assert!((0.0..1.0).contains(&f), "random_f32 should be in [0, 1)");
304 }
305
306 #[test]
307 fn test_process_host_functions() {
308 let wasm = wat::parse_str(
310 r#"
311 (module
312 (import "mielin" "process_platform" (func $process_platform (result i32)))
313 (import "mielin" "process_arch" (func $process_arch (result i32)))
314 (import "mielin" "process_cpu_count" (func $process_cpu_count (result i32)))
315 (import "mielin" "process_pointer_bits" (func $process_pointer_bits (result i32)))
316 (memory (export "memory") 1)
317 (global $platform (mut i32) (i32.const 0))
318 (global $arch (mut i32) (i32.const 0))
319 (global $cpus (mut i32) (i32.const 0))
320 (global $bits (mut i32) (i32.const 0))
321 (func (export "_start")
322 call $process_platform
323 global.set $platform
324 call $process_arch
325 global.set $arch
326 call $process_cpu_count
327 global.set $cpus
328 call $process_pointer_bits
329 global.set $bits
330 )
331 (func (export "get_platform") (result i32)
332 global.get $platform
333 )
334 (func (export "get_arch") (result i32)
335 global.get $arch
336 )
337 (func (export "get_cpus") (result i32)
338 global.get $cpus
339 )
340 (func (export "get_bits") (result i32)
341 global.get $bits
342 )
343 )
344 "#,
345 )
346 .unwrap();
347
348 let executor = WasmExecutor::new().unwrap();
349 let module = executor.compile_module(&wasm).unwrap();
350 let (instance, mut store) = executor
351 .instantiate(&module, HardwareCapabilities::NONE)
352 .unwrap();
353
354 let start = instance.get_func(&mut store, "_start").unwrap();
355 start.call(&mut store, &[], &mut []).unwrap();
356
357 let get_cpus = instance
359 .get_typed_func::<(), i32>(&mut store, "get_cpus")
360 .unwrap();
361 let cpus = get_cpus.call(&mut store, ()).unwrap();
362 assert!(cpus >= 1, "CPU count should be at least 1");
363
364 let get_bits = instance
365 .get_typed_func::<(), i32>(&mut store, "get_bits")
366 .unwrap();
367 let bits = get_bits.call(&mut store, ()).unwrap();
368 assert!(bits == 32 || bits == 64, "Pointer bits should be 32 or 64");
369 }
370}