# 架构与语义 ## 内核 当前任务是 Endor 的虚拟机实现层。`Vm::new()` 只创建空堆,不加载语言根类,不分配 Object/Type,也没有类创建、继承或元类 API。`EndorObject` 是公共运行时结构,不能与语言根类混为一谈。 `EndorObject` 保存 `ObjectHeader`、`Box`、托管属性和载荷引用快照。对象头仅保存身份、总强引用数和宿主外部强引用数。操作通过 Rust trait 的分发机制选择,不需要 Python type 系统;kind_name 只是调试标签,as_any 仅供原生 Rust 扩展识别自身的数据结构。 ### 分配与句柄 堆槽位为 `Option>`。Box 保持对象地址稳定,槽位向量扩容不移动实际对象。`ObjectRef` 由私有 VM 身份、索引、代数组成;每次访问先检查 VM,再检查范围、代数和对象是否存活。释放后槽位代数递增,耗尽后永久退役,不回绕。VM 身份由不回绕的原子计数器分配。无 unsafe、裸指针访问或外部句柄构造器。 ### 引用所有权 allocate/new_object 返回一个外部强引用。ObjectRef 是可复制的借用句柄;复制或 Value::clone 不 retain。宿主通过 retain/release 显式持有与释放。头部总计数等于外部计数加来自托管属性及载荷引用快照的入边数。 属性写入先验证目标、被引用对象和计数溢出,再增加新引用、替换属性、释放旧引用;同目标替换不会短暂释放对象。属性读取和原生调用返回借用值,宿主需要跨越所有者生命周期使用时应先 retain。没有外部引用时,release 返回 NoOwnedReference,不能误释放内部属性引用。release 不代表删除任意对象。 载荷通过 trace 报告自己持有的引用;分配时验证全部边并记录快照,相同引用出现两次就计数两次。分配失败不改变已存在对象的计数。载荷持有的边在分配后必须保持不变,可变引用通过 VM 托管属性修改。扩展未声明的借用句柄不受 GC 保护,访问或返回时仍需通过 VM 验证。 ### 清理与循环回收 总计数变为零时先摘除槽位,再用显式工作列表递减出边,最后 Drop 对象及原生资源;长链不会递归调用对象析构。对象不会因为仍有一个复制出的借用句柄而继续存活。 collect_cycles 是显式、全堆的追踪收集器:以外部引用数大于零的对象为根,沿属性和载荷快照标记,先批量摘除全部不可达对象,再扣减指向幸存对象的引用,最后 Drop 垃圾。这样可以处理自环、互相引用和原生载荷与属性构成的环,也不会误收仍可达的对象。trace API 遍历的是受管理引用,不是语言继承关系。 VM 销毁时 Box 的 Rust 所有权会清理全部剩余载荷,即使其计数仍大于零或尚未显式回收循环。没有语言级 __del__、复活、自动阈值、分代或增量收集。外部句柄不延长 VM 的生命周期。 ### 操作协议 ObjectPayload 定义 repr、str、is_true、hash、compare、call 及属性许可。默认表示带诊断名和身份,默认 str 复用 repr,默认真值为 true,默认哈希基于身份,默认 Eq/Ne 按身份,排序和调用默认报 UnsupportedOperation。compare 返回 None 时尝试右侧反向操作,再使用身份回退;没有 Python 继承优先级规则。 Record 支持托管属性,NativeFunction 包装 Rust 函数指针。原生调用先验证参数句柄,再执行回调,再验证结果句柄。回调只计算返回值,不能修改或分配当前 VM;对象结果是借用句柄。自定义载荷可覆盖操作,若提供内容相等语义,必须保持哈希一致,或显式拒绝哈希。错误通过 Result 返回,不是语言异常机制。 Value 中标量和字符串不强制堆分配。Float 暂用 Rust f64 语义;完整字符串、数值对象和语言类型规则尚未定义。更详细的代码说明见 endor-object.md。 ## 宿主与持久化 `aster-storage` 不引用任何内核类型。它连接一个确定的后端,初始化 `aster_metadata(key TEXT PRIMARY KEY NOT NULL, value TEXT NOT NULL)`,通过参数绑定完成幂等更新及读取。当前 schema 是单条幂等 DDL;修改 schema 时再引入版本化迁移,禁止把 CREATE IF NOT EXISTS 当作升级已有列结构的工具。 SQLite 文件模式自动创建父目录、开启 WAL,连接池最多 5 条连接,busy timeout 为 5 秒。内存模式单连接,关闭空闲回收和最大存活时间,防止池正常轮换导致数据库消失;独立 Storage 实例的内存数据库相互隔离。`Storage` 克隆共享连接池,`close` 关闭全部克隆的池。 PostgreSQL 最多 5 条连接,获取/建立连接超时 5 秒,启动真实连接而非惰性连接。其配置失败或初始化失败均上抛,不进入 SQLite 分支。SQLite 的缺省只发生在**未配置** DATABASE_URL 时。 元数据仅供宿主管理,不代表类、实例、句柄或整堆快照。重启宿主会创建新的空 VM;后续对象获得新身份和新句柄,只保留文件/数据库内的元数据。服务仅写入 `host.version`,不会把句柄调试值写入数据库。 `aster-server` 保存只读 VM 和共享 Storage。GET /bootstrap 只读运行时标识和对象数量;GET /health 探测数据库可用性。没有对象操作 API、语言执行 API 或鉴权协议。HTTP/Tokio/SQLx 都不进入内核。后续浏览器宿主应通过明确的能力接口桥接,不能把浏览器类型塞进核心对象工厂。 ## 已决定与未决定 已决定:EndorObject 实现层基础结构、稳定 Box 分配、代际句柄、外部/内部引用计数、手动全堆循环回收、Rust 操作分发、存储属于宿主。 未决定:语言根类、Python type/元类体系、继承、字节码格式、调用栈、可变 VM 回调上下文、语言异常与终结器、外部对象协议、共享可变 VM、自动/分代 GC、堆序列化和浏览器通信。不得在交接中把这些当成已实现契约。