D 2.0 - dalegates to function

Frits van Bommel fvbommel at REMwOVExCAPSs.nl
Thu Mar 1 03:43:18 PST 2007


sergk wrote:
> Perhaps it's time to to bump an old request postponed to 2.0 times =)
> 
> So, how about to add some thunking magic - how  complex/complicated to implement it?

(I'll be assuming an x86 for this post, and DMD. x86 because that's the 
assembler language I know (as well as the only architecture DMD runs 
on), and DMD because that's the calling convention documented at 
http://www.digitalmars.com/d/abi.html. Portability concerns are noted at 
the end)

Did you mean converting delegates to function pointers (without an 
explicit this pointer) or creating delegates to functions?

I think both can be implemented efficiently[1], perhaps even in library 
space. AFAIK it can't be done in an entirely generic fashion in the 
current though.
The big problem currently is detection of out/inout parameters, and 
specifically whether the last parameter is one.


[1]: Meaning: without re-pushing parameters.


Pseudo-code for creating a delegate that calls a regular function:
===
dg.ptr = &func;
static if (Parameters.length > 0 && "last parameter fits in EAX but is 
not 3 bytes large") {
     dg.funcptr = RetType function(Parameters) {
         asm {
             naked;
             pop ECX;      // return address
             mov EDX, EAX; // move function pointer out of the way
             pop EAX;      // last parameter must be in EAX
             push ECX;     // restore return address
             jmp [EDX];    // jump directly to function entry point
         }
     }
} else {
     dg.funcptr = RetType function(Parameters) {
         asm {
             naked;
             jmp [EAX];
         }
     }
}
===
We need to know whether the last parameter is out/inout to implement the 
static if(); if it wouldn't normally be passed in EAX but is out or 
inout it's still in there.
This is a reduced variant of the "perfect forwarding" problem (which 
requires that knowledge for all parameters). IIRC Andrei made some posts 
about how they're going to try to fix that one. Once that's done the 
above should be feasible.



Converting delegates to function pointers:
This could be done by heap-allocating a stub that loads EAX with the 
correct value and then performs the right jump. This would have to be 
done such that both of those values (the EAX parameter and the function 
address) are correctly aligned in the code (so the gc can see them); nop 
instructions may be needed here.
The heap-allocated code could look something like this (pseudo-asm):
===
asm {
     naked;
     static if(last param is in EAX) {
         pop ECX;  // pop return address
         push EAX; // push last parameter on stack
         push ECX; // restore return address
     }
     // some NOPs for alignment perhaps
     mov EAX, dword 0x........
     // some more NOPs?
     jmp 0x........
}
===
Where the "0x........" parts are filled at runtime.


Notes and warnings:
* First of all, above code is completely untested and written directly 
to this mail window. Use at own risk ;).
* This code assumes both the delegate and the function pointer have the 
same calling convention, and that it's the one used by DMD on x86. 
Different code will have to be written for other architectures, calling 
conventions and (if it's even possible) cross-calling-convention conversion.
* The second code sample assumes the heap is mapped with execute 
permission, which may be a non-portable assumption. For one thing, IIRC 
amd64 (aka x86-64) has an optional no-execute (NX) flag for memory pages 
that would break this; on OSs that use this for heap pages system calls 
would be required to disable this flag.
* It also assumes the instructions are encodable such that the 
"0x........" parts look like regular pointers to the GC (i.e. absolute 
addresses). This may be a non-portable assumption as well, I'm not even 
  sure x86 allows this (I think so though). An alternative would be for 
the GC to recognize such stubs and special-case them.



More information about the Digitalmars-d mailing list