docs(core): explain native dispatch and delegated return contracts
This commit is contained in:
@@ -858,15 +858,19 @@ impl Vm {
|
||||
Ok(frame)
|
||||
}
|
||||
|
||||
/// prepare_call 分派非源码载荷:上下文回调交 NativeContext,旧式回调自行验证并保留返回根。
|
||||
fn invoke_native(
|
||||
&mut self,
|
||||
function: ObjectRef,
|
||||
arguments: &[Value],
|
||||
) -> Result<NativeResult, VmError> {
|
||||
// 先验证当前函数句柄,不让失效/异堆身份进入原生协议。
|
||||
self.object(function)?;
|
||||
// 参数起初是借用,仅验证有效性;此循环本身不取得拥有根。
|
||||
for argument in arguments {
|
||||
self.validate_value(argument)?;
|
||||
}
|
||||
// 对象首参可能是方法接收者,普通覆盖和显式能力检查不可只靠原生数量约束。
|
||||
if let Some(Value::Object(receiver)) = arguments.first() {
|
||||
self.objects.check_method_contract_call(
|
||||
function,
|
||||
@@ -874,6 +878,7 @@ impl Vm {
|
||||
self.source_type_checks,
|
||||
)?;
|
||||
}
|
||||
// 已发布的数量区间必须满足,缺少元数据不在此处猜测数量。
|
||||
if let Some(arity) = self.objects.call_arity(function)?
|
||||
&& !arity.accepts(arguments.len())
|
||||
{
|
||||
@@ -884,22 +889,30 @@ impl Vm {
|
||||
provided: arguments.len(),
|
||||
});
|
||||
}
|
||||
// 克隆到的分派器 Arc 不借用载荷,可在 NativeContext 中安全可变访问 Store。
|
||||
if let Some(callable) = self.object(function)?.payload().native_callable() {
|
||||
return NativeContext::execute(&mut self.objects, function, arguments, callable);
|
||||
}
|
||||
// 无上下文旧式协议读取完整签名;有签名才检查参数/效果及结果。
|
||||
let signature = self.objects.native_signature(function)?;
|
||||
// 复制诊断类别名,不在执行回调后依赖之前的载荷借用。
|
||||
let name = self.object(function)?.payload().kind_name().to_owned();
|
||||
// 完整签名存在才执行相应参数或返回检查,缺失时维持旧协议行为。
|
||||
if let Some(signature) = &signature {
|
||||
signature.check_arguments(&self.objects, &name, arguments)?;
|
||||
}
|
||||
// 旧式回调返回借用值,不能立即作为拥有结果交给宿主。
|
||||
let result = self.object(function)?.payload().call(arguments)?;
|
||||
// 完整签名存在才执行相应参数或返回检查,缺失时维持旧协议行为。
|
||||
if let Some(signature) = &signature {
|
||||
signature.check_return(&self.objects, &name, &result)?;
|
||||
}
|
||||
// 验证并取得结果根,即使回调原样返回某个参数,也必须给结果独立所有权。
|
||||
self.retain_value(&result)?;
|
||||
Ok(NativeResult::Return(result))
|
||||
}
|
||||
|
||||
/// 同步调用、只读续执行、协程及 Call 指令共用准备循环,原生委托不递归进入求值器。
|
||||
fn prepare_call(
|
||||
&mut self,
|
||||
mut function: ObjectRef,
|
||||
@@ -907,42 +920,59 @@ impl Vm {
|
||||
executed: &mut usize,
|
||||
limits: ExecutionLimits,
|
||||
) -> Result<PreparedCall, VmError> {
|
||||
// 最初函数/实参借用;第一次 Invoke 后才接管 NativeContext 移交的函数/参数根。
|
||||
let mut owned = false;
|
||||
// 累计原生/能力返回约束,后续委托每一层完成都仍须满足这些要求。
|
||||
let mut returns = Vec::new();
|
||||
// 闭包把委托循环的提前错误汇总,外层统一清理尚未移交的约束与输入根。
|
||||
let result = (|| loop {
|
||||
// 源码载荷交给 prepare_frame,不走原生调用协议或 Rust 递归执行。
|
||||
if self
|
||||
.object(function)?
|
||||
.payload()
|
||||
.as_any()
|
||||
.is::<EndorFunctionObject>()
|
||||
{
|
||||
// 源码帧取得自己的函数/参数根,后面归还委托输入根不会使帧失效。
|
||||
let mut frame = self.prepare_frame(function, &arguments)?;
|
||||
// 暂取帧本地能力返回约束,将外层原生委托约束放在前面。
|
||||
let mut local = std::mem::take(&mut frame.native_returns);
|
||||
// 把累计约束所有权移入源码帧,外层 returns 变空,避免统一清理重复归还。
|
||||
frame.native_returns = std::mem::take(&mut returns);
|
||||
// 本地约束追加在外层之后,最终返回时按反序检查。
|
||||
frame.native_returns.append(&mut local);
|
||||
return Ok(PreparedCall::Frame(frame));
|
||||
}
|
||||
// 每次原生/委托分派前检查累计硬预算,避免无限原生委托链绕过指令限制。
|
||||
if *executed >= limits.max_instructions {
|
||||
return Err(VmError::ExecutionLimit("instructions"));
|
||||
}
|
||||
*executed += 1;
|
||||
// 非 Any 返回约束需要跨委托保留,不能只校验中间包装器直接返回值。
|
||||
if let Some(signature) = self.objects.native_signature(function)?
|
||||
&& !signature.returns.is_any()
|
||||
{
|
||||
// 诊断名与解析后的返回类型一并保存,不在最终返回时重查可能被重绑定的全局。
|
||||
let check = NativeReturn {
|
||||
name: self.object(function)?.payload().kind_name().into(),
|
||||
expected: signature.returns,
|
||||
};
|
||||
self.push_native_return(&mut returns, check)?;
|
||||
}
|
||||
// 对象首参可能是方法接收者,普通覆盖和显式能力检查不可只靠原生数量约束。
|
||||
if let Some(Value::Object(receiver)) = arguments.first() {
|
||||
// 有效接收者的全部能力返回约束同样跨委托保留。
|
||||
for (name, expected) in self.objects.method_trait_returns(function, *receiver)? {
|
||||
self.push_native_return(&mut returns, NativeReturn { name, expected })?;
|
||||
}
|
||||
}
|
||||
// 结果已经拥有:Return 的结果根或 Invoke 的函数/各参数根由本循环接管。
|
||||
match self.invoke_native(function, &arguments)? {
|
||||
// 最终直接结果要通过委托链所有返回检查后才可交付。
|
||||
NativeResult::Return(value) => {
|
||||
// 从最内层到外层校验,每项约束都必须满足。
|
||||
for check in returns.iter().rev() {
|
||||
// 检查失败先归还本次结果根,再让外层清理链上剩余资源。
|
||||
if let Err(error) = check.check(&self.objects, &value) {
|
||||
self.drop_root(value);
|
||||
return Err(error);
|
||||
@@ -954,22 +984,29 @@ impl Vm {
|
||||
function: next,
|
||||
arguments: values,
|
||||
} => {
|
||||
// 只有已接管 Invoke 输入时才归还当前函数/实参,初始借用输入不能释放。
|
||||
if owned {
|
||||
self.release(function)?;
|
||||
// 先清空旧拥有参数列表并逐项归还,随后安装新委托输出。
|
||||
for value in arguments.drain(..) {
|
||||
self.release_value(value)?;
|
||||
}
|
||||
}
|
||||
// 新委托函数/参数根已经由 NativeContext 保留,赋值只转交清理责任。
|
||||
function = next;
|
||||
arguments = values;
|
||||
// 从此循环退出时须统一归还当前委托输入;返回结果或源码帧各自已保活。
|
||||
owned = true;
|
||||
}
|
||||
}
|
||||
})();
|
||||
// 直接完成/错误清理仍在本地的约束,已移入源码帧的那部分不再在此表中。
|
||||
self.clear_native_returns(returns);
|
||||
// 只有已接管 Invoke 输入时才归还当前函数/实参,初始借用输入不能释放。
|
||||
if owned {
|
||||
self.release(function)
|
||||
.expect("delegated call owns its function");
|
||||
// 循环结束时归还最后一批拥有参数,重复对象参数逐项计数。
|
||||
for value in arguments {
|
||||
self.drop_root(value);
|
||||
}
|
||||
@@ -977,14 +1014,19 @@ impl Vm {
|
||||
result
|
||||
}
|
||||
|
||||
/// 委托链保留返回约束定义根,全部 retain 成功后才追加检查项,中途失败回滚已保留部分。
|
||||
fn push_native_return(
|
||||
&mut self,
|
||||
returns: &mut Vec<NativeReturn>,
|
||||
check: NativeReturn,
|
||||
) -> Result<(), VmError> {
|
||||
// 先记成功 retain 的定义身份,未全部成功前不提交检查项。
|
||||
let mut retained = Vec::new();
|
||||
// 枚举联合返回类型内全部定义引用,重复引用不能去重。
|
||||
for reference in check.expected.references() {
|
||||
// 后续定义根失败时,归还此前成功取得的根,不留下半安装约束。
|
||||
if let Err(error) = self.retain(reference) {
|
||||
// 回滚只处理本次取得的根,不触碰原签名载荷拥有边。
|
||||
for reference in retained {
|
||||
self.release(reference)?;
|
||||
}
|
||||
@@ -992,11 +1034,15 @@ impl Vm {
|
||||
}
|
||||
retained.push(reference);
|
||||
}
|
||||
// 全部定义根已取得,追加检查项后由返回链/帧负责清理。
|
||||
returns.push(check);
|
||||
Ok(())
|
||||
}
|
||||
/// 委托结束/帧销毁统一归还返回约束定义根,每个引用按拥有次数独立 release。
|
||||
fn clear_native_returns(&mut self, returns: Vec<NativeReturn>) {
|
||||
// 销毁每份检查项持有的定义根,Rust CallType 的 drop 不会自动 release。
|
||||
for check in returns {
|
||||
// 枚举联合返回类型内全部定义引用,重复引用不能去重。
|
||||
for reference in check.expected.references() {
|
||||
self.release(reference)
|
||||
.expect("native return check owns its type");
|
||||
|
||||
Reference in New Issue
Block a user