4 ms·
The D language's nested functions are implemented with a static link and a dynamic link. You're all familiar with the dynamic link, which is a pointer to the ca
by WalterBright 1mo ago
The D language's nested functions are implemented with a static link and a dynamic link. You're all familiar with the dynamic link, which is a pointer to the calling function's stack frame (EBP on x86_64 processors). The static link is the interesting one, it is a pointer to the statically enclosing stack frame.
Thus, to access stack variables two enclosing functions up, the static link is walked twice.
A reference to a nested function in D is represented by a pair - a pointer to the function, and the static link. (Called a "delegate" in D parlance.) Interestingly, this is the same layout as taking a reference to a member function, where the "this" pointer takes the place of the static link.
This means that references to nested functions are ABI compatible with references to member functions.
Lambdas in D are just a more compact syntax for nested functions.
- hirvi74 1mo agoIsn't it RBP the 64-bit register?
- WalterBright 1mo agoYes. My mistake.
- ack_complete 1mo agoSadly, I've never seen a C++ compiler use this (old) technique for lambda reference captures. The main compilers all seem to just use individual references for each capture instead of a single reference to the stack frame, which makes the lambdas with a lot of reference captures more expensive.
- gpderetta 1mo agoThings get complicated when a lambda that capture by reference is capturing things that are not on a single stack frame (or a stack frame at all). Then you have references to references. You could rely on the optimizer, but the capture has ABI implications.
- account42 1mo agoDoes ABI really matter when the lambda is always compiled in the same translation unit as the function from which variables are captured? Seems to me that compilers should be free to optimize the simple cases to a single stack frame reference while falling back to whatever for others.
- jcranmer 1mo agoYes, it does. The lambda still needs to follow the C++ object model in case someone might use it like a regular C++ object. It's possible to change the ABI with escape analysis that proves you know all of the uses of the lambda to change the ABI, but a) that escape analysis is surprisingly easily defeated [1] and b) ABI-changing optimizations tend to be much more common in research papers than production compilers because getting them right on real code is a lot more difficult than it looks. [1] The lambda function probably has the same linkage as the function the lambda is contained in, which likely isn't "the only copy of this function is in this TU" but rather "this function may appear in several TUs, but all of these copies are equivalent and you can pick whichever one you like as the actual body." Very different opportunities there!
- yvdriess 1mo agoI really like languages that embrace the duality of "closures are a poor man's object, objects are a poor man's closure".