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

624 lines
26 KiB
Rust

//! 宿主原生调用协议:Store 校验声明,VM 分派调用,NativeContext 管理临时根与输出所有权。
//! 返回 Invoke 把调用交回 VM 的帧循环,避免 Rust 回调递归进入求值器。
//! ReadOnly 是宿主承诺加托管写屏障;本模块不能拦截任意 Rust 回调自行执行的外部 I/O。
use std::{fmt, sync::Arc};
use crate::{ObjectPayload, ObjectRef, ObjectStore, Value, VmError, WeakObjectRef};
/// Borrowed results produced inside a native call. Invoke delegates to another
/// callable through the VM's existing frame loop, without recursively entering it.
#[derive(Debug)]
pub enum NativeResult {
/// 回调内为借用结果;execute 成功输出时其中对象已获得移交给 VM 的根。
Return(Value),
/// 委托目标与参数在 execute 成功输出时各有拥有根,VM 接管后负责释放。
Invoke {
function: ObjectRef,
arguments: Vec<Value>,
},
}
/// Accepted positional argument interval, including explicit receivers.
/// The store validates metadata before use; usize::MAX denotes an open upper bound.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CallArity {
/// 最少位置参数数量。
pub required: usize,
/// 最多位置参数数量,usize::MAX 表示开放上界。
pub maximum: usize,
}
impl CallArity {
/// 宿主声明固定位置参数数量,含显式接收者。
pub const fn exact(count: usize) -> Self {
Self::range(count, count)
}
/// 宿主声明闭区间,构造时不验证上下界;使用前 validate。
pub const fn range(required: usize, maximum: usize) -> Self {
Self { required, maximum }
}
/// VM/契约检查查询数量是否落在闭区间,不改变元数据。
pub fn accepts(self, count: usize) -> bool {
(self.required..=self.maximum).contains(&count)
}
/// Store/调用入口拒绝颠倒的上下界;成功返回原数量声明。
pub(crate) fn validate(self) -> Result<Self, VmError> {
// 上界不能小于下界,否则任何实际调用都无法满足有效区间。
if self.required > self.maximum {
return Err(VmError::InvalidArgument("invalid callable arity metadata"));
}
Ok(self)
}
/// 调用入口先验证声明,再生成携带函数名和实参数量的错误。
pub(crate) fn check(self, name: String, provided: usize) -> Result<(), VmError> {
self.validate()?;
// 元数据合法后再区分用户提供的数量不匹配。
if !self.accepts(provided) {
return Err(VmError::ArgumentCount {
name,
required: self.required,
maximum: self.maximum,
provided,
});
}
Ok(())
}
}
/// Declared host effect. ReadOnly may allocate results but must not mutate
/// existing objects or perform external I/O. Unknown legacy calls remain unknown.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CallEffect {
/// 可分配结果,但承诺不改已有对象或执行外部 I/O。
ReadOnly,
/// The native body itself is read-only; delegated effects are dynamic and
/// checked by the VM in the same execution/heap scope.
Delegated,
/// 声明可能修改已有托管对象,只读执行不允许。
Mutating,
/// 声明包含外部效果,只读执行不允许。
External,
}
/// Resolved native value contract. A union is flat, nonempty and preserves
/// all definition edges even when an earlier alternative already matches.
#[derive(Debug, Clone)]
pub enum CallType {
/// 单个已解析注解,不是源码字符串。
Single(crate::AnnotationType),
/// 平坦非空候选列表;所有定义引用都须有效。
Union(Vec<crate::AnnotationType>),
}
impl From<crate::AnnotationType> for CallType {
fn from(value: crate::AnnotationType) -> Self {
Self::Single(value)
}
}
impl CallType {
/// 宿主构造类型或 Unit 的平坦联合,供可空参数/返回值约束使用。
pub fn nullable(value: crate::AnnotationType) -> Self {
Self::Union(vec![value, crate::AnnotationType::Unit])
}
/// 内部检查和契约分析将单类型与联合统一为借用切片。
pub(crate) fn alternatives(&self) -> &[crate::AnnotationType] {
// 单项通过 from_ref 借用,联合直接借用 Vec,不额外分配或复制定义引用。
match self {
Self::Single(value) => std::slice::from_ref(value),
Self::Union(values) => values,
}
}
/// 载荷 trace/调用保护枚举所有名义类型与能力引用,不因提前匹配而漏边。
pub fn references(&self) -> impl Iterator<Item = ObjectRef> + '_ {
self.alternatives()
.iter()
.copied()
.filter_map(crate::AnnotationType::reference)
}
/// 契约分析检查联合是否含 Any,不代表其他分支的定义边可省略。
pub fn is_any(&self) -> bool {
self.alternatives()
.iter()
.any(|value| matches!(value, crate::AnnotationType::Any))
}
/// 调用/签名检查确认联合非空,且每个托管类型/能力引用有效并有正确载荷。
pub fn validate(&self, store: &ObjectStore) -> Result<(), VmError> {
// 空联合没有可接受值,必须作为声明错误拒绝。
if self.alternatives().is_empty() {
return Err(VmError::InvalidArgument("empty native union type"));
}
// 即使首个分支是 Any,也校验后续全部定义,不允许无效句柄藏在联合中。
for value in self.alternatives() {
// 只有名义/能力注解包含定义句柄,其他直接注解没有需验证的对象。
match *value {
crate::AnnotationType::Nominal(reference) => {
store.payload::<crate::EndorTypeObject>(reference, "Type")?;
}
crate::AnnotationType::Capability(reference) => {
store.payload::<crate::EndorTraitObject>(reference, "Trait")?;
}
_ => {}
}
}
Ok(())
}
/// 参数/返回检查先验证全部分支,再按顺序尝试匹配;全不匹配才生成类型错误。
pub fn check(
&self,
store: &ObjectStore,
name: &str,
position: String,
value: &Value,
) -> Result<(), VmError> {
self.validate(store)?;
// 通过完整声明校验后才允许按首个匹配项短路。
for expected in self.alternatives() {
// 匹配即成功;协议失败仍传播错误,而非当作不匹配。
if store.matches_annotation(value, *expected)? {
return Ok(());
}
}
// 所有项均不匹配时才组装诊断类型名,不在成功热路径构造文本。
let names = self
.alternatives()
.iter()
.map(|expected| store.annotation_type_name(*expected))
.collect::<Result<Vec<_>, _>>()?;
Err(VmError::TypeMismatch {
function: name.into(),
position,
expected: names.join(" | "),
actual: store.value_type_name(value)?,
})
}
}
/// Immutable native contract, including an explicit receiver where applicable.
/// Missing fixed slots are covered by variadic; optionality comes from arity.
#[derive(Debug, Clone)]
pub struct CallSignature {
/// 参数数量区间决定可省略的尾部参数,不由类型列表长度直接决定。
pub arity: CallArity,
/// 固定位置参数约束,含需要显式传入的接收者。
pub parameters: Vec<CallType>,
/// 固定列表之外的参数统一使用此约束。
pub variadic: Option<CallType>,
/// 直接/委托完成后应检查的结果约束。
pub returns: CallType,
/// 回调效果声明,供只读许可与方法替换契约判断。
pub effect: CallEffect,
}
impl CallSignature {
/// 宿主构造固定参数签名,不含可变参数;传入类型尚需使用前验证。
pub fn exact(
parameters: Vec<crate::AnnotationType>,
returns: crate::AnnotationType,
effect: CallEffect,
) -> Self {
Self {
arity: CallArity::exact(parameters.len()),
parameters: parameters.into_iter().map(CallType::from).collect(),
variadic: None,
returns: returns.into(),
effect,
}
}
/// 载荷 trace 和临时保护枚举固定、可变及返回类型中的全部托管引用。
pub fn references(&self) -> impl Iterator<Item = ObjectRef> + '_ {
self.parameters
.iter()
.chain(self.variadic.as_ref())
.chain([&self.returns])
.flat_map(CallType::references)
}
/// Store/执行入口校验数量区间和类型覆盖完整性,并验证全部定义引用。
pub fn validate(&self, store: &ObjectStore) -> Result<(), VmError> {
self.arity.validate()?;
// 没有可变约束时固定类型列表必须覆盖最大参数数;有可变约束时不能超出上界。
if self.parameters.len() > self.arity.maximum
|| (self.variadic.is_none() && self.parameters.len() != self.arity.maximum)
{
return Err(VmError::InvalidArgument("incomplete native signature"));
}
// 参数、可变项与返回项的定义引用都校验,不只验证本次实际传入的参数。
for expected in self
.parameters
.iter()
.chain(self.variadic.as_ref())
.chain([&self.returns])
{
expected.validate(store)?;
}
Ok(())
}
/// 原生调用进入回调前校验数量、效果许可和逐项类型,包括显式接收者。
pub fn check_arguments(
&self,
store: &ObjectStore,
name: &str,
arguments: &[Value],
) -> Result<(), VmError> {
self.validate(store)?;
self.arity.check(name.into(), arguments.len())?;
// Delegated 只保证宿主本体只读,被委托目标的效果由 VM 在相同作用域继续检查。
if store.is_read_only()
&& !matches!(self.effect, CallEffect::ReadOnly | CallEffect::Delegated)
{
return Err(VmError::InvalidArgument(
"native effect is forbidden during read-only execution",
));
}
// 按位置选择固定约束,超出固定部分才回退到可变约束。
for (index, value) in arguments.iter().enumerate() {
// 数量合法不代表类型覆盖完整,因此缺少约束仍作为声明错误。
let expected = self
.parameters
.get(index)
.or(self.variadic.as_ref())
.ok_or(VmError::InvalidArgument("incomplete native signature"))?;
expected.check(store, name, format!("parameter {}", index + 1), value)?;
}
Ok(())
}
/// 原生调用返回后校验结果类型;不重新验证整份参数元数据。
pub fn check_return(
&self,
store: &ObjectStore,
name: &str,
value: &Value,
) -> Result<(), VmError> {
self.returns.check(store, name, "return".into(), value)
}
}
/// 宿主实现接口;VM 克隆分派器 Arc 后调用 invoke,不持有载荷借用跨可变 Store 操作。
pub trait NativeCallable: fmt::Debug + Send + Sync + std::any::Any {
/// Immutable resolved types; referenced definitions must be traced by the
/// payload. ContextNativeFunction snapshots and traces them automatically.
fn signature(&self) -> Option<CallSignature> {
None
}
/// Optional positional contract. Missing metadata remains an explicit legacy gap.
fn arity(&self) -> Option<CallArity> {
self.signature().map(|signature| signature.arity)
}
/// 宿主在临时根作用域中执行;参数借用,结果可直接返回或委托 VM 调用其他函数。
fn invoke(
&self,
context: &mut NativeContext<'_>,
arguments: &[Value],
) -> Result<NativeResult, VmError>;
}
/// Native allocation/mutation scope. Allocations and upgraded weak references
/// are temporary owned roots. Return/Invoke promotes only its output roots;
/// Drop releases everything else, including on error or unwinding.
pub struct NativeContext<'a> {
// 整次回调独占借用存储,提供受控修改与查询。
store: &'a mut ObjectStore,
// 本作用域拥有的根清单,重复身份代表多份拥有根,不能去重。
roots: Vec<ObjectRef>,
// 当前调用函数的借用身份,execute 另外将其加入保护根。
callee: ObjectRef,
}
impl<'a> NativeContext<'a> {
/// Callable currently dispatched by the VM, borrowed for this scope.
pub fn callee(&self) -> ObjectRef {
self.callee
}
/// 宿主经 Store 附着不可替换的名义类型,沿用只读屏障。
pub fn attach_type(
&mut self,
object: ObjectRef,
type_object: ObjectRef,
) -> Result<(), VmError> {
self.store.attach_type(object, type_object)
}
/// 宿主注册能力,经 Store 校验,不直接改类型表。
pub fn implement_trait(
&mut self,
definition: ObjectRef,
capability: ObjectRef,
) -> Result<(), VmError> {
self.store.implement_trait(definition, capability)
}
/// 宿主只读查询存储,修改使用上下文受控入口。
pub fn store(&self) -> &ObjectStore {
self.store
}
/// 分配载荷并登记临时拥有根;未作为输出移交时由 Drop 释放。
pub fn allocate(&mut self, payload: impl ObjectPayload) -> Result<ObjectRef, VmError> {
// 只有分配/升级成功后才登记根,错误路径不留下虚假的释放条目。
let object = self.store.allocate(payload)?;
self.roots.push(object);
Ok(object)
}
/// 创建 Record,经 allocate 统一登记临时根。
pub fn new_object(&mut self) -> Result<ObjectRef, VmError> {
self.allocate(crate::Record)
}
/// Build a language function under this native scope using validated code.
/// 从代码创建无默认值/无捕获槽的源码函数,并登记临时根。
pub fn new_function(
&mut self,
name: impl Into<String>,
code: ObjectRef,
globals: ObjectRef,
) -> Result<ObjectRef, VmError> {
// Store 校验代码布局和命名空间;这里不自动创建默认值或捕获槽。
let function = self
.store
.new_function(name, code, globals, vec![], vec![])?;
self.roots.push(function);
Ok(function)
}
/// 创建空字典并登记其外部根。
pub fn new_dict(&mut self) -> Result<ObjectRef, VmError> {
// 只有分配/升级成功后才登记根,错误路径不留下虚假的释放条目。
let object = self.store.new_dict()?;
self.roots.push(object);
Ok(object)
}
/// 创建空/已初始化 Cell 并登记外部根。
pub fn new_cell(&mut self, value: Option<Value>) -> Result<ObjectRef, VmError> {
// 只有分配/升级成功后才登记根,错误路径不留下虚假的释放条目。
let object = self.store.new_cell(value)?;
self.roots.push(object);
Ok(object)
}
/// 属性写入交给 Store/Heap 维护强边、类型约束和写屏障。
pub fn set_attr(
&mut self,
object: ObjectRef,
name: impl Into<String>,
value: Value,
) -> Result<(), VmError> {
self.store.set_attr(object, name, value)
}
/// 属性删除交给 Store 校验,成功释放旧字段强边。
pub fn del_attr(&mut self, object: ObjectRef, name: &str) -> Result<(), VmError> {
self.store.del_attr(object, name)
}
/// 受控字典写入,保持容器身份和引用计数。
pub fn dict_set(&mut self, object: ObjectRef, key: Value, value: Value) -> Result<(), VmError> {
self.store.dict_set(object, key, value)
}
/// 受控删除字典键;缺键返回 false,协议失败另行报错。
pub fn dict_delete(&mut self, object: ObjectRef, key: &Value) -> Result<bool, VmError> {
self.store.dict_delete(object, key)
}
/// 受控更新共享 Cell,先保留新边再释放旧边。
pub fn cell_set(&mut self, object: ObjectRef, value: Value) -> Result<(), VmError> {
self.store.cell_set(object, value)
}
/// 替换载荷并重建边快照,保持对象身份。
pub fn replace_payload(
&mut self,
object: ObjectRef,
payload: impl ObjectPayload,
) -> Result<(), VmError> {
self.store.replace_payload(object, payload)
}
/// 升级成功的弱引用根登记为临时根;过期 None 不登记。
pub fn upgrade(&mut self, weak: WeakObjectRef) -> Result<Option<ObjectRef>, VmError> {
// 只有分配/升级成功后才登记根,错误路径不留下虚假的释放条目。
let object = self.store.upgrade(weak)?;
// 已过期弱引用不产生根,成功升级的一份根交给 Drop 管理。
if let Some(object) = object {
self.roots.push(object);
}
Ok(object)
}
/// 给借用对象 retain 一份临时根;直接值不需要托管计数。
fn protect(&mut self, value: &Value) -> Result<(), VmError> {
// retain 先成功才入清单,避免失败时 Drop 多释放一份根。
if let Value::Object(object) = value {
self.store.retain(*object)?;
self.roots.push(*object);
}
Ok(())
}
/// Internal execution bridge. Every returned object reference owns a root;
/// consumers must release Return values or all Invoke arguments/function.
/// VM 执行桥:校验/保护输入,执行回调,验证直接结果,最后移交输出根。
pub fn execute(
// 整次回调独占借用存储,提供受控修改与查询。
store: &'a mut ObjectStore,
function: ObjectRef,
arguments: &[Value],
// 可共享回调分派器;执行前克隆 Arc,避免持有载荷借用。
callable: Arc<dyn NativeCallable>,
) -> Result<NativeResult, VmError> {
// 执行回调前检查分派器声明的数量约束。
if let Some(arity) = callable.arity() {
arity.check(
store.object(function)?.payload().kind_name().into(),
arguments.len(),
)?;
}
// 从载荷快照取得完整签名,与 callable 的动态返回值分开。
let signature = store.native_signature(function)?;
// 诊断名在可变借用上下文建立前复制,避免跨调用持有载荷引用。
let name = store.object(function)?.payload().kind_name().to_owned();
// 可选完整签名存在时才校验/保护;缺失元数据保留既有调用协议。
if let Some(signature) = &signature {
signature.check_arguments(store, &name, arguments)?;
}
// 首参为对象时查询接收者的方法契约及应保持的返回约束。
let trait_returns = if let Some(Value::Object(receiver)) = arguments.first() {
store.check_method_contract_call(function, *receiver, false)?;
store.method_trait_returns(function, *receiver)?
} else {
Vec::new()
};
// 从这里起所有已登记根由 RAII Drop 清理,错误和展开路径同样有效。
let mut context = Self {
store,
roots: Vec::new(),
callee: function,
};
context.protect(&Value::Object(function))?;
// 可选完整签名存在时才校验/保护;缺失元数据保留既有调用协议。
if let Some(signature) = &signature {
for reference in signature.references() {
context.protect(&Value::Object(reference))?;
}
}
// 能力返回约束也可能持有类型定义,执行回调时必须保持其存活。
for (_, expected) in &trait_returns {
// 每条声明引用独立保护,重复边对应多份根并会逐次释放。
for reference in expected.references() {
context.protect(&Value::Object(reference))?;
}
}
// 输入每个对象参数取得临时根,防回调删除原持有边后参数失效。
for argument in arguments {
context.protect(argument)?;
}
// 回调错误直接传播,context 自动释放输入保护和回调内创建的临时对象根。
let result = callable.invoke(&mut context, arguments)?;
// 直接结果立即检查;Invoke 的最终结果由 VM 的委托返回检查继续处理。
if let (Some(signature), NativeResult::Return(value)) = (&signature, &result) {
signature.check_return(context.store(), &name, value)?;
}
// 直接结果还须满足接收者能力方法要求,不只满足原生自身签名。
if let NativeResult::Return(value) = &result {
// 每个能力的返回约束都要满足,不能在第一个成功后跳过其他能力。
for (name, expected) in &trait_returns {
expected.check(context.store(), name, "return".into(), value)?;
}
}
// 记录移交边界;新增输出根验证成功后才从清单中移走。
let transferred_from = context.roots.len();
// 给每个输出位置 retain;中途失败则清单仍完整,由 Drop 回收已取得的输出根。
match &result {
NativeResult::Return(value) => context.protect(value)?,
NativeResult::Invoke {
function,
arguments,
} => {
context.protect(&Value::Object(*function))?;
// 每个委托参数取得待移交的输出根,重复对象参数也逐项保留。
for argument in arguments {
context.protect(argument)?;
}
}
}
// truncate 只移走输出根的清单条目,不 release;调用者接管这些拥有根,其他根仍由 Drop 释放。
context.roots.truncate(transferred_from);
Ok(result)
}
}
impl Drop for NativeContext<'_> {
/// 作用域结束、回调错误或栈展开时回收全部未移交拥有根。
fn drop(&mut self) {
// 按取得的反序归还所有未移交根;每项代表一份所有权,不能按身份去重。
for root in self.roots.drain(..).rev() {
self.store
.release(root)
.expect("native scope owns its roots");
}
}
}
/// A context-aware function with explicit, immutable captured object edges.
#[derive(Debug)]
pub struct ContextNativeFunction {
// 宿主静态诊断名,不承担语言类型身份。
name: &'static str,
// 可共享回调分派器;执行前克隆 Arc,避免持有载荷借用。
callable: Arc<dyn NativeCallable>,
// 显式不可变托管捕获边,由 trace 逐条登记。
captures: Vec<ObjectRef>,
// 构造时从 callable 快照,作为不可变元数据并参与 trace。
signature: Option<CallSignature>,
}
impl ContextNativeFunction {
/// Borrow the concrete host implementation for intrinsic dispatch checks.
/// Function identity or a mutable class-table slot alone is not proof that
/// its current payload still implements a host intrinsic.
/// 宿主内建分派借用具体回调实现;类型不匹配返回 None,不以函数身份猜测实现。
pub fn implementation<T: NativeCallable>(&self) -> Option<&T> {
// 仅做 Rust Any 下转型,不执行回调,不检查语言层名义类型。
let implementation: &dyn std::any::Any = self.callable.as_ref();
implementation.downcast_ref()
}
/// 宿主包装上下文回调,快照签名与显式捕获边,随后由 Store 分配。
pub fn new(
// 宿主静态诊断名,不承担语言类型身份。
name: &'static str,
callable: impl NativeCallable,
// 显式不可变托管捕获边,由 trace 逐条登记。
captures: Vec<ObjectRef>,
) -> Self {
Self {
name,
signature: callable.signature(),
callable: Arc::new(callable),
captures,
}
}
}
impl ObjectPayload for ContextNativeFunction {
// Store 分配时可附着 Function 类型;可调用性和函数分类分开。
fn is_function(&self) -> bool {
true
}
// 本载荷无原地赋值实现,只读调用可以直接重绑定局部引用。
fn reference_assignment_only(&self) -> bool {
true
}
// Store/宿主 intrinsic 分派所需的载荷下转型入口。
fn as_any(&self) -> &dyn std::any::Any {
self
}
// 使用宿主配置的静态名生成诊断。
fn kind_name(&self) -> &'static str {
self.name
}
// Heap 快照签名定义边及显式捕获边;不能在分配后私下修改这些引用。
fn trace(&self, visit: &mut dyn FnMut(ObjectRef)) {
// 签名中的参数、可变参数和返回约束定义也属于载荷拥有边。
if let Some(signature) = &self.signature {
for reference in signature.references() {
visit(reference);
}
}
// 每个捕获项都拥有独立强边,包括重复捕获。
for capture in &self.captures {
visit(*capture);
}
}
// Store 查询构造时的签名快照,clone 不新增托管根。
fn call_signature(&self) -> Option<CallSignature> {
self.signature.clone()
}
// VM 克隆回调 Arc 后释放载荷借用,再创建可变 NativeContext。
fn native_callable(&self) -> Option<Arc<dyn NativeCallable>> {
Some(self.callable.clone())
}
}