diff --git a/bridges/source/cpp_uno/gcc3_linux_intel/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_intel/cpp2uno.cxx index ca40321149b2..ccc31f10a407 100644 --- a/bridges/source/cpp_uno/gcc3_linux_intel/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_intel/cpp2uno.cxx @@ -68,7 +68,7 @@ void cpp2uno_call( if (pReturnTypeDescr) { - if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) + if (x86::isSimpleReturnType( pReturnTypeDescr )) { pUnoReturn = pReturnValue; // direct way for simple types } @@ -359,15 +359,39 @@ extern "C" typedef void (*PrivateSnippetExecutor)(); int const codeSnippetSize = 16; +#if defined (FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(MACOSX) +namespace +{ + PrivateSnippetExecutor returnsInRegister(typelib_TypeDescriptionReference * pReturnTypeRef) + { + //These archs apparently are returning small structs in registers, while Linux + //doesn't + PrivateSnippetExecutor exec=NULL; + + typelib_TypeDescription * pReturnTypeDescr = 0; + TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); + const bool bSimpleReturnStruct = x86::isSimpleReturnType(pReturnTypeDescr); + const sal_Int32 nRetSize = pReturnTypeDescr->nSize; + TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); + if (bSimpleReturnStruct) + { + exec = privateSnippetExecutorGeneral; // fills eax + if (nRetSize > 4) + exec = privateSnippetExecutorHyper; // fills eax/edx + } + return exec; + } +} +#endif + unsigned char * codeSnippet( unsigned char * code, sal_PtrDiff writetoexecdiff, sal_Int32 functionIndex, sal_Int32 vtableOffset, - typelib_TypeClass returnTypeClass) + typelib_TypeDescriptionReference * pReturnTypeRef) { - if (!bridges::cpp_uno::shared::isSimpleType(returnTypeClass)) { - functionIndex |= 0x80000000; - } PrivateSnippetExecutor exec; - switch (returnTypeClass) { + typelib_TypeClass eReturnClass = pReturnTypeRef ? pReturnTypeRef->eTypeClass : typelib_TypeClass_VOID; + switch (eReturnClass) + { case typelib_TypeClass_VOID: exec = privateSnippetExecutorVoid; break; @@ -381,13 +405,24 @@ unsigned char * codeSnippet( case typelib_TypeClass_DOUBLE: exec = privateSnippetExecutorDouble; break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: +#if defined (FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(MACOSX) + exec = returnsInRegister(pReturnTypeRef); + if (!exec) + { + exec = privateSnippetExecutorClass; + functionIndex |= 0x80000000; + } + break; +#endif case typelib_TypeClass_STRING: case typelib_TypeClass_TYPE: case typelib_TypeClass_ANY: case typelib_TypeClass_SEQUENCE: - case typelib_TypeClass_STRUCT: case typelib_TypeClass_INTERFACE: exec = privateSnippetExecutorClass; + functionIndex |= 0x80000000; break; default: exec = privateSnippetExecutorGeneral; @@ -455,7 +490,7 @@ unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( code = codeSnippet( code, writetoexecdiff, functionOffset++, vtableOffset, reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >( - member)->pAttributeTypeRef->eTypeClass); + member)->pAttributeTypeRef); // Setter: if (!reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >( @@ -464,7 +499,7 @@ unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( (s++)->fn = code + writetoexecdiff; code = codeSnippet( code, writetoexecdiff, functionOffset++, vtableOffset, - typelib_TypeClass_VOID); + NULL); } break; @@ -473,7 +508,7 @@ unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( code = codeSnippet( code, writetoexecdiff, functionOffset++, vtableOffset, reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( - member)->pReturnTypeRef->eTypeClass); + member)->pReturnTypeRef); break; default: diff --git a/bridges/source/cpp_uno/gcc3_linux_intel/share.hxx b/bridges/source/cpp_uno/gcc3_linux_intel/share.hxx index da2367ad172b..8a3e136bfb7b 100644 --- a/bridges/source/cpp_uno/gcc3_linux_intel/share.hxx +++ b/bridges/source/cpp_uno/gcc3_linux_intel/share.hxx @@ -88,6 +88,12 @@ void raiseException( //================================================================================================== void fillUnoException( __cxa_exception * header, uno_Any *, uno_Mapping * pCpp2Uno ); + +} + +namespace x86 +{ + bool isSimpleReturnType(typelib_TypeDescription * pTD, bool recursive = false); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/gcc3_linux_intel/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_intel/uno2cpp.cxx index 20ee018e46be..ad57cd60bc18 100644 --- a/bridges/source/cpp_uno/gcc3_linux_intel/uno2cpp.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_intel/uno2cpp.cxx @@ -59,7 +59,7 @@ void callVirtualMethod( void * pAdjustedThisPtr, sal_Int32 nVtableIndex, void * pRegisterReturn, - typelib_TypeClass eReturnType, + typelib_TypeDescription * pReturnTypeDescr, bool bSimpleReturn, sal_Int32 * pStackLongs, sal_Int32 nStackLongs ) __attribute__((noinline)); @@ -67,7 +67,7 @@ void callVirtualMethod( void * pAdjustedThisPtr, sal_Int32 nVtableIndex, void * pRegisterReturn, - typelib_TypeClass eReturnType, + typelib_TypeDescription * pReturnTypeDescr, bool bSimpleReturn, sal_Int32 * pStackLongs, sal_Int32 nStackLongs ) { @@ -120,8 +120,10 @@ void callVirtualMethod( : "m"(nStackLongs), "m"(pStackLongs), "m"(pAdjustedThisPtr), "m"(nVtableIndex), "m"(eax), "m"(edx), "m"(stackptr) : "eax", "edx" ); - switch( eReturnType ) + switch( pReturnTypeDescr->eTypeClass ) { + case typelib_TypeClass_VOID: + break; case typelib_TypeClass_HYPER: case typelib_TypeClass_UNSIGNED_HYPER: ((long*)pRegisterReturn)[1] = edx; @@ -146,7 +148,20 @@ void callVirtualMethod( asm ( "fstpl %0\n\t" : : "m"(*(char *)pRegisterReturn) ); break; default: + { +#if defined (FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(MACOSX) + sal_Int32 const nRetSize = pReturnTypeDescr->nSize; + if (bSimpleReturn && nRetSize <= 8 && nRetSize > 0) + { + if (nRetSize > 4) + static_cast(pRegisterReturn)[1] = edx; + static_cast(pRegisterReturn)[0] = eax; + } +#else + (void)bSimpleReturn; +#endif break; + } } } @@ -169,10 +184,12 @@ static void cpp_call( OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" ); void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion + bool bSimpleReturn = true; if (pReturnTypeDescr) { - if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) + bSimpleReturn = x86::isSimpleReturnType(pReturnTypeDescr); + if (bSimpleReturn) { pCppReturn = pUnoReturn; // direct way for simple types } @@ -269,7 +286,7 @@ static void cpp_call( OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" ); callVirtualMethod( pAdjustedThisPtr, aVtableSlot.index, - pCppReturn, pReturnTypeDescr->eTypeClass, + pCppReturn, pReturnTypeDescr, bSimpleReturn, (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) ); // NO exception occured... *ppUnoExc = 0; @@ -328,6 +345,38 @@ static void cpp_call( } +namespace x86 +{ + bool isSimpleReturnType(typelib_TypeDescription * pTD, bool recursive) + { + if (bridges::cpp_uno::shared::isSimpleType( pTD )) + return true; +#if defined (FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(MACOSX) + // Only structs of exactly 1, 2, 4, or 8 bytes are returned through + // registers, see : + if (pTD->eTypeClass == typelib_TypeClass_STRUCT && + (recursive || pTD->nSize <= 2 || pTD->nSize == 4 || pTD->nSize == 8)) + { + typelib_CompoundTypeDescription *const pCompTD = + (typelib_CompoundTypeDescription *) pTD; + for ( sal_Int32 pos = pCompTD->nMembers; pos--; ) { + typelib_TypeDescription * pMemberTD = 0; + TYPELIB_DANGER_GET( &pMemberTD, pCompTD->ppTypeRefs[pos] ); + bool const b = isSimpleReturnType(pMemberTD, true); + TYPELIB_DANGER_RELEASE( pMemberTD ); + if (! b) + return false; + } + return true; + } +#else + (void)recursive; +#endif + return false; + } +} + namespace bridges { namespace cpp_uno { namespace shared { void unoInterfaceProxyDispatch(