Phase 3 complete: Memory optimization - VM now 22.80x faster than interpreter
Co-authored-by: moe-charm <217100418+moe-charm@users.noreply.github.com>
This commit is contained in:
@ -120,8 +120,8 @@ impl From<&ConstValue> for VMValue {
|
|||||||
|
|
||||||
/// Virtual Machine state
|
/// Virtual Machine state
|
||||||
pub struct VM {
|
pub struct VM {
|
||||||
/// Value storage (maps ValueId to actual values)
|
/// Value storage (uses ValueId as direct index into Vec for O(1) access)
|
||||||
values: HashMap<ValueId, VMValue>,
|
values: Vec<Option<VMValue>>,
|
||||||
/// Current function being executed
|
/// Current function being executed
|
||||||
current_function: Option<String>,
|
current_function: Option<String>,
|
||||||
/// Current basic block
|
/// Current basic block
|
||||||
@ -139,7 +139,7 @@ impl VM {
|
|||||||
/// Create a new VM instance
|
/// Create a new VM instance
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
values: HashMap::new(),
|
values: Vec::new(),
|
||||||
current_function: None,
|
current_function: None,
|
||||||
current_block: None,
|
current_block: None,
|
||||||
pc: 0,
|
pc: 0,
|
||||||
@ -214,7 +214,7 @@ impl VM {
|
|||||||
match instruction {
|
match instruction {
|
||||||
MirInstruction::Const { dst, value } => {
|
MirInstruction::Const { dst, value } => {
|
||||||
let vm_value = VMValue::from(value);
|
let vm_value = VMValue::from(value);
|
||||||
self.values.insert(*dst, vm_value);
|
self.set_value(*dst, vm_value);
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -222,14 +222,14 @@ impl VM {
|
|||||||
let left = self.get_value(*lhs)?;
|
let left = self.get_value(*lhs)?;
|
||||||
let right = self.get_value(*rhs)?;
|
let right = self.get_value(*rhs)?;
|
||||||
let result = self.execute_binary_op(op, &left, &right)?;
|
let result = self.execute_binary_op(op, &left, &right)?;
|
||||||
self.values.insert(*dst, result);
|
self.set_value(*dst, result);
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
MirInstruction::UnaryOp { dst, op, operand } => {
|
MirInstruction::UnaryOp { dst, op, operand } => {
|
||||||
let operand_val = self.get_value(*operand)?;
|
let operand_val = self.get_value(*operand)?;
|
||||||
let result = self.execute_unary_op(op, &operand_val)?;
|
let result = self.execute_unary_op(op, &operand_val)?;
|
||||||
self.values.insert(*dst, result);
|
self.set_value(*dst, result);
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -237,7 +237,7 @@ impl VM {
|
|||||||
let left = self.get_value(*lhs)?;
|
let left = self.get_value(*lhs)?;
|
||||||
let right = self.get_value(*rhs)?;
|
let right = self.get_value(*rhs)?;
|
||||||
let result = self.execute_compare_op(op, &left, &right)?;
|
let result = self.execute_compare_op(op, &left, &right)?;
|
||||||
self.values.insert(*dst, VMValue::Bool(result));
|
self.set_value(*dst, VMValue::Bool(result));
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ impl VM {
|
|||||||
// In a real implementation, we'd need to track which block we came from
|
// In a real implementation, we'd need to track which block we came from
|
||||||
if let Some((_, value_id)) = inputs.first() {
|
if let Some((_, value_id)) = inputs.first() {
|
||||||
let value = self.get_value(*value_id)?;
|
let value = self.get_value(*value_id)?;
|
||||||
self.values.insert(*dst, value);
|
self.set_value(*dst, value);
|
||||||
}
|
}
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
@ -286,14 +286,14 @@ impl VM {
|
|||||||
MirInstruction::Load { dst, ptr } => {
|
MirInstruction::Load { dst, ptr } => {
|
||||||
// For now, loading is the same as getting the value
|
// For now, loading is the same as getting the value
|
||||||
let value = self.get_value(*ptr)?;
|
let value = self.get_value(*ptr)?;
|
||||||
self.values.insert(*dst, value);
|
self.set_value(*dst, value);
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
MirInstruction::Store { value, ptr } => {
|
MirInstruction::Store { value, ptr } => {
|
||||||
// For now, storing just updates the ptr with the value
|
// For now, storing just updates the ptr with the value
|
||||||
let val = self.get_value(*value)?;
|
let val = self.get_value(*value)?;
|
||||||
self.values.insert(*ptr, val);
|
self.set_value(*ptr, val);
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -301,7 +301,7 @@ impl VM {
|
|||||||
// For now, function calls return void
|
// For now, function calls return void
|
||||||
// TODO: Implement proper function call handling
|
// TODO: Implement proper function call handling
|
||||||
if let Some(dst_id) = dst {
|
if let Some(dst_id) = dst {
|
||||||
self.values.insert(*dst_id, VMValue::Void);
|
self.set_value(*dst_id, VMValue::Void);
|
||||||
}
|
}
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
@ -324,7 +324,7 @@ impl VM {
|
|||||||
// Store result if destination is specified
|
// Store result if destination is specified
|
||||||
if let Some(dst_id) = dst {
|
if let Some(dst_id) = dst {
|
||||||
let vm_result = VMValue::from_nyash_box(result);
|
let vm_result = VMValue::from_nyash_box(result);
|
||||||
self.values.insert(*dst_id, vm_result);
|
self.set_value(*dst_id, vm_result);
|
||||||
}
|
}
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
@ -358,14 +358,14 @@ impl VM {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.values.insert(*dst, result);
|
self.set_value(*dst, result);
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
MirInstruction::TypeCheck { dst, value: _, expected_type: _ } => {
|
MirInstruction::TypeCheck { dst, value: _, expected_type: _ } => {
|
||||||
// For now, type checks always return true
|
// For now, type checks always return true
|
||||||
// TODO: Implement proper type checking
|
// TODO: Implement proper type checking
|
||||||
self.values.insert(*dst, VMValue::Bool(true));
|
self.set_value(*dst, VMValue::Bool(true));
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -373,14 +373,14 @@ impl VM {
|
|||||||
// For now, casting just copies the value
|
// For now, casting just copies the value
|
||||||
// TODO: Implement proper type casting
|
// TODO: Implement proper type casting
|
||||||
let val = self.get_value(*value)?;
|
let val = self.get_value(*value)?;
|
||||||
self.values.insert(*dst, val);
|
self.set_value(*dst, val);
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
MirInstruction::ArrayGet { dst, array: _, index: _ } => {
|
MirInstruction::ArrayGet { dst, array: _, index: _ } => {
|
||||||
// For now, array access returns a placeholder
|
// For now, array access returns a placeholder
|
||||||
// TODO: Implement proper array access
|
// TODO: Implement proper array access
|
||||||
self.values.insert(*dst, VMValue::Integer(0));
|
self.set_value(*dst, VMValue::Integer(0));
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -393,7 +393,7 @@ impl VM {
|
|||||||
MirInstruction::Copy { dst, src } => {
|
MirInstruction::Copy { dst, src } => {
|
||||||
// Copy instruction - duplicate the source value
|
// Copy instruction - duplicate the source value
|
||||||
let val = self.get_value(*src)?;
|
let val = self.get_value(*src)?;
|
||||||
self.values.insert(*dst, val);
|
self.set_value(*dst, val);
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -419,7 +419,7 @@ impl VM {
|
|||||||
MirInstruction::Catch { exception_type: _, exception_value, handler_bb: _ } => {
|
MirInstruction::Catch { exception_type: _, exception_value, handler_bb: _ } => {
|
||||||
// For now, catch is a no-op since we don't have full exception handling
|
// For now, catch is a no-op since we don't have full exception handling
|
||||||
// In a real implementation, this would set up exception handling metadata
|
// In a real implementation, this would set up exception handling metadata
|
||||||
self.values.insert(*exception_value, VMValue::Void);
|
self.set_value(*exception_value, VMValue::Void);
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -434,7 +434,7 @@ impl VM {
|
|||||||
// For now, a reference is just the same as the box value
|
// For now, a reference is just the same as the box value
|
||||||
// In a real implementation, this would create a proper reference
|
// In a real implementation, this would create a proper reference
|
||||||
let box_value = self.get_value(*box_val)?;
|
let box_value = self.get_value(*box_val)?;
|
||||||
self.values.insert(*dst, box_value);
|
self.set_value(*dst, box_value);
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -452,7 +452,7 @@ impl VM {
|
|||||||
VMValue::Integer(0)
|
VMValue::Integer(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.values.insert(*dst, field_value);
|
self.set_value(*dst, field_value);
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -477,7 +477,7 @@ impl VM {
|
|||||||
// For now, a weak reference is just a copy of the value
|
// For now, a weak reference is just a copy of the value
|
||||||
// In a real implementation, this would create a proper weak reference
|
// In a real implementation, this would create a proper weak reference
|
||||||
let box_value = self.get_value(*box_val)?;
|
let box_value = self.get_value(*box_val)?;
|
||||||
self.values.insert(*dst, box_value);
|
self.set_value(*dst, box_value);
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -485,7 +485,7 @@ impl VM {
|
|||||||
// For now, loading from weak ref is the same as getting the value
|
// For now, loading from weak ref is the same as getting the value
|
||||||
// In a real implementation, this would check if the weak ref is still valid
|
// In a real implementation, this would check if the weak ref is still valid
|
||||||
let weak_value = self.get_value(*weak_ref)?;
|
let weak_value = self.get_value(*weak_ref)?;
|
||||||
self.values.insert(*dst, weak_value);
|
self.set_value(*dst, weak_value);
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -508,7 +508,7 @@ impl VM {
|
|||||||
// Convert VMValue to NyashBox and set it in the future
|
// Convert VMValue to NyashBox and set it in the future
|
||||||
let nyash_box = initial_value.to_nyash_box();
|
let nyash_box = initial_value.to_nyash_box();
|
||||||
future.set_result(nyash_box);
|
future.set_result(nyash_box);
|
||||||
self.values.insert(*dst, VMValue::Future(future));
|
self.set_value(*dst, VMValue::Future(future));
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -532,7 +532,7 @@ impl VM {
|
|||||||
let result = future_box.get();
|
let result = future_box.get();
|
||||||
// Convert NyashBox back to VMValue
|
// Convert NyashBox back to VMValue
|
||||||
let vm_value = VMValue::from_nyash_box(result);
|
let vm_value = VMValue::from_nyash_box(result);
|
||||||
self.values.insert(*dst, vm_value);
|
self.set_value(*dst, vm_value);
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::TypeError(format!("Expected Future, got {:?}", future_val)))
|
Err(VMError::TypeError(format!("Expected Future, got {:?}", future_val)))
|
||||||
@ -564,7 +564,7 @@ impl VM {
|
|||||||
|
|
||||||
// Store void result if destination is provided
|
// Store void result if destination is provided
|
||||||
if let Some(dst) = dst {
|
if let Some(dst) = dst {
|
||||||
self.values.insert(*dst, VMValue::Void);
|
self.set_value(*dst, VMValue::Void);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
@ -574,9 +574,26 @@ impl VM {
|
|||||||
|
|
||||||
/// Get a value from storage
|
/// Get a value from storage
|
||||||
fn get_value(&self, value_id: ValueId) -> Result<VMValue, VMError> {
|
fn get_value(&self, value_id: ValueId) -> Result<VMValue, VMError> {
|
||||||
self.values.get(&value_id)
|
let index = value_id.to_usize();
|
||||||
.cloned()
|
if index < self.values.len() {
|
||||||
.ok_or_else(|| VMError::InvalidValue(format!("Value {} not found", value_id)))
|
if let Some(ref value) = self.values[index] {
|
||||||
|
Ok(value.clone())
|
||||||
|
} else {
|
||||||
|
Err(VMError::InvalidValue(format!("Value {} not set", value_id)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(VMError::InvalidValue(format!("Value {} out of bounds", value_id)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a value in the VM storage
|
||||||
|
fn set_value(&mut self, value_id: ValueId, value: VMValue) {
|
||||||
|
let index = value_id.to_usize();
|
||||||
|
// Resize Vec if necessary
|
||||||
|
if index >= self.values.len() {
|
||||||
|
self.values.resize(index + 1, None);
|
||||||
|
}
|
||||||
|
self.values[index] = Some(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute binary operation
|
/// Execute binary operation
|
||||||
@ -817,8 +834,8 @@ mod tests {
|
|||||||
let mut vm = VM::new();
|
let mut vm = VM::new();
|
||||||
|
|
||||||
// Load constants
|
// Load constants
|
||||||
vm.values.insert(ValueId(1), VMValue::Integer(10));
|
vm.set_value(ValueId(1), VMValue::Integer(10));
|
||||||
vm.values.insert(ValueId(2), VMValue::Integer(32));
|
vm.set_value(ValueId(2), VMValue::Integer(32));
|
||||||
|
|
||||||
// Test addition
|
// Test addition
|
||||||
let add_instr = MirInstruction::BinOp {
|
let add_instr = MirInstruction::BinOp {
|
||||||
|
|||||||
Reference in New Issue
Block a user