int DetectCallingConvention(bool isMethod, const asUPtr &ptr, int callConv, asSSystemFunctionInterface *internal) { memset(internal, 0, sizeof(asSSystemFunctionInterface)); internal->func = (size_t)ptr.f.func; asDWORD base = callConv; if( !isMethod ) { if( base == asCALL_CDECL ) internal->callConv = ICC_CDECL; else if( base == asCALL_STDCALL ) internal->callConv = ICC_STDCALL; else if( base == asCALL_GENERIC ) internal->callConv = ICC_GENERIC_FUNC; else return asNOT_SUPPORTED; } else { #ifndef AS_NO_CLASS_METHODS if( base == asCALL_THISCALL ) { internal->callConv = ICC_THISCALL; #ifdef GNU_STYLE_VIRTUAL_METHOD if( (size_t(ptr.f.func) & 1) ) internal->callConv = ICC_VIRTUAL_THISCALL; #endif internal->baseOffset = MULTI_BASE_OFFSET(ptr); #ifdef HAVE_VIRTUAL_BASE_OFFSET // We don't support virtual inheritance if( VIRTUAL_BASE_OFFSET(ptr) != 0 ) return asNOT_SUPPORTED; #endif } else #endif if( base == asCALL_CDECL_OBJLAST ) internal->callConv = ICC_CDECL_OBJLAST; else if( base == asCALL_CDECL_OBJFIRST ) internal->callConv = ICC_CDECL_OBJFIRST; else if( base == asCALL_GENERIC ) internal->callConv = ICC_GENERIC_METHOD; else return asNOT_SUPPORTED; } return 0; }
BEGIN_AS_NAMESPACE // ref: Member Function Pointers and the Fastest Possible C++ Delegates // describes the structure of class method pointers for most compilers // http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible // ref: The code comments for ItaniumCXXABI::EmitLoadOfMemberFunctionPointer in the LLVM compiler // describes the structure for class method pointers on Itanium and arm64 ABI // http://clang.llvm.org/doxygen/CodeGen_2ItaniumCXXABI_8cpp_source.html#l00937 int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *objForThiscall, asSSystemFunctionInterface *internal) { memset(internal, 0, sizeof(asSSystemFunctionInterface)); internal->func = ptr.ptr.f.func; internal->objForThiscall = 0; // Was a compatible calling convention specified? if( internal->func ) { if( ptr.flag == 1 && callConv != asCALL_GENERIC ) return asWRONG_CALLING_CONV; else if( ptr.flag == 2 && (callConv == asCALL_GENERIC || callConv == asCALL_THISCALL || callConv == asCALL_THISCALL_ASGLOBAL || callConv == asCALL_THISCALL_OBJFIRST || callConv == asCALL_THISCALL_OBJLAST) ) return asWRONG_CALLING_CONV; else if( ptr.flag == 3 && !(callConv == asCALL_THISCALL || callConv == asCALL_THISCALL_ASGLOBAL || callConv == asCALL_THISCALL_OBJFIRST || callConv == asCALL_THISCALL_OBJLAST) ) return asWRONG_CALLING_CONV; } asDWORD base = callConv; if( !isMethod ) { if( base == asCALL_CDECL ) internal->callConv = ICC_CDECL; else if( base == asCALL_STDCALL ) internal->callConv = ICC_STDCALL; else if( base == asCALL_THISCALL_ASGLOBAL ) { if( objForThiscall == 0 ) return asINVALID_ARG; internal->objForThiscall = objForThiscall; internal->callConv = ICC_THISCALL; // This is really a thiscall, so it is necessary to check for virtual method pointers base = asCALL_THISCALL; isMethod = true; } else if( base == asCALL_GENERIC ) internal->callConv = ICC_GENERIC_FUNC; else return asNOT_SUPPORTED; } if( isMethod ) { #ifndef AS_NO_CLASS_METHODS if( base == asCALL_THISCALL || base == asCALL_THISCALL_OBJFIRST || base == asCALL_THISCALL_OBJLAST ) { internalCallConv thisCallConv; if( base == asCALL_THISCALL ) { if( callConv != asCALL_THISCALL_ASGLOBAL && objForThiscall ) return asINVALID_ARG; thisCallConv = ICC_THISCALL; } else { #ifdef AS_NO_THISCALL_FUNCTOR_METHOD return asNOT_SUPPORTED; #else if( objForThiscall == 0 ) return asINVALID_ARG; internal->objForThiscall = objForThiscall; if( base == asCALL_THISCALL_OBJFIRST ) thisCallConv = ICC_THISCALL_OBJFIRST; else //if( base == asCALL_THISCALL_OBJLAST ) thisCallConv = ICC_THISCALL_OBJLAST; #endif } internal->callConv = thisCallConv; #ifdef GNU_STYLE_VIRTUAL_METHOD if( (size_t(ptr.ptr.f.func) & 1) ) internal->callConv = (internalCallConv)(thisCallConv + 2); #endif internal->baseOffset = ( int )MULTI_BASE_OFFSET(ptr); #if defined(AS_ARM) && (defined(__GNUC__) || defined(AS_PSVITA)) // As the least significant bit in func is used to switch to THUMB mode // on ARM processors, the LSB in the __delta variable is used instead of // the one in __pfn on ARM processors. if( (size_t(internal->baseOffset) & 1) ) internal->callConv = (internalCallConv)(thisCallConv + 2); #endif #ifdef HAVE_VIRTUAL_BASE_OFFSET // We don't support virtual inheritance if( VIRTUAL_BASE_OFFSET(ptr) != 0 ) return asNOT_SUPPORTED; #endif } else #endif if( base == asCALL_CDECL_OBJLAST ) internal->callConv = ICC_CDECL_OBJLAST; else if( base == asCALL_CDECL_OBJFIRST ) internal->callConv = ICC_CDECL_OBJFIRST; else if( base == asCALL_GENERIC ) internal->callConv = ICC_GENERIC_METHOD; else return asNOT_SUPPORTED; } return 0; }