From 6be33467c829fc25e6dc48f379406072dca1c7d9 Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Thu, 12 Nov 2026 21:48:14 +0800 Subject: [PATCH] docs(objects): explain store lifecycle and payload protocols --- crates/objects/src/object.rs | 164 ++++++++++++++++++++++++----------- crates/objects/src/store.rs | 129 +++++++++++++++++++++------ 2 files changed, 217 insertions(+), 76 deletions(-) diff --git a/crates/objects/src/object.rs b/crates/objects/src/object.rs index e1103dc..f73bab2 100644 --- a/crates/objects/src/object.rs +++ b/crates/objects/src/object.rs @@ -1,3 +1,6 @@ +//! 对象公共表示与宿主载荷协议;Heap 管生命周期,ObjectStore 调协议,core::Vm 管指令与调用帧。 +//! Value 的 Rust clone 只复制表示,不变更托管引用计数;所有权由产生/接收它的 API 约定决定。 + use std::any::Any; use std::collections::BTreeMap; use std::collections::hash_map::DefaultHasher; @@ -6,31 +9,43 @@ use std::hash::{Hash, Hasher}; use crate::{EndorNumber, ObjectRef, VmError}; -/// Immediate values stay outside the object heap. Copying an ObjectRef or -/// cloning a Value never retains a reference; ownership follows the API that -/// produced it. In particular, call/execute results own a root until released. +/// 直接值不占对象堆槽;复制 ObjectRef 或 clone Value 不自动保留引用,所有权以 API 为准。 +/// 特别是 VM 的 call/execute 返回对象时带有一份外部根,使用者需要归还。 #[derive(Debug, Clone, PartialEq)] pub enum Value { + // 语言空值,与 Cell 的未初始化 None 不同。 Nil, + // 直接布尔值,不占用对象槽。 Bool(bool), - /// Rust equality preserves representation; it is not numeric equivalence. + /// 直接数值;Rust 相等比较保留具体数值表示,不等于语言层数值等价判断。 Number(EndorNumber), + // 拥有文本的直接表示,与堆上的 EndorStringObject 可在字典键比较中按内容互通。 Text(String), + // 仅保存句柄;是否拥有外部根取决于 API,复制/丢弃此变体不会 retain/release。 Object(ObjectRef), } +/// VM 的比较运算标识;ObjectStore::compare 传入载荷,必要时再尝试反向运算。 #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CompareOp { + /// 相等;传给载荷解释,不直接使用 Rust 的对象地址比较。 Eq, + /// 不等;传给载荷解释,不直接使用 Rust 的对象地址比较。 Ne, + /// 小于;传给载荷解释,不直接使用 Rust 的对象地址比较。 Lt, + /// 小于等于;传给载荷解释,不直接使用 Rust 的对象地址比较。 Le, + /// 大于;传给载荷解释,不直接使用 Rust 的对象地址比较。 Gt, + /// 大于等于;传给载荷解释,不直接使用 Rust 的对象地址比较。 Ge, } impl CompareOp { + /// Store 对调左右载荷时使用;相等类不变,有序运算反转方向。 pub(crate) fn reflected(self) -> Self { + // 运算映射只改变方向,不执行比较,也不取反比较结果。 match self { Self::Eq => Self::Eq, Self::Ne => Self::Ne, @@ -42,82 +57,88 @@ impl CompareOp { } } -/// Non-blocking awaitable observation. Ready object values are borrowed from -/// the managed graph and must be retained by the consumer before dropping it. +/// eval 的非阻塞等待观察结果;Ready 中的对象仍借自托管图,消费方须在释放原图前保留结果。 #[derive(Debug)] pub enum AwaitPoll { + // 结果尚未就绪;执行器保存等待状态,之后再观察。 Pending, + // 已就绪的借用结果;消费方在释放原结果图之前须保留所需对象根。 Ready(Value), } -/// Rust-side operation interface, not a language type or metaclass. -/// -/// Implementations must report every payload-owned object reference in trace(), -/// including duplicates. Those edges must stay immutable after allocation; -/// mutable object references belong in VM-managed attributes or built-in -/// containers updated transactionally by the VM instead. -/// Rust Drop releases host resources when the payload is destroyed. -/// Equal payloads must provide compatible hashes, or reject hashing explicitly. +/// 宿主实现的 Rust 操作协议,不是语言层类型或元类;Store/VM 根据具体操作调用这些方法。 +/// trace 必须报告载荷拥有的每一条对象引用(包括重复边),分配后这些边不能私自改变。 +/// 可变托管引用应放入受控属性或内置容器,经 Store/Heap 更新;Rust Drop 负责释放宿主资源。 +/// 内容相等的载荷必须提供兼容哈希,或明确拒绝哈希。 pub trait ObjectPayload: Any + fmt::Debug + Send + Sync { + /// eval 的 await 路径轮询载荷;默认拒绝等待,宿主实现不得阻塞执行线程等待完成。 fn poll_await(&self) -> Result { Err(VmError::UnsupportedOperation("await")) } - /// Explicit function category; callable Type objects are not functions. + /// allocate 判定是否自动附着 Function 类型;可调用 Type 并不属于函数分类。 fn is_function(&self) -> bool { false } - /// Ordinary field storage may be indirect, independently of type identity. - /// Targets must be traced; retargeting records Contents on the forwarder. + /// Store::attribute_path 与类型属性协议查询转发目标;None 表示在自身存储属性。 + /// 目标须由托管强边持有;更换目标须在转发对象上记录 Contents,属性身份与类型身份分开。 fn attribute_target(&self, _store: &crate::ObjectStore) -> Result, VmError> { Ok(None) } - /// Shared-reference facades may expose the current referent's type. The - /// referent must also be held by traced managed edges. Ordinary objects - /// keep their immutable header type; this does not change inheritance. + /// types 的类型解析查询共享引用门面的当前目标;None 表示使用自身头部名义类型。 + /// 目标须有 trace 强边;此协议不修改普通对象不可变的头部类型或继承关系。 fn type_target(&self, _store: &crate::ObjectStore) -> Result, VmError> { Ok(None) } - /// Optional context-aware native entry. The VM clones this dispatcher before - /// borrowing the store mutably; callbacks never borrow a live payload. + /// VM 查找可访问 NativeContext 的原生分派器;先克隆 Arc,再可变借用 Store 执行。 + /// 回调期间不保留载荷借用,避免同时借用载荷和可变 Store。 fn native_callable(&self) -> Option> { None } + /// Store::payload 等借助 Any 下转型到具体 Rust 载荷;不代表语言层类型判断。 fn as_any(&self) -> &dyn Any; - /// A diagnostic label only, with no language type or inheritance semantics. + /// 错误/默认 repr 的诊断名称;不能据此判断语言名义类型、继承或能力。 fn kind_name(&self) -> &'static str; + /// Heap 在分配/替换载荷时收集内部强边(含重复边);GC 此后使用边快照。 + /// 默认无边;实现不能在快照建立后通过内部可变性悄悄改变这些引用。 fn trace(&self, _visit: &mut dyn FnMut(ObjectRef)) {} + /// Heap 属性写入检查是否允许动态字段;默认不允许,Record 显式开启。 fn allows_attributes(&self) -> bool { false } + /// Store::repr 的默认诊断表示包含载荷名称与对象身份,不递归展开整个对象图。 fn repr(&self, identity: ObjectRef) -> Result { Ok(format!("<{} {identity}>", self.kind_name())) } + /// Store::str 的文本协议;未覆盖时复用 repr,宿主可提供更适合显示的文本。 fn str(&self, identity: ObjectRef) -> Result { self.repr(identity) } + /// Store::is_true/VM 分支求真时调用;普通对象默认真,容器或标量载荷可覆盖。 fn is_true(&self) -> Result { Ok(true) } + /// Store::hash 默认按身份哈希;若实现内容相等,须同步实现兼容哈希或拒绝哈希。 fn hash(&self, identity: ObjectRef) -> Result { + // 哈希整个句柄身份,不使用载荷地址;结果不是跨进程稳定标识。 let mut hasher = DefaultHasher::new(); identity.hash(&mut hasher); Ok(hasher.finish()) } - /// None means "not implemented"; the VM tries the reflected operation, - /// then falls back to identity for Eq/Ne or rejects ordering. + /// Store::compare 调用;None 表示未实现,Some(false) 表示已经实现且不满足比较。 + /// Store 仅在 None 时尝试反向协议,最后相等回退身份、有序比较报错。 fn compare( &self, _other: &dyn ObjectPayload, @@ -126,42 +147,39 @@ pub trait ObjectPayload: Any + fmt::Debug + Send + Sync { Ok(None) } - /// Host-call entry: arguments and raw results are borrowed handles. The VM - /// validates/retains the result before exposing it as an owned call result. - /// Language functions are dispatched by Vm's frame evaluator instead. - /// Positional metadata for native call protocols; source code is queried by the store. + /// VM 原生调用协议查询位置参数/返回约束;默认从上下文分派器获取。 + /// 源码函数签名由 Store 查询代码对象,此方法不是执行调用的入口。 fn call_signature(&self) -> Option { self.native_callable() .and_then(|callable| callable.signature()) } + /// VM 查询参数数量限制;默认从上下文分派器获取,None 表示没有此处的数量元数据。 fn call_arity(&self) -> Option { self.native_callable().and_then(|callable| callable.arity()) } + /// VM 的无上下文宿主调用入口:参数及原始结果句柄是借用,VM 随后验证并保留结果根。 + /// 默认不可调用;源码函数另走执行帧,需访问 Store 的原生函数另走 native_callable。 fn call(&self, _arguments: &[Value]) -> Result { Err(VmError::UnsupportedOperation("call")) } - /// Opt-in shared-reference assignment. Returning true preserves the existing - /// object identity after replacing its host-owned target. Ordinary payloads - /// return false and retain normal value assignment. Implementations must - /// validate before mutation and must not add untraced managed-object edges. - /// True only when legacy assign_from always returns false. Read-only - /// callers can then rebind a local reference without attempting mutation. - /// assignment_cell is checked first and remains a protected write protocol. + /// Store::assign_from 的只读优化标志:true 承诺旧式 assign_from 总返回 false。 + /// 因而执行器可在只读调用中直接重绑定局部引用,不尝试修改旧载荷。 + /// 托管 assignment_cell 协议优先且仍受写屏障保护;此标志不赋予修改旧对象的权限。 fn reference_assignment_only(&self) -> bool { false } + /// Store 的旧式宿主原地赋值协议;true 保留目标身份,false 让执行器使用新引用。 + /// 实现须先校验再修改,且不能改变未重新登记的托管强边;默认不原地赋值。 fn assign_from(&self, _source: &dyn ObjectPayload) -> Result { Ok(false) } - /// Optional managed shared-reference assignment. Return a built-in Cell - /// owned by this payload after validating the source and any domain cycles. - /// The store writes the source object to the Cell transactionally. This - /// keeps mutable edges inside the GC graph, unlike native assign_from. + /// Store 优先采用的共享引用赋值协议:校验 source 与领域环路后返回本载荷持有的 Cell。 + /// Store 将 source 写入该 Cell 并记录变更,确保可变引用边始终由 GC 管理;None 表示不用此协议。 fn assignment_cell( &self, _source: ObjectRef, @@ -171,39 +189,53 @@ pub trait ObjectPayload: Any + fmt::Debug + Send + Sync { } } +/// Store::new_object 和普通名义实例的无额外载荷记录;字段保存在 EndorObject.attributes。 #[derive(Debug, Default)] pub struct Record; impl ObjectPayload for Record { + // Record 没有原地赋值实现,允许只读调用直接重绑定引用。 fn reference_assignment_only(&self) -> bool { true } + // Store 下转型入口,返回自身的 Rust 类型信息。 fn as_any(&self) -> &dyn Any { self } + // 供错误或默认对象表示使用的诊断名称。 fn kind_name(&self) -> &'static str { "record" } + // 普通记录允许 Heap 在对象公共属性表中写入动态字段。 fn allows_attributes(&self) -> bool { true } } +/// 无捕获函数指针型宿主回调;含状态/上下文的调用应使用 NativeCallable 协议。 pub type EndorNativeCall = fn(&[Value]) -> Result; +/// 保留给既有嵌入方的回调类型别名。 pub type NativeCall = EndorNativeCall; +/// 宿主把简单 Rust 回调包装成可分配函数载荷,供 VM 的原生调用路径分派。 #[derive(Debug)] pub struct EndorNativeFunctionObject { + // 诊断和参数数量错误使用的函数名称。 name: String, + // 无捕获 Rust 回调,不包含额外托管引用边。 function: NativeCall, + // 可选位置参数数量约束,也可由完整 signature 提供。 arity: Option, + // 完整签名可能引用托管类型,必须通过 trace 持有这些引用。 signature: Option, } impl EndorNativeFunctionObject { + /// 宿主构造尚未分配的载荷;初始没有数量或类型签名约束,之后由 Store::allocate 接管。 pub fn new(name: impl Into, function: NativeCall) -> Self { + // 名称转为拥有的 String;函数指针本身无需额外所有权管理。 Self { name: name.into(), function, @@ -212,56 +244,71 @@ impl EndorNativeFunctionObject { } } + /// 宿主/诊断借用函数名,不执行回调。 pub fn name(&self) -> &str { &self.name } + /// 构造阶段补充完整签名,并同步数量限制;分配后签名中的引用由 Heap 边快照持有。 pub fn with_signature(mut self, signature: crate::CallSignature) -> Self { self.arity = Some(signature.arity); self.signature = Some(signature); self } + /// 构造阶段单独设置数量限制;不会重写已有完整签名,调用方应避免配置互相矛盾。 pub fn with_arity(mut self, arity: crate::CallArity) -> Self { self.arity = Some(arity); self } } -/// Compatibility name for existing embedders. +/// 为已有嵌入方保留的函数载荷名称,不引入第二种运行时对象。 pub type NativeFunction = EndorNativeFunctionObject; impl ObjectPayload for EndorNativeFunctionObject { + // 让 Store::allocate 按配置为该原生函数附着 Function 名义类型。 fn is_function(&self) -> bool { true } + // 不实现旧式原地赋值,因此引用重绑定不要求修改本载荷。 fn reference_assignment_only(&self) -> bool { true } + // Store 下转型入口,返回自身的 Rust 类型信息。 fn as_any(&self) -> &dyn Any { self } + // 供错误或默认对象表示使用的诊断名称。 fn kind_name(&self) -> &'static str { "native-function" } + // 用名称生成诊断表示,不调用回调,也不显示内存地址。 fn repr(&self, _identity: ObjectRef) -> Result { Ok(format!("", self.name)) } + // Heap 分配/替换时收集签名持有的类型引用;函数指针和名称不产生托管强边。 fn trace(&self, visit: &mut dyn FnMut(ObjectRef)) { + // 无完整签名时没有签名边;references 统一枚举参数与返回约束中的引用。 if let Some(signature) = &self.signature { + // 不去重:每次拥有的引用都要计入 Heap 的强边数量。 for reference in signature.references() { visit(reference); } } } + // VM 查询签名时复制元数据,不因其中句柄的 clone 而增加外部根。 fn call_signature(&self) -> Option { self.signature.clone() } + // VM 查询构造时声明的数量约束,不经上下文分派器。 fn call_arity(&self) -> Option { self.arity } + // VM 分派或宿主直接调用:先检查数量,再将同一参数切片借给 Rust 回调。 fn call(&self, arguments: &[Value]) -> Result { + // 未声明 arity 时不在这里限制数量;声明后错误必须先于回调的任何副作用返回。 if let Some(arity) = self.arity { arity.check(self.name.clone(), arguments.len())?; } @@ -269,77 +316,96 @@ impl ObjectPayload for EndorNativeFunctionObject { } } -/// Common runtime state. Embedders may attach an immutable managed type. +/// Heap 维护的公共头部;宿主只读访问,计数、版本和类型附着由受控 Store 操作更新。 #[derive(Debug)] pub struct ObjectHeader { + // 完整身份含堆、槽位和代际;槽复用后旧身份不能再次访问新对象。 pub(crate) identity: ObjectRef, + // 总强计数 = 外部根 + 对象图内部强边。 pub(crate) strong_refs: usize, + // 宿主持有和 VM 活跃执行槽持有的根数,是环回收的可达性起点。 pub(crate) external_refs: usize, + // 已记录修改的单调版本,用于整对象依赖重验。 pub(crate) change_version: u64, + // 可选名义类型强边,附着后不能通过普通属性改写。 pub(crate) type_object: Option, } impl ObjectHeader { + /// types/宿主读取头部附着的借用类型句柄;共享引用的有效类型仍需走 type_target 协议。 pub fn type_object(&self) -> Option { self.type_object } + /// Store/缓存借用版本快照;此 getter 本身不登记读取。 pub fn change_version(&self) -> u64 { self.change_version } + /// 宿主诊断读取完整句柄,不新建根引用。 pub fn identity(&self) -> ObjectRef { self.identity } + /// Store/测试读取包含内部边的总强计数。 pub fn ref_count(&self) -> usize { self.strong_refs } - /// Host-owned references and live execution roots, excluding heap edges. + /// Heap 环回收及诊断读取外部根数,不包含对象间强边。 pub fn external_ref_count(&self) -> usize { self.external_refs } } -/// Runtime object foundation, analogous in role to CPython's common object -/// structure, without its binary layout. The heap boxes this -/// structure so its address remains stable throughout its lifetime. +/// Heap 中稳定装箱的对象实体,把公共头部、动态载荷、属性和强边快照放在同一基础结构。 +/// 对象存活期间该实体地址稳定;这不保证单独替换的载荷盒地址不变。 #[derive(Debug)] pub struct EndorObject { + // 生命周期、身份、版本和名义类型公共信息。 pub(crate) header: ObjectHeader, + // 动态 Rust 载荷;替换载荷不会移动外层 EndorObject 的稳定盒地址。 pub(crate) payload: Box, + // 受 Heap 写屏障和计数维护的动态属性表,键是普通 Rust 字符串。 pub(crate) attributes: BTreeMap, + // 分配/替换载荷时记录的强边快照,保留重复项供精确计数与回收。 pub(crate) payload_edges: Vec, } impl EndorObject { + /// Store/宿主只读借用公共头部,不提供绕过计数和类型保护的可变入口。 pub fn header(&self) -> &ObjectHeader { &self.header } + /// Store/宿主借用动态载荷执行协议或下转型;getter 自身不验证句柄或登记读取。 pub fn payload(&self) -> &dyn ObjectPayload { self.payload.as_ref() } - /// Visits owned edges, not external roots. Payload edges are snapshotted at - /// allocation and refreshed on VM-managed payload replacement; attributes - /// are maintained by the VM's reference accounting. + /// Heap 的回收/释放路径枚举内部拥有边,不含外部根;类型、载荷快照和属性各自计数。 + /// 不重新调用载荷 trace,避免内部可变性使 GC 所见图与引用计数脱节。 pub fn trace(&self, visit: &mut dyn FnMut(ObjectRef)) { + // 类型附着本身拥有一条强边。 if let Some(reference) = self.header.type_object { visit(reference); } + // 逐项输出载荷快照,重复引用不能合并。 for reference in &self.payload_edges { visit(*reference); } + // 属性只有 Object 变体贡献托管边;文本/数值等由 Value 自身持有。 for value in self.attributes.values() { + // 将属性拥有的对象引用交给访问器,不改变计数。 if let Value::Object(reference) = value { visit(*reference); } } } + /// Heap 需要拥有的边列表时使用,把 trace 的回调输出收集成 Vec,不新增引用根。 pub(crate) fn edges(&self) -> Vec { + // 这是身份列表快照,不是深拷贝对象图。 let mut edges = Vec::new(); self.trace(&mut |reference| edges.push(reference)); edges diff --git a/crates/objects/src/store.rs b/crates/objects/src/store.rs index 359fd2d..5e078e4 100644 --- a/crates/objects/src/store.rs +++ b/crates/objects/src/store.rs @@ -1,20 +1,27 @@ +//! VM 与宿主共用的对象存储门面:分配、根引用、载荷操作、属性路径和读取依赖都从这里进入。 +//! heap 负责底层句柄/计数/写屏障;types 与 store_builtins 扩展此 impl,分别提供类型协议和容器操作。 + use crate::heap::Heap; use crate::{ ChangeBatch, ChangeKey, CompareOp, EndorObject, ObjectPayload, ObjectRef, Record, Value, VmError, WeakObjectRef, }; -/// Object storage independent of the VM evaluator. Construction creates an empty -/// heap; dropping it releases all objects and their host resources. Mutable -/// access is limited to operations that validate and account for owned edges. +/// 独立于指令执行器的存储;Vm 持有它,宿主也可单独使用。构造时堆为空,Drop 时释放全部载荷。 +/// 修改必须经受控入口,使引用边、只读保护和变更记录保持一致。 #[derive(Debug)] pub struct ObjectStore { + // 实际对象槽、引用计数、读依赖和待取变更批次的唯一存储。 pub(crate) heap: Heap, + // 新建函数自动附着的名义类型;使用弱引用,避免配置本身延长类型寿命。 function_type: Option, + // 宿主显式开启的字段声明/替换检查开关;默认关闭。 pub(crate) field_type_checks: bool, + // types 的 RAII guard 按线程登记正在校验的对象,阻止属性/类型转发导致递归重入。 pub(crate) active_attribute_checks: std::sync::Mutex< std::collections::HashMap>, >, + // contracts 按线程记录正在核对的对象/能力对,处理递归契约检查时的重入。 pub(crate) active_trait_checks: std::sync::Mutex< std::collections::HashMap< std::thread::ThreadId, @@ -24,8 +31,9 @@ pub struct ObjectStore { } impl ObjectStore { - /// Opt-in declared-field and method substitution checks, shared with the VM. + /// Vm::set_source_type_checks 委托的配置入口;影响后续字段与方法替换检查,不遍历重验已有对象。 pub fn set_field_type_checks(&mut self, enabled: bool) -> Result<(), VmError> { + // 配置属于持久状态,不能由只读调用改变;即使传入相同配置也拒绝。 if self.is_read_only() { return Err(VmError::UnsupportedOperation( "configure field type checks during read-only call", @@ -35,18 +43,23 @@ impl ObjectStore { Ok(()) } - /// Existing objects are immutable; fresh result graphs may be constructed. - /// Scopes must end in LIFO order. Read handles are borrowed, never GC roots. + /// VM 的只读调用路径进入此作用域:进入前已有对象被冻结,新建结果图仍可构造。 + /// 返回嵌套深度令牌,结束必须按 LIFO;读集合中的句柄是借用,不是 GC 根。 pub fn begin_read_only(&mut self) -> usize { self.heap.begin_read_only() } + /// VM 结束只读调用,返回兼容的对象读取集合;令牌错误时保持作用域未弹出。 pub fn end_read_only(&mut self, scope: usize) -> Result, VmError> { self.heap.end_read_only(scope) } + /// 只读调用的精确版本,额外保留整对象、字典种类、指定名称等不同依赖。 pub fn end_read_only_precise(&mut self, scope: usize) -> Result { self.heap.end_read_only_precise(scope) } + /// 缓存使用者重验一次观察;失效句柄或当前读取失败都表示依赖不再有效。 + /// 经正常读取入口比较,因此若当前另有读取作用域,也会登记相应观察。 pub fn read_dependency_valid(&self, dependency: &crate::ReadDependency) -> bool { + // 整对象检查版本;种类只检查仍是字典;名称检查当前 Option 是否保持相等。 match dependency { crate::ReadDependency::Object { object, version } => { self.change_version(*object).ok() == Some(*version) @@ -63,21 +76,21 @@ impl ObjectStore { .is_ok_and(|current| current == *value), } } + /// VM 子调用结束读取区间,同时取回程序/验证分类以及精确依赖;不结束外层只读作用域。 pub fn end_read_tracking_precise(&self, token: usize) -> Result { self.heap.end_read_tracking_precise(token) } - /// Track one subcall inside the active read-only scope. Regions nest in - /// LIFO order and do not clear the enclosing call's read dependencies. - /// Handles returned by end_read_tracking are borrowed, never owning roots. + /// VM 在已有只读作用域内标记一次子调用;区间按 LIFO 嵌套,不清除外层已收集的依赖。 + /// 没有只读作用域会报错;结束区间返回的句柄不新增根引用。 pub fn begin_read_tracking(&self) -> Result { self.heap.begin_read_tracking() } + /// 兼容入口:结束子区间,只返回读取对象,不保留读取分类和具体依赖键。 pub fn end_read_tracking(&self, token: usize) -> Result, VmError> { self.heap.end_read_tracking(token) } - /// Like end_read_tracking, retaining the distinction between program reads - /// and VM annotation validation. Ordinary reads always dominate. + /// VM 核对调用契约时使用,区分程序内容读取与注解验证读取;两者都有时内容读取优先。 pub fn end_read_tracking_details( &self, token: usize, @@ -85,18 +98,20 @@ impl ObjectStore { self.heap.end_read_tracking_details(token) } + /// VM/宿主判断当前是否位于任意只读作用域,不表示所有新建对象也不可写。 pub fn is_read_only(&self) -> bool { self.heap.is_read_only() } + /// 宿主缓存或类型配置把有效强句柄转为弱句柄;不增加计数,也不消耗调用方已有根。 pub fn downgrade(&self, reference: ObjectRef) -> Result { self.object(reference)?; Ok(WeakObjectRef(reference)) } - /// Returns a new owned root, or None when the original object was released. - /// A foreign store is an error, not an expired reference. + /// 宿主升级弱句柄:存活则 retain 一份外部根,已释放返回 None;跨堆引用仍是错误。 pub fn upgrade(&mut self, weak: WeakObjectRef) -> Result, VmError> { + // 先验证代际与堆身份;只有 InvalidHandle 被解释为过期,其他错误原样传播。 match self.object(weak.0) { Ok(_) => { self.retain(weak.0)?; @@ -107,20 +122,23 @@ impl ObjectStore { } } + /// Vm::take_changes 及宿主缓存取走累计变更批次;清空待取记录,不重置对象版本。 pub fn take_changes(&mut self) -> ChangeBatch { self.heap.take_changes() } + /// 缓存读取对象版本;通过 object 进入,若正在收集依赖也会记录此对象的读取。 pub fn change_version(&self, reference: ObjectRef) -> Result { Ok(self.object(reference)?.header().change_version()) } - /// Replace a host payload transactionally, including all owned GC edges. + /// 宿主提交新载荷及其全部引用边;保持对象身份、属性和头部类型,校验失败不替换载荷。 pub fn replace_payload( &mut self, reference: ObjectRef, payload: impl ObjectPayload, ) -> Result<(), VmError> { + // Type 定义不可被换成其他载荷,防止类型布局在创建后发生变化。 if self .object(reference)? .payload() @@ -131,6 +149,7 @@ impl ObjectStore { "replace immutable type definition", )); } + // Trait 定义同样不可替换,防止已登记的能力契约发生隐式变化。 if self .object(reference)? .payload() @@ -141,44 +160,56 @@ impl ObjectStore { "replace immutable trait definition", )); } + // 先核对内置载荷结构,再交由 Heap 验证 trace 强边与引用计数。 self.validate_builtin(&payload)?; self.heap.replace_payload(reference, payload) } + /// eval::assignment_value 在新旧值都是对象时调用;true 表示更新旧对象并保留其身份。 + /// false 表示未执行此类原地赋值,执行器可改用传入的新对象引用。 pub fn assign_from(&mut self, target: ObjectRef, source: ObjectRef) -> Result { + // 两端必须是本堆存活对象;不能把异堆或过期句柄传给宿主赋值协议。 self.object(target)?; self.object(source)?; + // 优先采用托管 Cell 协议;载荷负责校验来源和领域环路,Store 负责实际更新引用边。 if let Some(cell) = self .object(target)? .payload() .assignment_cell(source, self)? { + // 转发对象本身也受只读保护,不能只检查承载引用的 Cell。 self.heap.prepare_change(target)?; - // Replacing the Cell edge may otherwise reclaim a target which is - // reachable only through the edge being removed. + // 更新 Cell 可能移除维持 target 存活的最后一条内部边;临时根保证记录变更前仍存活。 self.retain(target)?; + // 无论写入成功与否都释放临时根;仅成功时通知 target 的观察者。 let result = self.cell_set(cell, Value::Object(source)); + // Cell 自己会记录变更;这里另记转发对象的 Contents,覆盖经转发器读取的依赖。 if result.is_ok() { self.heap.record_change(target, ChangeKey::Contents); } self.release(target)?; return result.map(|()| true); } + // 仅引用赋值载荷承诺 legacy assign_from 总是 false,可在只读局部重绑定时跳过写屏障。 if self.is_read_only() && self.object(target)?.payload().reference_assignment_only() { return Ok(false); } + // 旧式宿主原地赋值在调用前检查写屏障;实现不得悄悄改变 trace 中的托管边。 self.heap.prepare_change(target)?; let changed = self .object(target)? .payload() .assign_from(self.object(source)?.payload())?; + // false 不产生变更;true 表示宿主已更新载荷,发布一次 Contents 通知。 if changed { self.heap.record_change(target, ChangeKey::Contents); } Ok(changed) } + /// Vm::new 及独立宿主创建空堆;不隐式创建语言根类型或内置函数。 pub fn new() -> Result { + // 初始没有函数类型配置,检查开关关闭,递归校验集合按需要惰性填充。 Ok(Self { heap: Heap::new()?, function_type: None, @@ -188,25 +219,34 @@ impl ObjectStore { }) } + /// 宿主/测试查询存活堆对象数;不是累计分配数,也不含直接 Value 标量。 pub fn object_count(&self) -> usize { self.heap.len() } - /// Returns one external strong reference. Copies of the returned handle - /// are borrowed; use retain/release to manage additional owned references. + /// new_*、类型构造及宿主创建载荷的共同入口;成功返回一份外部强根。 + /// 复制返回句柄不会 retain,额外所有权须显式 retain/release。 pub fn allocate(&mut self, payload: impl ObjectPayload) -> Result { + // 先核对内置载荷结构,再交由 Heap 验证 trace 强边与引用计数。 self.validate_builtin(&payload)?; + // 函数分类由载荷声明;不是所有可调用对象(例如 Type)都自动附着 Function 类型。 let function = payload.is_function(); + // Heap 分配稳定的对象盒并登记载荷强边;从此该对象已持有一份外部根。 let object = self.heap.allocate(Box::new(payload))?; + // 只有函数且配置过 Function 类型才附着;过期配置是错误,不静默创建无类型函数。 if function && let Some(weak) = self.function_type { + // 局部闭包收集附着结果,以便外层统一清理新对象的根。 let result = (|| { + // 升级得到临时类型根,附着后对象自身的类型边承担持有责任。 let definition = self.upgrade(weak)?.ok_or(VmError::InvalidArgument( "configured Function type has expired", ))?; + // 保存附着结果,先释放升级产生的根,再把附着错误交给外层处理。 let result = self.attach_type(object, definition); self.release(definition)?; result })(); + // 类型附着失败时释放本次分配的对象,不向调用者泄漏半初始化结果。 if let Err(error) = result { self.release(object)?; return Err(error); @@ -215,14 +255,18 @@ impl ObjectStore { Ok(object) } + /// Vm::set_function_type 在根类型初始化时配置后续函数的名义类型;同一类型可重复设置。 pub fn set_function_type(&mut self, definition: ObjectRef) -> Result<(), VmError> { self.payload::(definition, "Type")?; + // 配置属于持久状态,不能由只读调用改变;即使传入相同配置也拒绝。 if self.is_read_only() { return Err(VmError::UnsupportedOperation( "configure Function type during read-only call", )); } + // 只保存弱引用;类型生命周期由根类型集合或已附着的对象负责。 let weak = self.downgrade(definition)?; + // 已配置后不能换成另一个类型,避免新旧函数的隐式类型规则不一致。 if self.function_type.is_some_and(|old| old != weak) { return Err(VmError::InvalidArgument( "Function type is already configured", @@ -232,28 +276,35 @@ impl ObjectStore { Ok(()) } + /// Vm::new_object/宿主创建普通可附属性的 Record,名义类型由调用者另行附着。 pub fn new_object(&mut self) -> Result { self.allocate(Record) } + /// 宿主及各访问器借用完整对象;验证句柄并在只读收集上下文登记当前版本读取。 pub fn object(&self, reference: ObjectRef) -> Result<&EndorObject, VmError> { + // 不增加外部根;返回引用受 self 的 Rust 借用期约束。 let object = self.heap.get(reference)?; self.heap .record_read(reference, object.header().change_version()); Ok(object) } - /// Borrowed storage path: depend on Contents for intermediate objects and - /// Attribute(name) on the final storage object. Every handle is validated. + /// 属性读写与类型协议沿 attribute_target 查找实际存储对象,返回含起点和终点的借用句柄链。 + /// 此处每一跳通过 object 记录整对象读取;最终具体属性的读取由调用方继续处理。 pub fn attribute_path(&self, reference: ObjectRef) -> Result, VmError> { + // path 保存访问顺序,seen 检测转发环,current 是本轮需要验证并展开的对象。 let mut path = Vec::new(); let mut seen = std::collections::BTreeSet::new(); let mut current = reference; + // 每次至少加入一个对象;遇到无转发目标才正常结束,因此成功路径一定非空。 loop { + // 重访同一身份说明转发环路,不能靠无限追踪寻找属性终点。 if !seen.insert(current) { return Err(VmError::InvalidArgument("cyclic attribute storage")); } path.push(current); + // 有目标则继续;目标在下一轮验证归属/存活;None 表示该对象自行存储属性。 match self.object(current)?.payload().attribute_target(self)? { Some(target) => current = target, None => return Ok(path), @@ -261,54 +312,68 @@ impl ObjectStore { } } + /// VM 执行槽和宿主把借用句柄变为额外拥有的根,同时增加 external 和 strong 计数。 pub fn retain(&mut self, reference: ObjectRef) -> Result<(), VmError> { self.heap.retain(reference) } + /// VM 清理槽或宿主归还一份外部根;计数降零时连带释放对象拥有的内部边。 + /// 没有外部根时会报错,不能用它归还仅由其他对象持有的内部边。 pub fn release(&mut self, reference: ObjectRef) -> Result<(), VmError> { self.heap.release(reference) } + /// 测试/诊断查询总强计数,包含外部根和堆内强边,不新增读取版本依赖。 pub fn ref_count(&self, reference: ObjectRef) -> Result { Ok(self.heap.get(reference)?.header().ref_count()) } + /// VM/宿主做身份比较:两端均先验证,随后比较完整堆身份、槽与代际,不调用载荷相等协议。 pub fn is_same(&self, left: ObjectRef, right: ObjectRef) -> Result { self.heap.get(left)?; self.heap.get(right)?; Ok(left == right) } + /// Vm::repr 委托载荷生成诊断表示;直接 heap.get,不自动记录整对象读取。 pub fn repr(&self, reference: ObjectRef) -> Result { self.heap.get(reference)?.payload().repr(reference) } + /// Vm::str 委托用户可见文本表示,默认载荷实现回退到 repr。 pub fn str(&self, reference: ObjectRef) -> Result { self.heap.get(reference)?.payload().str(reference) } + /// VM 真值转换调用载荷协议;错误保持为错误,不把协议失败解释为 false。 pub fn is_true(&self, reference: ObjectRef) -> Result { self.heap.get(reference)?.payload().is_true() } + /// 通用字典键准入及宿主哈希调用载荷协议,载荷可明确拒绝哈希。 pub fn hash(&self, reference: ObjectRef) -> Result { self.heap.get(reference)?.payload().hash(reference) } + /// VM 对象比较和字典对象键查找共用的双向协议;不运行源码函数比较方法。 pub fn compare( &self, left: ObjectRef, right: ObjectRef, operation: CompareOp, ) -> Result { + // 借用双方载荷;这条底层协议路径不通过 object,因此不自动收集对象版本依赖。 let left_payload = self.heap.get(left)?.payload(); let right_payload = self.heap.get(right)?.payload(); + // 左侧能处理就立即返回;Some(false) 也是已实现结果,不能继续尝试右侧。 if let Some(result) = left_payload.compare(right_payload, operation)? { return Ok(result); } + // 右侧收到对调后的运算(如 a < b 变为 b > a),仅在左侧返回 None 时调用。 if let Some(result) = right_payload.compare(left_payload, operation.reflected())? { return Ok(result); } + // 两端均未实现:相等/不等回退身份,有序比较不能凭身份定义大小。 match operation { CompareOp::Eq => Ok(left == right), CompareOp::Ne => Ok(left != right), @@ -316,34 +381,39 @@ impl ObjectStore { } } - /// Reads a borrowed value. An Object result needs retain() if the host - /// wants it to survive removal of the attribute that currently owns it. + /// Vm::get_attr/宿主读取属性或继承方法;返回对象句柄是借用,跨原持有者寿命需 retain。 pub fn get_attr(&self, reference: ObjectRef, name: &str) -> Result { self.lookup_attr(reference, name) + // 此兼容入口将方法查找结果摊平成函数句柄;接收者绑定由 VM 的方法调用路径处理。 .map(|attribute| match attribute { crate::types::AttributeLookup::Value(value) => value, crate::types::AttributeLookup::Method { function, .. } => Value::Object(function), }) } - /// Object-valued attributes own internal strong references independently - /// of the caller's external references. Failure leaves the field unchanged. + /// Vm::set_attr 和宿主属性写入入口;对象值成为独立内部强边,不消耗传入句柄的外部根。 + /// 写入前核对类型/契约限制及实际存储路径,再由 Heap 执行写屏障与引用更新。 pub fn set_attr( &mut self, reference: ObjectRef, name: impl Into, value: Value, ) -> Result<(), VmError> { + // 名称只拥有一次,后续校验借用,最终交给 Heap 作为属性键。 let name = name.into(); + // 已附着的名义类型不能通过普通属性写入/删除来替换。 if name == "type" && self.type_of(reference)?.is_some() { return Err(VmError::UnsupportedOperation("write object type")); } + // 只有开启声明检查才校验字段值;能力方法的遮蔽限制在下一段独立执行。 if self.field_type_checks { self.check_field_write(reference, &name, &value)?; } + // 转发链每个对象都可能声明能力方法,不能借转发终点的属性绕过方法契约。 for object in self.attribute_path(reference)? { self.check_typed_method_write(object, &name)?; } + // 取经过验证的最后一个对象作为实际属性存储;attribute_path 成功时必非空。 let storage = *self .attribute_path(reference)? .last() @@ -351,13 +421,17 @@ impl ObjectStore { self.heap.set_attr(storage, name, value) } + /// Vm::del_attr/宿主删除属性;先防止删除受保护类型与声明字段,再定位实际存储。 pub fn del_attr(&mut self, reference: ObjectRef, name: &str) -> Result<(), VmError> { + // 开启声明检查后,字段必须维持存在;不能用删除规避字段类型约束。 if self.field_type_checks && self.declared_field(reference, name)?.is_some() { return Err(VmError::UnsupportedOperation("delete declared class field")); } + // 已附着的名义类型不能通过普通属性写入/删除来替换。 if name == "type" && self.type_of(reference)?.is_some() { return Err(VmError::UnsupportedOperation("delete object type")); } + // 取经过验证的最后一个对象作为实际属性存储;attribute_path 成功时必非空。 let storage = *self .attribute_path(reference)? .last() @@ -365,16 +439,17 @@ impl ObjectStore { self.heap.del_attr(storage, name) } - /// Validate a borrowed object handle without taking an owned reference. + /// 容器写入等路径验证 Value:仅对象变体需要检查句柄,不 retain,也不登记内容读取。 pub fn validate_value(&self, value: &Value) -> Result<(), VmError> { + // 直接值没有堆归属;对象值必须属于本堆且对应存活代际。 if let Value::Object(reference) = value { self.heap.get(*reference)?; } Ok(()) } - /// Explicit full collection. Execution slots use owned roots, so values - /// on live execution stacks participate in the same root accounting. + /// Vm::collect_cycles/宿主显式回收没有外部根可达的环;返回回收对象数。 + /// 活跃执行槽以外部根计数,正常参与存活判定,不另建特殊的 VM 栈扫描通道。 pub fn collect_cycles(&mut self) -> usize { self.heap.collect_cycles() }