D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 11331 - Inefficient initialization of struct with members = void
Summary: Inefficient initialization of struct with members = void
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P4 enhancement
Assignee: No Owner
URL:
Keywords: performance, spec
: 11817 15951 (view as issue list)
Depends on:
Blocks:
 
Reported: 2013-10-23 08:54 UTC by Andrei Alexandrescu
Modified: 2024-12-13 18:13 UTC (History)
7 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Andrei Alexandrescu 2013-10-23 08:54:25 UTC
Consider the following stack region:

struct InSituRegion2(size_t size)
{
    // The store will be aligned to realof.align
    union
    {
        private ubyte[size] _store = void;
        real _forAlignmentOnly;
    }
    void* _crt, _end;

    void[] allocate(size_t bytes)
    {
      	assert(_crt && _end);
        // round up
        const rounded = (bytes + real.alignof - 1) / real.alignof;
        auto newCrt = _crt + rounded;
        if (newCrt > _end) return null;
        auto result = _crt[0 .. bytes];
        _crt = newCrt;
        return result;
    }
}

size_t fun2(size_t s)
{
    InSituRegion2!(1024 * 64) r;
  	r._crt = r._store.ptr;
  	r._end = r._store.ptr + r._store.length;
    auto a = cast(uint[]) r.allocate(s);
    return a[s / 2];
}

(The code of fun2 has been written to be complex enough to avoid a few elisions effected by optimizers.)

Disassembly reveals that constructing the struct object entails a memcpy of the object's init over the object memory, even though most of the object is deliberately left uninitialized. This undoes the performance gains of defining and using an encapsulated stack region.

The initialization function should either use multiple memcpy calls or individual word assignments.
Comment 1 Dicebot 2013-10-23 09:26:14 UTC
Erm, isn't it by spec? `void` initializer is targeted for variables, not member fields. Here it just says that relevant `T.init` part can be garbage.

Fixing this issue would imply that there are no more guaranteed deterministic T.init values for all types.
Comment 2 Andrei Alexandrescu 2013-10-23 09:53:31 UTC
@Dicebot: yah, it's an enhancement. One of the spec as well :o). The .init value can still exist, but the initialization doesn't need to use it.
Comment 3 Dicebot 2013-10-23 09:55:29 UTC
(In reply to comment #2)
> @Dicebot: yah, it's an enhancement. One of the spec as well :o). The .init
> value can still exist, but the initialization doesn't need to use it.

Well, this sounds like quite an important change - I'd prefer this issue description to tell more about possible implications of that spec change than about generated assembly :)
Comment 4 Andrei Alexandrescu 2013-10-23 10:07:14 UTC
http://dlang.org/struct.html mentions that "Struct instances that are not instantiated with a constructor are default initialized to their .init value." and mentions that S() is "same as auto b = S.init;"

There is no guarantee about the values of the = void members in S.init, but definitely the spec clarifies that two default-constructed objects will compare equal. So we need to change the spec to only guarantee non-=void fields of default-constructed objects to be equal.
Comment 5 Jack 2016-09-11 21:18:42 UTC
Is anything being worked on to change this?
Comment 6 Martin Nowak 2016-10-10 20:54:00 UTC
It's almost somewhat of a language fix, b/c they are silently ignored, everybody expects them to work (seen that discussion/mistake several times already, recent occurence https://forum.dlang.org/post/ntfrgh$1l2n$1@digitalmars.com).

Until we use that information for more efficient initialization we should probably warn about that = void on a struct field has no effect.
Comment 7 anonymous4 2017-08-25 10:06:50 UTC
*** Issue 15951 has been marked as a duplicate of this issue. ***
Comment 8 anonymous4 2017-08-25 10:06:58 UTC
*** Issue 11817 has been marked as a duplicate of this issue. ***
Comment 9 johanengelen 2018-05-24 19:49:46 UTC
Assignment with T.init is used to remove dangling pointers after destruction: https://github.com/dlang/druntime/blob/54ab96e9977e0c6baa7ed9740810058fd4aec6ef/src/object.d#L3082-L3098
So if spec is changed/clarified on this issue, we probably need to change/fix that code too. (if there isn't already, we need help from traits to figure out which members are =void, such that we can zero them explicitly)
Comment 10 dlangBugzillaToGithub 2024-12-13 18:13:17 UTC
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/dmd/issues/18702

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB