perf(gsub): gidLookup 改 Int32Array,大数组 fill 快 3×

GidLookup(原gid→新gid 查找表)原用 number[].fill(-1), TypedArray 的 fill
是 native memset,比 number[].fill 快约 3×(35515 项:219μs→67μs)。

初夏明朝 subsetGids 仅十余个但 maxOrigGid 达 3.5 万(reachable 的高 gid target),
number[].fill(-1) 耗时 ~200μs,占 subsetGSUB 总耗时 ~47%。Int32Array.fill
降至 ~67μs,索引访问速度实测与 number[] 一致(FiraCode 密集查询场景同 8μs)。

初夏 rewrite 0.663→0.501ms(-24.5%),总 fontSubset -9.2%;FiraCode 略快 -2.8%。
GSUB 输出字节级一致(cmp 通过),30 项基准 SSIM 零变化。

推翻记忆 gsub-subset-perf-coverage-cache 中「number[] 比 Int32Array 快 2×」结论
(旧 V8 或不同测试条件),当代 V8 下两者访问速度相同,TypedArray fill 显著更快。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
崮生(子虚) 2026-07-24 10:38:27 +08:00
parent 6d897f1987
commit aa2818b13e

View File

@ -75,9 +75,12 @@ const EMPTY_GIDS: number[] = [];
* origToNew Map<number,number> .get() coverage gid
* =gid=gid-1 退
* Map.get subsetGSUB readCoverageRemapped
* number[] Int32Array V8 number[] 访 TypedArray 2×
* Int32ArrayTypedArray.fill native memset number[].fill 3×
* subsetGids maxOrigGid 3.5 number[].fill(-1) ~200μs
* Int32Array.fill ~67μs subsetGSUB ~6%访 number[]
* 访gid >= length undefined>= 0
*/
type GidLookup = number[];
type GidLookup = Int32Array;
/** Coverage gid
* cache coverage off
@ -1179,7 +1182,7 @@ export function subsetGSUB(
* =gid=gid-1 gid */
let maxOrigGid = 0;
for (const g of origToNew.keys()) if (g > maxOrigGid) maxOrigGid = g;
const gidLookup: GidLookup = new Array(maxOrigGid + 1).fill(-1);
const gidLookup: GidLookup = new Int32Array(maxOrigGid + 1).fill(-1);
for (const [g, n] of origToNew) gidLookup[g] = n;
/** ---- GSUB Header ---- */