457 lines
22 KiB
Rust
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()
|
|
}
|
|
}
|