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