feat(gen): 落地 @life(ret(...)) 返回值生命期契约(A2)
- GenApi:新增 compute_life_anno / _RetKindFromTag 与 RET_KIND_* 编码, 提供 get_ret_kind / get_ret_kind_method / lookup_ret_kind_via_vpi; _WillFreeMergeTag 不再拦截 ret(改由 compute_life_anno 收集校验)。 - StructGenMixin:EscDirTable 由 3 槽扩到 4 槽(新增 ret_kind 列), compute_escape_summary 把契约落在 box[5] 并登记。 - Stub:.vpi 行尾新增 escr=<ret_kind>(Converter 写、VpiReader 读 _g_vpi_esd_r)。 - AssignGenMixin.life_of_expr(Call):@life(ret(...)) 声明优先于任何推断; frame/heap/static/borrows=none 直接映射,borrows=x 取对应实参生命期, 方法调用按接收者静态类型解析类名。 - StmtGenCifMixin:同批移除定义端 return <本帧地址> 的 fail-fast, 返回值去向改由调用点按被调者契约判定。
This commit is contained in:
1 parent
4907e64714
commit
6da8e2e095
7 files changed
+347
-56
No files matched your search
@@ -524,6 +524,7 @@ def _PyiFunction(buf: bytes, buf_size: sizet, pos: sizet, fn: ast.FunctionDef*,
|
||||
ret_v_c: int = 0
|
||||
ef_v_c: int = 0
|
||||
ne_v_c: int = 0
|
||||
rk_v_c: int = 0
|
||||
if _PyiEnsureEscScratch() != 0:
|
||||
esc_box_c: sizet* = sizet*(uint64(_g_pyi_esc_scratch) + 520)
|
||||
if GenApi.compute_escape_summary(None, fn, _g_pyi_esc_scratch, esc_box_c) == 0:
|
||||
@@ -533,6 +534,8 @@ def _PyiFunction(buf: bytes, buf_size: sizet, pos: sizet, fn: ast.FunctionDef*,
|
||||
# 契约掩码落在 box[3]/box[4],随同行走 esce=/escn= 落盘,跨模块调用点才能最后套用。
|
||||
ef_v_c = int(esc_box_c[3])
|
||||
ne_v_c = int(esc_box_c[4])
|
||||
# A2(§14)`@life(ret(...))`:返回值生命期契约落 box[5],随同行走 escr= 落盘。
|
||||
rk_v_c = int(esc_box_c[5])
|
||||
# 跨模块常量特化:算"哪些常量绑定能清掉哪些逃逸位"(每条 = 打包的 p|k|m),随同行走 escg= 落盘。
|
||||
# 只在真有逃逸位时才有意义;算出来 0 条就不写(保持 vpi 干净)。
|
||||
clears_c: sizet* = None
|
||||
@@ -541,7 +544,7 @@ def _PyiFunction(buf: bytes, buf_size: sizet, pos: sizet, fn: ast.FunctionDef*,
|
||||
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 or ef_v_c != 0 or ne_v_c != 0:
|
||||
if esc_v_c != 0 or ret_v_c != 0 or wf_mask_c != 0 or n_clears_c > 0 or ef_v_c != 0 or ne_v_c != 0 or rk_v_c != 0:
|
||||
tmp_c: bytes = stdlib.malloc(96)
|
||||
if tmp_c is not None:
|
||||
if esc_v_c != 0 or ret_v_c != 0:
|
||||
@@ -568,6 +571,10 @@ def _PyiFunction(buf: bytes, buf_size: sizet, pos: sizet, fn: ast.FunctionDef*,
|
||||
if ne_v_c != 0:
|
||||
viperlib.snprintf(tmp_c, 96, " escn=%d", ne_v_c)
|
||||
pos = _PyiEmit(buf, buf_size, pos, tmp_c)
|
||||
# A2(§14):`@life(ret(...))` 的返回值生命期契约 → escr=(编码见 GenApi.RET_KIND_*)。
|
||||
if rk_v_c != 0:
|
||||
viperlib.snprintf(tmp_c, 96, " escr=%d", rk_v_c)
|
||||
pos = _PyiEmit(buf, buf_size, pos, tmp_c)
|
||||
stdlib.free(tmp_c)
|
||||
if clears_c is not None: stdlib.free(clears_c)
|
||||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||||
|
||||
@@ -133,11 +133,13 @@ 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
|
||||
# 声明式指令契约(`@life(escape(...))` / `@life(noescape(...))`):与 escg 表同键(sha1[.Cls].func),
|
||||
# 但每函数只一条(契约唯一);两列分别存"强制逃逸位"与"强制不逃逸位"。
|
||||
# 声明式指令契约(`@life(escape(...))` / `@life(noescape(...))` / `@life(ret(...))`):与 escg 表同键
|
||||
# (sha1[.Cls].func),但每函数只一条(契约唯一);三列分别存"强制逃逸位"、"强制不逃逸位"与
|
||||
# ret_kind(A2,编码见 GenApi.RET_KIND_*)。
|
||||
_g_vpi_esd_keys: bytes = None
|
||||
_g_vpi_esd_e: sizet* = None
|
||||
_g_vpi_esd_n: sizet* = None
|
||||
_g_vpi_esd_r: sizet* = None
|
||||
_g_vpi_esd_count: int = 0
|
||||
|
||||
_g_vpi_esc_keys: bytes = None
|
||||
@@ -901,7 +903,7 @@ def _ensure_vpi_ret_annot_loaded(src_sha1: str, temp_dir: str) -> int:
|
||||
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
|
||||
global _g_vpi_esd_keys, _g_vpi_esd_e, _g_vpi_esd_n, _g_vpi_esd_count
|
||||
global _g_vpi_esd_keys, _g_vpi_esd_e, _g_vpi_esd_n, _g_vpi_esd_r, _g_vpi_esd_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)
|
||||
@@ -913,10 +915,12 @@ def _cache_vpi_esc_clears_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
_g_vpi_esd_keys = stdlib.malloc(VPI_ESG_MAX * VPI_ESG_KEY_LEN)
|
||||
_g_vpi_esd_e = sizet*(stdlib.malloc(VPI_ESG_MAX * 8))
|
||||
_g_vpi_esd_n = sizet*(stdlib.malloc(VPI_ESG_MAX * 8))
|
||||
if _g_vpi_esd_keys is None or _g_vpi_esd_e is None or _g_vpi_esd_n is None: return 0
|
||||
_g_vpi_esd_r = sizet*(stdlib.malloc(VPI_ESG_MAX * 8))
|
||||
if _g_vpi_esd_keys is None or _g_vpi_esd_e is None or _g_vpi_esd_n is None or _g_vpi_esd_r is None: return 0
|
||||
string.memset(_g_vpi_esd_keys, 0, VPI_ESG_MAX * VPI_ESG_KEY_LEN)
|
||||
string.memset(_g_vpi_esd_e, 0, VPI_ESG_MAX * 8)
|
||||
string.memset(_g_vpi_esd_n, 0, VPI_ESG_MAX * 8)
|
||||
string.memset(_g_vpi_esd_r, 0, VPI_ESG_MAX * 8)
|
||||
sha1_len: sizet = string.strlen(src_sha1)
|
||||
buf_len: sizet = string.strlen(vpi_buf)
|
||||
cur_cls: bytes = None
|
||||
@@ -982,9 +986,10 @@ def _cache_vpi_esc_clears_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
j3 = kq
|
||||
else:
|
||||
j3 += 1
|
||||
# 声明式指令契约(esce= / escn=):每函数一条,只认 '#' 注释段
|
||||
# 声明式指令契约(esce= / escn= / escr=):每函数一条,只认 '#' 注释段
|
||||
de_v: int = 0
|
||||
dn_v: int = 0
|
||||
dr_v: int = 0
|
||||
j4: sizet = hm + 1
|
||||
while j4 + 5 <= le:
|
||||
if vpi_buf[j4] == 'e' and vpi_buf[j4 + 1] == 's' and vpi_buf[j4 + 2] == 'c' and vpi_buf[j4 + 3] == 'e' and vpi_buf[j4 + 4] == '=':
|
||||
@@ -1003,12 +1008,21 @@ def _cache_vpi_esc_clears_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
kq3 += 1
|
||||
if v3 > 0: dn_v = v3
|
||||
j4 = kq3
|
||||
elif vpi_buf[j4] == 'e' and vpi_buf[j4 + 1] == 's' and vpi_buf[j4 + 2] == 'c' and vpi_buf[j4 + 3] == 'r' and vpi_buf[j4 + 4] == '=':
|
||||
kq5: sizet = j4 + 5
|
||||
v5: int = 0
|
||||
while kq5 < le and vpi_buf[kq5] >= '0' and vpi_buf[kq5] <= '9':
|
||||
v5 = v5 * 10 + (int(vpi_buf[kq5]) - 48)
|
||||
kq5 += 1
|
||||
if v5 > 0: dr_v = v5
|
||||
j4 = kq5
|
||||
else:
|
||||
j4 += 1
|
||||
if (de_v != 0 or dn_v != 0) and _g_vpi_esd_count < VPI_ESG_MAX:
|
||||
if (de_v != 0 or dn_v != 0 or dr_v != 0) and _g_vpi_esd_count < VPI_ESG_MAX:
|
||||
string.strcpy(_g_vpi_esd_keys + sizet(_g_vpi_esd_count) * VPI_ESG_KEY_LEN, key_buf_e)
|
||||
_g_vpi_esd_e[_g_vpi_esd_count] = sizet(de_v)
|
||||
_g_vpi_esd_n[_g_vpi_esd_count] = sizet(dn_v)
|
||||
_g_vpi_esd_r[_g_vpi_esd_count] = sizet(dr_v)
|
||||
_g_vpi_esd_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)
|
||||
@@ -1050,9 +1064,10 @@ def _lookup_vpi_escape_clears(src_sha1: str, cls_name: str, method_name: str, en
|
||||
return cleared
|
||||
|
||||
|
||||
# _lookup_vpi_escape_dir - 跨模块声明式指令契约查询(`@life(escape(...))` / `@life(noescape(...))`)。
|
||||
# noescape != 0 取"强制不逃逸位",否则取"强制逃逸位";0 = 无该标注(含该模块未加载过)。
|
||||
def _lookup_vpi_escape_dir(src_sha1: str, cls_name: str, method_name: str, noescape: int) -> int:
|
||||
# _lookup_vpi_escape_dir - 跨模块声明式指令契约查询(`@life(escape(...))` / `@life(noescape(...))` /
|
||||
# `@life(ret(...))`)。which: 0=强制逃逸位 / 1=强制不逃逸位 / 2=ret_kind(A2)。
|
||||
# 0 = 无该标注(含该模块未加载过)。
|
||||
def _lookup_vpi_escape_dir(src_sha1: str, cls_name: str, method_name: str, which: int) -> int:
|
||||
if _g_vpi_esd_keys is None or _g_vpi_esd_count == 0: return 0
|
||||
if src_sha1 is None or method_name is None: return 0
|
||||
sha1_len: sizet = string.strlen(src_sha1)
|
||||
@@ -1070,7 +1085,8 @@ def _lookup_vpi_escape_dir(src_sha1: str, cls_name: str, method_name: str, noesc
|
||||
ent: bytes = _g_vpi_esd_keys + sizet(i) * VPI_ESG_KEY_LEN
|
||||
# 键以模块 sha1 打头:先比前 2 个十六进制字符,避免逐项 strcmp
|
||||
if ent[0] == kb[0] and ent[1] == kb[1] and string.strcmp(ent, kb) == 0:
|
||||
if noescape != 0: r = int(_g_vpi_esd_n[i])
|
||||
if which == 2: r = int(_g_vpi_esd_r[i])
|
||||
elif which != 0: r = int(_g_vpi_esd_n[i])
|
||||
else: r = int(_g_vpi_esd_e[i])
|
||||
break
|
||||
i += 1
|
||||
|
||||
Reference in new issue
Block a user