On Tue, 02 Mar 2010 21:02:51 -0500, Lionello Lunesu
<[email protected]> wrote:
The following has been discussed for years, and the biggest problem
(years ago) was that it was too late to change the D (1) ABI.
Is the D2 ABI compatible with D1? Should it be? If not, please consider
the following change:
alias void delegate() action_d;
void Callback() { } // global
action_d = &Callback; // should work
A function should be assignable to a delegate (but not vice versa*.)
This can work, since the code invoking the delegate will end up calling
the function with a context pointer ("this") in a register that's simply
ignored by the code in the function.
Except this also effects member functions, nested functions, etc.
This is fairly easy too: the calling convention for functions and
delegates should be identical, except for the context pointer, which
should be stored in a register that's unused in the function calling
convention.
This breaks the synergy of returns in EAX and params in EAX.
The reason for this change is that many times classes expose delegates
for callbacks, but it's impossible to bind a function to those
delegates. The code above can easily be made to compile:
action_d = { Callback(); }; //wrapped, works
but causes a dummy function to be called, only because the parameter
ABI's don't overlap:
_D1t4mainFZi12__dgliteral1MFZi comdat ;delegate literal
assume CS:_D1t4mainFZi12__dgliteral1MFZi
L0: push EAX
call near ptr _D1t8FunctionFZi ;global function
pop ECX
ret
_D1t4mainFZi12__dgliteral1MFZi ends
Of course, all of this applies to extern "D" code only.
* Binding a delegate to a function pointer will always need a (dynamic)
thunk, because the function will have been invoked without any context
pointer and it's the thunk's responsibility to assign the correct
context pointer.
It would be fairly easy for D (or anyone else) to implicitly define a
simple adapter that stores the function pointer in the delegate's this
pointer. The adapter function pointer points to one of two common stub
functions which either calls the this pointer or pops a value off the
stack into EAX and then calls the this pointer.