From 7f983ff969dabaa998fc01a34b55aea80256e6cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B4=AE=E7=94=9F=EF=BC=88=E5=AD=90=E8=99=9A=EF=BC=89?= <2234839456@qq.com> Date: Fri, 24 Jul 2026 15:44:53 +0800 Subject: [PATCH] =?UTF-8?q?perf(gsub):=20readClassDefMap=20=E7=94=A8=20gid?= =?UTF-8?q?Lookup=20=E6=95=B0=E7=BB=84=E6=9B=BF=E4=BB=A3=20Map.get?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fmt2 ChainContext 的 ClassDef 重映射原用 origToNew.get() 逐 gid 查询, FiraCode fmt2 ClassDef 展开后 9699 个 gid 每个 Map.get(~9ns) 是 fmt2 路径 热点。改用 gidLookup Int32Array 索引(~1ns),语义等价(gidLookup[g]>=0 ⟺ origToNew.has(g) 且值相同)。输出字节三字体 sha256 全一致,SSIM 不变 (FiraCode 0.9923)。writeChainFormat2 移除冗余 origToNew 参数。 Co-Authored-By: Claude Opus 4.8 (1M context) --- backend/font_util/gsub-subset.ts | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/backend/font_util/gsub-subset.ts b/backend/font_util/gsub-subset.ts index 74acae3..0668698 100644 --- a/backend/font_util/gsub-subset.ts +++ b/backend/font_util/gsub-subset.ts @@ -582,7 +582,7 @@ function serializeLigatureSubst( * format1: 逐 gid 赋 class;format2: 区间赋 class。 */ /** 读取 ClassDef 表为 (新gid → classIndex) map,class index 原样保留(不紧致重编号) */ -function readClassDefMap(r: Reader, off: number, origToNew: Map): Map { +function readClassDefMap(r: Reader, off: number, gidLookup: GidLookup): Map { const result = new Map(); if (off === 0) return result; const format = r.u16(off); @@ -591,8 +591,11 @@ function readClassDefMap(r: Reader, off: number, origToNew: Map) const count = r.u16(off + 4); for (let i = 0; i < count; i++) { const origGid = startGid + i; - const newGid = origToNew.get(origGid); - if (newGid !== undefined) result.set(newGid, r.u16(off + 6 + i * 2)); + /** 优化333:gidLookup(Int32Array 索引,~1ns)替代 origToNew.get(Map.get ~9ns)。 + * FiraCode fmt2 ClassDef 展开后 9699 个 gid 逐个 Map.get 是 fmt2 路径主热点(86μs/11 子表)。 + * 语义等价:gidLookup[g] >= 0 ⟺ origToNew.has(g) 且值相同。 */ + const newGid = gidLookup[origGid]; + if (newGid >= 0) result.set(newGid, r.u16(off + 6 + i * 2)); } } else if (format === 2) { const rangeCount = r.u16(off + 2); @@ -602,8 +605,9 @@ function readClassDefMap(r: Reader, off: number, origToNew: Map) const end = r.u16(p + 2); const cls = r.u16(p + 4); for (let g = start; g <= end; g++) { - const newGid = origToNew.get(g); - if (newGid !== undefined) result.set(newGid, cls); + /** 同上,gidLookup 数组索引替代 Map.get */ + const newGid = gidLookup[g]; + if (newGid >= 0) result.set(newGid, cls); } p += 6; } @@ -735,7 +739,7 @@ function serializeChainedContextSubst( } } if (classToRules.size === 0) return false; - writeChainFormat2(w, r, coverageOff, backtrackCDOff, inputCDOff, lookaheadCDOff, origToNew, classToRules, covCache, gidLookup); + writeChainFormat2(w, r, coverageOff, backtrackCDOff, inputCDOff, lookaheadCDOff, classToRules, covCache, gidLookup); return true; } @@ -864,7 +868,6 @@ function writeChainFormat2( backtrackCDOff: number, inputCDOff: number, lookaheadCDOff: number, - origToNew: Map, classToRules: Map }>>, covCache: CoverageCache, gidLookup: GidLookup, @@ -905,9 +908,9 @@ function writeChainFormat2( coverageHolder[0] = emitCoverage(w, newCovGids); /** 重映射三个 ClassDef 的 gid(class index 不变) */ - const backMap = readClassDefMap(r, backtrackCDOff, origToNew); - const inputMap = readClassDefMap(r, inputCDOff, origToNew); - const lookMap = readClassDefMap(r, lookaheadCDOff, origToNew); + const backMap = readClassDefMap(r, backtrackCDOff, gidLookup); + const inputMap = readClassDefMap(r, inputCDOff, gidLookup); + const lookMap = readClassDefMap(r, lookaheadCDOff, gidLookup); backHolder[0] = writeClassDefFromMap(w, backMap); inputHolder[0] = writeClassDefFromMap(w, inputMap); lookHolder[0] = writeClassDefFromMap(w, lookMap);