docs(objects): explain store lifecycle and payload protocols
This commit is contained in:
+115
-49
@@ -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<AwaitPoll, VmError> {
|
||||
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<Option<ObjectRef>, 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<Option<ObjectRef>, 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<std::sync::Arc<dyn crate::NativeCallable>> {
|
||||
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<String, VmError> {
|
||||
Ok(format!("<{} {identity}>", self.kind_name()))
|
||||
}
|
||||
|
||||
/// Store::str 的文本协议;未覆盖时复用 repr,宿主可提供更适合显示的文本。
|
||||
fn str(&self, identity: ObjectRef) -> Result<String, VmError> {
|
||||
self.repr(identity)
|
||||
}
|
||||
|
||||
/// Store::is_true/VM 分支求真时调用;普通对象默认真,容器或标量载荷可覆盖。
|
||||
fn is_true(&self) -> Result<bool, VmError> {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// Store::hash 默认按身份哈希;若实现内容相等,须同步实现兼容哈希或拒绝哈希。
|
||||
fn hash(&self, identity: ObjectRef) -> Result<u64, VmError> {
|
||||
// 哈希整个句柄身份,不使用载荷地址;结果不是跨进程稳定标识。
|
||||
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<crate::CallSignature> {
|
||||
self.native_callable()
|
||||
.and_then(|callable| callable.signature())
|
||||
}
|
||||
|
||||
/// VM 查询参数数量限制;默认从上下文分派器获取,None 表示没有此处的数量元数据。
|
||||
fn call_arity(&self) -> Option<crate::CallArity> {
|
||||
self.native_callable().and_then(|callable| callable.arity())
|
||||
}
|
||||
|
||||
/// VM 的无上下文宿主调用入口:参数及原始结果句柄是借用,VM 随后验证并保留结果根。
|
||||
/// 默认不可调用;源码函数另走执行帧,需访问 Store 的原生函数另走 native_callable。
|
||||
fn call(&self, _arguments: &[Value]) -> Result<Value, VmError> {
|
||||
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<bool, VmError> {
|
||||
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<Value, VmError>;
|
||||
/// 保留给既有嵌入方的回调类型别名。
|
||||
pub type NativeCall = EndorNativeCall;
|
||||
|
||||
/// 宿主把简单 Rust 回调包装成可分配函数载荷,供 VM 的原生调用路径分派。
|
||||
#[derive(Debug)]
|
||||
pub struct EndorNativeFunctionObject {
|
||||
// 诊断和参数数量错误使用的函数名称。
|
||||
name: String,
|
||||
// 无捕获 Rust 回调,不包含额外托管引用边。
|
||||
function: NativeCall,
|
||||
// 可选位置参数数量约束,也可由完整 signature 提供。
|
||||
arity: Option<crate::CallArity>,
|
||||
// 完整签名可能引用托管类型,必须通过 trace 持有这些引用。
|
||||
signature: Option<crate::CallSignature>,
|
||||
}
|
||||
|
||||
impl EndorNativeFunctionObject {
|
||||
/// 宿主构造尚未分配的载荷;初始没有数量或类型签名约束,之后由 Store::allocate 接管。
|
||||
pub fn new(name: impl Into<String>, 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<String, VmError> {
|
||||
Ok(format!("<native-function {}>", 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<crate::CallSignature> {
|
||||
self.signature.clone()
|
||||
}
|
||||
// VM 查询构造时声明的数量约束,不经上下文分派器。
|
||||
fn call_arity(&self) -> Option<crate::CallArity> {
|
||||
self.arity
|
||||
}
|
||||
// VM 分派或宿主直接调用:先检查数量,再将同一参数切片借给 Rust 回调。
|
||||
fn call(&self, arguments: &[Value]) -> Result<Value, VmError> {
|
||||
// 未声明 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<ObjectRef>,
|
||||
}
|
||||
|
||||
impl ObjectHeader {
|
||||
/// types/宿主读取头部附着的借用类型句柄;共享引用的有效类型仍需走 type_target 协议。
|
||||
pub fn type_object(&self) -> Option<ObjectRef> {
|
||||
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<dyn ObjectPayload>,
|
||||
// 受 Heap 写屏障和计数维护的动态属性表,键是普通 Rust 字符串。
|
||||
pub(crate) attributes: BTreeMap<String, Value>,
|
||||
// 分配/替换载荷时记录的强边快照,保留重复项供精确计数与回收。
|
||||
pub(crate) payload_edges: Vec<ObjectRef>,
|
||||
}
|
||||
|
||||
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<ObjectRef> {
|
||||
// 这是身份列表快照,不是深拷贝对象图。
|
||||
let mut edges = Vec::new();
|
||||
self.trace(&mut |reference| edges.push(reference));
|
||||
edges
|
||||
|
||||
+102
-27
@@ -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<WeakObjectRef>,
|
||||
// 宿主显式开启的字段声明/替换检查开关;默认关闭。
|
||||
pub(crate) field_type_checks: bool,
|
||||
// types 的 RAII guard 按线程登记正在校验的对象,阻止属性/类型转发导致递归重入。
|
||||
pub(crate) active_attribute_checks: std::sync::Mutex<
|
||||
std::collections::HashMap<std::thread::ThreadId, std::collections::BTreeSet<ObjectRef>>,
|
||||
>,
|
||||
// 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<Vec<ObjectRef>, VmError> {
|
||||
self.heap.end_read_only(scope)
|
||||
}
|
||||
/// 只读调用的精确版本,额外保留整对象、字典种类、指定名称等不同依赖。
|
||||
pub fn end_read_only_precise(&mut self, scope: usize) -> Result<crate::ReadSet, VmError> {
|
||||
self.heap.end_read_only_precise(scope)
|
||||
}
|
||||
/// 缓存使用者重验一次观察;失效句柄或当前读取失败都表示依赖不再有效。
|
||||
/// 经正常读取入口比较,因此若当前另有读取作用域,也会登记相应观察。
|
||||
pub fn read_dependency_valid(&self, dependency: &crate::ReadDependency) -> bool {
|
||||
// 整对象检查版本;种类只检查仍是字典;名称检查当前 Option<Value> 是否保持相等。
|
||||
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<crate::TrackedReads, VmError> {
|
||||
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<usize, VmError> {
|
||||
self.heap.begin_read_tracking()
|
||||
}
|
||||
/// 兼容入口:结束子区间,只返回读取对象,不保留读取分类和具体依赖键。
|
||||
pub fn end_read_tracking(&self, token: usize) -> Result<Vec<ObjectRef>, 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<WeakObjectRef, VmError> {
|
||||
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<Option<ObjectRef>, 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<u64, VmError> {
|
||||
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<bool, VmError> {
|
||||
// 两端必须是本堆存活对象;不能把异堆或过期句柄传给宿主赋值协议。
|
||||
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<Self, VmError> {
|
||||
// 初始没有函数类型配置,检查开关关闭,递归校验集合按需要惰性填充。
|
||||
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<ObjectRef, VmError> {
|
||||
// 先核对内置载荷结构,再交由 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::<crate::EndorTypeObject>(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<ObjectRef, VmError> {
|
||||
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<Vec<ObjectRef>, 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<usize, VmError> {
|
||||
Ok(self.heap.get(reference)?.header().ref_count())
|
||||
}
|
||||
|
||||
/// VM/宿主做身份比较:两端均先验证,随后比较完整堆身份、槽与代际,不调用载荷相等协议。
|
||||
pub fn is_same(&self, left: ObjectRef, right: ObjectRef) -> Result<bool, VmError> {
|
||||
self.heap.get(left)?;
|
||||
self.heap.get(right)?;
|
||||
Ok(left == right)
|
||||
}
|
||||
|
||||
/// Vm::repr 委托载荷生成诊断表示;直接 heap.get,不自动记录整对象读取。
|
||||
pub fn repr(&self, reference: ObjectRef) -> Result<String, VmError> {
|
||||
self.heap.get(reference)?.payload().repr(reference)
|
||||
}
|
||||
|
||||
/// Vm::str 委托用户可见文本表示,默认载荷实现回退到 repr。
|
||||
pub fn str(&self, reference: ObjectRef) -> Result<String, VmError> {
|
||||
self.heap.get(reference)?.payload().str(reference)
|
||||
}
|
||||
|
||||
/// VM 真值转换调用载荷协议;错误保持为错误,不把协议失败解释为 false。
|
||||
pub fn is_true(&self, reference: ObjectRef) -> Result<bool, VmError> {
|
||||
self.heap.get(reference)?.payload().is_true()
|
||||
}
|
||||
|
||||
/// 通用字典键准入及宿主哈希调用载荷协议,载荷可明确拒绝哈希。
|
||||
pub fn hash(&self, reference: ObjectRef) -> Result<u64, VmError> {
|
||||
self.heap.get(reference)?.payload().hash(reference)
|
||||
}
|
||||
|
||||
/// VM 对象比较和字典对象键查找共用的双向协议;不运行源码函数比较方法。
|
||||
pub fn compare(
|
||||
&self,
|
||||
left: ObjectRef,
|
||||
right: ObjectRef,
|
||||
operation: CompareOp,
|
||||
) -> Result<bool, VmError> {
|
||||
// 借用双方载荷;这条底层协议路径不通过 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<Value, VmError> {
|
||||
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<String>,
|
||||
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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user