Files

18 KiB
Raw Permalink Blame History

原生对象调用、弱引用与变更记录

本页定义宿主扩展使用的通用接口,不引入渲染或窗口语义。托管名义类型见类型机制。

有上下文的调用

旧 ObjectPayload::call 保留借用参数和借用结果协议。新载荷可通过 native_callable 返回 Arc;VM 先取得独立分派器,再可变访问 ObjectStore,避免同时借用 堆中载荷与可变对象存储。ContextNativeFunction 提供名称、分派器和不可变捕获边列表。 捕获中的 ObjectRef 必须全部在 captures 中登记,未登记句柄不能保活对象。

NativeCallable::invoke 接收 NativeContext 和借用参数。context 提供对象、字典、Cell 分配、托管属性和容器写入、载荷事务替换及弱引用升级。store() 仅暴露只读访问; callee() 返回当前可调用对象的借用句柄;attach_type 通过受校验的类型边事务附加实例类型。 new_function(name, code, globals) 可在当前作用域创建无默认参数、无闭包的语言函数;代码与 globals 使用现有 ObjectStore 校验,函数临时根随作用域管理。宿主可生成受静态验证的字节码来顺序调用多个处理器,再通过 Invoke 移交同一帧循环;这些调用继续共用当前预算,不逐个重置限额。 没有不受控的 &mut Vm、手动释放根或重入执行器入口。

context 内分配或升级得到的对象由本次作用域临时持有。NativeResult::Return(value) 返回借用结果;作用域为结果额外持有一份根,再释放其余临时根。出错或 unwind 也会 清理本作用域根,但此前完成的业务写入不会回滚;这不承诺整个执行帧的 panic 恢复。

NativeResult::Invoke { function, arguments } 将调用委托给另一个原生或语言函数。 function 和每个对象参数在移交前取得根;VM 完成调用准备后释放这些临时输入。 委托通过原有帧循环推进,不递归调用 Vm::call;语言函数使用原有帧限额。每次原生 分派计入同一指令预算,避免无界原生委托链。预算仍不能抢占一次长时间原生操作。 委托函数的结果就是该次调用结果,当前不提供任意原生调用后续 continuation。

只读调用与读取依赖

Vm::call_read_only_with_limits 沿用显式帧与预算,返回拥有式结果及借用式读取对象身份列表。进入时现存对象的属性、载荷、容器、Cell、类型边与共享赋值写入均在 prepare_change 屏障前拒绝;调用内新分配的结果图可以正常构造。局部变量对普通引用的重新绑定仍可进行:已知无可变 legacy assign_from 的载荷声明 reference_assignment_only=true,共享 assignment_cell 写入仍先检查屏障;未知宿主载荷默认保守拒绝。作用域正常返回或报错后恢复;这不提供 panic 恢复或外部 I/O 沙箱。

ObjectStore 的 begin_read_only/end_read_only 提供同样的 LIFO 嵌套机制,is_read_only 供宿主协议检查。保护集合与读取集合不持有 GC 根,代际句柄避免槽位复用误判。读取是对象粒度;宿主须把借用身份转为版本依赖并验证存活,不能据此保活整个对象图。

ObjectStore::begin_read_tracking/end_read_tracking 可在当前只读作用域中登记单次子调用的对象读取区域。区域按 LIFO 嵌套,重复读取仍分别进入每个活动区域,不清空整个调用的读取集合;返回身份仍是借用,不保活对象。NativeContext 可经 store() 使用此接口。没有只读作用域或关闭顺序不匹配时返回错误。外层只读调用退出时丢弃未结束区域,因此源码子调用出错不会把区域泄漏到下一次调用。

只读结果的构造仍维护自身变更版本,但不推送应用 ChangeBatch 通知;现有对象不会在此模式成功写入,因此没有遗漏已有观察者的修改。通过普通调用保存结果到旧对象时,保存动作仍照常通知。可信 Rust 的内部可变状态、外部资源与 I/O 需要宿主遵守只读契约;本机制只强制堆的公开变更入口。

托管共享引用赋值

assignment_cell(source, store) 是与原生 assign_from 并存的可选协议。实现先只读验证 目标及组合环,返回自身持有的内建 Cell;对象存储再事务性地将 source 写入 Cell。 修改的引用属于可追踪堆边,旧对象身份与方法不变。默认返回 None,沿用既有赋值规则。 Cell 的持有边也必须通过 trace 或托管字段登记;字典 API 和属性写入不隐式执行此协议。

弱引用

downgrade 验证对象后产生 WeakObjectRef,不增加强引用。upgrade 在同一个对象存储中 重新验证堆、槽位与代次;存活时返回一份新的拥有式根,过期返回 None,其他存储返回 ForeignHandle。释放后复用槽位不会使旧弱引用指向新对象。弱引用不保活 VM 本身。 宿主使用升级结果后须 release;NativeContext::upgrade 的升级根归当前调用作用域。

对象变更

每个对象头有从 0 开始的 change_version。成功的属性写入或删除产生 Attribute(name), 字典、Cell、通用载荷替换及共享引用赋值产生 Contents;失败写入不产生变更。 同值写入仍视为成功写入,消费方可自行比较派生结果。版本耗尽拒绝修改。

take_changes 按对象与变更键合并同一批写入,返回最终版本。记录不持有对象,消费时 对象可能已经回收,应重新验证身份。通知只保证修改信息,不包含旧值或回滚日志。 最多保留 4096 个不同变更键,超额后清空细项并设置 rescan_required,直到下一次提取; 消费方必须完整重查依赖,不能把溢出当成没有变化。版本仍继续递增。

引擎只记录通用对象变化,依赖订阅、视觉失效和事件提交由宿主负责。托管原生状态须 通过 replace_payload、属性或容器事务更新;载荷内部自行变动不会自动通知。

远端回归用例见 native_context.rs;本地不执行测试。

声明字段检查启用时,NativeContext::set_attr 使用同一字段写入屏障。NativeTyped 分配器应在副作用前调用 ObjectStore::check_class_field_arguments 检查自己的字段参数切片,具体参数组合仍由宿主定义;配置、声明环境与生命周期的唯一契约见名义类型。

统一位置参数数量

CallArity { required, maximum } 表示接受的位置参数区间,包含未绑定的显式接收者;exact(n) 与 range(min,max) 提供构造方式,accepts(n) 查询接受性。usize::MAX 表示开放上界。公开字段不能绕过使用时校验:required 大于 maximum 时,查询/调用报告 InvalidArgument,不能进入实现。CallArity 本身只描述数量;可选的 CallSignature 在此基础上声明类型与宿主效果。

上下文原生实现通过 NativeCallable::arity() 提供 Some(CallArity);默认 None 明确表示旧实现没有元数据。ObjectPayload::call_arity 默认委托该入口,也供直接 call 协议发布元数据;传统 NativeFunction 可使用 with_arity(...)。VM 在进入原生实现前检查数量,NativeContext::execute 也检查其 NativeCallable 元数据,失败不调用业务实现。传统无元数据的普通原生调用仍保留原协议,不伪造精确签名。

ObjectStore::call_arity(function)/Vm::call_arity(function) 统一查询源码与原生函数。源码从真实形参和默认值计算区间;绑定方法沿实际函数扣除每层接收者,最大值不足时报错,最小值饱和到零。查询返回无托管引用的复制数据,不增加 GC 根。旧 positional_parameter_count 保留“源码总形参数量减绑定接收者”的兼容语义,不用于新的原生回调分派。通用 Type 构造器的参数组合由宿主决定,返回 None;NativeTyped 内部委托和宿主实际构造仍各自检查。

显式 Trait 声明、源码派生及方法表更新使用统一区间检查“规范参数数量加 self”是否被接受;缺少元数据的原生方法不能再登记为能力实现。可选参数允许实现接受规范调用数量之外的额外形式。更新仍先检查后代再修改,无隐藏类型根。旧 new_trait 保留数量规则;new_typed_trait 的参数/返回类型、方差及已知效果检查见类型主题,参数名称不构成调用契约。

Tessera 为原生方法、回调和内部视觉 continuation 发布数量元数据,事件监听要求接受零参数或一个 Event;两者都接受时优先传 Event。绑定计算和 Task 回调要求接受零参数,登记前拒绝无元数据/不兼容函数;普通旧原生调用的兼容性不等于允许其参加这些严格回调契约。

校验读取与程序内容读取

只读子区域新增 ObjectStore::end_read_tracking_details(token) -> Vec<ReadAccess>,每项仍是借用 ObjectRef,content_read 表示是否存在普通内容读取。matches_annotation 内部的名义/基础值检查标为校验读取;同一区域随后发生普通读取时,content_read 合并为 true。嵌套区域均保留两类读取,不增加对象根。原 end_read_tracking 与完整 end_read_only 仍返回两类读取的完整并集,没有删除依赖或放宽只读写屏障。

校验分类按线程记录嵌套深度,作用域退出、错误和展开时通过 RAII 恢复,不让另一线程继承标签。公开 ReadAccess 仅提供信息,不保证调用者可忽略任何对象;动态类型/能力/全局定义等校验依赖仍须参与失效。Tessera 独立验证每次活动 Mount/归属/方法后,仅跳过该 Mount 的纯参数类型校验读取;程序实际读取 Mount 内容仍禁止复用测量缓存。其他读取继续记录版本。详见 core/tests/native_context.rs 的合并、完整依赖并集与错误恢复回归源码,仅编译未本地执行。

原生参数、返回类型与宿主效果

CallSignature 保存 CallArity、固定位置的 CallType 列表、可选 variadic 类型、returns 与 CallEffect。exact 提供无默认参数的便捷构造;可选参数仍通过 arity.required/maximum 表示,列表覆盖所有固定位置。开放上界必须有 variadic,有限上界未被固定列表覆盖的部分也必须有 variadic;错误区间、不完整列表、非 Type/Trait 的名义/能力引用和独立 arity 与签名不一致在调用前拒绝。名义类型引用是实际定义,不从字符串或调用者全局环境重新解析。

CallType::Single 封装一个现有 AnnotationType;Union 保存非空的平坦分支列表,nullable(T) 等价于 T | Unit。每个分支先完整校验,不能因较早的 Object/匹配分支而隐藏后续错误定义。匹配任一分支即接受,不匹配时报告按声明顺序组合的名称。全部分支的类型/能力引用都参加 trace 与委托返回执行根保活,包括未被本次值选中的分支;根取得中途出错会撤销已取得的根。exact 仍接受原来的单类型列表作便捷构造并转换为 Single。此能力属于原生宿主契约,没有增加 Endor 的联合类型语法。

NativeCallable::signature 默认 None,明确表示尚未发布类型/效果契约;默认 arity 从签名取得。ObjectPayload::call_signature 供自定义直接调用协议发布。ContextNativeFunction 在创建时保存不可变签名并在 trace 中自动登记每个类型/能力引用;其他捕获仍须显式传 captures。NativeFunction::with_signature 同样追踪签名边并设置数量。自定义载荷须在 trace 中登记自己的签名引用,元数据与其他载荷边一样禁止原地改变;更换使用 replace_payload。ObjectStore::native_signature 校验并返回借用描述,不创建隐藏强注册表。

已发布的原生签名总是检查,不依赖默认关闭的源码注解开关。所有实参在进入原生实现前匹配类型,失败不产生该实现的业务副作用;可选的未提供参数不检查,实际提供的重复参数逐个匹配。Return 在交付前匹配返回类型,错误释放本次作用域分配和结果根,但不回滚已经执行的业务写入。传统直接 call 结果仍按借用协议处理。NativeContext 的独立执行桥同样执行参数、效果与直接返回检查。

NativeResult::Invoke 仍是尾委托,不递归进入 Rust/VM。VM 为每层已声明的返回契约保留检查项;委托原生立即返回或 Endor 帧返回时,按由内到外顺序验证全部契约。返回定义作为执行根保留,原生载荷替换、释放原委托者或源码全局重绑定不会使检查丢失。准备失败、帧限额、指令限额、错误返回与正常完成都释放这些执行根。委托不会为检查额外创建 VM 帧;仍共享每次原生分派和 Endor 指令预算。NativeContext::execute 单独返回 Invoke 时,调用者须使用具有等效最终返回检查的求值器;通常直接使用 Vm::call。

CallEffect::ReadOnly 声明只读现存对象,可分配临时结果;Delegated 声明原生包装自身只读,但后续委托的整体效果动态确定,VM 保持同一只读/预算作用域并检查实际目标;Mutating 与 External 在 ObjectStore 只读作用域内、进入实现前拒绝。普通执行允许这些效果。ReadOnly 声明不绕过已有写屏障,也不证明可信 Rust 不会进行隐藏 I/O;未知旧原生函数仍沿原调用/宿主检查,不能把 None 理解为纯函数。这不是完整 I/O 沙箱或对阻塞原生代码的抢占。统一已知效果查询和保守源码/调用图只读证明见类型主题。

Tessera 的 measure/arrange/paint/hitTest、Point 几何查询、Window、Block/Container/Page、Mount、Task、Event、Subscription 方法和 ObjectList.at 发布签名。Page.open 的 Window | Unit、Page.window 的 Window | Unit 返回,以及 Block.on 的 Bool | String 可选阶段有准确元数据;Mount 的父/子/同级/Page 弱查询为可空结果。Mount.bounds 现在返回带 Bounds 名义类型的现有几何记录,可直接组合到 Point.inside 或视觉方法。滚动位置/字典等通用记录仍声明 Object,不冒充新语言类型;任务 owner 的具体资源资格仍按原域检查。构造器和其他管理 API 的签名覆盖仍未全部接入。已接入的方法覆写方差与动态名称规则见类型主题。旧能力注册保留数量模式;类型化能力还检查类型/已知效果,并在实际返回和尾委托结果处保留能力返回约束。

回归源码 native_context.rs 覆盖参数副作用前拒绝、错误结果清理、跨原生/源码委托检查、单帧限制、名义签名边与绑定方法循环回收、只读效果拒绝、传统直接函数及重复参数和元数据错误。只编译,不本地执行。

联合/可空回归另覆盖两个标量分支、nil、数值拒绝、Object 分支不掩盖非法名义类型、空联合拒绝,以及移除签名后联合返回定义仍存活。

Delegated 在替换兼容中视为未知整体效果,与源码未知效果一样不冒充静态纯度证明。包装不得在委托前进行业务写入或外部I/O,直接返回路径也须只读;委托的原生 Mutating/External 目标仍在当前只读作用域内、进入目标实现前拒绝。源码委托继续受堆写屏障约束,旧无元数据宿主调用仍须遵守可信边界。native_context.rs 的回归覆盖只读包装进入后拒绝写目标、普通作用域允许同一链,以及替换成纯目标后只读调用成功,仅编译。

ContextNativeFunction::implementation<T: NativeCallable>() 只借用当前具体宿主实现,不执行或复制载荷,也不改变捕获/签名的托管边。NativeCallable 继承Any(原有static要求保持);宿主可据自己的实现类型/操作识别原生快速路径,不能只凭函数句柄或当前可变类型方法表认定原生身份。替换载荷后查询跟随新实现,旧类型查询返回None;宿主缓存仍须订阅函数对象版本变化。此接口不暴露可变借用,不替代原生类型/数量/效果检查。

精确只读观察:end_read_only_precise返回ReadSet,兼容objects列表并提供ReadDependency;end_read_tracking_precise返回区域的ReadAccess与相同观察。Object依赖验证对象版本;DictionaryKind只验证存活/字典载荷;Name验证文本键的存在与值身份/表示。缺失名字也被记录,因此后续全局遮蔽内建名会失效;相同值删除/重建后可恢复有效,这是值观察而非“发生过写入”的通知。dict_get_name用于全局/注解/__builtins__名字查询,普通dict_get、dict_items和其他内容读取仍保守依赖整个对象。read_dependency_valid在只读区域内检查时会重记相同观察,使缓存命中仍向外传播依赖。所有对象句柄(包括Name中的Value::Object)均借用,不增加GC根;立即字符串/数字保留比较快照,值不写回业务对象。现有end_read_only/end_read_tracking/details仍返回保守对象列表,不自动替调用方放宽缓存。类型验证字典通过DictionaryKind观察,不把只验证载荷种类误当读取所有条目。

同步宿主可调用Vm::call_read_only_precise_with_limits(function, arguments, limits),返回拥有式Value及借用式ReadSet(objects与dependencies)。它与可恢复只读调用提供同样的名字观察,不创建新的调度器;单次调用仍同步执行并受正常硬预算约束,不能等待Pending await。旧call_read_only_with_limits委托同一执行逻辑,只返回ReadSet.objects,兼容原有保守宿主。成功或执行错误均先关闭只读作用域;不提供panic捕获。