docs(tests): correct execution root and closure result explanations

This commit is contained in:
2026-11-15 20:03:17 +08:00
parent 057228a0fd
commit ab0be1efd3
+13 -9
View File
@@ -1,5 +1,6 @@
//! 通过手工指令验证 VM 求值、根生命周期及暂停行为,测试框架直接调用,无需源码解析器。
//! op/simple/make_code 统一构造已验证代码;错误编码用 EndorCode 直接检验构造阶段拒绝。
//! 部分协议场景只核对局部结果/计数,保留的测试根由 VM 析构收尾;显式清理场景另断言失效或空堆。
use std::any::Any;
use std::sync::Arc;
@@ -26,8 +27,11 @@ fn text(value: &str) -> Value {
/// 测试辅助,编码并验证指令/常量/布局后分配代码拥有根;失败直接使测试失败。
fn make_code(
vm: &mut Vm,
// 逻辑指令借用输入;编码器处理扩展前缀,代码构造器检查索引、跳转和栈高。
instructions: &[Instruction],
// 常量表示移入代码,含对象时只有成功托管分配才建立内部强边;不消耗调用方对象根。
constants: Vec<Value>,
// 参数/局部/Cell/名称布局随代码移入,执行帧按它分配和寻址。
layout: CodeLayout,
) -> ObjectRef {
vm.new_code(EndorCode::from_instructions(instructions, constants, layout).unwrap())
@@ -151,7 +155,7 @@ fn opt_in_assignment_keeps_alias_identity_ordinary_values_and_root_accounting()
fn failed_opt_in_assignment_preserves_target_and_cleans_execution_roots() {
// 独立 VM 隔离对象计数/全局绑定,清理断言只针对本场景。
let mut vm = Vm::new().unwrap();
// 共享目标以 1 初始化,同时另由 alias 持有;赋值后身份应保持。
// 共享目标以 1 初始化,globals.value 稍后持有它;拒绝新值后身份及原内容都应保持。
let old = vm.allocate(SharedReference(AtomicUsize::new(1))).unwrap();
// 以哨兵值 99 触发校验拒绝,不允许污染旧目标值。
let rejected = vm.allocate(SharedReference(AtomicUsize::new(99))).unwrap();
@@ -505,7 +509,7 @@ fn argument_count_and_foreign_argument_failures_do_not_retain_inputs() {
let mut other = Vm::new().unwrap();
// 异堆参数在执行源码之前拒绝,不改变当前函数计数。
let foreign = other.new_object().unwrap();
// 保存调用前计数,结果交付多一根,归还结果后必须恢复。
// 保存函数调用前计数;异堆实参预检失败后不应留下临时函数执行根。
let before = vm.ref_count(function).unwrap();
assert_eq!(
vm.call(function, &[Value::Object(foreign)]),
@@ -573,7 +577,7 @@ fn native_return_of_a_temporary_argument_is_retained_before_inputs_are_popped()
let mut vm = Vm::new().unwrap();
// 函数执行环境的拥有根,函数也经载荷强边持有该字典。
let globals = vm.new_dict().unwrap();
// 创建源码/原生函数拥有根,代码/全局/默认值内部边由分配协议另计。
// 分配旧式原生 echo 根,本载荷没有源码代码/全局字段;globals 随后为它建立值边。
let function = vm
.allocate(EndorNativeFunctionObject::new("echo", echo))
.unwrap();
@@ -599,7 +603,7 @@ fn native_return_of_a_temporary_argument_is_retained_before_inputs_are_popped()
);
// 执行结果拥有根可跨越代码与全局生命周期。
let result = vm.execute(code, globals).unwrap();
// 移除代码常量边后,返回图必须自己保留所需对象;不是只靠旧帧保活。
// 包装代码的常量表为空;释放代码后,临时字典必须仅凭独立调用结果根继续存活。
vm.release(code).unwrap();
// 归还环境测试根,临时执行函数已清理,结果不能依赖其持续存在。
vm.release(globals).unwrap();
@@ -620,7 +624,7 @@ fn native_failure_unwinds_temporary_roots_and_keeps_execution_locations() {
let mut vm = Vm::new().unwrap();
// 函数执行环境的拥有根,函数也经载荷强边持有该字典。
let globals = vm.new_dict().unwrap();
// 创建源码/原生函数拥有根,代码/全局/默认值内部边由分配协议另计。
// 分配恒定报错的旧式原生回调根,环境另持函数边;后面的源码包装器负责 Call 与回溯位置。
let function = vm
.allocate(EndorNativeFunctionObject::new("fail", fail))
.unwrap();
@@ -703,9 +707,9 @@ fn recursion_uses_explicit_frames_and_unwinds_at_the_frame_limit() {
assert_eq!(vm.ref_count(function).unwrap(), roots);
// 调用前/后按场景归还测试函数根;全局字典可能仍持有函数内部边。
vm.release(function).unwrap();
// 移除代码常量边后,返回图必须自己保留所需对象;不是只靠旧帧保活。
// 归还代码测试根;递归函数仍持代码边,需随函数/环境无外根环一起回收。
vm.release(code).unwrap();
// 归还环境测试根,临时执行函数已清理,结果不能依赖其持续存在。
// 归还环境测试根后只剩 globals→function→globals 及代码边,显式 GC 应回收三个对象。
vm.release(globals).unwrap();
assert_eq!(vm.collect_cycles(), 3);
}
@@ -874,7 +878,7 @@ fn captured_argument_cells_keep_their_contents_after_the_frame_returns() {
.unwrap();
// 参数对象有测试根,帧初始化提升 Cell 时另建立内容强边。
let value = vm.new_string("captured").unwrap();
// 函数把已有参数/默认值作为结果,身份不变但结果仍取得独立拥有根。
// LoadClosure 返回新建的参数 Cell,并非原参数字符串;结果根保活 Cell,Cell 内部边再保活参数。
let returned = vm.call(function, &[Value::Object(value)]).unwrap();
// 归还原参数测试根,返回的 Cell 内容边仍须保活它。
vm.release(value).unwrap();
@@ -2010,7 +2014,7 @@ impl ObjectPayload for AwaitGate {
fn kind_name(&self) -> &'static str {
"await-gate"
}
/// Heap 分配、回收时遍历内部对象边;立即值没有托管引用,无需报告。
/// Heap 分配载荷时据此登记对象边快照,回收沿已登记的边处理;立即值无需报告。
fn trace(&self, visit: &mut dyn FnMut(ObjectRef)) {
// 只有对象值携带堆引用;必须报告这一边,使测试释放原根后结果仍存活。
if let Value::Object(reference) = self.value {