feat(lifetime): 声明式指令契约落 .vpi(esce=/escn=),跨模块调用点也能最终裁决
写侧 Converter:读 compute_escape_summary 落在 box[3]/box[4] 的契约掩码,随函数头行尾写 esce=<强制逃逸位> / escn=<强制不逃逸位>; 只有指令(既无 esc/ret 也无 wf)时也补一个 "# esc=0 ret=0" 注释段——读侧是"见 # 才解析"。 读侧 VpiReader:_cache_vpi_esc_clears_text 同一次行扫描里顺带收 esce=/escn= 进 _g_vpi_esd_*(与 escg 同键 sha1[.Cls].func); 新增 _lookup_vpi_escape_dir(.., noescape);CallGenBase.lookup_escape_dir_via_vpi 包装。 调用点:模块级函数 / 方法 / 构造器三条路径在本文件指令表为空(= 跨模块)时改查对方 .vpi, 仍放在所有推断/回退之后最后套用:esc_mask = (esc_mask | esce) & ~escn。
This commit is contained in:
1 parent
2bd37e80e3
commit
79299ec47d
5 files changed
+116
-7
No files matched your search
@@ -806,6 +806,14 @@ novirtual class CallGenBase:
|
||||
VpiReader._vpi_escape_mark_module(sha1)
|
||||
return VpiReader._lookup_vpi_escape_packed(sha1, cls_name, method_name)
|
||||
|
||||
# lookup_escape_dir_via_vpi - 跨模块声明式指令契约(@life(escape(...)) / @life(noescape(...)))。
|
||||
# 本文件指令表按文件重置,跨模块调用点必为空,只能靠 .vpi 行尾的 esce=/escn= 传递;
|
||||
# noescape != 0 取"强制不逃逸位",否则取"强制逃逸位"。0 = 无该标注(含该模块未加载过)。
|
||||
def lookup_escape_dir_via_vpi(self, cls_sha1: str, class_name: str, func_name: str, noescape: int) -> int:
|
||||
"""对方模块 .vpi 里落的契约掩码;0 = 无该标注"""
|
||||
if func_name is None or cls_sha1 is None: return 0
|
||||
return VpiReader._lookup_vpi_escape_dir(cls_sha1, class_name, func_name, noescape)
|
||||
|
||||
def lookup_escape_via_vpi(self, pool: memhub.MemBuddy*, cls_sha1: str, cls_name: str, method_name: str) -> int:
|
||||
"""跨模块逃逸摘要(v3):本类 + MRO 祖先各自的模块 sha1 依次查 .vpi,返回打包值(0=无摘要)。
|
||||
|
||||
|
||||
@@ -152,14 +152,19 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# `__new__` 不查:其形参与 __init__ 共享且可能被裁剪,位置对应不可靠。
|
||||
if arg_nodes is not None and string.strcmp(method_name, "__init__") == 0:
|
||||
esc_mask_ci: int = GenApi.get_param_escapes_method(pool, class_name, method_name)
|
||||
sha_ci: str = None
|
||||
if esc_mask_ci == 0:
|
||||
# 跨模块回退(v3):构造器常定义在别的模块(self.f = p 写在那边)
|
||||
sha_ci: str = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
sha_ci = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
pk_ci: int = self.Gen.CallGenBase.lookup_escape_via_vpi(pool, sha_ci, class_name, method_name)
|
||||
if pk_ci != 0: esc_mask_ci = int(pk_ci & 4294967295)
|
||||
# 声明式指令最终裁决(@life(escape/noescape):unsafe 但强制),在推断/回退之后最后套用
|
||||
f_ci: int = GenApi.get_param_escape_force_method(pool, class_name, method_name)
|
||||
n_ci: int = GenApi.get_param_noescape_force_method(pool, class_name, method_name)
|
||||
if f_ci == 0 and n_ci == 0 and sha_ci is not None:
|
||||
# 跨模块:本文件指令表为空,改查对方模块 .vpi 的 esce=/escn=
|
||||
f_ci = self.Gen.CallGenBase.lookup_escape_dir_via_vpi(sha_ci, class_name, method_name, 0)
|
||||
n_ci = self.Gen.CallGenBase.lookup_escape_dir_via_vpi(sha_ci, class_name, method_name, 1)
|
||||
if f_ci != 0 or n_ci != 0: esc_mask_ci = (esc_mask_ci | f_ci) & (~n_ci)
|
||||
if esc_mask_ci != 0:
|
||||
dummy_ptr_ci: mlirlite.LLVMType* = mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
@@ -556,9 +561,10 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
cargs_mc: list[ast.AST*]* = cl.args
|
||||
if cargs_mc is not None:
|
||||
esc_mask_mc: int = GenApi.get_param_escapes_method(pool, class_name, method_name)
|
||||
sha_mc: str = None
|
||||
if esc_mask_mc == 0:
|
||||
# 跨模块回退(v3):本文件摘要表按文件重置,跨模块只能查 .vpi 落盘的摘要
|
||||
sha_mc: str = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
sha_mc = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
pk_mc: int = self.Gen.CallGenBase.lookup_escape_via_vpi(pool, sha_mc, class_name, method_name)
|
||||
if pk_mc != 0: esc_mask_mc = int(pk_mc & 4294967295)
|
||||
# 跨模块常量特化:用实参常量套用对方模块 .vpi 落盘的守卫记录(形参位含 self 偏移)
|
||||
@@ -572,6 +578,10 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# 声明式指令最终裁决(@life(escape/noescape):unsafe 但强制),在推断/回退之后最后套用
|
||||
f_mc: int = GenApi.get_param_escape_force_method(pool, class_name, method_name)
|
||||
n_mc: int = GenApi.get_param_noescape_force_method(pool, class_name, method_name)
|
||||
if f_mc == 0 and n_mc == 0 and sha_mc is not None:
|
||||
# 跨模块:本文件指令表为空,改查对方模块 .vpi 的 esce=/escn=
|
||||
f_mc = self.Gen.CallGenBase.lookup_escape_dir_via_vpi(sha_mc, class_name, method_name, 0)
|
||||
n_mc = self.Gen.CallGenBase.lookup_escape_dir_via_vpi(sha_mc, class_name, method_name, 1)
|
||||
if f_mc != 0 or n_mc != 0: esc_mask_mc = (esc_mask_mc | f_mc) & (~n_mc)
|
||||
if esc_mask_mc != 0:
|
||||
dummy_ptr_mc: mlirlite.LLVMType* = mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
|
||||
@@ -152,11 +152,10 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# loc_mask:1=掩码来自**本文件**摘要表(只有这时才有"硬逃逸位"记录可用);
|
||||
# 走下面的跨模块回退时置 0 —— 跨模块的掩码是合并值,不能再按"字段位"裁剪(会变成漏报)。
|
||||
loc_mask: int = 1
|
||||
# 跨模块回退解析出的被调者模块 sha1(最终裁决要用它去查对方 .vpi 的指令契约)
|
||||
mod_sha_ec: str = None
|
||||
if esc_mask == 0:
|
||||
loc_mask = 0
|
||||
# 跨模块回退(v3):本文件摘要表按文件重置,跨模块的被调者只能靠 .vpi 传递。
|
||||
# 解析被调者所属模块 sha1:带模块前缀(mod.f)用限定名,否则用 from-import 别名。
|
||||
mod_sha_ec: str = None
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
at_ec: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
mod_p_ec: str = None
|
||||
@@ -197,6 +196,10 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# escape(...) 无条件置位、noescape(...) 无条件清位。
|
||||
fe_m: int = GenApi.get_param_escape_force(func_name)
|
||||
ne_m: int = GenApi.get_param_noescape_force(func_name)
|
||||
if fe_m == 0 and ne_m == 0 and mod_sha_ec is not None:
|
||||
# 跨模块:本文件指令表为空(按文件重置),改查对方模块 .vpi 的行尾 esce=/escn=
|
||||
fe_m = self.Gen.CallGenBase.lookup_escape_dir_via_vpi(mod_sha_ec, None, func_name, 0)
|
||||
ne_m = self.Gen.CallGenBase.lookup_escape_dir_via_vpi(mod_sha_ec, None, func_name, 1)
|
||||
if fe_m != 0 or ne_m != 0:
|
||||
esc_mask = (esc_mask | fe_m) & (~ne_m)
|
||||
if esc_mask != 0:
|
||||
|
||||
Reference in new issue
Block a user