Constructing nested objects where an inner object is initialized as part of the constructing expression triggers arbitrary amounts of repeated, redundant memory-zeroing. This example is an extreme/pure case, where the outer objects have no independent content at all, but in general, mostly the same memory will be repeatedly cleared even if some inner object constitutes 90% of the size of the the outer object.
Example
type
A = object
z: array[10_000_000, byte]
y: int # something small to initialize explicitly
B = object
z: A
C = object
z: B
D = object
z: C
E = object
z: D
# Zeros same memory several times
let z1 = (ref E)(z: D(z: C(z: B(z: A(y: 5)))))
# Zeros memory once
var z2 = new E
z2.z.z.z.z.y = 5
# Also zeros memory once
var z3 = (ref E)()
z3.z.z.z.z.y = 5
Current Output
tyObject_E__x9cQwcHAZw5NeEKypTvuMLw* T1_;
tyObject_E__x9cQwcHAZw5NeEKypTvuMLw* T2_;
T1_ = (tyObject_E__x9cQwcHAZw5NeEKypTvuMLw*)0;
T1_ = (tyObject_E__x9cQwcHAZw5NeEKypTvuMLw*) newObj((&NTIrefe__jtbhptF1jvfTx87eu46XFw_), sizeof(tyObject_E__x9cQwcHAZw5NeEKypTvuMLw));
nimZeroMem((void*)(&(*T1_).z), sizeof(tyObject_D__XKzsw9c8SjgoEXgf9bAInK1g));
nimZeroMem((void*)(&(*T1_).z.z), sizeof(tyObject_C__hUYmG8WlZd4qt0bWPvafWA));
nimZeroMem((void*)(&(*T1_).z.z.z), sizeof(tyObject_B__pLdaEJKI6wxN9cdTSKBr2Vg));
nimZeroMem((void*)(&(*T1_).z.z.z.z), sizeof(tyObject_A__GdxVJCTbM4CxccrEd50Y9aA));
(*T1_).z.z.z.z.y = ((NI) 5);
asgnRef((void**) (&z1_foo_12), T1_);
asgnRef((void**) (&z2_foo_40), new_foo_13());
(*z2_foo_40).z.z.z.z.y = ((NI) 5);
T2_ = (tyObject_E__x9cQwcHAZw5NeEKypTvuMLw*)0;
T2_ = (tyObject_E__x9cQwcHAZw5NeEKypTvuMLw*) newObj((&NTIrefe__jtbhptF1jvfTx87eu46XFw_), sizeof(tyObject_E__x9cQwcHAZw5NeEKypTvuMLw));
asgnRef((void**) (&z3_foo_41), T2_);
(*z3_foo_41).z.z.z.z.y = ((NI) 5);
Expected Output
tyObject_E__x9cQwcHAZw5NeEKypTvuMLw* T1_;
tyObject_E__x9cQwcHAZw5NeEKypTvuMLw* T2_;
T1_ = (tyObject_E__x9cQwcHAZw5NeEKypTvuMLw*)0;
T1_ = (tyObject_E__x9cQwcHAZw5NeEKypTvuMLw*) newObj((&NTIrefe__jtbhptF1jvfTx87eu46XFw_), sizeof(tyObject_E__x9cQwcHAZw5NeEKypTvuMLw));
/* These are all redundant, since newObj already zeroMem()s */
/* nimZeroMem((void*)(&(*T1_).z), sizeof(tyObject_D__XKzsw9c8SjgoEXgf9bAInK1g));
nimZeroMem((void*)(&(*T1_).z.z), sizeof(tyObject_C__hUYmG8WlZd4qt0bWPvafWA));
nimZeroMem((void*)(&(*T1_).z.z.z), sizeof(tyObject_B__pLdaEJKI6wxN9cdTSKBr2Vg));
nimZeroMem((void*)(&(*T1_).z.z.z.z), sizeof(tyObject_A__GdxVJCTbM4CxccrEd50Y9aA)); */
(*T1_).z.z.z.z.y = ((NI) 5);
asgnRef((void**) (&z1_foo_12), T1_);
asgnRef((void**) (&z2_foo_40), new_foo_13());
(*z2_foo_40).z.z.z.z.y = ((NI) 5);
T2_ = (tyObject_E__x9cQwcHAZw5NeEKypTvuMLw*)0;
T2_ = (tyObject_E__x9cQwcHAZw5NeEKypTvuMLw*) newObj((&NTIrefe__jtbhptF1jvfTx87eu46XFw_), sizeof(tyObject_E__x9cQwcHAZw5NeEKypTvuMLw));
asgnRef((void**) (&z3_foo_41), T2_);
(*z3_foo_41).z.z.z.z.y = ((NI) 5);
Tested with essentially the same behavior in
Nim Compiler Version 1.2.12 [Linux: amd64]
Compiled at 2021-06-11
Copyright (c) 2006-2020 by Andreas Rumpf
git hash: 121628357ec7fae91335bd392f03b0e6dd249319
active boot switches: -d:release
Nim Compiler Version 1.4.2 [Linux: amd64]
Compiled at 2021-05-13
Copyright (c) 2006-2020 by Andreas Rumpf
active boot switches: -d:release
and current git head:
Nim Compiler Version 1.5.1 [Linux: amd64]
Compiled at 2021-06-11
Copyright (c) 2006-2021 by Andreas Rumpf
git hash: c64d9176190b3b691391f1645873dd4ca5b09933
active boot switches: -d:release
Constructing nested objects where an inner object is initialized as part of the constructing expression triggers arbitrary amounts of repeated, redundant memory-zeroing. This example is an extreme/pure case, where the outer objects have no independent content at all, but in general, mostly the same memory will be repeatedly cleared even if some inner object constitutes 90% of the size of the the outer object.
Example
Current Output
Expected Output
Tested with essentially the same behavior in
and current git head: