On Monday, 15 May 2017 at 10:41:55 UTC, ag0aep6g wrote:
TL;DR: Changing the ABI of delegates so that the context
pointer is passed last would make functions implicitly
convertible to delegates, no?
In the discussion of issue 17156 [1], Eyal asks why functions
(function pointers?) don't convert implicitly to delegates.
Walter's answer is that their ABIs differ and that a wrapper
would have to be generated to treat a function transparently as
a delegate.
As far as I understand, the problem is that the hidden context
pointer of a delegate takes the first register, pushing the
other parameters back. That means the visible arguments are
passed in different registers than when calling a function.
Some code to show this:
----
void delegate(int a, int b) dg;
void f(int a, int b) { import std.stdio; writeln(a, " ", b); }
void main()
{
dg.funcptr = &f; /* This line should probably not compile,
but that's
another story. */
dg.ptr = cast(void*) 13;
f(1, 2); /* prints "1 2" - no surprise */
dg(1, 2); /* prints "2 13" */
}
----
Arguments are put into registers in reverse order. I.e., in a
sense, the call `f(1, 2)` passes (2, 1) to f. And the call
`dg(1, 2)` passes (13, 2, 1), because a delegate has a hidden
last parameter: the context pointer. But `f` isn't compiled
with such a hidden parameter, so it sees 13 in `b` and 2 in
`a`. The register that holds 1 is simply ignored because
there's no corresponding parameter.
Now, what if we changed the ABI of delegates so that the
context pointer is passed after the explicit arguments? That
is, `dg(1, 2)` would pass (2, 1, 13). Then `f` would see 2 in b
and 1 in a. It would ignore 13. Seems everything would just
work then.
This seems quite simple. But I'm most probably just too
ignorant to see the problems. Why wouldn't this work? Maybe
there's a reason why the context pointer has to be passed first?
[1] https://issues.dlang.org/show_bug.cgi?id=17156
First of all, please don't forget that we're not only targeting
X86, and that the args, according to the docs, shouldn't actually
be reversed (incl. extern(D) - just on Win32, everywhere else the
C ABI is to be followed).
Then some ABIs, like Microsoft's, treat ` this` in a special way,
not just like any other argument (in combination with
struct-return), which would apply to method calls via a delegate
with context = object reference.
Some additional context: https://github.com/dlang/dmd/pull/5232