压缩云工适配
把公共[压缩接口](../../../豫言操作系统接口/压缩/规范.汉语.md)映射到云工宿主的原生 DecompressionStream,全部用豫言写在 云工宿主的句柄桥之上,不含宿主 JS。
- 数据进宿主一次:条目数据经
云工物字造字节变成宿主 Blob(越过值桥一次,至多 16 MiB),之后的切片、拼接和流都在宿主内完成。 - 解压路径:
Blob.stream()经pipeThrough接入DecompressionStream,豫言用云工读取流块安全逐块读取输出:先读块的byteLength,累计超过最大输出就释放块句柄、取消读取器并返回状态 1,绝不把超限的块复制进 Wasm;流出错为状态 2;读完则把各块按“栈顶最新、邻近同量级则合并”的规则拼接(总复制量为 O(n log n)),只在结果处复制一次。块的大小由宿主决定(Node 为 16 KiB,本地 workerd 为 4 KiB)。 - 归档条目校验:条目被包成 gzip 容器——10 字节头、条目的 deflate 流、8 字节尾(CRC-32 与 ISIZE,小端)——交给
DecompressionStream('gzip'),由平台校验。存储方法的数据先被包成 deflate 存储块:每块至多 65535 字节,块头是新建的 5 字节小 Blob,块体是原数据 Blob 的slice,末块置 BFINAL;空数据产生一个空的末块。容器全部在宿主里用 Blob 拼接,不把大数据逐字节搬进豫言,也不在豫言里算 CRC-32。 - 区分状态 2 与 3:存储方法先比较长度(大于最大输出为 1,不等于预期为 3);deflate 方法在 gzip 校验失败后用 raw deflate 复解一遍并按同一上限累计(超限 1、失败 2、成功则是 CRC-32 或大小不符 3)。真实 workerd 遇到 gzip 尾部校验失败时不先交出已解出的块,Node 则先交出,所以结论不依赖流先出块还是先报错。
- 句柄:每个用到的宿主句柄(Blob、流、转换流、读取器、块、存储块头与切片)用毕即释放;测试在同一事件里反复解压不触及 4096 的句柄上限。
- 参数校验在豫言里做:最大输出、输入长度、方法、CRC-32 范围、预期大小;违规抛出豫言异常(不是宿主 JS 错误)。
验证:Node 与 wrangler 4.129.0 的本地 workerd 都通过同一份测试(见 一致性验证/):与 zlib.inflateRawSync、zlib.deflateRawSync、zlib.crc32 对拍,覆盖存储块边界、压缩炸弹(200 MiB 输出取消于 1 MiB 上限,用时数毫秒至数十毫秒)与随机扰动对拍。