feat(phase-9.77): Implement BoxCall instructions and fix wasmtime version

Phase 9.77 WASM Emergency Recovery Progress:
-  Task 1.1: Implement BoxCall instruction for toString(), print(), equals(), clone(), log()
-  Task 1.2: Update wasmtime 18.0 → 35.0.0 and add runtime imports
- 🔄 Task 1.3: Working on UTF-8 encoding error fix

Changes:
- Add generate_box_call() method in codegen.rs with 5 helper methods
- Update wasmtime dependency to 35.0.0 for AOT compatibility
- Add BoxCall runtime imports (box_to_string, box_print, box_equals, box_clone)
- Implement wat_to_wasm() with UTF-8 validation and debug output
- Update CURRENT_TASK.md with Copilot handoff notes

Current issue: 'Generated WASM is not valid UTF-8' error source unknown
Next: Copilot to investigate error origin and complete Task 1.3

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm
2025-08-16 21:21:51 +09:00
parent fa1a3ad644
commit cde961defc
9 changed files with 288 additions and 5 deletions

View File

@ -403,6 +403,11 @@ impl WasmCodegen {
Ok(instructions)
},
// Phase 9.77: BoxCall Implementation - Critical Box method calls
MirInstruction::BoxCall { dst, box_val, method, args, effects: _ } => {
self.generate_box_call(*dst, *box_val, method, args)
},
// Unsupported instructions
_ => Err(WasmError::UnsupportedInstruction(
format!("Instruction not yet supported: {:?}", instruction)
@ -570,6 +575,117 @@ impl WasmCodegen {
.copied()
.ok_or_else(|| WasmError::CodegenError(format!("Local variable not found for ValueId: {:?}", value_id)))
}
/// Phase 9.77: Generate BoxCall method invocation
/// Implements critical Box methods: toString, print, equals, clone
fn generate_box_call(&mut self, dst: Option<ValueId>, box_val: ValueId, method: &str, args: &[ValueId]) -> Result<Vec<String>, WasmError> {
match method {
"toString" => self.generate_to_string_call(dst, box_val),
"print" => self.generate_print_call(dst, box_val),
"equals" => self.generate_equals_call(dst, box_val, args),
"clone" => self.generate_clone_call(dst, box_val),
"log" => self.generate_log_call(dst, box_val, args),
_ => Err(WasmError::UnsupportedInstruction(
format!("Unsupported BoxCall method: {}", method)
))
}
}
/// Generate toString() method call - Box → String conversion
fn generate_to_string_call(&mut self, dst: Option<ValueId>, box_val: ValueId) -> Result<Vec<String>, WasmError> {
let Some(dst) = dst else {
return Err(WasmError::CodegenError("toString() requires destination".to_string()));
};
Ok(vec![
format!(";; toString() implementation for ValueId({})", box_val.as_u32()),
format!("local.get ${}", self.get_local_index(box_val)?),
"call $box_to_string".to_string(),
format!("local.set ${}", self.get_local_index(dst)?),
])
}
/// Generate print() method call - Basic output
fn generate_print_call(&mut self, dst: Option<ValueId>, box_val: ValueId) -> Result<Vec<String>, WasmError> {
let mut instructions = vec![
format!(";; print() implementation for ValueId({})", box_val.as_u32()),
format!("local.get ${}", self.get_local_index(box_val)?),
"call $box_print".to_string(),
];
// Store void result if destination is provided
if let Some(dst) = dst {
instructions.extend(vec![
"i32.const 0".to_string(), // Void result
format!("local.set ${}", self.get_local_index(dst)?),
]);
}
Ok(instructions)
}
/// Generate equals() method call - Box comparison
fn generate_equals_call(&mut self, dst: Option<ValueId>, box_val: ValueId, args: &[ValueId]) -> Result<Vec<String>, WasmError> {
let Some(dst) = dst else {
return Err(WasmError::CodegenError("equals() requires destination".to_string()));
};
if args.len() != 1 {
return Err(WasmError::CodegenError(
format!("equals() expects 1 argument, got {}", args.len())
));
}
Ok(vec![
format!(";; equals() implementation for ValueId({}) == ValueId({})", box_val.as_u32(), args[0].as_u32()),
format!("local.get ${}", self.get_local_index(box_val)?),
format!("local.get ${}", self.get_local_index(args[0])?),
"call $box_equals".to_string(),
format!("local.set ${}", self.get_local_index(dst)?),
])
}
/// Generate clone() method call - Box duplication
fn generate_clone_call(&mut self, dst: Option<ValueId>, box_val: ValueId) -> Result<Vec<String>, WasmError> {
let Some(dst) = dst else {
return Err(WasmError::CodegenError("clone() requires destination".to_string()));
};
Ok(vec![
format!(";; clone() implementation for ValueId({})", box_val.as_u32()),
format!("local.get ${}", self.get_local_index(box_val)?),
"call $box_clone".to_string(),
format!("local.set ${}", self.get_local_index(dst)?),
])
}
/// Generate log() method call - Console logging (ConsoleBox.log)
fn generate_log_call(&mut self, dst: Option<ValueId>, box_val: ValueId, args: &[ValueId]) -> Result<Vec<String>, WasmError> {
let mut instructions = vec![
format!(";; log() implementation for ValueId({})", box_val.as_u32()),
];
// Load box_val (ConsoleBox instance)
instructions.push(format!("local.get ${}", self.get_local_index(box_val)?));
// Load all arguments
for arg in args {
instructions.push(format!("local.get ${}", self.get_local_index(*arg)?));
}
// Call console log function
instructions.push("call $console_log".to_string());
// Store void result if destination is provided
if let Some(dst) = dst {
instructions.extend(vec![
"i32.const 0".to_string(), // Void result
format!("local.set ${}", self.get_local_index(dst)?),
]);
}
Ok(instructions)
}
}
#[cfg(test)]

View File

@ -61,9 +61,36 @@ impl WasmBackend {
// Generate WAT (WebAssembly Text) first for debugging
let wat_text = self.compile_to_wat(mir_module)?;
// Convert WAT to WASM binary using wabt
wabt::wat2wasm(&wat_text)
.map_err(|e| WasmError::WasmValidationError(format!("WAT to WASM conversion failed: {}", e)))
// 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<Vec<u8>, 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)

View File

@ -89,6 +89,40 @@ impl RuntimeImports {
result: None,
});
// Phase 9.77: BoxCall runtime functions
// box_to_string - Convert any Box to string representation
self.imports.push(ImportFunction {
module: "env".to_string(),
name: "box_to_string".to_string(),
params: vec!["i32".to_string()], // box_ptr
result: Some("i32".to_string()), // string_box_ptr
});
// box_print - Print any Box to console
self.imports.push(ImportFunction {
module: "env".to_string(),
name: "box_print".to_string(),
params: vec!["i32".to_string()], // box_ptr
result: None,
});
// box_equals - Compare two Boxes for equality
self.imports.push(ImportFunction {
module: "env".to_string(),
name: "box_equals".to_string(),
params: vec!["i32".to_string(), "i32".to_string()], // box1_ptr, box2_ptr
result: Some("i32".to_string()), // bool result
});
// box_clone - Clone a Box
self.imports.push(ImportFunction {
module: "env".to_string(),
name: "box_clone".to_string(),
params: vec!["i32".to_string()], // box_ptr
result: Some("i32".to_string()), // cloned_box_ptr
});
// Future: env.file_read, env.file_write for file I/O
// Future: env.http_request for network access
}