Sign in to follow this  
Licu

Registering pointers to class functions without asMETHOD

Recommended Posts

Licu    128
I'm currently trying to register class methods thru an interface (virtual table) to the engine script (because the engine script implementation can be any scripting engine, not necessarily AngelScript). For this reason I cannot use asMETHOD macro since the class of the function cannot be sent thru the interface. Now, one method could be to register with asCALL_CDECL_OBJFIRST (or OBJLAST) and use an additional function to encapsulate the real class function. But this will mean 2 function calls. I've read thru the AngelScript code and I saw the asSMethodPtr template that it is used by asMETHOD macro in order to cope with different platforms specifics. From what I understand all I need is a method to send the proper member function pointer and its correct size to the scripting engine. It seems that the size of the pointer is variable from one compiler/platform to another (for Visual C++ it seems to always be 4 bytes, the offset from “this” pointer). What I do is use the following function in the engine script interface:
void ScriptEngine::RegClassMbrFunc(const char *class_name, const char *decl, 
     const void *pnt_to_func_pnt, const size_t func_pnt_size)
{
   asUPtr func_ptr;
   asMemClear(&func_ptr, sizeof(func_ptr));
   asMemCopy(&func_ptr, pnt_to_func_pnt, func_pnt_size);

   angel_script_engine->RegisterObjectMethod(class_name, decl, 
      func_ptr, asCALL_THISCALL);
}

This function receives the pointer to the function pointer and its size and constructs the asUPtr without the use of the asMETHOD macro. One possible usage is:
   typedef void (MyClass::*class_func)();
   class_func p = (class_func)&MyClass::ClassFunc;
   script_engine->RegClassMbrFunc("MyClass", 
     "void f(string &in)", &p, sizeof(p));

What I need to ask is: Is this a portable (working for all platforms) solution? And second, why is the pointer size variable from one compiler to another? Is it not the offset from the “this” pointer (and always 4 bytes)? If this is a portable solution maybe you will consider adding it to the angel script interface as an additional method of registering class functions (with parameters: pointer to function pointer and pointer function size). Regards Adrian Licu Quad Software

Share this post


Link to post
Share on other sites
WitchLord    4678
Hi,

I cannot say if your solution is portable or not. It would seem to be basically the same thing that I do with asFUNCTION() and asMETHOD(), but it is possible that in converting the method pointer to void* you risk loosing some vital information, if the compiler lets you do that conversion at all.

The pointer size is not just variable between compiler to compiler, it can even be variable within the same compiler. Visual C++ uses 5 different sizes for method pointers, ranging from 4 to 20 bytes, depending on the type of the class and wether the compilation is for a 32bit processor or a 64bit processor.

For 32bit processors:

- normal class method: 4 bytes, the pointer points to the function implementation
- virtual class method: 4 bytes, the pointer points to a function stub that reads the virtual function table and jumps to the true function implementation
- virtual class method with multiple inheritance: 8 bytes, a function pointer, and an offset to the true virtual function table
- virtual class method with virtual inheritance: 12 bytes, a function pointer, and an offset to the true virtual function table, plus another offset to find the true object. One needed value is missing from this pointer type, since the MSVC++ compiler hardcodes it when the method is invoked
- class method for an unknown implementation: 16 bytes, the same as the virtual inheritance pointer, except that the missing value is now included.

On 64bit processors, an additional 4 bytes are needed, since all pointers are 64bit.

On GNUC the method pointer is always 8 bytes in size independently of the class type (I would think it is 12 bytes on 64bit processors but cannot say for sure). And they manage to keep all the important information in those 8 bytes. They use a trick where the least significant bit of the function pointer shows wether it is an address or an offset in the vftable.

If you are interested in more details, there is a really interesting article on the code project that explains everything you need: Member Function Pointers and the Fastest Possible C++ Delegates

Regards,
Andreas

Share this post


Link to post
Share on other sites
Licu    128
Hi Andreas,

Thanks for all the information, I really appreciate it.

About converting to void*, I'm not converting the function pointer, but a pointer to the pointer function ;) which is always a normal pointer.

Regards

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this