From 6fddeedef316b72f0401d3df3a2e0f24a1c6db59 Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Sun, 15 Nov 2026 17:52:09 +0800 Subject: [PATCH] docs(core): explain frame initialization and execution root ownership --- crates/core/src/eval.rs | 52 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/crates/core/src/eval.rs b/crates/core/src/eval.rs index d562cb9..992ad83 100644 --- a/crates/core/src/eval.rs +++ b/crates/core/src/eval.rs @@ -637,57 +637,76 @@ impl Vm { &self.last_traceback } + /// 宿主归还 call/execute/协程完成结果,或执行器清理拥有值;标量由 Rust 释放,对象归还一份外部根。 pub fn release_value(&mut self, value: Value) -> Result<(), VmError> { + // 仅 Object 变体占用托管根,直接值不调用 release/retain。 if let Value::Object(reference) = value { self.release(reference)?; } Ok(()) } + /// 执行器把借用值放入拥有槽/结果前先验证并保留对象根,标量不需要计数。 fn retain_value(&mut self, value: &Value) -> Result<(), VmError> { + // 先检查对象来自当前堆且存活,不能为异堆/过期值建立执行根。 self.validate_value(value)?; + // 仅 Object 变体占用托管根,直接值不调用 release/retain。 if let Value::Object(reference) = value { self.retain(*reference)?; } Ok(()) } + /// 已知拥有根的内部清理入口,失败代表执行器所有权不变量破坏,不静默忽略。 fn drop_root(&mut self, value: Value) { self.release_value(value) .expect("execution owns every object root it releases"); } + /// 返回/失败/取消时统一销毁活跃帧:清理约束、栈、局部槽、函数及返回注解根。 fn clear_frame(&mut self, frame: EndorFrame) { + // 先释放委托返回约束持有的定义根,不依赖元数据 Rust Drop 管理托管计数。 self.clear_native_returns(frame.native_returns); + // 每个栈项独立拥有计数,重复对象值必须逐项归还。 for entry in frame.stack { + // Null 是协议标记,不是对象或语言 Nil,不参与根释放。 if let StackEntry::Value(value) = entry { self.drop_root(value); } } + // 未绑定 None 跳过,其余每个局部/自由变量槽拥有的对象根逐项释放。 for value in frame.localsplus.into_iter().flatten() { self.drop_root(value); } + // 函数根保证代码/全局/内置空间在帧内可达;这些借用字段不额外 release。 self.release(frame.function) .expect("frame owns its function root"); + // 帧创建时额外保留的名义/能力返回定义根,也必须单独归还。 if let Some(reference) = frame.return_type.and_then(|kind| kind.reference()) { self.release(reference) .expect("frame owns its return type root"); } } + /// prepare_call 为源码函数建立帧,先校验数量/值/契约,再取得根并初始化局部和捕获槽。 fn prepare_frame( &mut self, function: ObjectRef, arguments: &[Value], ) -> Result { + // 复制函数元数据以跨可变 Store 操作使用;clone 不是取得托管根。 let data = self .payload::(function, "function")? .clone(); + // 共享不可变 Rust 执行数据,常量图仍需后面的函数根保活。 let executable = self .payload::(data.code(), "code")? .shared_code(); + // 源码参数槽总数含显式 self,与默认值共同决定数量区间。 let maximum = executable.parameters().len(); + // 函数构造已保证默认值数量不超过参数数量,因此减法安全。 let required = maximum - data.defaults().len(); + // 数量先检查,后续默认值索引依赖 required..maximum 不变量。 if arguments.len() < required || arguments.len() > maximum { return Err(VmError::ArgumentCount { name: data.name().into(), @@ -696,12 +715,16 @@ impl Vm { provided: arguments.len(), }); } + // 所有传入对象先验证,不能等到部分槽初始化后才发现异堆参数。 for value in arguments { + // 先检查对象来自当前堆且存活,不能为异堆/过期值建立执行根。 self.validate_value(value)?; } + // 优先实参首项;仅当所有参数均可默认且无实参时才尝试首默认值作为 self。 let receiver = arguments .first() .or_else(|| { + // 至少一个必填参数时不能从默认值假造接收者。 if required == 0 { data.defaults().first() } else { @@ -712,23 +735,30 @@ impl Vm { Value::Object(receiver) => Some(*receiver), _ => None, }); + // 对象首参触发方法契约门禁;返回 bool 决定即使普通源码检查关闭是否仍要验注解。 let typed_method = if let Some(receiver) = receiver { self.objects .check_method_contract_call(function, receiver, self.source_type_checks)? } else { false }; + // 尚未解析的返回约束不拥有根,解析完成后才统一保留。 let mut return_type = None; + // 显式开关或类型化能力要求启用源码注解检查;无源码签名仍跳过这段解析。 if (self.source_type_checks || typed_method) && let Some(signature) = executable.source_signature() { + // 所有参数(含使用默认值的位置)逐个匹配,不仅检查调用方显式传入部分。 for (index, expected_name) in signature.parameters.iter().enumerate() { + // 缺失的尾参数从默认值列表按 index-required 读取。 let value = arguments .get(index) .unwrap_or_else(|| &data.defaults()[index - required]); + // 注解按函数环境和可能的接收者解析,方法自身类名可绑定真实声明定义。 let expected = self .objects .annotation_type(function, expected_name, receiver)?; + // 匹配失败生成具名参数诊断,在取得帧拥有根之前退出。 if !self.objects.matches_annotation(value, expected)? { return Err(VmError::TypeMismatch { function: data.name().into(), @@ -738,19 +768,23 @@ impl Vm { }); } } + // 先解析返回约束,随后额外保留其定义根,防执行期间全局重绑定使其失效。 return_type = Some(self.objects.annotation_type( function, &signature.return_type, receiver, )?); } + // 从这里开始函数成为帧拥有根,代码/全局/内置空间通过函数内部边维持存活。 self.retain(function)?; + // 若返回类型根无法保留,归还刚取得的函数根,不创建半拥有帧。 if let Some(reference) = return_type.and_then(|kind| kind.reference()) && let Err(error) = self.retain(reference) { self.release(function)?; return Err(error); } + // 建立空槽帧;函数/返回定义根已持有,其他槽后续逐项初始化。 let mut frame = EndorFrame { return_type, native_returns: Vec::new(), @@ -767,8 +801,11 @@ impl Vm { stack: Vec::with_capacity(executable.stack_size()), executable, }; + // 局部闭包汇总初始化失败,外层 clear_frame 统一处理已成功安装的根。 let initialized = (|| -> Result<(), VmError> { + // 方法能力返回约束也要保留,后续返回需满足所有能力而非仅源码声明。 if let Some(receiver) = receiver { + // push_native_return 负责保留各类型定义,失败时其自身清理未提交部分。 for (name, expected) in self.objects.method_trait_returns(function, receiver)? { self.push_native_return( &mut frame.native_returns, @@ -776,33 +813,44 @@ impl Vm { )?; } } + // 已传参数会覆盖默认值前段,仅拼接尚缺的尾部默认值。 let defaults = data.defaults().iter().skip(arguments.len() - required); + // 实参先于缺失默认值,依次填参数前缀,其余未绑定局部仍为 None。 for (slot, value) in frame .localsplus .iter_mut() .zip(arguments.iter().chain(defaults)) { + // 先 retain 再写槽,失败槽仍空;已写槽由外层失败清理释放。 self.retain_value(value)?; *slot = Some(value.clone()); } - // Captured local cells occupy the original local slots, as in - // CPython's localsplus layout. Free cells follow the local slots. + // 捕获局部保留原局部槽位置但改存 Cell;外部自由变量 Cell 追加在全部局部之后。 + // 捕获局部不增加槽位置,仅将原值替换为拥有该值的 Cell。 let local_count = frame.executable.layout().locals.len(); + // 只遍历局部段,外部自由变量 Cell 在后续单独安装。 for (index, slot) in frame.localsplus[..local_count].iter_mut().enumerate() { + // 需要被内部闭包捕获的局部改用共享 Cell,即使原槽未绑定也创建空 Cell。 if frame.executable.is_cell_slot(index) { + // 新 Cell 的载荷强边先保留旧值,返回的一份外部根由该局部槽接管。 let cell = self.new_cell(slot.clone())?; + // 槽原值已被 Cell 内部边接管,归还原来那份槽执行根,不重复持有。 if let Some(old) = slot.replace(Value::Object(cell)) { self.drop_root(old); } } } + // 外层捕获 Cell 段紧跟所有局部槽,顺序与代码 free_variables 一致。 let first_free = frame.executable.layout().locals.len(); + // 闭包 Cell 已由函数持边,但每个活跃自由变量槽仍需独立执行根。 for (index, cell) in data.closure().iter().enumerate() { + // retain 成功才写槽;函数构造的闭包数量校验保证目标索引合法。 self.retain(*cell)?; frame.localsplus[first_free + index] = Some(Value::Object(*cell)); } Ok(()) })(); + // 失败时清理已装入槽的根及函数/返回约束,未装入槽不需要回滚。 if let Err(error) = initialized { self.clear_frame(frame); return Err(error);