feat(lifetime): @life(escape/noescape) 多形参、硬逃逸位同命精化、归纳变量区间与跨模块常量特化
- GenApi:escape/noescape 标签支持多实参;新增 compute_escape_directives 与若干委托 - StructGenMixin:硬逃逸位(box[2])、常量与归纳变量区间折叠、_PackEscapeClear/compute_escape_clears - Call 系:调用点同命裁剪(_FrameArgsEscapeClears)+ 跨模块 escg= 查询;写侧 Converter、读侧 VpiReader - AssignGenMixin:裸 T()(无 new、无 __new__)判为帧生命期
This commit is contained in:
1 parent
14a8dcb98b
commit
fc797da542
8 files changed
+937
-36
No files matched your search
@@ -527,7 +527,15 @@ def _PyiFunction(buf: bytes, buf_size: sizet, pos: sizet, fn: ast.FunctionDef*,
|
||||
if GenApi.compute_escape_summary(None, fn, _g_pyi_esc_scratch, esc_box_c) == 0:
|
||||
esc_v_c = int(esc_box_c[0])
|
||||
ret_v_c = int(esc_box_c[1])
|
||||
if esc_v_c != 0 or ret_v_c != 0 or wf_mask_c != 0:
|
||||
# 跨模块常量特化:算"哪些常量绑定能清掉哪些逃逸位"(每条 = 打包的 p|k|m),随同行走 escg= 落盘。
|
||||
# 只在真有逃逸位时才有意义;算出来 0 条就不写(保持 vpi 干净)。
|
||||
clears_c: sizet* = None
|
||||
n_clears_c: int = 0
|
||||
if esc_v_c != 0:
|
||||
clears_c = sizet*(stdlib.malloc(4 * 8))
|
||||
if clears_c is not None:
|
||||
n_clears_c = GenApi.compute_escape_clears(fn, clears_c, 4)
|
||||
if esc_v_c != 0 or ret_v_c != 0 or wf_mask_c != 0 or n_clears_c > 0:
|
||||
tmp_c: bytes = stdlib.malloc(96)
|
||||
if tmp_c is not None:
|
||||
if esc_v_c != 0 or ret_v_c != 0:
|
||||
@@ -535,7 +543,16 @@ def _PyiFunction(buf: bytes, buf_size: sizet, pos: sizet, fn: ast.FunctionDef*,
|
||||
else: viperlib.snprintf(tmp_c, 96, " # esc=%d ret=%d", esc_v_c, ret_v_c)
|
||||
else: viperlib.snprintf(tmp_c, 96, " # wf=%d", wf_mask_c)
|
||||
pos = _PyiEmit(buf, buf_size, pos, tmp_c)
|
||||
# 跨模块常量特化:每条"常量守卫"落一个 escg= 字段(打包 p|k|m,见
|
||||
# StructGenMixin._PackEscapeClear)。同一函数多条 → 重复该字段,读侧按同键全部收集。
|
||||
if clears_c is not None:
|
||||
ci_c: int = 0
|
||||
while ci_c < n_clears_c:
|
||||
viperlib.snprintf(tmp_c, 96, " escg=%d", int(clears_c[ci_c]))
|
||||
pos = _PyiEmit(buf, buf_size, pos, tmp_c)
|
||||
ci_c += 1
|
||||
stdlib.free(tmp_c)
|
||||
if clears_c is not None: stdlib.free(clears_c)
|
||||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||||
return pos
|
||||
|
||||
|
||||
@@ -124,6 +124,15 @@ define VPI_WF_KEY_LEN = 224
|
||||
_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 一致(越界位一律不信)
|
||||
define VPI_ESG_ENV_PARAM_MAX = 64
|
||||
_g_vpi_esg_keys: bytes = None
|
||||
_g_vpi_esg_vals: sizet* = None
|
||||
_g_vpi_esg_count: int = 0
|
||||
|
||||
_g_vpi_esc_keys: bytes = None
|
||||
_g_vpi_esc_vals: sizet* = None
|
||||
@@ -880,6 +889,124 @@ def _ensure_vpi_ret_annot_loaded(src_sha1: str, temp_dir: str) -> int:
|
||||
return 1
|
||||
|
||||
|
||||
# _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=缓冲区或分配失败"""
|
||||
global _g_vpi_esg_keys, _g_vpi_esg_vals, _g_vpi_esg_count
|
||||
if vpi_buf is None or src_sha1 is None: return 0
|
||||
if _g_vpi_esg_keys is None:
|
||||
_g_vpi_esg_keys = stdlib.malloc(VPI_ESG_MAX * VPI_ESG_KEY_LEN)
|
||||
_g_vpi_esg_vals = sizet*(stdlib.malloc(VPI_ESG_MAX * 8))
|
||||
if _g_vpi_esg_keys is None or _g_vpi_esg_vals is None: return 0
|
||||
string.memset(_g_vpi_esg_keys, 0, VPI_ESG_MAX * VPI_ESG_KEY_LEN)
|
||||
string.memset(_g_vpi_esg_vals, 0, VPI_ESG_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:
|
||||
if le - i >= 6 and string.strncmp(vpi_buf + i, "class ", 6) == 0:
|
||||
cstart: sizet = i + 6
|
||||
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'
|
||||
elif le - i >= 4 and string.strncmp(vpi_buf + i, "def ", 4) == 0:
|
||||
# 模块级函数(无缩进)清掉类上下文,避免上一类泄漏
|
||||
if i == ls and cur_cls is not None:
|
||||
stdlib.free(cur_cls)
|
||||
cur_cls = None
|
||||
# 只在注释段('#' 之后)里找 escg=:避开参数名
|
||||
hm: sizet = le
|
||||
j: sizet = i
|
||||
while j < le:
|
||||
if vpi_buf[j] == '#':
|
||||
hm = j
|
||||
break
|
||||
j += 1
|
||||
dstart: sizet = i + 4
|
||||
dend: sizet = dstart
|
||||
while dend < le and vpi_buf[dend] != '(': dend += 1
|
||||
if hm < le and dend > dstart:
|
||||
mname_len: sizet = dend - dstart
|
||||
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_ESG_KEY_LEN:
|
||||
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:
|
||||
string.strncpy(mname_buf_e, vpi_buf + dstart, mname_len)
|
||||
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)
|
||||
j3: sizet = hm + 1
|
||||
while j3 + 5 <= le:
|
||||
if vpi_buf[j3] == 'e' and vpi_buf[j3 + 1] == 's' and vpi_buf[j3 + 2] == 'c' and vpi_buf[j3 + 3] == 'g' and vpi_buf[j3 + 4] == '=':
|
||||
kq: sizet = j3 + 5
|
||||
eg_v: int = 0
|
||||
while kq < le and vpi_buf[kq] >= '0' and vpi_buf[kq] <= '9':
|
||||
eg_v = eg_v * 10 + (int(vpi_buf[kq]) - 48)
|
||||
kq += 1
|
||||
if eg_v > 0 and _g_vpi_esg_count < VPI_ESG_MAX:
|
||||
string.strcpy(_g_vpi_esg_keys + sizet(_g_vpi_esg_count) * VPI_ESG_KEY_LEN, key_buf_e)
|
||||
_g_vpi_esg_vals[_g_vpi_esg_count] = sizet(eg_v)
|
||||
_g_vpi_esg_count += 1
|
||||
j3 = kq
|
||||
else:
|
||||
j3 += 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
|
||||
if cur_cls is not None: stdlib.free(cur_cls)
|
||||
return 1
|
||||
|
||||
|
||||
# _lookup_vpi_escape_clears - 跨模块常量守卫查询:按调用点常量环境算出"该清掉的位";0 = 无命中
|
||||
def _lookup_vpi_escape_clears(src_sha1: str, cls_name: str, method_name: str, env: sizet*) -> int:
|
||||
"""env = 常量环境(2 槽/形参:[0]=是否已知、[1]=值,下标 = 形参位);返回该清掉的位掩码 OR 值"""
|
||||
if _g_vpi_esg_keys is None or _g_vpi_esg_count == 0: return 0
|
||||
if src_sha1 is None or method_name is None or env is None: return 0
|
||||
sha1_len: sizet = string.strlen(src_sha1)
|
||||
cl_len: sizet = 0
|
||||
if cls_name is not None: cl_len = string.strlen(cls_name)
|
||||
me_len: sizet = string.strlen(method_name)
|
||||
key_len: sizet = sha1_len + 1 + cl_len + 1 + me_len
|
||||
kb: bytes = stdlib.malloc(key_len + 1)
|
||||
if kb is None: return 0
|
||||
if cls_name is not None: viperlib.snprintf(kb, key_len + 1, "%s.%s.%s", src_sha1, cls_name, method_name)
|
||||
else: viperlib.snprintf(kb, key_len + 1, "%s.%s", src_sha1, method_name)
|
||||
cleared: int = 0
|
||||
idx: int = 0
|
||||
while idx < _g_vpi_esg_count:
|
||||
ent: bytes = _g_vpi_esg_keys + sizet(idx) * VPI_ESG_KEY_LEN
|
||||
# 键以模块 sha1 打头:先比前 2 个十六进制字符,避免逐项 strcmp
|
||||
if ent[0] == kb[0] and ent[1] == kb[1] and string.strcmp(ent, kb) == 0:
|
||||
v: int = int(_g_vpi_esg_vals[idx])
|
||||
if v > 0:
|
||||
p: int = v & 255
|
||||
kv: int = (v >> 8) & 255
|
||||
if kv >= 128: kv -= 256
|
||||
m: int = v >> 16
|
||||
if p >= 0 and p < VPI_ESG_ENV_PARAM_MAX and env[p * 2] != 0:
|
||||
if int64(env[p * 2 + 1]) == int64(kv): cleared = cleared | m
|
||||
idx += 1
|
||||
stdlib.free(kb)
|
||||
return cleared
|
||||
|
||||
|
||||
# _cache_vpi_annots_text - 所有"从 vpi 文本解析"的缓存**单一入口**。
|
||||
# 任何新增的文本缓存都加在这里,不要再散落到各加载点——漏喂一处就会**静默退化**
|
||||
# (现场:逃逸摘要只在 _ensure_vpi_ret_annot_loaded 里喂,而 stub 注入加载点没喂,
|
||||
@@ -892,6 +1019,7 @@ def _cache_vpi_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
_cache_vpi_param_annots_text(vpi_buf, src_sha1)
|
||||
_cache_vpi_escape_annots_text(vpi_buf, src_sha1)
|
||||
_cache_vpi_willfree_annots_text(vpi_buf, src_sha1)
|
||||
_cache_vpi_esc_clears_text(vpi_buf, src_sha1)
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user