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: