Before it's too late: delegate calling convention
Burton Radons
burton-radons at smocky.com
Wed Nov 1 13:42:59 PST 2006
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.
More information about the Digitalmars-d
mailing list