Skip to content

Nested object construction can zero same memory multiple times #18238

@tersec

Description

@tersec

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

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions