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

Reply via email to