diff --git a/crates/core/src/eval.rs b/crates/core/src/eval.rs index f5ec9b8..24f43b2 100644 --- a/crates/core/src/eval.rs +++ b/crates/core/src/eval.rs @@ -1308,6 +1308,8 @@ impl Vm { .new_class_with_scope(name, base, fields, methods, Some(frame.function)) } + /// 所有同步/切片/协程入口共用的显式帧循环:Some 是拥有结果,None 是软预算或允许的 await 停放。 + /// 错误不在本函数销毁全部帧,由外层保存回溯再统一清理;指令索引/栈高已在代码构造时验证。 fn eval_frames( &mut self, frames: &mut Vec, @@ -1316,43 +1318,58 @@ impl Vm { slice_end: usize, allow_wait: bool, ) -> Result, VmError> { + // 每轮只推进当前最内层帧,源码调用通过帧向量增长而非 Rust 递归。 loop { + // 硬上限先于软边界检查,同点到达硬上限必须报错,不能继续 Pending。 if *executed >= limits.max_instructions { return Err(VmError::ExecutionLimit("instructions")); } + // 软量子结束保留帧、栈和指令指针,外层决定如何停放。 if *executed >= slice_end { return Ok(None); } + // 实际取指前累计一次,原生委托准备另在 prepare_call 计数。 *executed += 1; + // 当前帧必须存在;源码 Return 最外层时会提前返回结果退出循环。 let frame = frames.last_mut().expect("an evaluation frame is active"); + // 按完整逻辑指令起点取指,扩展前缀已合并,非法指针返回位置错误。 let decoded = frame.executable.instruction_at(frame.instruction_offset)?; + // 保存当前起点给错误诊断,同时预置顺序后继;跳转/等待会覆盖下一位置。 frame.current_offset = decoded.offset; frame.instruction_offset = decoded.next_offset; + // 本轮操作种类,后面的栈和槽更新按此分派。 let opcode = decoded.instruction.opcode; + // 完整 u32 操作数转为索引/数量,范围合法性由代码验证保证。 let argument = decoded.instruction.argument as usize; + // 每条指令成功后保持根计数与栈/槽一致,错误交外层清理当前帧。 match opcode { Opcode::Await => { + // 只读调用不允许 await,不可用等待期间外部修改破坏只读快照。 if self.objects.is_read_only() { return Err(VmError::UnsupportedOperation( "await during read-only execution", )); } + // 等待协议仅对象可实现,直接 Nil/数字/文本都不能 await。 let Value::Object(awaitable) = Self::top_value(frame)? else { return Err(VmError::ObjectKindMismatch("awaitable object")); }; + // poll_await 非阻塞观察当前状态,不重跑生成等待对象的表达式。 match self.object(awaitable)?.payload().poll_await()? { + // 操作数根继续留栈,协程状态稍后接管;同步入口不允许这种停放。 crate::AwaitPoll::Pending => { + // 仅可变协程支持 Pending await,同步调用不能悄悄变为暂停。 if !allow_wait { return Err(VmError::UnsupportedOperation( "pending await outside a coroutine", )); } - // Keep the evaluated operand, never replay its call - // or the statements before this await instruction. + // 保留已求值等待操作数,指针回到 Await 本身;不会重放此前调用或语句。 frame.waiting = true; frame.instruction_offset = decoded.offset; return Ok(None); } + // 先取得结果根再释放等待操作数,避免结果仅由等待对象图持有时失效。 crate::AwaitPoll::Ready(value) => { self.retain_value(&value)?; self.discard(frame, 1); @@ -1361,47 +1378,61 @@ impl Vm { } } } + // 无操作,只消耗本轮预算并继续预置后继。 Opcode::Nop => {} Opcode::LoadConst => { + // clone 仍为借用表示,push_borrowed 为结果栈项取得独立根。 let value = frame.executable.constants()[argument].clone(); self.push_borrowed(frame, value)?; } Opcode::LoadFast => { + // 未绑定 None 报具名局部错误,已绑定值压栈时另保留根。 let value = frame.localsplus[argument].clone().ok_or_else(|| { VmError::UnboundLocal(frame.executable.slot_name(argument).into()) })?; self.push_borrowed(frame, value)?; } + // 局部赋值先保留新槽根,再释放原栈输入及被替换旧槽根。 Opcode::StoreFast => { + // 先执行共享引用赋值选择,可能保留旧对象身份,再按目标槽/字典协议提交。 let value = self.assignment_value( frame.localsplus[argument].clone(), Self::top_value(frame)?, )?; self.retain_value(&value)?; self.discard(frame, 1); + // 新值先保留/写入,最后归还被替换的旧槽根,即使新旧同身份也安全。 if let Some(old) = frame.localsplus[argument].replace(value) { self.drop_root(old); } } Opcode::DeleteFast => { + // 先移走槽拥有值,使局部恢复 None,再归还旧根。 let value = frame.localsplus[argument].take().ok_or_else(|| { VmError::UnboundLocal(frame.executable.slot_name(argument).into()) })?; self.drop_root(value); } Opcode::LoadGlobal => { + // 从代码 names 表借用名称,索引不来自任意运行时文本。 let name = &frame.executable.layout().names[argument]; + // 按名记录命中/缺失,只在全局缺失时查询捕获的内置字典。 let mut value = self.objects.dict_get_name(frame.globals, name)?; + // Some(Nil) 也是命中,不会回退内置空间。 if value.is_none() && let Some(builtins) = frame.builtins { value = self.objects.dict_get_name(builtins, name)?; } + // 全局和可选内置均未命中才报 NameNotFound。 let value = value.ok_or_else(|| VmError::NameNotFound(name.clone()))?; self.push_borrowed(frame, value)?; } + // 全局修改由字典拥有新值内部边,成功后释放输入栈根。 Opcode::StoreGlobal => { + // 全局写入使用直接文本键,与名称读取协议对应。 let key = Value::Text(frame.executable.layout().names[argument].clone()); + // 先执行共享引用赋值选择,可能保留旧对象身份,再按目标槽/字典协议提交。 let value = self.assignment_value( self.dict_get(frame.globals, &key)?, Self::top_value(frame)?, @@ -1410,17 +1441,22 @@ impl Vm { self.discard(frame, 1); } Opcode::DeleteGlobal => { + // 从代码 names 表借用名称,索引不来自任意运行时文本。 let name = &frame.executable.layout().names[argument]; + // 删除缺键报告名称错误,字典删除协议其他错误正常传播。 if !self.dict_delete(frame.globals, &Value::Text(name.clone()))? { return Err(VmError::NameNotFound(name.clone())); } } Opcode::LoadDeref | Opcode::LoadClosure => { + // 对应槽必须存活且为 Cell,本帧与闭包函数均可能持有其根/边。 let cell = self.cell_slot(frame, argument)?; + // LoadClosure 压 Cell 本身,LoadDeref 压当前内容,两者都经 push_borrowed 取得栈根。 let value = if opcode == Opcode::LoadClosure { Value::Object(cell) } else { self.cell_get(cell).map_err(|error| { + // 语言层将空捕获槽映射为变量未绑定,其余底层错误保持原样。 if error == VmError::EmptyCell { VmError::UnboundLocal(frame.executable.slot_name(argument).into()) } else { @@ -1430,15 +1466,20 @@ impl Vm { }; self.push_borrowed(frame, value)?; } + // 空 Cell 读取经 ok() 视作没有旧值,写入成功后才弹出输入。 Opcode::StoreDeref => { + // 对应槽必须存活且为 Cell,本帧与闭包函数均可能持有其根/边。 let cell = self.cell_slot(frame, argument)?; + // 读取/计算下一状态后再更新栈,失败由原帧保留输入清理责任。 let value = self.assignment_value(self.cell_get(cell).ok(), Self::top_value(frame)?)?; self.cell_set(cell, value)?; self.discard(frame, 1); } Opcode::DeleteDeref => { + // 对应槽必须存活且为 Cell,本帧与闭包函数均可能持有其根/边。 let cell = self.cell_slot(frame, argument)?; + // 当前实现将读取错误视为未绑定;上方 cell_slot 已检查槽载荷。 if self.cell_get(cell).is_err() { return Err(VmError::UnboundLocal( frame.executable.slot_name(argument).into(), @@ -1446,41 +1487,56 @@ impl Vm { } self.cell_clear(cell)?; } + // 丢弃一个拥有栈项,协议 Null 则不 release。 Opcode::PopTop => self.discard(frame, 1), Opcode::Copy => { + // Copy 复制表示不自动 retain,对象项下方另取新栈根,Null 可直接复制。 let entry = frame.stack[frame.stack.len() - argument].clone(); + // 协议 Null 没有对象根;普通对象项复制时须取得一份新根。 if let StackEntry::Value(value) = &entry { self.retain_value(value)?; } frame.stack.push(entry); } Opcode::Swap => { + // Swap 仅交换现有拥有槽,不增加或释放任何根。 let length = frame.stack.len(); frame.stack.swap(length - 1, length - argument); } + // 压入专用调用标记,不能与 Value::Nil 混淆。 Opcode::PushNull => frame.stack.push(StackEntry::Null), Opcode::Call => { + // 调用布局是函数、receiver/Null、显式参数,argument 只计显式实参。 let start = frame.stack.len() - argument - 2; + // 调用目标必须为对象,是否可调用由 prepare_call/载荷协议继续判定。 let Value::Object(function) = Self::stack_value(frame, start)? else { return Err(VmError::UnsupportedOperation("call")); }; + // 先收集借用参数,原栈输入直到调用准备完成前保持根保护。 let mut arguments = Vec::with_capacity(argument + 1); + // 非 Null 的协议接收者先加入实际参数,Null 则不传入语言实参。 if let StackEntry::Value(value) = &frame.stack[start + 1] { arguments.push(value.clone()); } + // 后续显式参数按源码顺序传入,不在此处归还原栈根。 for index in start + 2..frame.stack.len() { arguments.push(Self::stack_value(frame, index)?); } + // 准备成功得到已持根源码帧或拥有结果,之后才能清理当前帧调用输入。 match self.prepare_call(function, arguments, executed, limits)? { + // 新帧还未加入向量,若深度预算不足必须主动清理它。 PreparedCall::Frame(mut callee) => { + // 硬帧限制包括现有所有源码帧,不把原生委托另算源码帧。 if frames.len() >= limits.max_frames { self.clear_frame(callee); return Err(VmError::ExecutionLimit("frames")); } + // 记录调用者索引,无裸指针,不受向量扩容影响。 callee.previous = Some(frames.len() - 1); self.discard(frames.last_mut().unwrap(), argument + 2); frames.push(callee); } + // 原生直接结果已经拥有根,清除调用输入后直接移入栈,不再 retain。 PreparedCall::Value(value) => { self.discard(frames.last_mut().unwrap(), argument + 2); frames @@ -1492,7 +1548,9 @@ impl Vm { } } Opcode::ReturnValue => { + // 返回值先借用读取,实际根在后面 pop 时从帧栈移交,不能提前 release。 let result = Self::top_value(frame)?; + // 源码返回注解已解析并保活,执行中全局重绑定不能替换该约束。 if let Some(expected) = frame.return_type && !self.objects.matches_annotation(&result, expected)? { @@ -1508,31 +1566,39 @@ impl Vm { actual: self.objects.value_type_name(&result)?, }); } + // 所有委托返回约束都要满足,按最内层到外层顺序检查。 for check in frame.native_returns.iter().rev() { check.check(&self.objects, &result)?; } + // 仅移出结果项不 release,将它原有的栈根转交调用者/外层结果。 frame.stack.pop(); self.clear_frame(frames.pop().unwrap()); + // 还有调用者则接管结果根到其栈;最外层直接移交给宿主。 if let Some(caller) = frames.last_mut() { caller.stack.push(StackEntry::Value(result)); } else { return Ok(Some(result)); } } + // 无条件跳转仅改变下一位置,不改变栈高度或引用计数。 Opcode::JumpForward | Opcode::JumpBackward => { frame.instruction_offset = decoded.jump_target()? } Opcode::PopJumpIfFalse | Opcode::PopJumpIfTrue => { + // 先求真再丢弃输入根,协议错误时输入仍在帧中供外层清理。 let truth = self.value_is_true(&Self::top_value(frame)?)?; self.discard(frame, 1); + // 条件成立才覆盖预置顺序后继,跳转距离以代码单元计算。 if truth == (opcode == Opcode::PopJumpIfTrue) { frame.instruction_offset = decoded.jump_target()?; } } Opcode::ToBool | Opcode::UnaryNot => { + // 先求真再丢弃输入根,协议错误时输入仍在帧中供外层清理。 let truth = self.value_is_true(&Self::top_value(frame)?)?; self.discard(frame, 1); frame.stack.push(StackEntry::Value(Value::Bool( + // ToBool 保留真值,UnaryNot 取反,两者都输出直接 Bool。 if opcode == Opcode::UnaryNot { !truth } else { @@ -1541,10 +1607,15 @@ impl Vm { ))); } Opcode::BinaryArithmetic => { + // 加法额外支持两个直接 Text 拼接,堆字符串不在此快速路径中。 if decoded.instruction.argument == 0 { + // 读取左输入借用表示,原栈根继续维持对象存活。 let left = Self::stack_value(frame, frame.stack.len() - 2)?; + // 读取右输入借用表示,不能先弹栈再访问对象载荷。 let right = Self::top_value(frame)?; + // 仅双直接文本走拼接,其他情况继续数值运算并校验 Number。 if let (Value::Text(a), Value::Text(b)) = (left, right) { + // 限制合并 UTF-8 字节数为 1 MiB,饱和相加防预算绕回。 if a.len().saturating_add(b.len()) > 1_048_576 { return Err(VmError::InvalidArgument( "text concatenation exceeds operation budget", @@ -1555,14 +1626,19 @@ impl Vm { continue; } } + // 读取左输入借用表示,原栈根继续维持对象存活。 let left = Self::stack_value(frame, frame.stack.len() - 2)?; + // 读取右输入借用表示,不能先弹栈再访问对象载荷。 let right = Self::top_value(frame)?; + // 直接/堆数值统一为借用 Number;缺失表示报 Number 种类错误。 let left = self .number_value(&left)? .ok_or(VmError::ObjectKindMismatch("Number"))?; + // 右值同样要求数值,不能隐式把文本或 Bool 转数字。 let right = self .number_value(&right)? .ok_or(VmError::ObjectKindMismatch("Number"))?; + // 操作数映射已由代码验证,运算仍可因零除/预算/非有限值报错。 let result = left.arithmetic( right, crate::ArithmeticOp::from_argument(decoded.instruction.argument).unwrap(), @@ -1571,17 +1647,23 @@ impl Vm { frame.stack.push(StackEntry::Value(Value::Number(result))); } Opcode::UnaryNegate => { + // 借用栈顶,原拥有根保留至协议运算或修改成功。 let value = Self::top_value(frame)?; + // 数值取负只接受直接/堆 Number,不丢弃其他类型信息做隐式转换。 let value = self .number_value(&value)? .ok_or(VmError::ObjectKindMismatch("Number"))?; + // 先成功计算再释放输入,输出直接 Number 自己拥有 Rust 数值数据。 let result = value.negated()?; self.discard(frame, 1); frame.stack.push(StackEntry::Value(Value::Number(result))); } Opcode::CompareOp => { + // 读取左输入借用表示,原栈根继续维持对象存活。 let left = Self::stack_value(frame, frame.stack.len() - 2)?; + // 读取右输入借用表示,不能先弹栈再访问对象载荷。 let right = Self::top_value(frame)?; + // 数学/文本/对象协议在辅助函数统一选择,结果是直接 Bool。 let result = self.compare_values( &left, &right, @@ -1591,23 +1673,28 @@ impl Vm { frame.stack.push(StackEntry::Value(Value::Bool(result))); } Opcode::LoadAttr => { + // 属性协议需要对象 owner,直接值不能假装有托管动态字段。 let Value::Object(owner) = Self::top_value(frame)? else { return Err(VmError::ObjectKindMismatch("object")); }; + // 读取/计算下一状态后再更新栈,失败由原帧保留输入清理责任。 let value = self.bind_attr(owner, &frame.executable.layout().names[argument])?; self.discard(frame, 1); frame.stack.push(StackEntry::Value(value)); } Opcode::BuildClass => { + // 构类成功返回拥有根,之后才丢弃名称/基类/字段/方法输入四项。 let class = self.build_class(frame)?; self.discard(frame, 4); frame.stack.push(StackEntry::Value(Value::Object(class))); } Opcode::StoreAttr => { + // 属性协议需要对象 owner,直接值不能假装有托管动态字段。 let Value::Object(owner) = Self::top_value(frame)? else { return Err(VmError::ObjectKindMismatch("object")); }; + // 读取/计算下一状态后再更新栈,失败由原帧保留输入清理责任。 let value = Self::stack_value(frame, frame.stack.len() - 2)?; self.set_attr( owner, @@ -1617,6 +1704,7 @@ impl Vm { self.discard(frame, 2); } Opcode::BuildMap => { + // 字典构造取得根后,释放原键值栈根,由字典内部边接管持有。 let dictionary = self.build_map(frame, argument)?; self.discard(frame, argument * 2); frame @@ -1624,12 +1712,15 @@ impl Vm { .push(StackEntry::Value(Value::Object(dictionary))); } Opcode::MakeFunction => { + // 函数构造校验并保留全部边后才消费原栈输入,避免捕获值提前释放。 let function = self.make_function(frame, decoded.instruction.argument)?; + // 按与构造器相同的位段计数弹出默认值、Cell 与代码项。 let (defaults, closure) = Instruction::function_counts(decoded.instruction.argument); self.discard(frame, defaults + closure + 1); frame.stack.push(StackEntry::Value(Value::Object(function))); } + // 扩展参数已由解码器合并,验证代码不含可执行的独立前缀。 Opcode::ExtendedArg => unreachable!("EXTENDED_ARG was decoded before evaluation"), } }