1+ // Copyright 2025 Jonas Kruckenberg
2+ //
3+ // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4+ // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5+ // http://opensource.org/licenses/MIT>, at your option. This file may not be
6+ // copied, modified, or distributed except according to those terms.
7+
8+ //! Hello World WASM module for testing WASI integration
9+
10+ use crate :: wasm:: { Engine , Linker , Module , Store } ;
11+ use crate :: wasm:: host_funcs;
12+ use crate :: wasm:: vm:: { ConstExprEvaluator , instance_alloc:: PlaceholderAllocatorDontUse } ;
13+ use wasmparser:: Validator ;
14+ use wast:: parser:: ParseBuffer ;
15+
16+ /// The Hello World WAT module source
17+ const HELLO_WORLD_WAT : & str = r#"
18+ (module
19+ ;; Import fd_write from WASI
20+ (import "wasi_snapshot_preview1" "fd_write"
21+ (func $fd_write (param i32 i32 i32 i32) (result i32)))
22+
23+ ;; Memory with at least 1 page
24+ (memory (export "memory") 1)
25+
26+ ;; Data segment with our message
27+ (data (i32.const 8) "Hello World from WASI!\n")
28+
29+ ;; IoVec structure at offset 0
30+ ;; Points to our string at offset 8, length 23
31+ (data (i32.const 0) "\08\00\00\00\17\00\00\00")
32+
33+ ;; Start function
34+ (func $main (export "_start")
35+ ;; Call fd_write(stdout=1, iovs=0, iovs_len=1, nwritten=100)
36+ i32.const 1 ;; fd: stdout
37+ i32.const 0 ;; iovs: pointer to IoVec array
38+ i32.const 1 ;; iovs_len: we have 1 IoVec
39+ i32.const 100 ;; nwritten: where to store bytes written
40+ call $fd_write
41+ drop ;; ignore return value
42+ )
43+ )
44+ "# ;
45+
46+ /// Run the Hello World WASM module
47+ pub fn run ( ) -> Result < ( ) , & ' static str > {
48+ tracing:: debug!( "Running Hello World WASM module" ) ;
49+
50+ // Parse WAT to WASM
51+ let buf = ParseBuffer :: new ( HELLO_WORLD_WAT )
52+ . map_err ( |_| "Failed to create parse buffer" ) ?;
53+ let mut wat = wast:: parser:: parse :: < wast:: Wat > ( & buf)
54+ . map_err ( |_| "Failed to parse WAT" ) ?;
55+
56+ // Convert to WASM bytes
57+ let wasm_bytes = wat. encode ( )
58+ . map_err ( |_| "Failed to encode WAT to WASM" ) ?;
59+
60+ // Create engine
61+ let engine = Engine :: default ( ) ;
62+
63+ // Create allocator and store
64+ let alloc = & PlaceholderAllocatorDontUse as & ( dyn crate :: wasm:: vm:: InstanceAllocator + Send + Sync ) ;
65+ let mut store = Store :: new ( & engine, alloc, ( ) ) ;
66+
67+ // Create validator and module from WASM bytes
68+ let mut validator = Validator :: new ( ) ;
69+ let module = Module :: from_bytes ( & engine, & mut validator, & wasm_bytes)
70+ . map_err ( |_| "Failed to create module" ) ?;
71+
72+ // Create linker and register host functions
73+ let mut linker = Linker :: new ( & engine) ;
74+ host_funcs:: register_host_functions ( & mut linker)
75+ . map_err ( |_| "Failed to register host functions" ) ?;
76+
77+ // Create const expression evaluator
78+ let mut const_eval = ConstExprEvaluator :: default ( ) ;
79+
80+ // Instantiate module
81+ let instance = linker. instantiate ( & mut store, & mut const_eval, & module)
82+ . map_err ( |_| "Failed to instantiate module" ) ?;
83+
84+ // Get and call _start function
85+ let start = instance
86+ . get_func ( & mut store, "_start" )
87+ . ok_or ( "No _start function found" ) ?;
88+
89+ // Call the function
90+ start. call ( & mut store, & [ ] , & mut [ ] )
91+ . map_err ( |_| "Failed to call _start" ) ?;
92+
93+ tracing:: debug!( "Hello World WASM module completed successfully" ) ;
94+ Ok ( ( ) )
95+ }
0 commit comments