| Thread overview | |||||||
|---|---|---|---|---|---|---|---|
|
April 09, 2015 Understanding the D memory model re: Voldemort types | ||||
|---|---|---|---|---|
| ||||
I have a bit of confusion about the D memory model when it comes to returning nested classes (i.e. "Voldemort types") and am hoping someone can take a minute to clear it up. Consider the following short program:
auto foo()
{
import std.random;
import std.conv;
auto i = dice(0.5, 0.5);
string s = "Hello, scopes";
class Bar {
string what() { return s ~ " " ~ i.to!string; }
}
return new Bar;
}
void main()
{
import std.stdio;
auto b = foo();
writeln(b.what());
}
I was under the impression that nested classes captured their context via a pointer to the current stack frame. But if that were the case, reading i and s when b.what() is called would cause invalid reads below the current stack pointer, and this data could be thrashed by inserting any calls between the call to foo() and the call to b.what(). Running the above program through valgrind also indicates no foul play.
So what is actually going on here? Do nested classes capture their context some other way? Does the compiler do semantic analysis and capture local variables by value if an instance of the Voldemort type is going to get returned out of the function?
| ||||
April 09, 2015 Re: Understanding the D memory model re: Voldemort types | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Matt Kline | On Thu, Apr 09, 2015 at 06:08:17PM +0000, Matt Kline via Digitalmars-d wrote: [...] > auto foo() > { > import std.random; > import std.conv; > > auto i = dice(0.5, 0.5); > string s = "Hello, scopes"; > > class Bar { > string what() { return s ~ " " ~ i.to!string; } > } > > return new Bar; > } > > void main() > { > import std.stdio; > > auto b = foo(); > writeln(b.what()); > } > > I was under the impression that nested classes captured their context via a pointer to the current stack frame. But if that were the case, reading i and s when b.what() is called would cause invalid reads below the current stack pointer, and this data could be thrashed by inserting any calls between the call to foo() and the call to b.what(). Running the above program through valgrind also indicates no foul play. > > So what is actually going on here? Do nested classes capture their context some other way? Does the compiler do semantic analysis and capture local variables by value if an instance of the Voldemort type is going to get returned out of the function? The compiler detects when a variable is being closed over by a nested function, and allocates them on the heap instead of the stack. T -- Computerese Irregular Verb Conjugation: I have preferences. You have biases. He/She has prejudices. -- Gene Wirchenko | |||
April 09, 2015 Re: Understanding the D memory model re: Voldemort types | ||||
|---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Thursday, 9 April 2015 at 18:15:16 UTC, H. S. Teoh wrote:
> The compiler detects when a variable is being closed over by a nested
> function, and allocates them on the heap instead of the stack.
Is there somewhere I can read more about this (besides the compiler source code)? What ramifications are there for local variables being closed over that have destructors? Does the Voldemort object then get implicit destructor code that destroys the closed-over variables when it falls out of scope?
| |||
April 09, 2015 Re: Understanding the D memory model re: Voldemort types | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Matt Kline | On 4/9/15 2:23 PM, Matt Kline wrote: > On Thursday, 9 April 2015 at 18:15:16 UTC, H. S. Teoh wrote: > >> The compiler detects when a variable is being closed over by a nested >> function, and allocates them on the heap instead of the stack. > > Is there somewhere I can read more about this (besides the compiler > source code)? What ramifications are there for local variables being > closed over that have destructors? Does the Voldemort object then get > implicit destructor code that destroys the closed-over variables when it > falls out of scope? It's called a closure. It's not specific to voldemort types, it's done whenever you take a delegate that needs the context pointer to the stack. I believe destruction is performed on the stack frame data when the GC collects the stack frame. See here: http://dlang.org/function.html#closures In regards to voldemort types triggering a heap allocation of the stack frame, I can't find specific documentation on this, probably a good idea to add it. -Steve | |||
April 10, 2015 Re: Understanding the D memory model re: Voldemort types | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Matt Kline | On Thursday, 9 April 2015 at 18:23:31 UTC, Matt Kline wrote:
> Does the Voldemort object then get implicit destructor code that destroys the closed-over variables when it falls out of scope?
Closures may or may not be destroyed by GC. Such scenario used to be problematic, but there was some progress on it recently wrt support of struct destructors allocated on heap, though I don't know whether it affects closures.
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply