mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
fix: 修复复用 VM IC 缓存未清除问题
This commit is contained in:
@@ -118,6 +118,22 @@ impl OpCode {
|
|||||||
| OpCode::JOIN
|
| OpCode::JOIN
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_ic_ext_words(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
OpCode::IC_GET_PROP
|
||||||
|
| OpCode::IC_SET_PROP
|
||||||
|
| OpCode::MEMBER_INC
|
||||||
|
| OpCode::MEMBER_DEC
|
||||||
|
| OpCode::COMPOUND_MEMBER_ADD
|
||||||
|
| OpCode::COMPOUND_MEMBER_SUB
|
||||||
|
| OpCode::COMPOUND_MEMBER_MUL
|
||||||
|
| OpCode::COMPOUND_MEMBER_DIV
|
||||||
|
| OpCode::COMPOUND_MEMBER_MOD
|
||||||
|
| OpCode::COMPOUND_MEMBER_EXP
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<u8> for OpCode {
|
impl TryFrom<u8> for OpCode {
|
||||||
|
|||||||
@@ -864,9 +864,27 @@ impl Vm {
|
|||||||
self.regs = [JsValue::undefined(); 256];
|
self.regs = [JsValue::undefined(); 256];
|
||||||
self.frames.clear();
|
self.frames.clear();
|
||||||
self.for_in_iters.clear();
|
self.for_in_iters.clear();
|
||||||
|
self.clear_ic_caches();
|
||||||
self.dispatch()
|
self.dispatch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clear_ic_caches(&mut self) {
|
||||||
|
let mut i = 0;
|
||||||
|
while i < self.bytecode.len() {
|
||||||
|
let op = opcode::opcode(self.bytecode[i]);
|
||||||
|
if op.has_ic_ext_words() {
|
||||||
|
if i + 3 < self.bytecode.len() {
|
||||||
|
self.bytecode[i + 1] = 0;
|
||||||
|
self.bytecode[i + 2] = 0;
|
||||||
|
self.bytecode[i + 3] = 0;
|
||||||
|
}
|
||||||
|
i += 4;
|
||||||
|
} else {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(&mut self, module: &CompiledModule) -> Result<JsValue, String> {
|
pub fn run(&mut self, module: &CompiledModule) -> Result<JsValue, String> {
|
||||||
self.constants = self.convert_constants(module);
|
self.constants = self.convert_constants(module);
|
||||||
self.sub_modules = module.sub_modules.clone();
|
self.sub_modules = module.sub_modules.clone();
|
||||||
|
|||||||
@@ -30,10 +30,29 @@ fn regression_to_boolean_empty_string() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn regression_continue_in_for() {
|
fn regression_rerun_clears_ic_cache() {
|
||||||
|
let allocator = Allocator::default();
|
||||||
|
let source = "var o = {a: 1}; o.a";
|
||||||
|
let program = oxide_parser::parse(&allocator, source).expect("parse");
|
||||||
|
let module = Compiler::new().compile(&program).expect("compile");
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
assert_eq!(format!("{}", vm.run(&module).unwrap()), "1");
|
||||||
|
|
||||||
|
let source2 = "var o = {a: 2}; o.a";
|
||||||
|
let program2 = oxide_parser::parse(&allocator, source2).expect("parse");
|
||||||
|
let module2 = Compiler::new().compile(&program2).expect("compile");
|
||||||
|
vm.run(&module2).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
eval("var r=0; for(i=0;i<3;i=i+1){if(i==1)continue;r=r+i;}r"),
|
format!("{}", vm.rerun().unwrap()),
|
||||||
"2",
|
"2",
|
||||||
"continue should skip iteration body"
|
"rerun should re-read IC-cached property, not stale value from previous run"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn regression_recursion_depth_limit() {
|
||||||
|
assert_eq!(
|
||||||
|
eval("function f(){f()} f()"),
|
||||||
|
"vm error: RangeError: Maximum call stack size exceeded"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user