From efb4a54428fe015dbf6ff7bc11e0c482c81b2f4e Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 9 Oct 2026 08:45:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(gen):=20P4=20=E8=87=AA=E5=88=AB=E5=90=8D?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E8=B5=8B=E5=80=BC=E4=B8=8D=E5=BE=97=E9=87=8A?= =?UTF-8?q?=E6=94=BE=E5=85=B1=E6=8C=81=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit q = p; q = p 这类自别名重复赋值在覆盖释放时会把两个槽共持的对象提前释放(q 与 p 同时悬垂)。新增 _SlifeDropOwnedUnlessSame:在 IR 里比较 target 与源槽的当前值,相同则跳过整个覆盖释放(含析构调度),不同才走常规保护式释放。P4 转移改用它。 --- App/lib/core/Gen/AssignGenMixin.vp | 5 ++-- App/lib/core/Gen/VarGenMixin.vp | 37 +++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 399bea4..02dc840 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -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) diff --git a/App/lib/core/Gen/VarGenMixin.vp b/App/lib/core/Gen/VarGenMixin.vp index 5cb9135..0594d96 100644 --- a/App/lib/core/Gen/VarGenMixin.vp +++ b/App/lib/core/Gen/VarGenMixin.vp @@ -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: