I am developing a VM and I would like to make it possible to call compiled functions. However, because every function may end up having a different signature, my plan is to generalize all calls to 2 possible scenarios - a call for function with no return and no parameters, and a call to a function which takes one void *
parameter.
The plan is to use it similarly to thiscall
- all parameters are properly aligned at the location of the passed pointer and parameters are retrieved through indirection. Shouldn't be slower than reading them from the stack, at least IMO.
So instead of:
int foo(int a, int b) { return a+b; }
I can have something like:
void foo2(void *p) {
*(int*)p = *(int*)(p + 4) + *(int*)(p + 8);
}
So my question is what could potentially go wrong using this approach? What I can tell right away is it works "in the dark" so it would be crucial to calculate the offsets correctly. It is also a little inconvenient since all the temporaries need to be provided by the user. Assuming my VM compiler will deal with those two issues, I am mostly concerned about performance - I don't want to create a normal function and for each normal function a void *
wrapper - I would like to directly use that convention for all functions, so I can't help but wonder how good of a job will the compiler do of inlining the functions when used in compiled code? Are there going to be any other possible performance implications I am overlooking (excluding __fastcall
which will use one more register and one less indirection)?
After running a few benchmarks I'd say the compiler does a pretty good job of optimizing similar pointer functions. The void *
function is just as fast as the add
function and the regular +
operator.
It seems that this convention will be useful to provide the necessary calling abstraction without hurting optimizations and overall performance. The only sacrifice is safety, which may or may not be a primary concern depending on the application context.