Files
endorphin-aster-vm/crates/objects/src/store.rs
T

457 lines
22 KiB
Rust

//! VM 与宿主共用的对象存储门面:分配、根引用、载荷操作、属性路径和读取依赖都从这里进入。
//! heap 负责底层句柄/计数/写屏障;types 与 store_builtins 扩展此 impl,分别提供类型协议和容器操作。
use crate::heap::Heap;
use crate::{
ChangeBatch, ChangeKey, CompareOp, EndorObject, ObjectPayload, ObjectRef, Record, Value,
VmError, WeakObjectRef,
};
/// 独立于指令执行器的存储;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,
std::collections::BTreeSet<(ObjectRef, ObjectRef)>,
>,
>,
}
impl ObjectStore {
/// 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",
));
}
self.field_type_checks = enabled;
Ok(())
}
/// 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)
}
crate::ReadDependency::DictionaryKind { object } => {
self.dictionary_kind(*object).is_ok()
}
crate::ReadDependency::Name {
object,
name,
value,
} => self
.dict_get_name(*object, name)
.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)
}
/// 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)
}
/// VM 核对调用契约时使用,区分程序内容读取与注解验证读取;两者都有时内容读取优先。
pub fn end_read_tracking_details(
&self,
token: usize,
) -> Result<Vec<crate::ReadAccess>, VmError> {
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))
}
/// 宿主升级弱句柄:存活则 retain 一份外部根,已释放返回 None;跨堆引用仍是错误。
pub fn upgrade(&mut self, weak: WeakObjectRef) -> Result<Option<ObjectRef>, VmError> {
// 先验证代际与堆身份;只有 InvalidHandle 被解释为过期,其他错误原样传播。
match self.object(weak.0) {
Ok(_) => {
self.retain(weak.0)?;
Ok(Some(weak.0))
}
Err(VmError::InvalidHandle) => Ok(None),
Err(error) => Err(error),
}
}
/// 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())
}
/// 宿主提交新载荷及其全部引用边;保持对象身份、属性和头部类型,校验失败不替换载荷。
pub fn replace_payload(
&mut self,
reference: ObjectRef,
payload: impl ObjectPayload,
) -> Result<(), VmError> {
// Type 定义不可被换成其他载荷,防止类型布局在创建后发生变化。
if self
.object(reference)?
.payload()
.as_any()
.is::<crate::EndorTypeObject>()
{
return Err(VmError::UnsupportedOperation(
"replace immutable type definition",
));
}
// Trait 定义同样不可替换,防止已登记的能力契约发生隐式变化。
if self
.object(reference)?
.payload()
.as_any()
.is::<crate::EndorTraitObject>()
{
return Err(VmError::UnsupportedOperation(
"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)?;
// 更新 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,
field_type_checks: false,
active_attribute_checks: std::sync::Mutex::new(std::collections::HashMap::new()),
active_trait_checks: std::sync::Mutex::new(std::collections::HashMap::new()),
})
}
/// 宿主/测试查询存活堆对象数;不是累计分配数,也不含直接 Value 标量。
pub fn object_count(&self) -> usize {
self.heap.len()
}
/// 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);
}
}
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",
));
}
self.function_type = Some(weak);
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)
}
/// 属性读写与类型协议沿 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),
}
}
}
/// 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),
_ => Err(VmError::UnsupportedOperation("ordering")),
}
}
/// 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),
})
}
/// 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()
.expect("nonempty attribute path");
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()
.expect("nonempty attribute path");
self.heap.del_attr(storage, name)
}
/// 容器写入等路径验证 Value:仅对象变体需要检查句柄,不 retain,也不登记内容读取。
pub fn validate_value(&self, value: &Value) -> Result<(), VmError> {
// 直接值没有堆归属;对象值必须属于本堆且对应存活代际。
if let Value::Object(reference) = value {
self.heap.get(*reference)?;
}
Ok(())
}
/// Vm::collect_cycles/宿主显式回收没有外部根可达的环;返回回收对象数。
/// 活跃执行槽以外部根计数,正常参与存活判定,不另建特殊的 VM 栈扫描通道。
pub fn collect_cycles(&mut self) -> usize {
self.heap.collect_cycles()
}
}