fix(gen): P4 自别名重复赋值不得释放共持对象
q = p; q = p 这类自别名重复赋值在覆盖释放时会把两个槽共持的对象提前释放(q 与 p 同时悬垂)。新增 _SlifeDropOwnedUnlessSame:在 IR 里比较 target 与源槽的当前值,相同则跳过整个覆盖释放(含析构调度),不同才走常规保护式释放。P4 转移改用它。
This commit is contained in:
1 parent
3209a7a633
commit
efb4a54428
2 files changed
+39
-3
No files matched your search
@@ -768,8 +768,9 @@ novirtual class AssignGenMixin:
|
||||
if self.Gen.VarGen._SlifeOwned(src_slot) != 0:
|
||||
tsh: mlirlite.Value* = self.Gen.VarGen._SlifeEnsureOwned(pool, builder, target_slot)
|
||||
if tsh is not None:
|
||||
# 先把 q 原有对象按覆盖释放处理,再转移影子(顺序与插入顺序一致)
|
||||
self._SlifeDropOwned(pool, builder, mod, trans, target_slot)
|
||||
# 覆盖释放 target 原有对象:若它与源是**同一个对象**(自别名 `q = p; q = p`)
|
||||
# 则跳过,否则会把两个槽共持的对象提前释放。
|
||||
self.Gen.VarGen._SlifeDropOwnedUnlessSame(pool, builder, mod, trans, target_slot, src_slot)
|
||||
self.Gen.VarGen._SlifeNoteStore(pool, builder, tsh, 1)
|
||||
ssh: mlirlite.Value* = self.Gen.VarGen._SlifeShadow(src_slot)
|
||||
if ssh is not None: self.Gen.VarGen._SlifeNoteStore(pool, builder, ssh, 0)
|
||||
|
||||
@@ -588,7 +588,42 @@ novirtual class VarGenMixin:
|
||||
if r is None: return 0
|
||||
return 1
|
||||
|
||||
def _SlifeSlotFirstSeen(self, idx: int, slot: uint64) -> int:
|
||||
def _SlifeDropOwnedUnlessSame(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, trans: HT.Translator*, target_slot: mlirlite.Value*, src_slot: mlirlite.Value*) -> int:
|
||||
"""P4:覆盖释放 target 的当前对象;若它与 src 的当前值相同(自别名 `q = p; q = p`)则整体跳过。
|
||||
|
||||
没有这个运行时判等,重复自别名赋值会把两个槽共同持有的对象释放掉(q 与 p 同时悬垂);
|
||||
判等放在 IR 里做(编译期无法知道两个槽是否指向同一对象)。"""
|
||||
if target_slot is None or src_slot is None or trans is None: return 0
|
||||
sh: mlirlite.Value* = self._SlifeShadow(target_slot)
|
||||
if sh is None or target_slot.Ty is None: return 0
|
||||
el_ty: mlirlite.LLVMType* = target_slot.Ty.Pointee
|
||||
qv: mlirlite.Value* = mlirlite.build_load(builder, el_ty, target_slot)
|
||||
pv: mlirlite.Value* = mlirlite.build_load(builder, el_ty, src_slot)
|
||||
if qv is None or pv is None: return 0
|
||||
same: mlirlite.Value* = mlirlite.build_icmp(builder, mlirlite.ICMP_EQ, qv, pv)
|
||||
if same is None: return 0
|
||||
cur_func: mlirlite.Function* = trans._cur_func
|
||||
if cur_func is None: return 0
|
||||
cnt: int = trans._label_counter
|
||||
trans._label_counter = cnt + 1
|
||||
nm_free: str = pool.alloc(32)
|
||||
if nm_free is None: return 0
|
||||
viperlib.snprintf(nm_free, 32, "slife.xfer.free.%d", cnt)
|
||||
nm_end: str = pool.alloc(32)
|
||||
if nm_end is None: return 0
|
||||
viperlib.snprintf(nm_end, 32, "slife.xfer.end.%d", cnt)
|
||||
free_bb = mlirlite.create_block(pool, cur_func, nm_free)
|
||||
end_bb = mlirlite.create_block(pool, cur_func, nm_end)
|
||||
if free_bb is None or end_bb is None: return 0
|
||||
# 相同 → 直接到 end(不释放);不同 → 走常规"保护式释放"(含 §3.6 析构调度)
|
||||
mlirlite.build_cond_br(builder, same, end_bb, free_bb)
|
||||
mlirlite.position_at_end(builder, free_bb)
|
||||
self._SlifeEmitGuardedFree(pool, builder, mod, trans, target_slot, sh)
|
||||
mlirlite.build_br(builder, end_bb)
|
||||
mlirlite.position_at_end(builder, end_bb)
|
||||
return 0
|
||||
|
||||
def _SlifeSlotFirstSeen(self, idx: int, slot: uint64) -> int:
|
||||
"""槽 slot 在 (idx, _g_slife_top) 里是否已经出现过;1=本次首次出现(该释放)/ 0=重复(跳过)"""
|
||||
j: int = idx + 1
|
||||
while j < _g_slife_top:
|
||||
|
||||
Reference in new issue
Block a user