Files
OxideJS-New/crates/oxide_vm/tests/generator_gc_tests.rs
T

55 lines
2.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 生成器 × session GC 回归:full_reset 逐对象释放 session 生成器(本体 + 堆数据
//! + upvalue 列表,各单所有权),不 double-free、不悬垂,VM 继续可用。
//! sweep 变体与闭包捕获变体见 `vm_support.rs` 内部测试(需 crate 内 `resume_generator`
//! 在模块表未重建时恢复执行,integration 层无法触达)。
use std::sync::Arc;
use oxide_compiler::compiler::Compiler;
use oxide_parser::Allocator;
use oxide_vm::vm::Vm;
fn compile(source: &str) -> oxide_bytecode::module::CompiledModule {
let allocator = Allocator::default();
let program = oxide_parser::parse(&allocator, source).expect("parse");
Compiler::new().compile(&program).expect("compile")
}
/// full_reset 变体:global 根持有生成器,full_reset 释放其本体、堆数据与
/// upvalue 列表(各单所有权),不 double-free、不悬垂,VM 继续可用。
#[test]
fn generator_promoted_to_global_survives_full_reset_cleanly() {
let mut vm = Vm::new();
vm.run(&Arc::new(compile(
"function* g(){ yield 1; yield 2; } globalThis.it = g(); globalThis.it.next(); 0",
)))
.expect("run1");
assert!(vm.session_object_count() > 0, "生成器挂 global 应为 session 对象");
// global 含 session 对象即强制重建:旧 global 丢弃、it 槽不存在,全程无悬垂访问。
vm.full_reset();
assert_eq!(vm.session_object_count(), 0, "full_reset 应清空 session 对象");
let result = vm.run(&Arc::new(compile("typeof it"))).expect("run2");
let text = vm.lookup_str(result).expect("typeof 应返回字符串").to_string();
assert_eq!(text, "undefined");
// 新会话可正常创建并推进生成器。
let ok = vm
.run(&Arc::new(compile("function* h(){ yield 9; } var it2 = h(); it2.next().value")))
.expect("run3");
assert_eq!(format!("{ok}"), "9");
}
/// 闭包跨 yield 读 upvalue:生成器挂起再恢复时活动镜像必须还原为生成器自己的
/// 表(恢复置位漏掉时,恢复体读顶层空表,upvalue 读回退惰性路径得 undefined)。
#[test]
fn generator_reads_upvalue_across_yield() {
let mut vm = Vm::new();
let result = vm
.run(&Arc::new(compile(
"function make() { var x = 1; function* g() { yield x; yield x; } var it = g(); it.next(); x = 2; return it.next().value; } make()",
)))
.expect("run");
assert_eq!(format!("{result}"), "2");
}