Thread overview
Delegate Memory Usage & Optimization
Dec 12, 2013
Walter Bright
Dec 12, 2013
Manu
Dec 12, 2013
Manu
Dec 12, 2013
Timon Gehr
Dec 12, 2013
Orvid King
December 12, 2013
I have a use case where I will need to generate millions (possibly hundreds of millions) of delegates with the same type signature. I'd like to know more about the memory usage characteristics. I have two questions:

1. Delegates have environment/context pointer. If the delegate does not capture/access any variables from the englobing function (if it behaves like a static nested function), will a context object be allocated anyways, or will this pointer be null? Does DMD optimize this case?

2. Delegates are a function pointer and an environment pointer. Are they passed/stored by value, as a struct would be, or heap allocated and passed by reference?
December 12, 2013
On 12/11/2013 6:27 PM, Maxime Chevalier-Boisvert wrote:
> I have a use case where I will need to generate millions (possibly hundreds of
> millions) of delegates with the same type signature. I'd like to know more about
> the memory usage characteristics. I have two questions:
>
> 1. Delegates have environment/context pointer. If the delegate does not
> capture/access any variables from the englobing function (if it behaves like a
> static nested function), will a context object be allocated anyways,

No.


> or will this pointer be null?

No. It'll be a pointer to the enclosing stack frame, even if it is never used.


> Does DMD optimize this case?

Yes. It only allocates a closure if (1) it thinks the delegate may escape the scope and (2) uplevel references are used in the delegate.


> 2. Delegates are a function pointer and an environment pointer. Are they
> passed/stored by value, as a struct would be,

Yes.


> or heap allocated and passed by reference?

No.

I strongly suggest trying out a couple examples, and disassembling the result to confirm.

December 12, 2013
> It only allocates a closure if (1) it thinks the delegate may escape the scope and (2) uplevel references are used in the delegate.

The delegate will escape the enclosing scope. I'm wondering if there will still be some kind of scope object allocated to represent escaping values in the englobing stack frame, even when there are no escaping values.

I don't mind paying the small cost of an extraneous null context pointer, but having a whole unnecessary context object allocated seems wasteful.

> I strongly suggest trying out a couple examples, and disassembling the result to confirm.

I'll look into that.
December 12, 2013
On 12 December 2013 13:45, Maxime Chevalier-Boisvert < maximechevalierb@gmail.com> wrote:

> It only allocates a closure if (1) it thinks the delegate may escape the
>> scope and (2) uplevel references are used in the delegate.
>>
>
> The delegate will escape the enclosing scope. I'm wondering if there will still be some kind of scope object allocated to represent escaping values in the englobing stack frame, even when there are no escaping values.
>
> I don't mind paying the small cost of an extraneous null context pointer, but having a whole unnecessary context object allocated seems wasteful.


If you have no use for the context pointer, then it sounds like what you want is a function pointer, not a delegate.

A delegate is just a function-ptr+context-ptr pair, it is a trivial struct
that is passed by value, the same as a dynamic array. The context pointer
may be to a stack frame (in case of a closure), or a class object (in the
case of a class method pointer).
If you intend a null context pointer (ie, function doesn't reference any
state), than what you really have is a function pointer, not a delegate.
You should use a function pointer instead.

Can you show your usage?

 I strongly suggest trying out a couple examples, and disassembling the
>> result to confirm.
>>
>
> I'll look into that.
>


December 12, 2013
On 12 December 2013 14:06, Manu <turkeyman@gmail.com> wrote:

> On 12 December 2013 13:45, Maxime Chevalier-Boisvert < maximechevalierb@gmail.com> wrote:
>
>> It only allocates a closure if (1) it thinks the delegate may escape the
>>> scope and (2) uplevel references are used in the delegate.
>>>
>>
>> The delegate will escape the enclosing scope. I'm wondering if there will still be some kind of scope object allocated to represent escaping values in the englobing stack frame, even when there are no escaping values.
>>
>> I don't mind paying the small cost of an extraneous null context pointer, but having a whole unnecessary context object allocated seems wasteful.
>
>
> If you have no use for the context pointer, then it sounds like what you want is a function pointer, not a delegate.
>
> A delegate is just a function-ptr+context-ptr pair, it is a trivial struct
> that is passed by value, the same as a dynamic array. The context pointer
> may be to a stack frame (in case of a closure), or a class object (in the
> case of a class method pointer).
> If you intend a null context pointer (ie, function doesn't reference any
> state), than what you really have is a function pointer, not a delegate.
> You should use a function pointer instead.
>

Oh sorry, I see. you just mean in some cases functions that don't access
state will be bound to your delegate.
It seems unusual to me for a function that doesn't access any state to
produce a delegate. Wouldn't it be static, or a free function in that case?

There are tricks to bind a free function to a delegate using a little
call-through stub. It sets the delegate function to a callthrough-stub
which internally casts 'this' to a 'function' and calls it with the same
arguments.
Don does it to bind static functions to delegates in his C++ FastDelegate
library. I wonder if there's a helper in phobos?
You can be sure when assigning functions to delegates in this way that
there will never be any associated state.

Can you show your usage?
>
>  I strongly suggest trying out a couple examples, and disassembling the
>>> result to confirm.
>>>
>>
>> I'll look into that.
>>
>
>


December 12, 2013
On Wed, 11 Dec 2013 22:16:08 -0600, Manu <turkeyman@gmail.com> wrote:

> On 12 December 2013 14:06, Manu <turkeyman@gmail.com> wrote:
>> On 12 December 2013 13:45, Maxime Chevalier-Boisvert <maximechevalierb@gmail.com> wrote:
>>>> It only allocates a closure if (1) it thinks the delegate may escape the scope and (2) uplevel references are used in the delegate.
>>>
>>> The delegate will escape the enclosing scope. I'm wondering if there will still be some kind of scope object allocated to represent escaping values in >>>the englobing stack frame, even when there are no escaping values.
>>>
>>> I don't mind paying the small cost of an extraneous null context pointer, but having a whole unnecessary context object allocated seems wasteful.
>>
>> If you have no use for the context pointer, then it sounds like what you want is a function pointer, not a delegate.
>>
>> A delegate is just a function-ptr+context-ptr pair, it is a trivial
>> struct that is passed by value, the same as a dynamic array. The
>> context pointer may be >>to a stack frame (in case of a closure), or a
>> class object (in the case of a class method pointer).
>> If you intend a null context pointer (ie, function doesn't reference
>> any state), than what you really have is a function pointer, not a
>> delegate. You >>should use a function pointer instead.
>
> Oh sorry, I see. you just mean in some cases functions that don't access
> state will be bound to your delegate.
> It seems unusual to me for a function that doesn't access any state to
> produce a delegate. Wouldn't it be static, or a free function in that
> case?
>
> There are tricks to bind a free function to a delegate using a little
> call-through stub. It sets the delegate function to a callthrough-stub
> which internally >casts 'this' to a 'function' and calls it with the
> same arguments.
> Don does it to bind static functions to delegates in his C++
> FastDelegate library. I wonder if there's a helper in phobos?
> You can be sure when assigning functions to delegates in this way that
> there will never be any associated state.
>
>> Can you show your usage?
>>
>>>> I strongly suggest trying out a couple examples, and disassembling the result to confirm.
>>>
>>> I'll look into that.
>>
>

Actually, you could simply use function pointers rather than delegates, and when you need to pass them as a delegate, pass them through std.functional.toDelegate, which, for a function pointer at least, utilizes a union to set the delegate's context pointer to null, and sets the function pointer to the one you've passed in.

December 12, 2013
I went ahead and wrote a little test program:

---------

import std.stdio;

alias int delegate() Dg;

Dg[] dgList;

Dg foo()
{
    auto f = delegate int()
    {
        return 0;
    };

    return f;
}

Dg bar()
{
    int n = 0;

    auto f = delegate int()
    {
        return n++;
    };

    return f;
}

void main()
{
    auto d0 = foo();
    writeln(d0.ptr);
    dgList ~= d0;

    auto d1 = bar();
    writeln(d1.ptr);
    dgList ~= d1;
}

---------

This outputs:

null
7F37305DDFF0

So it seems DMD optimizes this well, as I had hoped.
December 12, 2013
On 12/12/2013 05:16 AM, Manu wrote:
> Don does it to bind static functions to delegates in his C++
> FastDelegate library. I wonder if there's a helper in phobos?
> You can be sure when assigning functions to delegates in this way that
> there will never be any associated state.

std.functional.toDelegate