fix(lifetime): 方法路径补上"同命裁剪"(此前缺失)—— h.set_q(l) 不该报

现场:h: S* = new heap slife S()(生命期本就是 FRAME:作用域出口释放)+ l 是栈数组;
h.set_q(l) 却报"escaping method parameter"。根因:同命裁剪只做在模块级函数路径,方法路径一直没接
(此前已明确告知"还差一半")。

新增 CallGenMixin._FrameArgsEscapeClearsMethod:位 0 = 接收者(self)、位 (i+1) = 用户第 i 个实参;
某位可清 ⇔ 该位对应实参是 FRAME/VALUE 且其余全部实参(含接收者)也在本帧。
CallGenCall 方法路径在 refine 之后、指令最终裁决之前套用;硬位仍用 get_param_escapes_hard_method 排除。
构造器路径暂未接(__init__ 的 self 是"正在构造的对象",此处拿不到接收者 AST 变量)。
This commit is contained in:
TermiNexus committed 2026-10-09 22:30:35 +08:00
1 parent 6000734704
commit bf5ecd7668
2 files changed
+45 -1

No files matched your search

+14 -1
View File
@@ -574,7 +574,20 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
# 跨过程常量特化(P3 收尾):同文件能拿到方法体时,用常量实参重算摘要(形参位含 self 偏移)
if esc_mask_mc != 0:
can_rf: sizet = len(cargs_mc)
esc_mask_mc = GenApi.refine_escape_mask_method(pool, class_name, method_name, cargs_mc, can_rf, esc_mask_mc)
esc_mask_mc = GenApi.refine_escape_mask_method(pool, class_name, method_name, cargs_mc, can_rf, esc_mask_mc)
# 同命裁剪(**方法路径,此前缺失**):只清"写进形参对象字段"那一类位 —— 若其余实参(含
# 接收者)也都在本帧,则接收者与本帧同命、并不真的逃逸。现场:`h.set_q(l)`,h 是
# `new heap slife S()`(生命期本就是 FRAME)、l 是栈数组 → 两都在本帧 → 不该报。
if esc_mask_mc != 0:
hard_mc: int = GenApi.get_param_escapes_hard_method(pool, class_name, method_name)
fld_mc: int = esc_mask_mc & (~hard_mc)
if fld_mc != 0:
recv_mc: ast.AST* = None
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
recv_mc = ast.Attribute*(cl.func).value
can_sf: sizet = len(cargs_mc)
cl_sfm: int = self.Gen.CallGen._FrameArgsEscapeClearsMethod(trans, recv_mc, cargs_mc, can_sf, fld_mc)
if cl_sfm != 0: esc_mask_mc = esc_mask_mc & (~cl_sfm)
# 声明式指令最终裁决(@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)
+31
View File
@@ -60,6 +60,37 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
return 0
# _FrameArgsEscapeClearsMethod - 方法调用版"同命"裁剪(与函数版同口径,但位有 self 偏移)
# 位 0 = 接收者(self),位 (i+1) = 用户第 i 个实参。
# 某位可清 ⇔ 该位对应的实参是帧生命期(FRAME/VALUE),且**其余全部实参(含接收者)也在本帧**。
# 现场:`h.set_q(l)` 里 h = `new heap slife S()`(生命期本就是 FRAME:作用域出口释放)、
# l 是栈数组 → 两都在本帧 → 不该报。
def _FrameArgsEscapeClearsMethod(self, trans: HT.Translator*, recv_node: ast.AST*, cargs: list[ast.AST*]*, can: sizet, only_fld: int) -> int:
"""返回方法调用中可安全清掉的位掩码(0 = 一位都清不掉)"""
if trans is None or only_fld == 0: return 0
cleared: int = 0
bi: int = 1
while bi <= int(can):
if ((only_fld >> bi) & 1) == 0:
bi += 1
continue
all_frame: int = 1
if recv_node is not None:
lr: int = self.Gen.AssignGen.life_of_expr(trans, recv_node, None)
if lr != GenTypes.LIFE_FRAME and lr != GenTypes.LIFE_VALUE: all_frame = 0
j: sizet = 0
while j < can:
if all_frame == 0: break
if int(j) != bi - 1:
a_j: ast.AST* = cargs.get(j)
if a_j is not None:
lj: int = self.Gen.AssignGen.life_of_expr(trans, a_j, None)
if lj != GenTypes.LIFE_FRAME and lj != GenTypes.LIFE_VALUE: all_frame = 0
j += 1
if all_frame != 0: cleared = cleared | (1 << bi)
bi += 1
return cleared
# _FrameArgsEscapeClears - "同命"精化(P3 同命规则在**调用点**的对应物):
# 候选位 only_fld 只由"写进某个**形参对象**的字段"造成;若调用点交出的其它实参也都在本帧
# (LIFE_FRAME)或纯值语义(LIFE_VALUE),则对象与本帧同命、并不真的逃逸 → 可清。