From 4497d892673f4f469144e58c764a2bd29e8fc7ff Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 8 Jun 2026 14:54:15 +0800 Subject: [PATCH] fixes #18238; Nested object construction can zero same memory multiple times for `--mm:refc` (#25834) fixes #18238 This pull request makes a targeted change to the object construction logic in the `genObjConstr` procedure. The main update refines the conditions under which memory zeroing is required during object construction, making the behavior more accurate for different garbage collection and destructor options. Key logic update: - Improved the `needsZeroMem` condition in `genObjConstr` to check for the presence of garbage-collected references and the `optSeqDestructors` option, instead of relying solely on the selected garbage collector and field flags. This ensures memory is zeroed only when necessary, potentially improving performance and correctness. ```c T1_ = NIM_NIL; T1_ = ((tyObject_E__uEKympBdEK4SY9anUbpNaLQ*) newObj((&NTIrefe__bJ9cSuxv8xHYxmdolQqFkUw_), sizeof(tyObject_E__uEKympBdEK4SY9anUbpNaLQ))); nimZeroMem(((void*) ((&(*T1_).z.z.z.z))), sizeof(tyObject_A__G2lWlL9cFqoiWWwZmWqfJ9bA)); (*T1_).z.z.z.z.y = ((NI) 5); asgnRef(((void**) ((&z1__test8_u12))), T1_); asgnRef(((void**) ((&z2__test8_u55))), new__test8_u13()); (*z2__test8_u55).z.z.z.z.y = ((NI) 5); T2_ = NIM_NIL; T2_ = ((tyObject_E__uEKympBdEK4SY9anUbpNaLQ*) newObj((&NTIrefe__bJ9cSuxv8xHYxmdolQqFkUw_), sizeof(tyObject_E__uEKympBdEK4SY9anUbpNaLQ))); asgnRef(((void**) ((&z3__test8_u56))), T2_); (*z3__test8_u56).z.z.z.z.y = ((NI) 5); ``` The original test case has already been fixed for `ORC`, now extends it to `refc`: if a constructor is fully initialized, it does not need a zero-fill step --- compiler/ccgexprs.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 62302146f1..c6e6057223 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1904,7 +1904,9 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = var tmp: TLoc = default(TLoc) var r: Rope - let needsZeroMem = p.config.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcYrc} or nfAllFieldsSet notin e.flags + let needsZeroMem = + nfAllFieldsSet notin e.flags or + (optSeqDestructors notin p.config.globalOptions and containsGarbageCollectedRef(t)) if useTemp: tmp = getTemp(p, t) r = rdLoc(tmp)