perf(全仓库/正则): 字面量正则全部改模块级预编译常量(15 文件 / 115 个调用点)

背景(prof 基线 PROF/20260930_224857,主进程 433.69s):正则这一族合计 ≈45s ——
`re.match`(未预编译入口)被调 1970 万次 / 自身 10.70s、它内部 `Pattern.match` 占 8.06s,
`re._compile`(缓存查找)1975 万次 / 7.19s,`re._make`(真正编译)274 万次 / 7.62s
(说明 re 的 512 条缓存已被打穿,每 7 次调用就有 1 次重新编译)。
每次 `re.match(字面量, s)` 都要做"模式串哈希 → 缓存查找";预编译后这层全省掉。

改动:把 15 个文件里 97 处"字面量当模式"的 `re.match/search/sub/subn/fullmatch/
findall/finditer/split(...)` 提升为模块级 `_RE_*: re.Pattern[str] = re.compile(...)`,
共 115 个调用点(含同字面量跨处共用)。模式串与 flags 一字未改(flags 从调用处
搬进 re.compile,含原先以**位置参数**传入的 flags)。4 处拼接型动态模式按设计不动
(FuncGen 2 处、HandlesImports 2 处)。

核验(不靠肉眼):写了 AST 指纹对拍脚本,对每个文件取 HEAD 版与新工作区版,把
"旧 re.<m>(字面量, 其余实参, 关键字) + flags" 与 "新 _RE_X.<m>(实参, 关键字) +
常量 (模式, flags)" 做多重集比对 —— 15 个文件、115 个调用点全部逐一等价(0 失败),
另查无重名常量、无遗留字面量调用、GetDiagnostics 全空。
对拍过程中查出一处子代理抄写错误:`_RE_GLOBAL_DSOLOCAL_MULTILINE` 丢了行首锚 `^`
(原文注释明确"使用 ^ + MULTILINE 避免匹配字符串常量内容中的 define/declare"),已修正。

同轮经查证后**未做改动**的两项(避免把假热点当真事修):
- VLogger 的 `re.sub` 6.43s:profile 当时的 VLogger 版本里根本没有 `import re`
  (`git show 3658ab06:lib/core/VLogger.py` 已确认),属 C 帧错挂,不做。
- tokenize 274 万次:那是 `_generate_tokens_from_c_tokenizer` 的 **token 产出次数**
  (≈350 个整文件的词法量),SymbolUtils 的 4 个 tokenize 调用点 nc 仅数百,且已有
  `_EXPAND_CACHE` 去重;再加一层 token 缓存无收益,不做。
This commit is contained in:
TermiNexus committed 2026-09-30 23:47:36 +08:00
1 parent 4641777db1
commit b18d57fa38
15 files changed
+318 -96

No files matched your search

+7 -2
View File
@@ -13,6 +13,11 @@ from lib.core.VLogger import get_logger as _vlog
# (profile:`_TypedPointerType.__init__` 3,750,259 次中有一份来自这里)。
_I8_PTR: ir.Type = ir.PointerType(ir.IntType(8))
# `_strip_unnecessary_quotes` 识别 LLVM IR 裸标识符 / 给引用名去引号用的**预编译**正则
# (性能:该函数对整段 IR 文本做替换,字面量正则预编译避免 re 缓存查找与编译开销)。
_RE_IR_IDENTIFIER: re.Pattern[str] = re.compile(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$')
_RE_QUOTED_IR_NAME: re.Pattern[str] = re.compile(r'([@%])"([^"]+)"')
class StructGenMixin:
@@ -185,10 +190,10 @@ class StructGenMixin:
name: str = m.group(2)
if '.' in name:
return m.group(0)
if re.match(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$', name):
if _RE_IR_IDENTIFIER.match(name):
return prefix + name
return m.group(0)
return re.sub(r'([@%])"([^"]+)"', _unquote, ir_str)
return _RE_QUOTED_IR_NAME.sub(_unquote, ir_str)
def finalize(self) -> str:
self._set_Vtable_initializers()