refactor: share VPI escape and willFree scanners

Replace the two near-identical VPI annotation line scanners with one marker scanner parameterized by annotation kind. Source-only change: 91 added, 123 deleted (net -32 lines).
This commit is contained in:
TermiNexus committed 2026-11-02 13:29:29 +08:00
1 parent 38a521fcd2
commit 9e0729b855
2 files changed
+95 -125

No files matched your search

+91 -123
View File
@@ -121,7 +121,6 @@ define VPI_IDX_FNV_OFFSET = 2166136261
define VPI_IDX_FNV_PRIME = 16777619
define VPI_IDX_FNV_MASK = 4294967295
# v3 跨模块逃逸摘要缓存(.vpi 行尾 `# esc=<mask> ret=<ret>`,由 StubGen.Converter._PyiFunction 写出)。
# 键 = "{sha1}.{Class}.{method}"(方法)或 "{sha1}.{func}"(模块级函数);
# 值打包:低 32 位 = 形参逃逸掩码,高 32 位 = 返回借用位。无逃逸/无返回借用的 def 不写条目,
# 因此"查不到"即"无摘要"(调用点保守放行),与本地表口径一致。
@@ -137,7 +136,6 @@ _g_vpi_wf_keys: bytes = None
_g_vpi_wf_vals: sizet* = None
_g_vpi_wf_count: int = 0
# 跨模块常量特化(P3 收尾):同一函数可有多条 `escg=`(打包 p|k|m,见 StructGenMixin._PackEscapeClear),
# 所以是"一键多行"表:键列与 wf 表同构,值列是打包整数。
define VPI_ESG_MAX = 8192
define VPI_ESG_KEY_LEN = 224
# 常量环境的形参位上限:必须与 StructGenMixin.EC_ENV_MAX 一致(越界位一律不信)
@@ -1124,7 +1122,6 @@ def _ensure_vpi_ret_annot_loaded(src_sha1: str, temp_dir: str) -> int:
# _cache_vpi_esc_clears_text - 抽取行尾**所有** `escg=<packed>` 标记(跨模块常量特化)。
# 与 wf 表同构,但同一行可有多条(一条一个打包值),故是"一键多行"。值 = p|k|m 打包整数
# (见 StructGenMixin._PackEscapeClear:p=守卫形参位、k=常量、m=可清掉的位掩码)。
def _cache_vpi_esc_clears_text(vpi_buf: bytes, src_sha1: str) -> int:
"""抽取 vpi 行尾的 escg= 标记进缓存;1=处理完成 / 0=缓冲区或分配失败"""
@@ -1395,18 +1392,27 @@ def _cache_vpi_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
return 1
# _cache_vpi_escape_annots_text - extract the trailing `# esc=<mask> ret=<ret>` markers.
# v3 跨模块逃逸摘要:不依赖 AST,按行扫描(与 _cache_vpi_return_annots_text 同构)。
def _cache_vpi_escape_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
"""抽取 vpi 行尾逃逸摘要标记进缓存;1=处理完成 / 0=缓冲区或分配失败"""
# _cache_vpi_marker_annots_text - scan .vpi def lines and cache per-method markers.
# kind 0 = escape summary (`# esc=<mask> ret=<ret>`), kind 1 = willFree (`# ... wf=<mask>`).
def _cache_vpi_marker_annots_text(vpi_buf: bytes, src_sha1: str, kind: int) -> int:
global _g_vpi_esc_keys, _g_vpi_esc_vals, _g_vpi_esc_count
global _g_vpi_wf_keys, _g_vpi_wf_vals, _g_vpi_wf_count
if vpi_buf is None or src_sha1 is None: return 0
if _g_vpi_esc_keys is None:
_g_vpi_esc_keys = stdlib.malloc(VPI_ESC_MAX * VPI_ESC_KEY_LEN)
_g_vpi_esc_vals = sizet*(stdlib.malloc(VPI_ESC_MAX * 8))
if _g_vpi_esc_keys is None or _g_vpi_esc_vals is None: return 0
string.memset(_g_vpi_esc_keys, 0, VPI_ESC_MAX * VPI_ESC_KEY_LEN)
string.memset(_g_vpi_esc_vals, 0, VPI_ESC_MAX * 8)
if kind == 0:
if _g_vpi_esc_keys is None:
_g_vpi_esc_keys = stdlib.malloc(VPI_ESC_MAX * VPI_ESC_KEY_LEN)
_g_vpi_esc_vals = sizet*(stdlib.malloc(VPI_ESC_MAX * 8))
if _g_vpi_esc_keys is None or _g_vpi_esc_vals is None: return 0
string.memset(_g_vpi_esc_keys, 0, VPI_ESC_MAX * VPI_ESC_KEY_LEN)
string.memset(_g_vpi_esc_vals, 0, VPI_ESC_MAX * 8)
else:
if _g_vpi_wf_keys is None:
_g_vpi_wf_keys = stdlib.malloc(VPI_WF_MAX * VPI_WF_KEY_LEN)
_g_vpi_wf_vals = sizet*(stdlib.malloc(VPI_WF_MAX * 8))
if _g_vpi_wf_keys is None or _g_vpi_wf_vals is None: return 0
string.memset(_g_vpi_wf_keys, 0, VPI_WF_MAX * VPI_WF_KEY_LEN)
string.memset(_g_vpi_wf_vals, 0, VPI_WF_MAX * 8)
sha1_len: sizet = string.strlen(src_sha1)
buf_len: sizet = string.strlen(vpi_buf)
cur_cls: bytes = None
@@ -1418,7 +1424,6 @@ def _cache_vpi_escape_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
i: sizet = ls
while i < le and vpi_buf[i] == ' ': i += 1
if i < le:
# class X: -> 记录当前类上下文(与方法键一致;兼容 virtual/novirtual 前缀)
cls_off_e: int = _vpi_class_name_offset(vpi_buf, i, le)
if cls_off_e >= 0:
cstart: sizet = sizet(cls_off_e)
@@ -1430,34 +1435,65 @@ def _cache_vpi_escape_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
if cur_cls is not None:
string.strncpy(cur_cls, vpi_buf + cstart, cend - cstart)
cur_cls[cend - cstart] = '\0'
# def name(...) ... # esc=<mask> ret=<ret>
elif le - i >= 4 and _vpi_func_name_offset(vpi_buf, i, le) >= 0:
# 模块级函数(无缩进)清掉类上下文,避免上一类泄漏
if i == ls and cur_cls is not None:
stdlib.free(cur_cls)
cur_cls = None
# 找同行 "# esc=" 标记
mark: sizet = le
hm: sizet = le
j: sizet = i
while j + 6 <= le:
if vpi_buf[j] == '#' and vpi_buf[j + 1] == ' ' and string.strncmp(vpi_buf + j + 2, "esc=", 4) == 0:
mark = j
while j < le:
if vpi_buf[j] == '#':
hm = j
break
j += 1
if mark < le:
kp: sizet = mark + 6
esc_v: int = 0
while kp < le and vpi_buf[kp] >= '0' and vpi_buf[kp] <= '9':
esc_v = esc_v * 10 + (int(vpi_buf[kp]) - 48)
kp += 1
ret_v: int = 0
while kp < le and vpi_buf[kp] != 'e': kp += 1
if kp + 4 <= le:
kp += 4
esc_v: int = 0
ret_v: int = 0
wf_v: int = 0
if kind == 0:
j2: sizet = i
while j2 + 6 <= le:
if vpi_buf[j2] == '#' and vpi_buf[j2 + 1] == ' ' and string.strncmp(vpi_buf + j2 + 2, "esc=", 4) == 0:
mark = j2
break
j2 += 1
if mark < le:
kp: sizet = mark + 6
while kp < le and vpi_buf[kp] >= '0' and vpi_buf[kp] <= '9':
ret_v = ret_v * 10 + (int(vpi_buf[kp]) - 48)
esc_v = esc_v * 10 + (int(vpi_buf[kp]) - 48)
kp += 1
if (esc_v != 0 or ret_v != 0) and _g_vpi_esc_count < VPI_ESC_MAX:
while kp < le and vpi_buf[kp] != 'e': kp += 1
if kp + 4 <= le:
kp += 4
while kp < le and vpi_buf[kp] >= '0' and vpi_buf[kp] <= '9':
ret_v = ret_v * 10 + (int(vpi_buf[kp]) - 48)
kp += 1
else:
if hm < le:
j3: sizet = hm + 1
while j3 + 3 <= le:
if vpi_buf[j3] == 'w' and vpi_buf[j3 + 1] == 'f' and vpi_buf[j3 + 2] == '=':
mark = j3
break
j3 += 1
if mark < le:
kp2: sizet = mark + 3
while kp2 < le and vpi_buf[kp2] >= '0' and vpi_buf[kp2] <= '9':
wf_v = wf_v * 10 + (int(vpi_buf[kp2]) - 48)
kp2 += 1
has_marker: int = 0
if kind == 0:
if esc_v != 0 or ret_v != 0: has_marker = 1
else:
if wf_v != 0: has_marker = 1
if has_marker != 0:
can_store: int = 0
if kind == 0:
if _g_vpi_esc_count < VPI_ESC_MAX: can_store = 1
else:
if _g_vpi_wf_count < VPI_WF_MAX: can_store = 1
if can_store != 0:
dstart: sizet = sizet(_vpi_func_name_offset(vpi_buf, i, le))
dend: sizet = dstart
while dend < le and vpi_buf[dend] != '(': dend += 1
@@ -1466,7 +1502,12 @@ def _cache_vpi_escape_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
cls_len_e: sizet = 0
if cur_cls is not None: cls_len_e = string.strlen(cur_cls)
key_len_e: sizet = sha1_len + 1 + cls_len_e + 1 + mname_len
if key_len_e < VPI_ESC_KEY_LEN:
key_ok: int = 0
if kind == 0:
if key_len_e < VPI_ESC_KEY_LEN: key_ok = 1
else:
if key_len_e < VPI_WF_KEY_LEN: key_ok = 1
if key_ok != 0:
mname_buf_e: bytes = stdlib.malloc(mname_len + 1)
key_buf_e: bytes = stdlib.malloc(key_len_e + 1)
if mname_buf_e is not None and key_buf_e is not None:
@@ -1474,9 +1515,14 @@ def _cache_vpi_escape_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
mname_buf_e[mname_len] = '\0'
if cur_cls is not None: viperlib.snprintf(key_buf_e, key_len_e + 1, "%s.%s.%s", src_sha1, cur_cls, mname_buf_e)
else: viperlib.snprintf(key_buf_e, key_len_e + 1, "%s.%s", src_sha1, mname_buf_e)
string.strcpy(_g_vpi_esc_keys + sizet(_g_vpi_esc_count) * VPI_ESC_KEY_LEN, key_buf_e)
_g_vpi_esc_vals[_g_vpi_esc_count] = sizet(esc_v) | (sizet(ret_v) << 32)
_g_vpi_esc_count += 1
if kind == 0:
string.strcpy(_g_vpi_esc_keys + sizet(_g_vpi_esc_count) * VPI_ESC_KEY_LEN, key_buf_e)
_g_vpi_esc_vals[_g_vpi_esc_count] = sizet(esc_v) | (sizet(ret_v) << 32)
_g_vpi_esc_count += 1
else:
string.strcpy(_g_vpi_wf_keys + sizet(_g_vpi_wf_count) * VPI_WF_KEY_LEN, key_buf_e)
_g_vpi_wf_vals[_g_vpi_wf_count] = sizet(wf_v)
_g_vpi_wf_count += 1
if mname_buf_e is not None: stdlib.free(mname_buf_e)
if key_buf_e is not None: stdlib.free(key_buf_e)
pos = le + 1
@@ -1484,6 +1530,12 @@ def _cache_vpi_escape_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
return 1
# _cache_vpi_escape_annots_text - cache the escape summary markers.
def _cache_vpi_escape_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
"""Cache escape-summary markers from one .vpi text."""
return _cache_vpi_marker_annots_text(vpi_buf, src_sha1, 0)
# _lookup_vpi_escape_packed - query the cross-module escape summary cache (v3).
def _lookup_vpi_escape_packed(src_sha1: str, cls_name: str, method_name: str) -> int:
"""查跨模块逃逸摘要;返回打包值(低32位 mask | ret<<32),0 = 无摘要"""
@@ -1504,94 +1556,10 @@ def _lookup_vpi_escape_packed(src_sha1: str, cls_name: str, method_name: str) ->
return res
# _cache_vpi_willfree_annots_text - extract the trailing `wf=<mask>` marker (P2 willFree).
# 与逃逸摘要同构:不依赖 AST,按行扫描;只在有 wf 标记的 def 上建条目。
# _cache_vpi_willfree_annots_text - cache the P2 willFree markers.
def _cache_vpi_willfree_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
"""抽取 vpi 行尾 P2 willFree 标记(`# ... wf=<mask>`)进缓存;1=处理完成 / 0=缓冲区或分配失败"""
global _g_vpi_wf_keys, _g_vpi_wf_vals, _g_vpi_wf_count
if vpi_buf is None or src_sha1 is None: return 0
if _g_vpi_wf_keys is None:
_g_vpi_wf_keys = stdlib.malloc(VPI_WF_MAX * VPI_WF_KEY_LEN)
_g_vpi_wf_vals = sizet*(stdlib.malloc(VPI_WF_MAX * 8))
if _g_vpi_wf_keys is None or _g_vpi_wf_vals is None: return 0
string.memset(_g_vpi_wf_keys, 0, VPI_WF_MAX * VPI_WF_KEY_LEN)
string.memset(_g_vpi_wf_vals, 0, VPI_WF_MAX * 8)
sha1_len: sizet = string.strlen(src_sha1)
buf_len: sizet = string.strlen(vpi_buf)
cur_cls: bytes = None
pos: sizet = 0
while pos < buf_len:
ls: sizet = pos
le: sizet = pos
while le < buf_len and vpi_buf[le] != '\n': le += 1
i: sizet = ls
while i < le and vpi_buf[i] == ' ': i += 1
if i < le:
# class X: -> 记录当前类上下文(与方法键一致;兼容 virtual/novirtual 前缀)
cls_off_e: int = _vpi_class_name_offset(vpi_buf, i, le)
if cls_off_e >= 0:
cstart: sizet = sizet(cls_off_e)
cend: sizet = cstart
while cend < le and vpi_buf[cend] != ':' and vpi_buf[cend] != ' ' and vpi_buf[cend] != '(': cend += 1
if cend > cstart:
if cur_cls is not None: stdlib.free(cur_cls)
cur_cls = stdlib.malloc(cend - cstart + 1)
if cur_cls is not None:
string.strncpy(cur_cls, vpi_buf + cstart, cend - cstart)
cur_cls[cend - cstart] = '\0'
# def name(...) ... # [esc=<mask> ret=<ret>] wf=<mask>
elif le - i >= 4 and _vpi_func_name_offset(vpi_buf, i, le) >= 0:
# 模块级函数(无缩进)清掉类上下文,避免上一类泄漏
if i == ls and cur_cls is not None:
stdlib.free(cur_cls)
cur_cls = None
# 只在注释段里找 "wf=":避开参数名(如 def f(wf: int))
mark: sizet = le
hm: sizet = le
j: sizet = i
while j < le:
if vpi_buf[j] == '#':
hm = j
break
j += 1
if hm < le:
j2: sizet = hm + 1
while j2 + 3 <= le:
if vpi_buf[j2] == 'w' and vpi_buf[j2 + 1] == 'f' and vpi_buf[j2 + 2] == '=':
mark = j2
break
j2 += 1
if mark < le:
kp: sizet = mark + 3
wf_v: int = 0
while kp < le and vpi_buf[kp] >= '0' and vpi_buf[kp] <= '9':
wf_v = wf_v * 10 + (int(vpi_buf[kp]) - 48)
kp += 1
if wf_v != 0 and _g_vpi_wf_count < VPI_WF_MAX:
dstart: sizet = sizet(_vpi_func_name_offset(vpi_buf, i, le))
dend: sizet = dstart
while dend < le and vpi_buf[dend] != '(': dend += 1
if dend > dstart:
mname_len: sizet = dend - dstart
cls_len_w: sizet = 0
if cur_cls is not None: cls_len_w = string.strlen(cur_cls)
key_len_w: sizet = sha1_len + 1 + cls_len_w + 1 + mname_len
if key_len_w < VPI_WF_KEY_LEN:
mname_buf_w: bytes = stdlib.malloc(mname_len + 1)
key_buf_w: bytes = stdlib.malloc(key_len_w + 1)
if mname_buf_w is not None and key_buf_w is not None:
string.strncpy(mname_buf_w, vpi_buf + dstart, mname_len)
mname_buf_w[mname_len] = '\0'
if cur_cls is not None: viperlib.snprintf(key_buf_w, key_len_w + 1, "%s.%s.%s", src_sha1, cur_cls, mname_buf_w)
else: viperlib.snprintf(key_buf_w, key_len_w + 1, "%s.%s", src_sha1, mname_buf_w)
string.strcpy(_g_vpi_wf_keys + sizet(_g_vpi_wf_count) * VPI_WF_KEY_LEN, key_buf_w)
_g_vpi_wf_vals[_g_vpi_wf_count] = sizet(wf_v)
_g_vpi_wf_count += 1
if mname_buf_w is not None: stdlib.free(mname_buf_w)
if key_buf_w is not None: stdlib.free(key_buf_w)
pos = le + 1
if cur_cls is not None: stdlib.free(cur_cls)
return 1
"""Cache willFree markers from one .vpi text."""
return _cache_vpi_marker_annots_text(vpi_buf, src_sha1, 1)
# _lookup_vpi_willfree - query the cross-module P2 willFree cache (key shape = escape summary).
+4 -2
View File
@@ -114,7 +114,7 @@ Retained: `ClassGenEnum.RenumTableDump` is referenced from a diagnostic f-string
The following duplicate implementations were merged or redirected:
- `Phase2`: one directory walker for `.vp` and `.s` sources.
- `VpiReader`: shared `_vpi_method_key` for all cached-annotation lookups, a shared pre-registration walker for defaults/enums, and a shared `.vpi` read helper for the two annotation cache loaders.
- `VpiReader`: shared `_vpi_method_key` for all cached-annotation lookups, a shared pre-registration walker for defaults/enums, a shared `.vpi` read helper for the two annotation cache loaders, and one marker scanner for escape/willFree annotations.
- `StubMergerStore`: shared store initialization/append and alias parsing.
- `AssignGenMixin` / `ExprGenCdef`: one `TypeGenCDef.NormalizeDefineBits`.
- `AssignGenMixin` / `ExprGenCls`: removed the weaker duplicate class-annotation helpers; calls now use `ExprGenCls`.
@@ -128,7 +128,9 @@ Measured source-only reduction for the main consolidation batch: **235 added / 7
Follow-up batch: VLogger level filtering and the VpiReader pre-registration/read helpers, **53 added / 81 deleted = net -28 lines**.
Remaining candidates: `VpiReader` escape/willfree annotation scanners, `BuildPipeline` MLIR path setup, `LSP _SliceStr/_ByteAt`, and the list/dict iteration helpers.
Scanner batch: one VpiReader marker scanner for escape/willFree annotations, **91 added / 123 deleted = net -32 lines**.
Remaining candidates: `BuildPipeline` MLIR path setup, `LSP _SliceStr/_ByteAt`, the list/dict iteration helpers, and the nested-function rescan walkers.
---