跳到正文
豫言包管理
← 全部包

客体二号 0.1.0

豫言 · 可执行文件

用户态豫言客体执行器二号(底层模式):解释执行普通豫言的 WasmGC 程序。

用户态豫言客体执行器二号,以底层模式的普通豫言编写(旧的括号式 .低阶 源码由此取代)。它解释执行普通豫言编译得到的 WasmGC 模块:栈机解释器、分配与标记清扫回收、异常、结构与数组、宿主原语(输出、文件、命令行、同步子进程)、持久文件系统与 Virtio 块设备驱动。

构建

node 豫言操作系统/宿主/节点/宿主.cjs yy豫构.wasm 构建 客体二号 --输出 /tmp/yy客体二号.wasm

产物是标准 Wasm 模块(导出 启动),由验证工具 豫言操作系统/裸机/普通豫言验证。豫 读入后追加客体模块与标志数据段,生成裸机镜像。内存布局常量(布局)的地址与验证工具约定一致,不得随意改动。

模块

布局 内存布局与状态格常量;基础 输出、变长整数、内存与宽整数助手;其余模块依依赖顺序排列。语言约定见 应用/豫言编译器/文档/底层模式.汉语.md。

域名报文 用普通豫言底层模式写 DNS 单问题查询及 A、AAAA 回答的编解码,支持回答名的压缩指针;原生进程在 Linux 上经 UDP 使用它。固定报文探针覆盖两种记录及无效指针。

豫言操作系统底层接口:裸机后端

裸机底层状态码、裸机底层基础、裸机底层句柄、裸机底层文件、裸机底层终端、裸机底层网络、裸机底层进程 七个模块,是[豫言操作系统底层接口](../../../豫言操作系统底层接口/总纲.汉语.md)在裸机上的实现(45 个函数,方案见[底层接口方案](../../../文档/豫言操作系统底层接口方案.汉语.md))。它们是新增、独立的模块:直接复用既有的文件系统(fs读文件、fs写文件、fs建目录、fs删除等)、控制台(读字节、读行、打印串)与时钟(时钟滴答、墙钟秒)原语,不改动这些既有实现;入口只在启动时新增一次 底柄_初始化 调用(在固定状态格 3664、3668 保存动态句柄表地址与终端模式;表头保存行输入剩余状态,经 取区域 分配句柄表、路径缓冲与内容缓冲,暂存缓冲仍供文件和时钟操作临时使用)。

子任务重启会清空动态区;重启准备 同时清除旧句柄表指针,下一次启动重新分配句柄表并建立根句柄 3。当前子任务没有块设备,底层文件操作仍需由初始任务经独立邮箱协议代办;GC 文件原语已有自己的对象协议。

  • 句柄模型:句柄 0/1/2 是标准三流;句柄 3 恒为根目录(唯一的预开目录);4 起的 13 个槽按需分配给已打开的文件与目录,每槽有独立的路径缓冲(22400 字节)与内容缓冲(409600 字节,整文件缓存)。底层文件另从动态区取得临时路径和数据缓冲。
  • 路径解析:相对目录句柄解析,不含当前目录,.. 越出目录句柄子树报错,与既有 主机文件 里依赖“当前目录”状态的路径规范化是两套独立的逻辑。
  • 已知限制(均已在各文件的双语注释里逐条注明):底层网络、底层进程 全部返回“不支持”(网络因裸机无网络栈;进程因桥接既有的 GC 对象参数子进程机制不在本轮范围);建管道、取终端尺寸 返回“不支持”;填随机字节 返回“不支持”(裸机熵源未定);文件与目录内容缓存上限 409600 字节,超过则相应操作返回“溢出”;单调时钟精度 10 毫秒(内核滴答),墙钟精度 1 秒(RTC)。
  • GC shim 的改接:控制台输出原语(1–4 号)经本接口的 写;Linux 上的文件原语经本接口的 Linux 后端(见下节)。裸机上的文件原语仍直接用执行器内的文件系统(待办事项:放大整文件缓存的上限后改经本接口)。

多平台:同一份执行器在 Linux 与 macOS 上运行

执行器是同一份整数 Wasm 模块,由寄存器降级按目标生成裸机镜像、Linux 可执行文件或 macOS 可执行文件。运行时靠目标内建导入 导入:目标:平台号(降级时绑定为常量:裸机 1、Linux 2、macOS 3)选择平台实现;其他目标的导入降级为陷阱桩,不会被执行。

  • 林系统、苹系统:Linux 系统调用包装(导入模块名 Linux)与 macOS libSystem 包装(导入模块名“苹果”,返回 -1 时导入桩已换成 -errno),以及 是林、是苹 与各自的 errno 转换表(两个系统的 errno 编号不同)。原生系统 在两者之间分派写、读、退出、时钟与终端判断。
  • 平台:写字节、读字节、退出、时钟滴答、墙钟、中断查询在原生系统上改走系统调用或 libSystem;任务与邮箱服务在原生系统上尚未实现,按失败返回(待办事项)。
  • 林启动、苹启动:启动时写程序名区、参数区与环境块。Linux 读 /proc/self/exe、cmdline、environ;macOS 用 sysctl 的 KERN_PROCARGS2(缓冲是启动时新增长的两页)。之后的宿主原语不必区分平台。
  • 林底层、苹底层:底层接口 45 个函数的 Linux 与 macOS 后端,原生底层 按平台号在两者之间分派(函数名加前缀“原底_”);裸机后端各函数开头在原生系统上转到这里。句柄就是文件描述符,3 号是根目录“/”。Linux 打开用 openat2 加 RESOLVE_BENEATH(越界返回 76),ENOSYS 时逐段用 O_PATH|O_NOFOLLOW 解析;路径状态经受限句柄查询,建删、改名和读链接先安全打开父目录,双架构路径探针通过。macOS 打开用 O_RESOLVE_BENEATH,路径状态用 AT_RESOLVE_BENEATH,其他路径操作先受限打开父目录;本机 ARM64 路径探针覆盖树内链接、越界链接及文件变更,均通过。状态分别取自 statx 与 fstatat,目录分别取自 getdents64 与 __getdirentries64。待办事项:Linux 旧核逐段回退与两平台父目录打开后的并发更名竞态、旧版 macOS 不支持边界标志时的回退。终端模式:Linux 用 TCGETS/TCSETS,macOS 用 TIOCGETA/TIOCSETA(原始模式与 libuv 相同)。
  • 原生进程:两个系统共用的进程、等待与网络实现,系统差别集中在“进_”开头的小函数里。运行程序:fork(Linux 用 clone(SIGCHLD)),子进程接好标准流与工作目录后 execve,失败时经 O_CLOEXEC 管道把 errno 告诉父进程;进程句柄从 2^30 起编号,进程表在暂存区。等待用 ppoll(macOS 用 poll),进程订阅每轮检查(有运行中的进程时每轮至多等 10 毫秒)。TCP 支持 IPv4、数字 IPv6、localhost 与 /etc/hosts 名表;Linux 和 macOS 均依次尝试 /etc/resolv.conf 中的服务器,以 UDP 查询 A、AAAA,原名未解析时依次拼接 search 或 domain 后缀。Linux 空主机监听双栈,macOS 空主机仍用 IPv4;macOS 的 resolv.conf 未必涵盖系统全部 DNS 路由(待办事项:系统 DNS 路由接入、IPv4 嵌入式 IPv6 地址、区域号)。启动时忽略 SIGPIPE,子进程在 execve 前恢复默认。启动顺序上,底层句柄表与原生后端暂存区都用 取区域,必须在 初始化堆 之前(之后的区域顶就是堆起点,会与堆重叠)。
  • 原生子进程:原生系统上的同步子进程原语 43–46(程序名按 PATH 解析,经 运行程序 启动;45 接 /dev/null,46 用两条管道同时读取标准输出与标准错误)。切换当前目录时同步进程的真实工作目录,子进程因此在同一目录运行。异步子进程 67–69 也在这里:子进程表(至多 1024 个)在启动时用 取区域 分配,回收时整表作为根扫描;两条捕获管道设为不阻塞,收取与等待时读尽现有数据并查询退出码,等待时用底层接口的 等待 同时等全部管道与进程句柄,行为与 Node 宿主相同(豫构调度器测试在原生宿主上与 Node 输出逐字相同)。待办事项:设置子进程输入、环境(70、71)尚未接到原生系统。
  • 原生网络原语:TCP 宿主原语 77–90(语义同 Node 宿主:不阻塞,返回(状态,值)),在原生系统上经底层网络包实现;裸机返回 -58。
  • 字节串原语:91 号 豫言_字节串_截取(从起点取定长字节成新串,越界时以 134 退出)在各平台由执行器直接实现,原生运行的编译器写出产物时要用它。11 号“运行于MacOS”在 macOS 上返回真。
  • 原生文件原语:原生系统上的文件宿主原语,路径仍由 规范参数 规范成绝对路径,再经底层接口访问宿主文件系统;启动时当前目录取自 /proc/self/cwd 或 getcwd。
  • WASI名称 与 WASI分派:识别 WASI preview1 的 46 个函数名,已实现参数与环境读取、时钟、随机数、标准流与文件读写、预开根目录、路径打开与变更、句柄及路径状态、寻址与定位读写、目录读取、等待与退出。时钟、流、文件和等待调用经底层接口;裸机尚无熵源,随机调用返回不支持。未实现的调用返回 ENOSYS。函数表分配后清零,使本地函数与导入函数准确区分。22 个现有样例各至少在一个原生目标运行过;其中 文件测试、文件边界、睡眠 的 Linux 双架构标准输出经 cmp 验证逐字相同,出入 的双架构标准输出与标准错误也分别逐字相同。全平台与参照实现的逐字一致性仍待验证。
  • 生成与验证:yy原生生成 Linux|苹果 臂六十四|兼容六十四 执行器.wasm 输出 客体.wasm 把客体模块嵌进执行器,得到独立可执行文件(macOS 目前只有 arm64);yy原生一致性(豫言操作系统/裸机/原生一致性。豫)把普通探针与文件探针在 Linux(两种架构;非 Linux 系统上加 --经 docker)或 macOS(--系统 苹果,本机运行)上运行,与裸机验证所用的期望输出逐字比较。

WASI path_readlink 已通过客体内存边界检查接到底层文件接口;原生系统可读符号链接,裸机底层当前返回不支持。此调用尚未经过外来程序的端到端验证。

预编:WasmGC 函数直接成为机器码(路二乙档第一版)

yy原生生成 … 执行器.wasm 输出 客体.wasm --预编(或 yy原生一致性 --预编)把客体 WasmGC 模块的每个函数转译成一个整数 Wasm 函数,并入执行器模块后一起经寄存器降级生成机器码;执行器照常解析模块、建类型表、初始化全局与数据,但不再解释函数体。转译器在 库/裸机后端/预编转译。豫,执行器一侧的运行时接口在 预编接口。豫。

  • 值都在值栈上:布局与解释器相同(每槽 8 字节,引用与 32 位整数在低字),所以保守回收照常看得见;转译函数的签名是(帧)→ i32,参数与局部变量从帧起,操作数栈在其上,调用者把参数放在栈顶、被调用者的帧就从那里开始。
  • 简单指令内联,复杂指令调解释器的处理函数:局部变量、常量、i32 运算与比较、少数 i64 指令、引用判空与相等、控制流直接写成整数指令;结构、数组、类型转换、i64 其余与浮点、访存、表与杂项指令调用执行器导出的“预编_”函数(就是解释器的指令处理函数),传入立即数在模块字节中的地址。
  • 控制流一一对应:块、循环、条件对应整数 Wasm 的同名结构,分支先把携带的值搬到目标槽;尾调用(return_call 及间接、引用尾调用)先把参数搬到帧首,再“调用后立即返回”,寄存器降级把这种形状变成尾跳;间接调用经执行器导出的 预编派发(按函数号二分,叶子上尾跳到转译函数)。
  • 异常用标志传播:抛出时记下载荷并置 状态_预编异常,每次调用转译函数后检查,在尝试表里就跳到它的处理代码,否则返回;最外层仍有异常即按未捕获异常退出(137)。
  • 大模块:超过 448 KiB 模块窗口的客体(如编译器)不嵌入窗口,而作为尾块写进可执行文件(Linux 附在文件末尾,macOS 放在 __LINKEDIT 里签名之前),执行器启动时读回到动态区开头;Linux 代码太大时单独放一个载入段(ARM64 在 0x10000000,x86-64 在 0x50000000)。
  • 降级器随之扩充:“调用后立即返回”变尾跳;每 512 KiB 代码插一个陷阱岛,越界与除零检查跳到最近的岛;大函数(超过 2 万条指令)的条件跳转改用“反条件跳过 + b”;汇编器只在条件分支上计算 19 位位移(原先 b、bl 超过 1 MiB 也会误报超程)。

现状(2026-09-28):macOS arm64 上普通探针、文件探针与原生探针共 12 项在预编模式下与参照输出逐字一致;短程序比解释执行快约两倍(多为启动开销)。待办事项:内联更多热指令(ref.cast、struct.get、array.get、i31)、非引用值留在寄存器里、Linux 上的预编验证、编译器本身的预编与原生自举。

续记(2026-09-29):Linux ARM64 的完整预编一致性组 15 项通过,普通、文件与原生探针均与裸机或 Node 参照逐字相同。Linux x86-64 的解释模式打印探针通过;同机 Docker 的 Rosetta 在装载较大的预编产物时报告 failed to mmap segment: 22,尚须在真实 Linux x86-64 运行器上验预编。编译器自身的原生自举仍待完成。

依赖

查看包配置

上传历史

当前上传修订:1 ·

  1. 上传修订 1
    下载 ZIP

包层级

父包:豫言裸机

没有子包。