Skip to content

Commit e03d857

Browse files
committed
pass test
1 parent e3f183a commit e03d857

File tree

2 files changed

+147
-73
lines changed

2 files changed

+147
-73
lines changed

crates/luars/src/compiler/expr.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,16 @@ fn compile_binary_expr_desc(c: &mut Compiler, expr: &LuaBinaryExpr) -> Result<Ex
312312
c,
313313
Instruction::encode_abc(OpCode::Add, result_reg, left_reg, right_reg),
314314
);
315+
emit(
316+
c,
317+
Instruction::create_abck(
318+
OpCode::MmBin,
319+
left_reg,
320+
right_reg,
321+
TagMethod::Add.as_u32(),
322+
false,
323+
),
324+
);
315325
}
316326
BinaryOperator::OpSub => {
317327
result_reg = if can_reuse_left {
@@ -323,6 +333,16 @@ fn compile_binary_expr_desc(c: &mut Compiler, expr: &LuaBinaryExpr) -> Result<Ex
323333
c,
324334
Instruction::encode_abc(OpCode::Sub, result_reg, left_reg, right_reg),
325335
);
336+
emit(
337+
c,
338+
Instruction::create_abck(
339+
OpCode::MmBin,
340+
left_reg,
341+
right_reg,
342+
TagMethod::Sub.as_u32(),
343+
false,
344+
),
345+
);
326346
}
327347
BinaryOperator::OpMul => {
328348
result_reg = if can_reuse_left {
@@ -352,6 +372,16 @@ fn compile_binary_expr_desc(c: &mut Compiler, expr: &LuaBinaryExpr) -> Result<Ex
352372
c,
353373
Instruction::encode_abc(OpCode::Mul, result_reg, left_reg, right_reg),
354374
);
375+
emit(
376+
c,
377+
Instruction::create_abck(
378+
OpCode::MmBin,
379+
left_reg,
380+
right_reg,
381+
TagMethod::Mul.as_u32(),
382+
false,
383+
),
384+
);
355385
}
356386
}
357387
BinaryOperator::OpDiv => {
@@ -381,6 +411,16 @@ fn compile_binary_expr_desc(c: &mut Compiler, expr: &LuaBinaryExpr) -> Result<Ex
381411
c,
382412
Instruction::encode_abc(OpCode::Div, result_reg, left_reg, right_reg),
383413
);
414+
emit(
415+
c,
416+
Instruction::create_abck(
417+
OpCode::MmBin,
418+
left_reg,
419+
right_reg,
420+
TagMethod::Div.as_u32(),
421+
false,
422+
),
423+
);
384424
}
385425
}
386426
BinaryOperator::OpIDiv => {
@@ -404,6 +444,16 @@ fn compile_binary_expr_desc(c: &mut Compiler, expr: &LuaBinaryExpr) -> Result<Ex
404444
c,
405445
Instruction::encode_abc(OpCode::IDiv, result_reg, left_reg, right_reg),
406446
);
447+
emit(
448+
c,
449+
Instruction::create_abck(
450+
OpCode::MmBin,
451+
left_reg,
452+
right_reg,
453+
TagMethod::IDiv.as_u32(),
454+
false,
455+
),
456+
);
407457
}
408458
}
409459
BinaryOperator::OpMod => {

crates/luars/src/lua_vm/dispatcher/table_instructions.rs

Lines changed: 97 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -84,25 +84,31 @@ pub fn exec_settable(vm: &mut LuaVM, instr: u32) -> LuaResult<DispatchAction> {
8484
let c = Instruction::get_c(instr) as usize;
8585
let k = Instruction::get_k(instr);
8686

87-
let frame = vm.current_frame();
88-
let base_ptr = frame.base_ptr;
87+
// CRITICAL: Read all values BEFORE any metamethod calls
88+
// because metamethods can modify the register stack
89+
let (table_value, key_value, set_value) = {
90+
let frame = vm.current_frame();
91+
let base_ptr = frame.base_ptr;
8992

90-
let table = vm.register_stack[base_ptr + a];
91-
let key = vm.register_stack[base_ptr + b];
92-
93-
let value = if k {
94-
// OPTIMIZATION: Get constant directly
95-
let func_ptr = frame.get_function_ptr().ok_or_else(|| {
96-
LuaError::RuntimeError("Not a Lua function".to_string())
97-
})?;
98-
unsafe { (*func_ptr).borrow().chunk.constants.get(c).copied().ok_or_else(|| {
99-
LuaError::RuntimeError(format!("Invalid constant index: {}", c))
100-
})? }
101-
} else {
102-
vm.register_stack[base_ptr + c]
93+
let table = vm.register_stack[base_ptr + a];
94+
let key = vm.register_stack[base_ptr + b];
95+
96+
let value = if k {
97+
// OPTIMIZATION: Get constant directly
98+
let func_ptr = frame.get_function_ptr().ok_or_else(|| {
99+
LuaError::RuntimeError("Not a Lua function".to_string())
100+
})?;
101+
unsafe { (*func_ptr).borrow().chunk.constants.get(c).copied().ok_or_else(|| {
102+
LuaError::RuntimeError(format!("Invalid constant index: {}", c))
103+
})? }
104+
} else {
105+
vm.register_stack[base_ptr + c]
106+
};
107+
108+
(table, key, value)
103109
};
104110

105-
vm.table_set_with_meta(table, key, value)?;
111+
vm.table_set_with_meta(table_value, key_value, set_value)?;
106112

107113
Ok(DispatchAction::Continue)
108114
}
@@ -137,24 +143,30 @@ pub fn exec_seti(vm: &mut LuaVM, instr: u32) -> LuaResult<DispatchAction> {
137143
let c = Instruction::get_c(instr) as usize;
138144
let k = Instruction::get_k(instr);
139145

140-
let frame = vm.current_frame();
141-
let base_ptr = frame.base_ptr;
146+
// CRITICAL: Read all values BEFORE any metamethod calls
147+
// because metamethods can modify the register stack
148+
let (table_value, key_value, set_value) = {
149+
let frame = vm.current_frame();
150+
let base_ptr = frame.base_ptr;
142151

143-
let table = vm.register_stack[base_ptr + a];
144-
let key = crate::LuaValue::integer(b as i64);
145-
146-
let value = if k {
147-
let func_ptr = frame.get_function_ptr().ok_or_else(|| {
148-
LuaError::RuntimeError("Not a Lua function".to_string())
149-
})?;
150-
unsafe { (*func_ptr).borrow().chunk.constants.get(c).copied().ok_or_else(|| {
151-
LuaError::RuntimeError(format!("Invalid constant index: {}", c))
152-
})? }
153-
} else {
154-
vm.register_stack[base_ptr + c]
152+
let table = vm.register_stack[base_ptr + a];
153+
let key = crate::LuaValue::integer(b as i64);
154+
155+
let value = if k {
156+
let func_ptr = frame.get_function_ptr().ok_or_else(|| {
157+
LuaError::RuntimeError("Not a Lua function".to_string())
158+
})?;
159+
unsafe { (*func_ptr).borrow().chunk.constants.get(c).copied().ok_or_else(|| {
160+
LuaError::RuntimeError(format!("Invalid constant index: {}", c))
161+
})? }
162+
} else {
163+
vm.register_stack[base_ptr + c]
164+
};
165+
166+
(table, key, value)
155167
};
156168

157-
vm.table_set_with_meta(table, key, value)?;
169+
vm.table_set_with_meta(table_value, key_value, set_value)?;
158170

159171
Ok(DispatchAction::Continue)
160172
}
@@ -203,27 +215,33 @@ pub fn exec_setfield(vm: &mut LuaVM, instr: u32) -> LuaResult<DispatchAction> {
203215
let c = Instruction::get_c(instr) as usize;
204216
let k = Instruction::get_k(instr);
205217

206-
let frame = vm.current_frame();
207-
let base_ptr = frame.base_ptr;
208-
209-
let func_ptr = frame.get_function_ptr().ok_or_else(|| {
210-
LuaError::RuntimeError("Not a Lua function".to_string())
211-
})?;
212-
let key = unsafe { (*func_ptr).borrow().chunk.constants.get(b).copied().ok_or_else(|| {
213-
LuaError::RuntimeError(format!("Invalid constant index: {}", b))
214-
})? };
218+
// CRITICAL: Read all values BEFORE any metamethod calls
219+
// because metamethods can modify the register stack
220+
let (table_value, key_value, set_value) = {
221+
let frame = vm.current_frame();
222+
let base_ptr = frame.base_ptr;
223+
224+
let func_ptr = frame.get_function_ptr().ok_or_else(|| {
225+
LuaError::RuntimeError("Not a Lua function".to_string())
226+
})?;
227+
let key = unsafe { (*func_ptr).borrow().chunk.constants.get(b).copied().ok_or_else(|| {
228+
LuaError::RuntimeError(format!("Invalid constant index: {}", b))
229+
})? };
215230

216-
let table = vm.register_stack[base_ptr + a];
217-
218-
let value = if k {
219-
unsafe { (*func_ptr).borrow().chunk.constants.get(c).copied().ok_or_else(|| {
220-
LuaError::RuntimeError(format!("Invalid constant index: {}", c))
221-
})? }
222-
} else {
223-
vm.register_stack[base_ptr + c]
231+
let table = vm.register_stack[base_ptr + a];
232+
233+
let value = if k {
234+
unsafe { (*func_ptr).borrow().chunk.constants.get(c).copied().ok_or_else(|| {
235+
LuaError::RuntimeError(format!("Invalid constant index: {}", c))
236+
})? }
237+
} else {
238+
vm.register_stack[base_ptr + c]
239+
};
240+
241+
(table, key, value)
224242
};
225243

226-
vm.table_set_with_meta(table, key, value)?;
244+
vm.table_set_with_meta(table_value, key_value, set_value)?;
227245

228246
Ok(DispatchAction::Continue)
229247
}
@@ -269,34 +287,40 @@ pub fn exec_settabup(vm: &mut LuaVM, instr: u32) -> LuaResult<DispatchAction> {
269287
let c = Instruction::get_c(instr) as usize;
270288
let k = Instruction::get_k(instr);
271289

272-
let frame = vm.current_frame();
273-
let base_ptr = frame.base_ptr;
274-
275-
let func_ptr = frame.get_function_ptr().ok_or_else(|| {
276-
LuaError::RuntimeError("Not a Lua function".to_string())
277-
})?;
278-
let func = unsafe { &*func_ptr };
279-
let func_ref = func.borrow();
280-
281-
let key = func_ref.chunk.constants.get(b).copied().ok_or_else(|| {
282-
LuaError::RuntimeError(format!("Invalid constant index: {}", b))
283-
})?;
290+
// CRITICAL: Read all values BEFORE any metamethod calls
291+
// because metamethods can modify the register stack
292+
let (table_value, key_value, set_value) = {
293+
let frame = vm.current_frame();
294+
let base_ptr = frame.base_ptr;
295+
296+
let func_ptr = frame.get_function_ptr().ok_or_else(|| {
297+
LuaError::RuntimeError("Not a Lua function".to_string())
298+
})?;
299+
let func = unsafe { &*func_ptr };
300+
let func_ref = func.borrow();
301+
302+
let key = func_ref.chunk.constants.get(b).copied().ok_or_else(|| {
303+
LuaError::RuntimeError(format!("Invalid constant index: {}", b))
304+
})?;
284305

285-
let upvalue = func_ref.upvalues.get(a).ok_or_else(|| {
286-
LuaError::RuntimeError(format!("Invalid upvalue index: {}", a))
287-
})?;
306+
let upvalue = func_ref.upvalues.get(a).ok_or_else(|| {
307+
LuaError::RuntimeError(format!("Invalid upvalue index: {}", a))
308+
})?;
288309

289-
let table = upvalue.get_value(&vm.frames, &vm.register_stack);
290-
291-
let value = if k {
292-
func_ref.chunk.constants.get(c).copied().ok_or_else(|| {
293-
LuaError::RuntimeError(format!("Invalid constant index: {}", c))
294-
})?
295-
} else {
296-
vm.register_stack[base_ptr + c]
310+
let table = upvalue.get_value(&vm.frames, &vm.register_stack);
311+
312+
let value = if k {
313+
func_ref.chunk.constants.get(c).copied().ok_or_else(|| {
314+
LuaError::RuntimeError(format!("Invalid constant index: {}", c))
315+
})?
316+
} else {
317+
vm.register_stack[base_ptr + c]
318+
};
319+
320+
(table, key, value)
297321
};
298322

299-
vm.table_set_with_meta(table, key, value)?;
323+
vm.table_set_with_meta(table_value, key_value, set_value)?;
300324

301325
Ok(DispatchAction::Continue)
302326
}

0 commit comments

Comments
 (0)