Before it's too late: delegate calling convention
Gregor Richards
Richards at codu.org
Wed Nov 1 14:47:49 PST 2006
Burton Radons wrote:
> Gregor Richards wrote:
>
>> And a solution that's less nasty: Allow casting of function pointers
>> to delegate pointers by automatic thunktion generation.
>
>
> And vice versa, they'd actually be very simple with D. As a matter of
> fact...
>
> void thunk_delegate_to_function_args () { asm { naked; mov ECX, EAX;
> mov EAX, [ESP+4]; jmp ECX; } }
> void thunk_delegate_to_function_noargs () { asm { naked; jmp EAX; } }
>
> template ThunkBase (From, To, bool HasArgs)
> {
> To ThunkBase (From from)
> {
> size_t thunk_length;
> ubyte [] data;
> size_t pos;
> To to;
>
> void add (ubyte [] stuff...) { data [pos .. pos +
> stuff.length] = stuff; pos += stuff.length; }
>
> static if (from.sizeof == 4)
> {
> union Delegate { struct { void *data, func; } To result; }
> Delegate output;
>
> output.data = from;
> static if (HasArgs)
> output.func = &thunk_delegate_to_function_args;
> else
> output.func = &thunk_delegate_to_function_noargs;
> return output.result;
> }
> else
> {
> static assert (to.sizeof == 4);
>
> union Delegate { struct { void *self, func; } From all; }
> Delegate fromd;
>
> fromd.all = from;
>
> thunk_length = 10 + 13;
> data = new ubyte [thunk_length];
>
> add (0x8B, 0x0C, 0x24, 0x83, 0xEC, 0x04, 0x89, 0x0C,
> 0x24, 0x89, 0x44, 0x24, 0x04); // mov ECX, [ESP+0]; sub ESP, 4; mov
> [ESP+0], ECX; mov [ESP+4], EAX;
> add (0xB8); add ((cast (ubyte *) &fromd.self) [0 .. 4]);
> // mov EAX, from.this;
>
> int offset = cast (int) (cast (void *) fromd.func -
> (cast (void *) data + pos + 5));
> add (0xE9); add ((cast (ubyte *) &offset) [0 .. 4]);
>
> return cast (To) data.ptr;
> }
> }
> }
>
> /// Convert a delegate into a function or vice versa.
> struct Thunk (ReturnType, A = void, B = void, C = void, D = void, E
> = void, F = void, G = void, H = void, I = void, J = void, K = void, L =
> void, M = void, N = void, O = void, P = void, Q = void, R = void, S =
> void, T = void, U = void, V = void, W = void, X = void, Y = void, Z = void)
> {
> static if (is (A == void)) { alias ReturnType delegate () TD;
> alias ReturnType function () TF; }
> else static if (is (B == void)) { alias ReturnType delegate (A)
> TD; alias ReturnType function (A) TF; }
> else static if (is (C == void)) { alias ReturnType delegate (A,
> B) TD; alias ReturnType function (A, B) TF; }
> else static if (is (D == void)) { alias ReturnType delegate (A,
> B, C) TD; alias ReturnType function (A, B, C) TF; }
> else static if (is (E == void)) { alias ReturnType delegate (A,
> B, C, D) TD; alias ReturnType function (A, B, C, D) TF; }
> else static if (is (F == void)) { alias ReturnType delegate (A,
> B, C, D, E) TD; alias ReturnType function (A, B, C, D, E) TF; }
> else static if (is (G == void)) { alias ReturnType delegate (A,
> B, C, D, E, F) TD; alias ReturnType function (A, B, C, D, E, F) TF; }
> else static if (is (H == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G) TD; alias ReturnType function (A, B, C, D, E, F, G) TF; }
> else static if (is (I == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H) TD; alias ReturnType function (A, B, C, D, E, F, G,
> H) TF; }
> else static if (is (J == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I) TD; alias ReturnType function (A, B, C, D, E, F,
> G, H, I) TF; }
> else static if (is (K == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J) TD; alias ReturnType function (A, B, C, D, E,
> F, G, H, I, J) TF; }
> else static if (is (L == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K) TD; alias ReturnType function (A, B, C, D,
> E, F, G, H, I, J, K) TF; }
> else static if (is (M == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K, L) TD; alias ReturnType function (A, B, C,
> D, E, F, G, H, I, J, K, L) TF; }
> else static if (is (N == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K, L, M) TD; alias ReturnType function (A, B,
> C, D, E, F, G, H, I, J, K, L, M) TF; }
> else static if (is (O == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K, L, M, N) TD; alias ReturnType function (A,
> B, C, D, E, F, G, H, I, J, K, L, M, N) TF; }
> else static if (is (P == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K, L, M, N, O) TD; alias ReturnType function
> (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) TF; }
> else static if (is (Q == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) TD; alias ReturnType
> function (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) TF; }
> else static if (is (R == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q) TD; alias ReturnType
> function (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q) TF; }
> else static if (is (S == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) TD; alias ReturnType
> function (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) TF; }
> else static if (is (T == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S) TD; alias
> ReturnType function (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
> R, S) TF; }
> else static if (is (U == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T) TD; alias
> ReturnType function (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
> R, S, T) TF; }
> else static if (is (V == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U) TD; alias
> ReturnType function (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
> R, S, T, U) TF; }
> else static if (is (W == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V) TD; alias
> ReturnType function (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
> R, S, T, U, V) TF; }
> else static if (is (X == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W) TD;
> alias ReturnType function (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
> P, Q, R, S, T, U, V, W) TF; }
> else static if (is (Y == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X) TD;
> alias ReturnType function (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
> P, Q, R, S, T, U, V, W, X) TF; }
> else static if (is (Z == void)) { alias ReturnType delegate (A,
> B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y)
> TD; alias ReturnType function (A, B, C, D, E, F, G, H, I, J, K, L, M, N,
> O, P, Q, R, S, T, U, V, W, X, Y) TF; }
> else { alias ReturnType delegate (A, B, C, D, E, F, G, H, I, J,
> K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z) TD; alias ReturnType
> function (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U,
> V, W, X, Y, Z) TF; }
>
>
> static if (!is (A == void) && A.sizeof <= 4 && !is (A == float))
> const bool hasargs = true;
> else
> const bool hasargs = false;
>
> static TD opCall (TF from)
> {
> return ThunkBase! (TF, TD, hasargs) (from);
> }
>
> static TF opCall (TD from)
> {
> return ThunkBase! (TD, TF, hasargs) (from);
> }
> }
>
> Use like:
>
> int zambo (float a, float b) { writef ("Hello %s, %s!\n", a, b); }
> alias Thunk! (int, float, float) thunker;
> auto rambo = thunker (zambo);
> rambo (16, 32);
>
> Note that casting a function to a delegate doesn't even require an
> allocation, it's just a matter of choosing the right wrapper.
>
> Not tested thoroughly since I don't care, it'll likely fail like crazy
> if you do bad things to it.
It's also DMD-with-D-calling-convention-specific X_X
(eg: won't work with GDC, won't work with C functions)
- Gregor Richards
More information about the Digitalmars-d
mailing list