July 23, 2020
On Thursday, 23 July 2020 at 05:12:30 UTC, Walter Bright wrote:
> The compiler already does this if the variable being new`d is `scope`.

Yeah, I know, I just want to make sure that this doesn't change and that the spec is written to allow it.

Right now, the spec says:

"NewExpressions are used to allocate memory on the garbage collected heap (default) or using a class or struct specific allocator.

[...]

If a NewExpression is used as an initializer for a function local variable with scope storage class, and the ArgumentList to new is empty, then the instance is allocated on the stack rather than the heap or using the class specific allocator. "


So it arguably is a violation of the spec to use stack optimization without the scope keyword, and vice versa. It should really just specify it allocates and initializes the class while leaving where it does it as implementation-defined.


When lowering to a template, it should also be careful to say it will not necessarily lower to the same thing; a user should NOT expect the template to actually even be called and the template is free to change its strategy.


So the implementation right now is ok and I expect the lowering to a template will be equally OK. Just be careful not to specify too much.
July 23, 2020
On Thursday, 23 July 2020 at 00:47:21 UTC, Andrei Alexandrescu wrote:
> Was thinking about this, see https://issues.dlang.org/show_bug.cgi?id=21065.
>
> One problem I noticed with the current instrumentation of allocations is that it is extremely slow. https://github.com/dlang/dmd/pull/11381 takes care of that trivially and quickly because it takes advantage of defining one static variable per instantiation.

How does this fit in with plans for std.experimental.allocator? What are the current plans for std.experimental.allocator?
July 23, 2020
On Thursday, 23 July 2020 at 12:16:55 UTC, Per Nordlöw wrote:
> I actually see 3 (instead of 2) kinds of allocations here:
>
> 1. GC: destruction during `GC.collect()`
> 2. C/C++-style heap: (too large to fit on stack) scoped destruction (could be inferred?)

The passing of the unittest in the following module verifies that `scope`-qualified class variables are destructed when they go out of scope even when the GC is disabled. Nice. If the scope qualfifier is removed from `x` then the unittest fails as expected.


/** Test how destruction of scoped classes is handled.
 *
 * See_Also:
 */
module scoped_class_dtor;

bool g_dtor_called = false;

class C
{
@safe nothrow @nogc:
    this(int x) { this.x = x; }
    ~this() { g_dtor_called = true; }
    int x;
}

void scopedC() @safe nothrow
{
    scope x = new C(42);
}

unittest
{
    import core.memory : GC;
    GC.disable();
    scopedC();
    assert(g_dtor_called);
    GC.enable();
}


Does this mean that the allocation of `scope`d classes is done on a thread-local heap separate from the GC-heap? I would be nice to get a reference to the places in dmd and/or druntime were this logic is defined.
July 23, 2020
On Thursday, 23 July 2020 at 00:47:21 UTC, Andrei Alexandrescu wrote:
> Was thinking about this, see https://issues.dlang.org/show_bug.cgi?id=21065.
>
> One problem I noticed with the current instrumentation of allocations is that it is extremely slow. https://github.com/dlang/dmd/pull/11381 takes care of that trivially and quickly because it takes advantage of defining one static variable per instantiation.

As Mathias has already point out in your issue.
You are instantiating more templates.

In the _worst_ case this can almost double the number of template instances.
I.E. when the new is inside a template itself.

What do you envision the prototype to be like, and why couldn't that be just a function call to the runtime if a hook exists?

July 23, 2020
On Thursday, 23 July 2020 at 18:51:33 UTC, Stefan Koch wrote:
> In the _worst_ case this can almost double the number of template instances.
> I.E. when the new is inside a template itself.

There should be only one new instance per type, and it should be trivially inlined....
July 23, 2020
On Thursday, 23 July 2020 at 19:57:25 UTC, Adam D. Ruppe wrote:
> On Thursday, 23 July 2020 at 18:51:33 UTC, Stefan Koch wrote:
>> In the _worst_ case this can almost double the number of template instances.
>> I.E. when the new is inside a template itself.
>
> There should be only one new instance per type, and it should be trivially inlined....

It's anyone's guess how many types you actually have.
Template code tends to create a huge number of em.
July 23, 2020
On 7/23/20 2:15 AM, Petar Kirov [ZombineDev] wrote:
> On Thursday, 23 July 2020 at 06:13:52 UTC, Petar Kirov [ZombineDev] wrote:
>> On Thursday, 23 July 2020 at 05:12:30 UTC, Walter Bright wrote:
>>> On 7/22/2020 6:05 PM, Adam D. Ruppe wrote:
>>>> [...]
>>>
>>> The compiler already does this if the variable being new`d is `scope`.
>>
>> LDC has an optimization pass [1] which promotes heap allocations to stack allocations, without  the user having to manually use the `scope` storage class for function-local variables.
>> Do you think we could formalize this optimization and move it up the pipeline into the front-end, so that it's guaranteed to be performed by all 3 compilers?
>>
>> [1]: https://github.com/ldc-developers/ldc/blob/v1.23.0-beta1/gen/passes/GarbageCollect2Stack.cpp 
>>
> 
> ... building upon the infrastructure in src/dmd/escape.d

That'd be awesome. The user just types new Whatever and the compiler decides whether to lower or simply use the stack.
July 23, 2020
On 7/23/20 2:51 PM, Stefan Koch wrote:
> On Thursday, 23 July 2020 at 00:47:21 UTC, Andrei Alexandrescu wrote:
>> Was thinking about this, see https://issues.dlang.org/show_bug.cgi?id=21065.
>>
>> One problem I noticed with the current instrumentation of allocations is that it is extremely slow. https://github.com/dlang/dmd/pull/11381 takes care of that trivially and quickly because it takes advantage of defining one static variable per instantiation.
> 
> As Mathias has already point out in your issue.
> You are instantiating more templates.
> 
> In the _worst_ case this can almost double the number of template instances.
> I.E. when the new is inside a template itself.

Not a problem. We must go with templates all the way, it's been that way since the STL was created and there's no going back. All transformations of nonsense C-style crap into templates in object.d have been as many success stories. If anything there's too few templates in there.

When "new C" is issued everything is right there for the grabs - everything! The instance size, the alignment, the constructor to call. Yet what do we do? We gladly throw all that on the floor to call a crummy C function that uses indirect access to get access to those. No wonder -trace=gc is so slow. This entire inefficient pomp and circumstance around creating an object is an embarrassment.

To say nothing about built-in hash tables. It's 2020 and we still use an indirect call for each comparison, right? We should make a vow to fix that until the next Pandemic.

> What do you envision the prototype to be like, and why couldn't that be just a function call to the runtime if a hook exists?

In the simplest form:

template __new_instance(C)
if (is(C == class))
{
    static foreach (all overloads of __ctor in C)
    {
        C __new_instance(__appropriate__parameter__set)
        {
            ...
        }
    }
}

This would be a terrific opportunity to fix the perfect forwarding problem.

Further improvements: use introspection to detect if the class defines its own __new_instance, and if it does, defer to it. That way the deprecated feature per-class new makes a comeback the right way.
July 23, 2020
On 7/23/20 9:34 AM, jmh530 wrote:
> On Thursday, 23 July 2020 at 00:47:21 UTC, Andrei Alexandrescu wrote:
>> Was thinking about this, see https://issues.dlang.org/show_bug.cgi?id=21065.
>>
>> One problem I noticed with the current instrumentation of allocations is that it is extremely slow. https://github.com/dlang/dmd/pull/11381 takes care of that trivially and quickly because it takes advantage of defining one static variable per instantiation.
> 
> How does this fit in with plans for std.experimental.allocator? What are the current plans for std.experimental.allocator?

Allocators need a champion. Ideally a good integration with the GC would be achieved but I'm not a GC expert and don't have the time to dedicate to it.

As far as I know there's little use of allocators, which is unlike C++ where there's a lot of excitement around them in spite of a much scarcer API. I recall there's a little use of allocators (copied to code.dlang.org and improved) in Mir. Not much else I've heard of.

I was hoping there'd be a lot of experimentation accumulating with new allocators by now, for example to this day I have no idea whether FreeTree is any good. (It never rebalances, but I thought I'd wait until someone says the trees get lopsided... still waiting).
July 24, 2020
On Friday, 24 July 2020 at 03:23:07 UTC, Andrei Alexandrescu wrote:
> On 7/23/20 2:51 PM, Stefan Koch wrote:
>> In the _worst_ case this can almost double the number of template instances.
>> I.E. when the new is inside a template itself.
>
> Not a problem. We must go with templates all the way, it's been that way since the STL was created and there's no going back. All transformations of nonsense C-style crap into templates in object.d have been as many success stories. If anything there's too few templates in there.
>
> When "new C" is issued everything is right there for the grabs - everything! The instance size, the alignment, the constructor to call. Yet what do we do? We gladly throw all that on the floor to call a crummy C function that uses indirect access to get access to those. No wonder -trace=gc is so slow. This entire inefficient pomp and circumstance around creating an object is an embarrassment.

Yes, I have wished many times that the call to druntime for newing an object was templated. For one that makes it easier to do without TypeInfo, but in general it gives more control.