Fix upvalues and stack values being different references

This commit is contained in:
Sofia 2026-03-16 15:56:57 +02:00
parent c9a0a5560d
commit 1eb62b078e
2 changed files with 103 additions and 45 deletions

View File

@ -3,6 +3,7 @@ local b = 5
function add(x)
return function (y)
x = x + 1
b = b + 1
return x + y, 1, 2, b
end
end
@ -17,4 +18,6 @@ end
print(max(11, 9))
print(add(10)(15))
print(add(10)(15))
print(b)
print(min(11, 9))

145
src/vm.rs
View File

@ -162,7 +162,7 @@ impl Closure {
pub fn run(&self, params: Vec<Value>) -> ClosureRunner {
let mut stack = HashMap::new();
for (i, param) in params.iter().enumerate() {
stack.insert(i as u16, param.clone());
stack.insert(i as u16, Rc::new(RefCell::new(param.clone())));
}
ClosureRunner {
closure: self.clone(),
@ -179,7 +179,7 @@ impl Closure {
pub struct ClosureRunner {
pub closure: Closure,
pub program_counter: usize,
pub stack: HashMap<u16, Value>,
pub stack: HashMap<u16, Rc<RefCell<Value>>>,
pub inner: Option<Box<ClosureRunner>>,
pub function_register: u16,
pub return_registers: Vec<u16>,
@ -187,20 +187,34 @@ pub struct ClosureRunner {
}
impl ClosureRunner {
pub fn set_stack(&mut self, idx: u16, value: Value) {
if let Some(stack_slot) = self.stack.get(&idx) {
*stack_slot.borrow_mut() = value;
} else {
self.stack.insert(idx, Rc::new(RefCell::new(value)));
}
}
pub fn next(&mut self) -> Option<Vec<Value>> {
if let Some(inner) = &mut self.inner {
if let Some(ret_values) = inner.next() {
self.inner = None;
if self.return_registers.len() == 0 {
for (i, value) in ret_values.iter().enumerate() {
self.stack
.insert(self.function_register + i as u16 + 1, value.clone());
self.stack.insert(
self.function_register + i as u16 + 1,
Rc::new(RefCell::new(value.clone())),
);
}
self.top = self.function_register + ret_values.len() as u16;
}
for (i, reg) in self.return_registers.iter().enumerate() {
self.stack
.insert(*reg, ret_values.get(i).cloned().unwrap_or(Value::Nil));
self.stack.insert(
*reg,
Rc::new(RefCell::new(
ret_values.get(i).cloned().unwrap_or(Value::Nil),
)),
);
}
} else {
return None;
@ -212,17 +226,24 @@ impl ClosureRunner {
.vm
.prototypes
.get(&self.closure.prototype)
.unwrap();
.unwrap()
.clone();
let constants = &self.closure.vm.constants;
if let Some(instr) = instructions.get(self.program_counter) {
match instr {
Instruction::Move(a, b) => {
self.stack
.insert(*a, self.stack.get(b).unwrap_or(&Value::Nil).clone());
self.set_stack(
*a,
self.stack
.get(b)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil)
.clone(),
);
}
Instruction::LoadK(reg, constant) => {
self.stack.insert(
self.set_stack(
*reg,
match constants.get(*constant as usize).unwrap() {
Constant::String(_) => todo!(),
@ -232,13 +253,17 @@ impl ClosureRunner {
}
Instruction::LoadNil(from_reg, to_reg) => {
for i in *from_reg..=*to_reg {
self.stack.insert(i, Value::Nil);
self.stack.insert(i, Rc::new(RefCell::new(Value::Nil)));
}
}
Instruction::SetGlobal(reg, global) => {
self.closure.environment.borrow_mut().globals.insert(
constants.get(*global as usize).unwrap().clone(),
self.stack.get(reg).unwrap_or(&Value::Nil).clone(),
self.stack
.get(reg)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil)
.clone(),
);
}
Instruction::GetGlobal(reg, global) => {
@ -249,37 +274,44 @@ impl ClosureRunner {
.globals
.get(constants.get(*global as usize).unwrap())
{
self.stack.insert(*reg, global.clone());
self.stack
.insert(*reg, Rc::new(RefCell::new(global.clone())));
} else {
todo!("Global not found: {:?}", constants.get(*global as usize))
}
}
Instruction::GetUpVal(reg, upvalreg) => {
self.stack.insert(
*reg,
self.closure
.upvalues
.get(upvalreg)
.unwrap()
.borrow()
.clone(),
);
self.stack
.insert(*reg, self.closure.upvalues.get(upvalreg).unwrap().clone());
}
Instruction::SetUpVal(upvalreg, reg) => {
*self.closure.upvalues.get(upvalreg).unwrap().borrow_mut() =
self.stack.get(reg).cloned().unwrap_or(Value::Nil);
*self.closure.upvalues.get(upvalreg).unwrap().borrow_mut() = self
.stack
.get(reg)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil);
}
Instruction::Jmp(b) => {
self.program_counter = (self.program_counter as i32 + *b) as usize
}
Instruction::Test(a, b, c) => {
let is_true = match self.stack.get(b).unwrap_or(&Value::Nil) {
Value::Number(val) => (LuaNumber::from_bits(*val) as u16) == *c,
let is_true = match self
.stack
.get(b)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil)
{
Value::Number(val) => (LuaNumber::from_bits(val) as u16) == *c,
_ => false,
};
if is_true {
self.stack
.insert(*a, self.stack.get(b).cloned().unwrap_or(Value::Nil));
self.set_stack(
*a,
self.stack
.get(b)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil),
);
} else {
self.program_counter += 1;
}
@ -303,25 +335,30 @@ impl ClosureRunner {
params.push(
self.stack
.get(&(param_start_func_reg + i + 1))
.unwrap_or(&Value::Nil)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil)
.clone(),
);
}
let value = self.stack.get(func_reg).unwrap_or(&Value::Nil);
let value = self
.stack
.get(func_reg)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil);
match value {
Value::RustFunction(func) => {
let ret_values = func.borrow_mut().execute(params);
if *ret_len != 0 {
for i in 0..=(*ret_len - 2) {
self.stack.insert(
self.set_stack(
*func_reg + i,
ret_values.get(i as usize).cloned().unwrap_or(Value::Nil),
);
}
} else {
for (i, value) in ret_values.iter().enumerate() {
self.stack.insert(*func_reg + i as u16 + 1, value.clone());
self.set_stack(*func_reg + i as u16 + 1, value.clone());
}
self.top = *func_reg + ret_values.len() as u16;
}
@ -339,7 +376,7 @@ impl ClosureRunner {
dbg!(&value);
if *ret_len > 0 {
for i in 0..=(*ret_len - 2) {
self.stack.insert(*func_reg + i, Value::Nil);
self.set_stack(*func_reg + i, Value::Nil);
}
}
}
@ -358,14 +395,11 @@ impl ClosureRunner {
dbg!(&self.stack);
let mut upvalues = self.closure.upvalues.clone();
for (reg, value) in &self.stack {
upvalues.insert(
reg + highest_upvalue + 1,
Rc::new(RefCell::new(value.clone())),
);
upvalues.insert(reg + highest_upvalue + 1, value.clone());
}
dbg!(&upvalues);
self.stack.insert(
self.set_stack(
*reg,
Value::Function(Closure {
vm: self.closure.vm.clone(),
@ -388,19 +422,40 @@ impl ClosureRunner {
(*reg_start, *reg_end)
};
for i in reg_start..=reg_end {
ret_values.push(self.stack.get(&i).cloned().unwrap_or(Value::Nil));
ret_values.push(
self.stack
.get(&i)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil),
);
}
return Some(ret_values);
}
Instruction::Add(res, lhs, rhs) => {
let lhs = self.stack.get(lhs).unwrap_or(&Value::Nil);
let rhs = self.stack.get(rhs).unwrap_or(&Value::Nil);
self.stack.insert(*res, lhs.add(rhs));
let lhs = self
.stack
.get(lhs)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil);
let rhs = self
.stack
.get(rhs)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil);
self.set_stack(*res, lhs.add(&rhs));
}
Instruction::LessThan(res, lhs, rhs) => {
let lhs = self.stack.get(lhs).unwrap_or(&Value::Nil);
let rhs = self.stack.get(rhs).unwrap_or(&Value::Nil);
self.stack.insert(*res, lhs.lt(rhs));
let lhs = self
.stack
.get(lhs)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil);
let rhs = self
.stack
.get(rhs)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil);
self.set_stack(*res, lhs.lt(&rhs));
}
};