/*! * WASM Backend - Phase 8 Implementation * * Converts MIR instructions to WebAssembly for sandboxed execution * Targets browser execution and wasmtime runtime */ mod codegen; mod memory; mod runtime; // mod executor; // TODO: Fix WASM executor build errors pub use codegen::{WasmCodegen, WasmModule}; pub use memory::{BoxLayout, MemoryManager}; pub use runtime::RuntimeImports; // pub use executor::WasmExecutor; // TODO: Fix WASM executor build errors use crate::mir::MirModule; /// WASM compilation error #[derive(Debug)] pub enum WasmError { CodegenError(String), MemoryError(String), UnsupportedInstruction(String), WasmValidationError(String), IOError(String), } impl std::fmt::Display for WasmError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { WasmError::CodegenError(msg) => write!(f, "Codegen error: {}", msg), WasmError::MemoryError(msg) => write!(f, "Memory error: {}", msg), WasmError::UnsupportedInstruction(msg) => write!(f, "Unsupported instruction: {}", msg), WasmError::WasmValidationError(msg) => write!(f, "WASM validation error: {}", msg), WasmError::IOError(msg) => write!(f, "IO error: {}", msg), } } } impl std::error::Error for WasmError {} /// Main WASM backend compiler pub struct WasmBackend { codegen: WasmCodegen, memory_manager: MemoryManager, runtime: RuntimeImports, } impl WasmBackend { /// Create a new WASM backend pub fn new() -> Self { Self { codegen: WasmCodegen::new(), memory_manager: MemoryManager::new(), runtime: RuntimeImports::new(), } } /// Compile MIR module to WASM bytes pub fn compile_module(&mut self, mir_module: MirModule) -> Result, WasmError> { // Generate WAT (WebAssembly Text) first for debugging let wat_text = self.compile_to_wat(mir_module)?; // Phase 9.77 Task 1.3: Fix UTF-8 encoding error in WATβ†’WASM conversion self.wat_to_wasm(&wat_text) } /// Convert WAT text to WASM binary with proper UTF-8 handling fn wat_to_wasm(&self, wat_source: &str) -> Result, WasmError> { // Debug: Print WAT source for analysis eprintln!("πŸ” WAT Source Debug (length: {}):", wat_source.len()); eprintln!("WAT Content:\n{}", wat_source); // UTF-8 validation to prevent encoding errors if !wat_source.is_ascii() { eprintln!("❌ WAT source contains non-ASCII characters"); return Err(WasmError::WasmValidationError( "WAT source contains non-ASCII characters".to_string(), )); } eprintln!("βœ… WAT source is ASCII-compatible"); // Convert to bytes as required by wabt::wat2wasm eprintln!("πŸ”„ Converting WAT to WASM bytes..."); let wasm_bytes = wabt::wat2wasm(wat_source.as_bytes()).map_err(|e| { eprintln!("❌ wabt::wat2wasm failed: {}", e); WasmError::WasmValidationError(format!("WAT to WASM conversion failed: {}", e)) })?; eprintln!( "βœ… WASM conversion successful, {} bytes generated", wasm_bytes.len() ); Ok(wasm_bytes) } /// Compile MIR module to WAT text format (for debugging) pub fn compile_to_wat(&mut self, mir_module: MirModule) -> Result { let wasm_module = self.codegen .generate_module(mir_module, &self.memory_manager, &self.runtime)?; Ok(wasm_module.to_wat()) } /// Execute WASM bytes using wasmtime (for testing) pub fn execute_wasm(&self, wasm_bytes: &[u8]) -> Result { let engine = wasmtime::Engine::default(); let module = wasmtime::Module::new(&engine, wasm_bytes).map_err(|e| { WasmError::WasmValidationError(format!("Module creation failed: {}", e)) })?; let mut store = wasmtime::Store::new(&engine, ()); // Create print function import let print_func = wasmtime::Func::wrap(&mut store, |value: i32| { println!("{}", value); }); // Create print_str function import for string debugging let print_str_func = wasmtime::Func::wrap( &mut store, |mut caller: wasmtime::Caller<'_, ()>, ptr: i32, len: i32| -> Result<(), wasmtime::Error> { let memory = caller .get_export("memory") .and_then(|export| export.into_memory()) .ok_or_else(|| wasmtime::Error::msg("Memory export not found"))?; let data = memory.data(&caller); let start = ptr as usize; let end = start + len as usize; if end <= data.len() { let bytes = &data[start..end]; if let Ok(s) = std::str::from_utf8(bytes) { println!("String: {}", s); } else { println!("Invalid UTF-8 bytes: {:?}", bytes); } } else { println!( "String out of bounds: ptr={}, len={}, memory_size={}", ptr, len, data.len() ); } Ok(()) }, ); let imports = [print_func.into(), print_str_func.into()]; let instance = wasmtime::Instance::new(&mut store, &module, &imports).map_err(|e| { WasmError::WasmValidationError(format!("Instance creation failed: {}", e)) })?; // Call main function let main_func = instance .get_typed_func::<(), i32>(&mut store, "main") .map_err(|e| { WasmError::WasmValidationError(format!("Main function not found: {}", e)) })?; let result = main_func .call(&mut store, ()) .map_err(|e| WasmError::WasmValidationError(format!("Execution failed: {}", e)))?; Ok(result) } } impl Default for WasmBackend { fn default() -> Self { Self::new() } } #[cfg(test)] mod tests { use super::*; use crate::mir::MirModule; #[test] fn test_backend_creation() { let _backend = WasmBackend::new(); // Should not panic assert!(true); } #[test] fn test_empty_module_compilation() { let mut backend = WasmBackend::new(); let module = MirModule::new("test".to_string()); // Should handle empty module gracefully let result = backend.compile_to_wat(module); assert!(result.is_ok()); } }